Browse Source

Dropping support for PHP 7.4

• Tests did pass in 7.4, but numerous warnings were triggered concerning 
method declaration type differences because php 7.4's type declarations 
for DOM methods were mostly nonexistent.
wrapper-classes
Dustin Wilson 3 years ago
parent
commit
24ac00c5eb
  1. 2
      composer.json
  2. 27
      lib/Document.php
  3. 16
      lib/traits/ChildNode.php
  4. 66
      lib/traits/ChildNodePolyfill.php
  5. 5
      lib/traits/Node.php
  6. 4
      lib/traits/ParentNode.php
  7. 78
      lib/traits/ParentNodePolyfill.php
  8. 29
      tests/cases/TestChildNode.php
  9. 18
      tests/cases/TestDocument.php
  10. 11
      tests/cases/TestNode.php

2
composer.json

@ -3,7 +3,7 @@
"description": "Modern DOM library written in PHP for HTML documents",
"type": "library",
"require": {
"php": ">=7.4",
"php": ">=8.0",
"ext-dom": "*",
"mensbeam/html-parser": ">=1.0",
"mensbeam/framework": "^1.0"

27
lib/Document.php

@ -10,9 +10,9 @@ namespace MensBeam\HTML\DOM;
use MensBeam\Framework\MagicProperties,
MensBeam\HTML\Parser;
use MensBeam\HTML\Parser\{
Charset,
Data
};
Charset,
Data
};
class Document extends \DOMDocument {
@ -124,16 +124,7 @@ class Document extends \DOMDocument {
}
public function __construct($source = null, ?string $encoding = null) {
// Because we cannot have union types until php 8... :)
if ($source !== null && !$source instanceof \DOMDocument && !is_string($source)) {
$type = gettype($source);
if ($type === 'object') {
$type = get_class($source);
}
throw new Exception(Exception::ARGUMENT_TYPE_ERROR, 1, 'source', '\DOMDocument|string|null', $type);
}
public function __construct(\DOMDocument|string|null $source = null, ?string $encoding = null) {
parent::__construct();
$this->registerNodeClass('DOMAttr', '\MensBeam\HTML\DOM\Attr');
@ -156,7 +147,7 @@ class Document extends \DOMDocument {
}
public function createAttribute($localName): ?Attr {
public function createAttribute(string $localName): ?Attr {
# The createAttribute(localName) method steps are:
# 1. If localName does not match the Name production in XML, then throw an
# "InvalidCharacterError" DOMException.
@ -329,7 +320,7 @@ class Document extends \DOMDocument {
}
}
public function createElementNS($namespaceURI, $qualifiedName, $value = null): Element {
public function createElementNS(?string $namespaceURI, string $qualifiedName, $value = null): Element {
# The internal createElementNS steps, given document, namespace, qualifiedName,
# and options, are as follows:
// DEVIATION: We cannot follow the createElement parameters per the DOM spec
@ -399,7 +390,7 @@ class Document extends \DOMDocument {
return $node;
}
public function load($filename, $options = null, ?string $encoding = null): bool {
public function load(string $filename, $options = null, ?string $encoding = null): bool {
$f = fopen($filename, 'r');
if (!$f) {
return false;
@ -462,7 +453,7 @@ class Document extends \DOMDocument {
throw new DOMException(DOMException::NOT_SUPPORTED, __CLASS__ . ' is only meant for HTML; use \\DOMDocument::loadXML instead');
}
public function save($filename, $options = null) {
public function save(string $filename, $options = null) {
return file_put_contents($filename, $this->saveHTML());
}
@ -508,7 +499,7 @@ class Document extends \DOMDocument {
return $this->serializeNode($node, $formatOutput);
}
public function saveHTMLFile($filename): int {
public function saveHTMLFile(string $filename): int {
return $this->save($filename);
}

16
lib/traits/ChildNode.php

@ -11,10 +11,20 @@ namespace MensBeam\HTML\DOM;
# 4.2.8. Mixin ChildNode
trait ChildNode {
use ChildNodePolyfill;
public function after(...$nodes): void {
// PHP's declaration for \DOMCharacterData::after doesn't include the
// DOMNode|string typing for the nodes that it should, so type checking will
// need to be done manually.
foreach ($nodes as $node) {
if (!$node instanceof \DOMNode && !is_string($node)) {
$type = gettype($node);
if ($type === 'object') {
$type = get_class($node);
}
throw new Exception(Exception::ARGUMENT_TYPE_ERROR, 1, 'nodes', '\DOMNode|string', $type);
}
}
# The after(nodes) method steps are:
#
# 1. Let parent be this’s parent.

66
lib/traits/ChildNodePolyfill.php

@ -1,66 +0,0 @@
<?php
/**
* @license MIT
* Copyright 2017, Dustin Wilson, J. King et al.
* See LICENSE and AUTHORS files for details
*/
declare(strict_types=1);
namespace MensBeam\HTML\DOM;
// @codeCoverageIgnoreStart
if (version_compare(\PHP_VERSION, '8.0', '<')) {
# 4.2.7. Mixin NonDocumentTypeChildNode
// DEVIATION: Since we do not extend \DOMDocumentType there's no need to have
// any differentiation between ChildNode and NonDocumentTypeChildNode
trait ChildNodePolyfill {
protected function __get_nextElementSibling(): Element {
# The nextElementSibling getter steps are to return the first following sibling
# that is an element; otherwise null.
if ($this->parentNode !== null) {
$start = false;
foreach ($this->parentNode->childNodes as $child) {
if (!$start) {
if ($child->isSameNode($this)) {
$start = true;
}
continue;
}
if (!$child instanceof Element) {
continue;
}
return $child;
}
}
return null;
}
protected function __get_previousElementSibling(): Element {
# The previousElementSibling getter steps are to return the first preceding
# sibling that is an element; otherwise null.
if ($this->parentNode !== null) {
foreach ($this->parentNode->childNodes as $child) {
if ($child->isSameNode($this)) {
return null;
}
if (!$child instanceof Element) {
continue;
}
return $child;
}
}
return null;
}
}
} else {
// @codeCoverageIgnoreEnd
trait ChildNodePolyfill {}
}

5
lib/traits/Node.php

@ -56,11 +56,6 @@ trait Node {
$document = ($this instanceof Document) ? $this : $this->ownerDocument;
$node = (count($nodes) > 1) ? $document->createDocumentFragment() : null;
foreach ($nodes as $k => &$n) {
// Can't do union types until PHP 8... OTL
if (!$n instanceof \DOMNode && !is_string($n)) {
throw new Exception(Exception::ARGUMENT_TYPE_ERROR, $k, 'nodes', '\DOMNode|string', gettype($n));
}
if (is_string($n)) {
$n = $this->ownerDocument->createTextNode($n);
}

4
lib/traits/ParentNode.php

@ -11,7 +11,7 @@ namespace MensBeam\HTML\DOM;
# 4.2.6. Mixin ParentNode
trait ParentNode {
use Node, ParentNodePolyfill;
use Node;
protected function __get_children(): \DOMNodeList {
@ -67,7 +67,7 @@ trait ParentNode {
return $node;
}
public function replaceChildren(...$nodes) {
public function replaceChildren(\DOMNode|string ...$nodes) {
# The replaceChildren(nodes) method steps are:
# 1. Let node be the result of converting nodes into a node given nodes and
# this’s node document.

78
lib/traits/ParentNodePolyfill.php

@ -1,78 +0,0 @@
<?php
/**
* @license MIT
* Copyright 2017, Dustin Wilson, J. King et al.
* See LICENSE and AUTHORS files for details
*/
declare(strict_types=1);
namespace MensBeam\HTML\DOM;
// @codeCoverageIgnoreStart
if (version_compare(\PHP_VERSION, '8.0', '<')) {
/**
* Used for PHP7 installations to polyfill getters, setters, and methods that
* PHP's DOM handles natively in PHP8
*/
trait ParentNodePolyfill {
protected function __get_childElementCount(): int {
# The childElementCount getter steps are to return the number of children of
# this that are elements.
$count = 0;
foreach ($this->childNodes as $child) {
if ($child instanceof Element) {
$count++;
}
}
return $count;
}
protected function __get_firstElementChild(): ?Element {
# The firstElementChild getter steps are to return the first child that is an
# element; otherwise null.
foreach ($this->childNodes as $child) {
if ($child instanceof Element) {
return $child;
}
}
return null;
}
protected function __get_lastElementChild(): ?Element {
# The lastElementChild getter steps are to return the last child that is an
# element; otherwise null.
for ($i = $this->childNodes->length - 1; $i >= 0; $i--) {
$child = $this->childNodes->item($i);
if ($child instanceof Element) {
return $child;
}
}
return null;
}
public function append(...$nodes): void {
# The append(nodes) method steps are:
# 1. Let node be the result of converting nodes into a node given nodes and
# this’s node document.
$node = $this->convertNodesToNode($nodes);
# 2. Append node to this.
$this->appendChild($node);
}
public function prepend(...$nodes): void {
# The prepend(nodes) method steps are:
#
# 1. Let node be the result of converting nodes into a node given nodes and
# this’s node document.
$node = $this->convertNodesToNode($nodes);
# 2. Pre-insert node into this before this’s first child.
$this->insertBefore($node, $this->firstChild);
}
}
} else {
// @codeCoverageIgnoreEnd
trait ParentNodePolyfill {}
}

29
tests/cases/TestChildNode.php

@ -8,7 +8,10 @@
declare(strict_types=1);
namespace MensBeam\HTML\DOM\TestCase;
use MensBeam\HTML\DOM\Document;
use MensBeam\HTML\DOM\{
Document,
Exception
};
/** @covers \MensBeam\HTML\DOM\ChildNode */
@ -34,4 +37,28 @@ class TestChildNode extends \PHPUnit\Framework\TestCase {
$c = $d->createComment('ook');
$this->assertNull($c->after($d->createTextNode('ook')));
}
public function provideAfterFailure(): array {
return [
[ false ],
[ new \DateTime() ],
];
}
/**
* @dataProvider provideAfterFailure
* @covers \MensBeam\HTML\DOM\ChildNode::after
*/
public function testAfterFailure($object): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::ARGUMENT_TYPE_ERROR);
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
$o = $d->body->appendChild($d->createTextNode('ook'));
$div2 = $d->body->appendChild($d->createElement('div'));
$div->after($object);
}
}

18
tests/cases/TestDocument.php

@ -193,24 +193,6 @@ class TestDocument extends \PHPUnit\Framework\TestCase {
}
public function provideDocumentCreationFailures(): iterable {
return [
[ true ],
[ (new Document)->createElement('ook') ]
];
}
/**
* @dataProvider provideDocumentCreationFailures
* @covers \MensBeam\HTML\DOM\Document::__construct
*/
public function testDocumentCreationFailures($source): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::ARGUMENT_TYPE_ERROR);
$d = new Document($source);
}
public function provideElementCreation(): iterable {
return [
// HTML element

11
tests/cases/TestNode.php

@ -17,17 +17,6 @@ use MensBeam\HTML\DOM\{
/** @covers \MensBeam\HTML\DOM\Node */
class TestNode extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\Node::convertNodesToNode */
public function testConvertNodesToNodeFailure(): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::ARGUMENT_TYPE_ERROR);
$d = new Document();
$t = $d->createElement('template');
$d->appendChild($t);
$t->after(false);
}
public function provideDisabledMethods(): iterable {
return [
[ function() {

Loading…
Cancel
Save