Skip to content
Open
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
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,29 @@ jobs:

- name: Tests
run: composer test

phpstan:
name: PHPStan Static Analysis
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4

- name: Cache PHP dependencies
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-8.4-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-php-8.4-composer-

- name: Install dependencies
run: composer install

- name: Run PHPStan
run: composer phpstan
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
"nyholm/psr7": "^1.2",
"oscarotero/php-cs-fixer-config": "^1.0",
"brick/varexporter": "^0.3.1",
"symfony/css-selector": "^5.0"
"symfony/css-selector": "^5.0",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-strict-rules": "^2.0"
},
"suggest": {
"symfony/css-selector": "If you want to get elements using css selectors"
Expand All @@ -64,6 +66,7 @@
"demo": "php -S localhost:8888 demo/index.php",
"test": "phpunit",
"cs-fix": "php-cs-fixer fix",
"phpstan": "phpstan --memory-limit=-1",
"update-resources": [
"php scripts/update-oembed.php",
"php scripts/update-suffix.php"
Expand Down
15 changes: 15 additions & 0 deletions phpstan.dist.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon

parameters:
level: max
paths:
- src
# - tests
excludePaths:
- tests/cache
- tests/fixtures
checkMissingCallableSignature: true
checkUninitializedProperties: true
checkTooWideReturnTypesInProtectedAndPublicMethods: true
checkImplicitMixed: true
3 changes: 3 additions & 0 deletions src/Adapters/Archive/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Api
{
use HttpApiTrait;

/**
* @return array<string, mixed>
*/
protected function fetchData(): array
{
$this->endpoint = $this->extractor->getUri()->withQuery('output=json');
Expand Down
9 changes: 6 additions & 3 deletions src/Adapters/Archive/Detectors/AuthorName.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Archive\Detectors;

use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\AuthorName as Detector;

class AuthorName extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('metadata', 'creator')
?: parent::detect();
$result = $api->str('metadata', 'creator');
return (is_string($result) && trim($result) !== '') ? $result : parent::detect();
}
}
9 changes: 6 additions & 3 deletions src/Adapters/Archive/Detectors/Description.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Archive\Detectors;

use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\Description as Detector;

class Description extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('metadata', 'extract')
?: parent::detect();
$result = $api->str('metadata', 'extract');
return (is_string($result) && trim($result) !== '') ? $result : parent::detect();
}
}
18 changes: 13 additions & 5 deletions src/Adapters/Archive/Detectors/PublishedTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@
namespace Embed\Adapters\Archive\Detectors;

use DateTime;
use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\PublishedTime as Detector;

class PublishedTime extends Detector
{
public function detect(): ?DateTime
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->time('metadata', 'publicdate')
?: $api->time('metadata', 'addeddate')
?: $api->time('metadata', 'date')
?: parent::detect();
$fields = ['publicdate', 'addeddate', 'date'];
foreach ($fields as $field) {
$result = $api->time('metadata', $field);
if ($result !== null) {
return $result;
}
}

return parent::detect();
}
}
9 changes: 6 additions & 3 deletions src/Adapters/Archive/Detectors/Title.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Archive\Detectors;

use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\Title as Detector;

class Title extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('metadata', 'title')
?: parent::detect();
$result = $api->str('metadata', 'title');
return (is_string($result) && trim($result) !== '') ? $result : parent::detect();
}
}
19 changes: 17 additions & 2 deletions src/Adapters/Archive/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,35 @@
namespace Embed\Adapters\Archive;

use Embed\Extractor as Base;
use Embed\Http\Crawler;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

