Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More tests #8

Merged
merged 4 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 24 additions & 21 deletions src/Embed/Embed.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,45 @@

namespace Hyvor\Unfold\Embed;

use Hyvor\Unfold\Embed\Exception\ParserException;
use Hyvor\Unfold\Embed\Exception\UnableToResolveEmbedException;
use Hyvor\Unfold\Embed\Platforms\Reddit;
use Hyvor\Unfold\Embed\Platforms\Tiktok;
use Hyvor\Unfold\Embed\Platforms\Twitter;
use Hyvor\Unfold\Embed\Platforms\Youtube;
use Hyvor\Unfold\UnfoldConfigObject;
//use Hyvor\Unfold\Embed\Platforms\GithubGist;
//use Hyvor\Unfold\Embed\Platforms\Reddit;
//use Hyvor\Unfold\Embed\Platforms\Tiktok;
//use Hyvor\Unfold\Embed\Platforms\Twitter;
//use Hyvor\Unfold\Embed\Platforms\Youtube;
use Hyvor\Unfold\Exception\EmbedUnableToResolveException;
use Hyvor\Unfold\Exception\EmbedParserException;
use Hyvor\Unfold\Exception\UnfoldException;
use Hyvor\Unfold\UnfoldCallContext;
use Hyvor\Unfold\UnfoldConfig;
use Hyvor\Unfold\Unfolded\Unfolded;
use Hyvor\Unfold\UnfoldException;
use Hyvor\Unfold\UnfoldMethod;
use Hyvor\Unfold\UnfoldCallContext;

