diff --git a/.gitignore b/.gitignore index a064c15..1c81cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ build composer.lock vendor phpcs.xml -phpunit.xml \ No newline at end of file +phpunit.xml +.idea diff --git a/composer.json b/composer.json index 6b46a9f..c79d646 100644 --- a/composer.json +++ b/composer.json @@ -20,8 +20,9 @@ } ], "require": { - "php" : "~7.0", - "ext-dom": "*" + "php" : "~8.1", + "ext-dom": "*", + "ext-libxml": "*" }, "require-dev": { "phpunit/phpunit" : ">=5.4.3", diff --git a/src/MicrodataDOMDocument.php b/src/MicrodataDOMDocument.php index bf3c47d..c590cc3 100644 --- a/src/MicrodataDOMDocument.php +++ b/src/MicrodataDOMDocument.php @@ -2,10 +2,12 @@ namespace YusufKandemir\MicrodataParser; -class MicrodataDOMDocument extends \DOMDocument +use DOMDocument; +use DOMXPath; + +class MicrodataDOMDocument extends DOMDocument { - /** @var \DOMXPath */ - public $xpath; + public DOMXPath $xpath; /** * Get top-level items of the document @@ -23,11 +25,11 @@ public function getItems() : \DOMNodeList * {@inheritdoc} * Also assigns $xpath with DOMXPath of freshly loaded DOMDocument */ - public function loadHTML($source, $options = 0) + public function loadHTML($source, $options = 0): DOMDocument|bool { $return = parent::loadHTML($source, $options); - $this->xpath = new \DOMXPath($this); + $this->xpath = new DOMXPath($this); return $return; } @@ -36,11 +38,11 @@ public function loadHTML($source, $options = 0) * {@inheritdoc} * Also assigns $xpath with DOMXPath of freshly loaded DOMDocument */ - public function loadHTMLFile($filename, $options = 0) + public function loadHTMLFile($filename, $options = 0): DOMDocument|bool { $return = parent::loadHTMLFile($filename, $options); - $this->xpath = new \DOMXPath($this); + $this->xpath = new DOMXPath($this); return $return; } diff --git a/src/MicrodataDOMElement.php b/src/MicrodataDOMElement.php index d5acdb0..2dcc63b 100644 --- a/src/MicrodataDOMElement.php +++ b/src/MicrodataDOMElement.php @@ -2,10 +2,13 @@ namespace YusufKandemir\MicrodataParser; +use function array_key_exists; +use function in_array; + class MicrodataDOMElement extends \DOMElement { /** @var array "tag name" to "attribute name" mapping */ - private static $tagNameLookup = [ + private static array $tagNameLookup = [ 'audio' => 'src', 'embed' => 'src', 'iframe' => 'src', @@ -23,7 +26,7 @@ class MicrodataDOMElement extends \DOMElement ]; /** @var array Attributes that have absolute values */ - private static $absoluteAttributes = ['src', 'href', 'data',]; + private static array $absoluteAttributes = ['src', 'href', 'data',]; /** * @see https://www.w3.org/TR/2018/WD-microdata-20180426/#dfn-item-properties for details of algorithm @@ -94,11 +97,11 @@ public function getPropertyNames() : array /** * @see https://www.w3.org/TR/2018/WD-microdata-20180426/#dfn-property-value for details of algorithm * - * @param callable $absoluteUriHandler + * @param callable|null $absoluteUriHandler * * @return $this|string */ - public function getPropertyValue(callable $absoluteUriHandler = null) + public function getPropertyValue(callable $absoluteUriHandler = null): string|static { if ($this->hasAttribute('itemscope')) { return $this; @@ -110,11 +113,11 @@ public function getPropertyValue(callable $absoluteUriHandler = null) $value = ''; - if (\array_key_exists($this->tagName, self::$tagNameLookup)) { + if (array_key_exists($this->tagName, self::$tagNameLookup)) { $attribute = self::$tagNameLookup[$this->tagName]; $value = $this->getAttribute($attribute); - if (!empty($value) && \in_array($attribute, self::$absoluteAttributes) && !$this->isAbsoluteUri($value)) { + if (!empty($value) && in_array($attribute, self::$absoluteAttributes) && !$this->isAbsoluteUri($value)) { $value = $absoluteUriHandler($value, $this->ownerDocument->documentURI); } } @@ -132,7 +135,7 @@ public function getPropertyValue(callable $absoluteUriHandler = null) * * @return false|int */ - protected function isAbsoluteUri(string $uri) + protected function isAbsoluteUri(string $uri): bool|int { return preg_match("/^\w+:/", trim($uri)); } @@ -142,7 +145,7 @@ protected function isAbsoluteUri(string $uri) * * @return array Result array which contains child ElementNodes */ - protected function getChildElementNodes() + protected function getChildElementNodes(): array { $childNodes = []; @@ -160,9 +163,9 @@ protected function getChildElementNodes() * * @param string $attributeName Name of the attribute * - * @return array|array[]|false|string[] + * @return array|false */ - public function tokenizeAttribute(string $attributeName) + public function tokenizeAttribute(string $attributeName): array|bool { $attribute = []; @@ -176,15 +179,15 @@ public function tokenizeAttribute(string $attributeName) /** * Splits given attribute value in space characters to array * + * @param string $attribute + * + * @return array|false * @see \preg_split() for possible return values and behaviour * * @see https://www.w3.org/TR/2018/WD-microdata-20180426/#dfn-split-a-string-on-spaces for definition of tokens * - * @param string $attribute - * - * @return array[]|false|string[] */ - protected function tokenize(string $attribute) + protected function tokenize(string $attribute): array|bool { return preg_split('/\s+/', trim($attribute)); } diff --git a/src/MicrodataParser.php b/src/MicrodataParser.php index 262ec98..92c59f1 100644 --- a/src/MicrodataParser.php +++ b/src/MicrodataParser.php @@ -2,10 +2,12 @@ namespace YusufKandemir\MicrodataParser; +use DOMElement; +use stdClass; + class MicrodataParser { - /** @var MicrodataDOMDocument */ - protected $dom; + protected MicrodataDOMDocument $dom; /** * Handler will be called with $value(non-absolute uri string) and $base(base uri) parameters @@ -26,7 +28,7 @@ class MicrodataParser */ public function __construct(MicrodataDOMDocument $dom, callable $absoluteUriHandler = null) { - $dom->registerNodeClass(\DOMElement::class, MicrodataDOMElement::class); + $dom->registerNodeClass(DOMElement::class, MicrodataDOMElement::class); $this->dom = $dom; $this->absoluteUriHandler = $absoluteUriHandler ?: function ($value, $base) { @@ -48,9 +50,9 @@ public function toArray() : array /** * Extracts and converts microdata to object * - * @return \stdClass + * @return stdClass */ - public function toObject() : \stdClass + public function toObject() : stdClass { return $this->extractMicrodata(); } @@ -58,24 +60,24 @@ public function toObject() : \stdClass /** * Extracts and converts microdata to json using \json_encode() * - * @see \json_encode() to description of parameters and return values - * * @param int $options * @param int $depth * * @return false|string + * @see \json_encode() to description of parameters and return values + * */ - public function toJSON($options = 0, $depth = 512) + public function toJSON(int $options = 0, int $depth = 512): bool|string { return json_encode($this->extractMicrodata(), $options, $depth); } /** - * @return \stdClass + * @return stdClass */ - protected function extractMicrodata() : \stdClass + protected function extractMicrodata() : stdClass { - $result = new \stdClass; + $result = new stdClass; $result->items = []; @@ -92,11 +94,11 @@ protected function extractMicrodata() : \stdClass * @param MicrodataDOMElement $item * @param array $memory * - * @return \stdClass + * @return stdClass */ - protected function getObject(MicrodataDOMElement $item, $memory = []) : \stdClass + protected function getObject(MicrodataDOMElement $item, array $memory = []) : stdClass { - $result = new \stdClass; + $result = new stdClass; $memory[] = $item; @@ -108,7 +110,7 @@ protected function getObject(MicrodataDOMElement $item, $memory = []) : \stdClas } // @todo Check if item ids are valid absolute urls or like isbn:xxx - $properties = new \stdClass; + $properties = new stdClass; foreach ($item->getProperties() as $element) { $value = $element->getPropertyValue($this->absoluteUriHandler); diff --git a/tests/MicrodataParserTest.php b/tests/MicrodataParserTest.php index d9c4480..ffd2ac9 100644 --- a/tests/MicrodataParserTest.php +++ b/tests/MicrodataParserTest.php @@ -2,17 +2,18 @@ namespace YusufKandemir\MicrodataParser\Tests; +use PHPUnit\Framework\TestCase; use YusufKandemir\MicrodataParser\MicrodataDOMDocument; use YusufKandemir\MicrodataParser\MicrodataParser; -class MicrodataParserTest extends \PHPUnit\Framework\TestCase +class MicrodataParserTest extends TestCase { - protected function setUp() + protected function setUp() :void { libxml_use_internal_errors(true); // Ignore warnings of DOMDocument::loadHTML check } - protected function getParser($data) + protected function getParser($data): MicrodataParser { $dom = new MicrodataDOMDocument; $dom->loadHTML($data['source']); @@ -66,7 +67,7 @@ public function testItUsesAbsoluteUriHandlerWhenHandlingAbsoluteUris() $resultBefore = $parser->toObject(); $resultBeforeUri = $resultBefore->items[0]->properties->work[0]; - $this->assertNotContains($baseUri, $resultBeforeUri); + $this->assertStringNotContainsString($baseUri, $resultBeforeUri); $parser->setAbsoluteUriHandler( function (string $value, string $base) use ($baseUri) : string { @@ -77,13 +78,19 @@ function (string $value, string $base) use ($baseUri) : string { $resultAfter = $parser->toObject(); $resultAfterUri = $resultAfter->items[0]->properties->work[0]; - $this->assertContains($baseUri, $resultAfterUri); + $this->assertStringContainsString($baseUri, $resultAfterUri); } /** * @todo Provide more test data + * @return array{ + * 'W3C Example': array{uri: string, source: string, result: string}[], + * 'Itemref & src based tags': array{uri: string, source: string, result: string}[], + * 'Object & Data tags': array{uri: string, source: string, result: string}[], + * 'Itemid & Content attributes': array{uri: string, source: string, result: string}[] + * } */ - public function data() + public function data(): array { return [ // https://www.w3.org/TR/microdata/#ex-jsonconv @@ -102,13 +109,20 @@ public function data() ]; } - private function getTestData($folderName, $sourceName, $resultName) + /** + * @return array{uri: string, source: string, result: string} + */ + private function getTestData($folderName, $sourceName, $resultName): array { $folderPath = __DIR__.'/data/'.$folderName.'/'; $source = file_get_contents($folderPath . $sourceName); $result = file_get_contents($folderPath . $resultName); + if ($source === false || $result === false) { + throw new \Exception('Could not load test data'); + } + $uri = ''; // Set $uri if URI specified in test data if (preg_match('//', $source, $matches)) { diff --git a/tests/MicrodataTest.php b/tests/MicrodataTest.php index d3a9aec..2a87983 100644 --- a/tests/MicrodataTest.php +++ b/tests/MicrodataTest.php @@ -2,12 +2,13 @@ namespace YusufKandemir\MicrodataParser\Tests; +use DOMDocument; use YusufKandemir\MicrodataParser\Microdata; use YusufKandemir\MicrodataParser\MicrodataParser; class MicrodataTest extends \PHPUnit\Framework\TestCase { - protected $htmlFileName = __DIR__ . '/data/W3C/source.html'; + protected string $htmlFileName = __DIR__ . '/data/W3C/source.html'; public function testItCreatesMicrodataParserFromHtml() { @@ -26,7 +27,7 @@ public function testItCreatesMicrodataParserFromHtmlFile() public function testItCreatesMicrodataParserFromDomDocument() { - $dom = new \DOMDocument; + $dom = new DOMDocument; $dom->loadHTMLFile($this->htmlFileName); $microdata = Microdata::fromDOMDocument($dom);