class Extractor extends Base
{
private Api $api;

public function __construct(
UriInterface $uri,
RequestInterface $request,
ResponseInterface $response,
Crawler $crawler
) {
parent::__construct($uri, $request, $response, $crawler);
$this->api = new Api($this);
}

public function getApi(): Api
{
return $this->api;
}

/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
$this->api = new Api($this);

return [
'title' => new Detectors\Title($this),
'description' => new Detectors\Description($this),
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/Bandcamp/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
return [
Expand Down
4 changes: 2 additions & 2 deletions src/Adapters/CadenaSer/Detectors/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class Code extends Detector
{
public function detect(): ?EmbedCode
{
return parent::detect()
?: $this->fallback();
$result = parent::detect();
return $result !== null ? $result : $this->fallback();
}

private function fallback(): ?EmbedCode
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/CadenaSer/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
return [
Expand Down
4 changes: 2 additions & 2 deletions src/Adapters/Facebook/Detectors/Title.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function detect(): ?string
$document = $this->extractor->getDocument();
$oembed = $this->extractor->getOEmbed();

return $oembed->str('title')
?: $document->select('.//head/title')->str();
$result = $oembed->str('title');
return $result !== null ? $result : $document->select('.//head/title')->str();
}
}
3 changes: 3 additions & 0 deletions src/Adapters/Facebook/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
$this->oembed = new OEmbed($this);
Expand Down
4 changes: 2 additions & 2 deletions src/Adapters/Facebook/OEmbed.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ protected function detectEndpoint(): ?UriInterface
{
$token = $this->extractor->getSetting('facebook:token');

if (!$token) {
if (!is_string($token) || $token === '') {
return null;
}

$uri = $this->extractor->getUri();
if (strpos($uri->getPath(), 'login') !== false) {
parse_str($uri->getQuery(), $params);
if (!empty($params['next'])) {
if (isset($params['next']) && is_string($params['next']) && $params['next'] !== '' && $params['next'] !== '0') {
$uri = $this->extractor->getCrawler()->createUri($params['next']);
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/Adapters/Flickr/Detectors/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ class Code extends Detector
{
public function detect(): ?EmbedCode
{
return parent::detect()
?: $this->fallback();
$result = parent::detect();
if ($result !== null) {
return $result;
}

return $this->fallback();
}

private function fallback(): ?EmbedCode
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/Flickr/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
return [
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/Gist/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Api
{
use HttpApiTrait;

/**
* @return array<string, mixed>
*/
protected function fetchData(): array
{
$uri = $this->extractor->getUri();
Expand Down
9 changes: 6 additions & 3 deletions src/Adapters/Gist/Detectors/AuthorName.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Gist\Detectors;

use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\AuthorName as Detector;

class AuthorName extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('owner')
?: parent::detect();
$result = $api->str('owner');
return (is_string($result) && trim($result) !== '') ? $result : parent::detect();
}
}
11 changes: 8 additions & 3 deletions src/Adapters/Gist/Detectors/AuthorUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@

namespace Embed\Adapters\Gist\Detectors;

use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\AuthorUrl as Detector;
use Psr\Http\Message\UriInterface;

class AuthorUrl extends Detector
{
public function detect(): ?UriInterface
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();
$owner = $api->str('owner');

if ($owner) {
return $this->extractor->getCrawler()->createUri("https://github.com/{$owner}");
// Exclude empty string and '0' to maintain original truthy check behavior
// The string '0' is not a valid GitHub username and should not generate a URL
if (is_string($owner) && $owner !== '' && $owner !== '0') {
return $extractor->getCrawler()->createUri("https://github.com/{$owner}");
}

return parent::detect();
Expand Down
13 changes: 9 additions & 4 deletions src/Adapters/Gist/Detectors/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace Embed\Adapters\Gist\Detectors;

use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\Code as Detector;
use Embed\EmbedCode;
use function Embed\html;
Expand All @@ -11,21 +12,25 @@ class Code extends Detector
{
public function detect(): ?EmbedCode
{
return parent::detect()
?: $this->fallback();
$parentResult = parent::detect();
return $parentResult !== null ? $parentResult : $this->fallback();
}

private function fallback(): ?EmbedCode
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

$code = $api->html('div');
$stylesheet = $api->str('stylesheet');

if ($code && $stylesheet) {
if ($code !== null && $stylesheet !== null) {
return new EmbedCode(
html('link', ['rel' => 'stylesheet', 'href' => $stylesheet]).$code
);
}

return null;
}
}
Loading