From d6cd13492d19a00a94c84ef0d464a86c85e4be15 Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Sat, 16 Mar 2024 21:51:43 +0100 Subject: [PATCH] Use JSLikeHTMLElement in type hints We use `DOMDocument::registerNodeClass()` to make DOM methods return `JSLikeHTMLElement` instead of `DOMElement`. Unfortunately, it is not possible for PHPStan to detect that so we need to cast it ourselves: https://github.com/phpstan/phpstan/discussions/10748 We may want to deprecate it in the future just to get rid of this mess. This also allows us to get rid of the assertions in tests. --- phpstan.neon | 3 +++ src/Readability.php | 12 ++++++------ stubs/dom.stub | 36 ++++++++++++++++++++++++++++++++++ tests/ReadabilityTest.php | 41 --------------------------------------- 4 files changed, 45 insertions(+), 47 deletions(-) create mode 100644 stubs/dom.stub diff --git a/phpstan.neon b/phpstan.neon index 7e5d5d8..95b916d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,6 +8,9 @@ parameters: bootstrapFiles: - vendor/bin/.phpunit/phpunit/vendor/autoload.php + stubFiles: + - stubs/dom.stub + includes: - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon diff --git a/src/Readability.php b/src/Readability.php index 7cb6588..078d8d3 100644 --- a/src/Readability.php +++ b/src/Readability.php @@ -36,12 +36,12 @@ class Readability implements LoggerAwareInterface public $revertForcedParagraphElements = false; /** - * @var ?\DOMElement + * @var ?JSLikeHTMLElement */ public $articleTitle; /** - * @var ?\DOMElement + * @var ?JSLikeHTMLElement */ public $articleContent; @@ -245,7 +245,7 @@ public function setLogger(LoggerInterface $logger): void /** * Get article title element. * - * @return \DOMElement + * @return JSLikeHTMLElement */ public function getTitle() { @@ -259,7 +259,7 @@ public function getTitle() /** * Get article content element. * - * @return \DOMElement + * @return JSLikeHTMLElement */ public function getContent() { @@ -447,7 +447,7 @@ public function addFootnotes(\DOMElement $articleContent): void */ public function prepArticle(\DOMNode $articleContent): void { - if (!$articleContent instanceof \DOMElement) { + if (!$articleContent instanceof JSLikeHTMLElement) { return; } @@ -644,7 +644,7 @@ public function getWeight(\DOMElement $e): int /** * Remove extraneous break tags from a node. */ - public function killBreaks(\DOMElement $node): void + public function killBreaks(JSLikeHTMLElement $node): void { $html = $node->getInnerHTML(); $html = preg_replace($this->regexps['killBreaks'], '
', $html); diff --git a/stubs/dom.stub b/stubs/dom.stub new file mode 100644 index 0000000..ac85e9d --- /dev/null +++ b/stubs/dom.stub @@ -0,0 +1,36 @@ + + */ + public function getElementsByTagName($name) {} +} + +class DOMNode +{ + +} + +class DOMElement extends DOMNode +{ + /** + * @param string $name + * @return DOMNodeList + */ + public function getElementsByTagName($name) {} +} diff --git a/tests/ReadabilityTest.php b/tests/ReadabilityTest.php index b09a97a..74b4d31 100644 --- a/tests/ReadabilityTest.php +++ b/tests/ReadabilityTest.php @@ -5,7 +5,6 @@ use Monolog\Handler\TestHandler; use Monolog\Logger; use Psr\Log\LoggerInterface; -use Readability\JSLikeHTMLElement; use Readability\Readability; class ReadabilityTest extends \PHPUnit\Framework\TestCase @@ -80,8 +79,6 @@ public function testInitNoContent(): void $res = $readability->init(); $this->assertFalse($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertEmpty($readability->getTitle()->getInnerHtml()); $this->assertStringContainsString('Sorry, Readability was unable to parse this page for content.', $readability->getContent()->getInnerHtml()); } @@ -92,8 +89,6 @@ public function testInitP(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('
getContent()->getInnerHtml()); @@ -105,8 +100,6 @@ public function testInitDivP(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('
getContent()->getInnerHtml()); @@ -119,8 +112,6 @@ public function testInitDiv(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('
getContent()->getInnerHtml()); @@ -134,8 +125,6 @@ public function testWithFootnotes(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('
getContent()->getInnerHtml()); @@ -151,8 +140,6 @@ public function testStandardClean(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('
getContent()->getInnerHtml()); @@ -167,8 +154,6 @@ public function testWithIframe(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('
getContent()->getInnerHtml()); @@ -182,8 +167,6 @@ public function testWithArticle(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertStringContainsString('alt="article"', $readability->getContent()->getInnerHtml()); $this->assertEmpty($readability->getTitle()->getInnerHtml()); $this->assertStringContainsString('This is an awesome text with some links, here there are', $readability->getContent()->getInnerHtml()); @@ -197,8 +180,6 @@ public function testWithAside(): void $res = $readability->init(); $this->assertTrue($res); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getContent()); - $this->assertInstanceOf(JSLikeHTMLElement::class, $readability->getTitle()); $this->assertEmpty($readability->getTitle()->getInnerHtml()); $this->assertStringContainsString('This is an awesome text with some links, here there are', $readability->getContent()->getInnerHtml()); $this->assertStringNotContainsString('