class Embed
{

/**
* @var EmbedParserAbstract[]
* @return string[]
*/
public const PARSERS = [
Youtube::class,
Reddit::class,
Tiktok::class,
Twitter::class,
Reddit::class,
];
public static function getParsers(): array
{
$namespace = __NAMESPACE__ . '\\Platforms\\';
return array_map(
fn($file) => $namespace . pathinfo($file, PATHINFO_FILENAME),
glob(__DIR__ . '/Platforms/*.php')

Check failure on line 29 in src/Embed/Embed.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Parameter #2 $array of function array_map expects array, array<int, string>|false given.
);
}

/**
* @throws ParserException
* @throws EmbedParserException
*/
public static function parse(
string $url,
?UnfoldConfigObject $config = null,
?UnfoldConfig $config = null,
): ?EmbedResponseObject {
foreach (self::PARSERS as $parserClass) {
foreach (self::getParsers() as $parserClass) {
$parser = new $parserClass($url, $config);
if ($parser->match()) {

Check failure on line 42 in src/Embed/Embed.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Call to an undefined method object::match().
return $parser->parse();

Check failure on line 43 in src/Embed/Embed.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Call to an undefined method object::parse().
}
}
return null;
Expand All @@ -47,7 +50,7 @@
* @return $context->method is EmbedMethodEnum::EMBED ? Unfolded : ?Unfolded
* @throws UnfoldException
*/
public static function getUnfoldedObject(

Check failure on line 53 in src/Embed/Embed.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Method Hyvor\Unfold\Embed\Embed::getUnfoldedObject() has no return type specified.

Check failure on line 53 in src/Embed/Embed.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

PHPDoc tag @return has invalid value ($context->method is EmbedMethodEnum::EMBED ? Unfolded : ?Unfolded): Unexpected token "$context", expected type at offset 19
string $url,
UnfoldCallContext $context,
) {
Expand All @@ -55,7 +58,7 @@

if ($oembed === null) {
if ($context->method === UnfoldMethod::EMBED) {
throw new UnableToResolveEmbedException();
throw new EmbedUnableToResolveException();
} else {
return null;
}
Expand Down
50 changes: 36 additions & 14 deletions src/Embed/EmbedParserAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;
use Hyvor\Unfold\Embed\Exception\ParserException;
use Hyvor\Unfold\UnfoldConfigObject;
use Hyvor\Unfold\Exception\EmbedParserException;
use Hyvor\Unfold\Exception\UnfoldException;
use Hyvor\Unfold\UnfoldConfig;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;

Expand All @@ -15,13 +16,13 @@
*/
abstract class EmbedParserAbstract
{
protected UnfoldConfigObject $config;
protected UnfoldConfig $config;

public function __construct(
protected string $url,
?UnfoldConfigObject $config = null,
?UnfoldConfig $config = null,
) {
$this->config = $config ?? new UnfoldConfigObject();
$this->config = $config ?? new UnfoldConfig();
}


Expand Down Expand Up @@ -65,14 +66,25 @@
return false;
}

public function parse(): ?EmbedResponseObject
/**
* @throws UnfoldException
*/
public function parse(): EmbedResponseObject
{
$oEmbedUrl = $this->oEmbedUrl();

if (!$oEmbedUrl) {
// TODO: Check config option for fallback
return null;
if ($this instanceof EmbedParserOEmbedInterface) {
return $this->parseOEmbed();

Check failure on line 75 in src/Embed/EmbedParserAbstract.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Method Hyvor\Unfold\Embed\EmbedParserAbstract::parse() should return Hyvor\Unfold\Embed\EmbedResponseObject but returns Hyvor\Unfold\Embed\EmbedResponseObject|null.
} elseif ($this instanceof EmbedParserCustomInterface) {
return $this->parseCustom();
} else {
throw new \Exception(
'EmbedParserAbstract should be implemented with either EmbedParserOEmbedInterface or EmbedParserCustomInterface'
); // @codeCoverageIgnore
}
}

public function parseOEmbed(): ?EmbedResponseObject
{
$oEmbedUrl = $this->oEmbedUrl();

Check failure on line 87 in src/Embed/EmbedParserAbstract.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Call to an undefined method Hyvor\Unfold\Embed\EmbedParserAbstract::oEmbedUrl().

$uri = Uri::withQueryValues(
new Uri($oEmbedUrl),
Expand All @@ -97,7 +109,7 @@
try {
$response = $client->sendRequest($request);
} catch (ClientExceptionInterface $e) {
throw new ParserException(
throw new EmbedParserException(
"Failed to fetch oEmbed data from the endpoint",
previous: $e
);
Expand All @@ -107,18 +119,28 @@
$content = $response->getBody()->getContents();

if ($status !== 200) {
throw new ParserException(
throw new EmbedParserException(
"Failed to fetch oEmbed data from the endpoint. Status: $status. Response: $content"
);
}

$parsed = json_decode($content, true);

if (!is_array($parsed)) {
throw new ParserException("Failed to parse JSON response from oEmbed endpoint");
throw new EmbedParserException("Failed to parse JSON response from oEmbed endpoint");
}

return EmbedResponseObject::fromArray($parsed);
}

private function parseCustom()

Check failure on line 136 in src/Embed/EmbedParserAbstract.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Method Hyvor\Unfold\Embed\EmbedParserAbstract::parseCustom() has no return type specified.
{
$html = $this->getEmbedHtml();

Check failure on line 138 in src/Embed/EmbedParserAbstract.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Call to an undefined method Hyvor\Unfold\Embed\EmbedParserAbstract::getEmbedHtml().

return EmbedResponseObject::fromArray([
'type' => 'embed',
'html' => $html
]);
}

}
2 changes: 1 addition & 1 deletion src/Embed/EmbedParserOEmbedInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

interface EmbedParserOEmbedInterface
{
public function oEmbedUrl(): ?string;
public function oEmbedUrl(): string;

}
9 changes: 0 additions & 9 deletions src/Embed/Exception/ParserException.php

This file was deleted.

6 changes: 3 additions & 3 deletions src/Embed/Platforms/Instagram.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use GuzzleHttp\Psr7\Uri;
use Hyvor\Unfold\Embed\EmbedParserAbstract;
use Hyvor\Unfold\Embed\EmbedParserOEmbedInterface;
use Hyvor\Unfold\Embed\Exception\ParserException;
use Hyvor\Unfold\Exception\EmbedParserException;
use Psr\Http\Message\RequestInterface;

// TODO:
Expand All @@ -17,7 +17,7 @@ public function oEmbedRequestFilter(RequestInterface $request): RequestInterface
$facebookAccessToken = $this->config->facebookAccessToken;

if (!$facebookAccessToken) {
throw new ParserException('Facebook Access Token is required for Instagram embeds');
throw new EmbedParserException('Facebook Access Token is required for Instagram embeds');
}

$uri = Uri::withQueryValue($uri, 'access_token', $facebookAccessToken);
Expand Down Expand Up @@ -57,7 +57,7 @@ public function regex()
];
}

public function oEmbedUrl(): ?string
public function oEmbedUrl(): string
{
return 'https://graph.facebook.com/v16.0/instagram_oembed';
}
Expand Down
2 changes: 1 addition & 1 deletion src/Embed/Platforms/Reddit.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function regex()
];
}

public function oEmbedUrl(): ?string
public function oEmbedUrl(): string
{
return 'https://www.reddit.com/oembed';
}
Expand Down
5 changes: 3 additions & 2 deletions src/Embed/Platforms/Tiktok.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace Hyvor\Unfold\Embed\Platforms;

use Hyvor\Unfold\Embed\EmbedParserAbstract;
use Hyvor\Unfold\Embed\EmbedParserOEmbedInterface;

class Tiktok extends EmbedParserAbstract
class Tiktok extends EmbedParserAbstract implements EmbedParserOEmbedInterface
{
public function regex()
{
Expand All @@ -14,7 +15,7 @@ public function regex()
];
}

public function oEmbedUrl(): ?string
public function oEmbedUrl(): string
{
return 'https://www.tiktok.com/oembed';
}
Expand Down
2 changes: 1 addition & 1 deletion src/Embed/Platforms/Twitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function regex()
];
}

public function oEmbedUrl(): ?string
public function oEmbedUrl(): string
{
return 'https://publish.twitter.com/oembed';
}
Expand Down
2 changes: 1 addition & 1 deletion src/Embed/Platforms/Youtube.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function regex()
];
}

public function oEmbedUrl(): ?string
public function oEmbedUrl(): string
{
return 'https://www.youtube.com/oembed';
}
Expand Down
7 changes: 7 additions & 0 deletions src/Exception/EmbedParserException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Hyvor\Unfold\Exception;

class EmbedParserException extends UnfoldException
{
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<?php

namespace Hyvor\Unfold\Embed\Exception;
namespace Hyvor\Unfold\Exception;

use Hyvor\Unfold\UnfoldException;

class UnableToResolveEmbedException extends UnfoldException
class EmbedUnableToResolveException extends UnfoldException
{
public function __construct(string $message = "", int $code = 0, ?\Throwable $previous = null)

Check failure on line 7 in src/Exception/EmbedUnableToResolveException.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Constructor of class Hyvor\Unfold\Exception\EmbedUnableToResolveException has an unused parameter $message.
{
parent::__construct('Unable to resolve embed', $code, $previous);
}
Expand Down
8 changes: 8 additions & 0 deletions src/Exception/LinkScrapeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Hyvor\Unfold\Exception;

class LinkScrapeException extends UnfoldException
{

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Hyvor\Unfold;
namespace Hyvor\Unfold\Exception;

class UnfoldException extends \Exception
{
Expand Down
15 changes: 9 additions & 6 deletions src/Link/Link.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace Hyvor\Unfold\Link;

use GuzzleHttp\Psr7\Request;
use Hyvor\Unfold\Exception\LinkScrapeException;
use Hyvor\Unfold\Link\Metadata\MetadataParser;
use Hyvor\Unfold\UnfoldConfigObject;
use Hyvor\Unfold\UnfoldConfig;
use Hyvor\Unfold\Unfolded\Unfolded;
use Hyvor\Unfold\UnfoldCallContext;
use Psr\Http\Client\ClientExceptionInterface;
Expand All @@ -13,7 +14,7 @@ class Link
{
public function __construct(
private string $url,
private UnfoldConfigObject $config,
private UnfoldConfig $config,
) {
}

Expand All @@ -27,14 +28,16 @@ public function scrape(): string
try {
$response = $this->config->httpClient->sendRequest($request);
} catch (ClientExceptionInterface $e) {
//
throw new LinkScrapeException($e->getMessage());
}

$status = $response->getStatusCode();
$content = $response->getBody()->getContents();
// TODO:

return $response->getBody();
if ($status < 200 || $status >= 300) {
throw new LinkScrapeException("Unable to scrape link. HTTP status code: $status");
}

return $response->getBody()->getContents();
}


Expand Down
39 changes: 39 additions & 0 deletions src/Link/Metadata/MetadataKeyType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Hyvor\Unfold\Link\Metadata;

use Hyvor\Unfold\Unfolded\UnfoldedAuthor;
use Hyvor\Unfold\Unfolded\UnfoldedTag;

enum MetadataKeyType
{
case TITLE;
Expand Down Expand Up @@ -48,4 +51,40 @@ enum MetadataKeyType
case TWITTER_DESCRIPTION;
case TWITTER_TITLE;
case TWITTER_IMAGE;

/**
* Gets the value of the metadata from a given content string
* ex: article:published_time is converted to DateTimeInterface
*/
public function getValue(string $content)
{
if (
$this === MetadataKeyType::OG_ARTICLE_PUBLISHED_TIME ||
$this === MetadataKeyType::OG_ARTICLE_MODIFIED_TIME
) {
return MetadataParser::getDateTimeFromString($content);
}

if (
$this === MetadataKeyType::OG_ARTICLE_AUTHOR ||
$this === MetadataKeyType::TWITTER_CREATOR
) {
return $this->getAuthorFromString($content);
}

if ($this === MetadataKeyType::OG_ARTICLE_TAG) {
return new UnfoldedTag($content);
}

return $content;
}

private function getAuthorFromString(string $value): UnfoldedAuthor
{
if (str_contains($value, 'http://') || str_contains($value, 'https://')) {
return new UnfoldedAuthor(null, $value);
} else {
return new UnfoldedAuthor($value, null);
}
}
}
Loading
Loading