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

Increase type safety #87

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 0 additions & 2 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
'concat_space' => ['spacing' => 'one'],
// Pulled in by @Symfony:risky but we still support PHP 7.4
'modernize_strpos' => false,
// Pulled in by @Symfony, we cannot add property types until we bump PHP to ≥ 7.4
'no_null_property_initialization' => false,
])
->setFinder($finder)
;
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
level: 1
level: 5
paths:
- src
- tests
Expand Down
100 changes: 31 additions & 69 deletions src/JSLikeHTMLElement.php
Original file line number Diff line number Diff line change
@@ -1,59 +1,45 @@
<?php

declare(strict_types=1);

// SPDX-FileCopyrightText: 2011 Keyvan Minoukadeh - http://www.keyvan.net - keyvan@keyvan.net
// SPDX-License-Identifier: Apache-2.0

namespace Readability;

/**
* JavaScript-like HTML DOM Element.
* Wrapper for DOMElement adding methods for accessing string representation of inner HTML contents.
*
* This class extends PHP's DOMElement to allow
* users to get and set the innerHTML property of
* HTML elements in the same way it's done in
* JavaScript.
* Inspired by JavaScript innerHTML property.
* https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
*
* Example usage:
* require_once 'JSLikeHTMLElement.php';
* header('Content-Type: text/plain');
* $doc = new DOMDocument();
* $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
* $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
* $elem = $doc->getElementsByTagName('div')->item(0);
*
* // print innerHTML
* echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>'
* echo "\n\n";
*
* // set innerHTML
* $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>';
* echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>'
* echo "\n\n";
* ```php
* $doc = new DOMDocument();
* $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
* $elem = $doc->getElementsByTagName('div')->item(0);
*
* // print document (with our changes)
* echo $doc->saveXML();
* // Get inner HTML
* assert($elem->getInnerHtml() === '<p>Para 1</p><p>Para 2</p>');
*
* @author Keyvan Minoukadeh - http://www.keyvan.net - keyvan@keyvan.net
* // Set inner HTML
* $elem->setInnerHtml('<a href="http://fivefilters.org">FiveFilters.org</a>');
* assert($elem->getInnerHtml() === '<a href="http://fivefilters.org">FiveFilters.org</a>');
*
* @see http://fivefilters.org (the project this was written for)
* // print document (with our changes)
* echo $doc->saveXML();
* ```
*/
class JSLikeHTMLElement extends \DOMElement
final class JSLikeHTMLElement extends \DOMElement
{
/**
* Used for setting innerHTML like it's done in JavaScript:.
*
* ```php
* $div->innerHTML = '<h2>Chapter 2</h2><p>The story begins...</p>';
* ```
* Sets inner HTML.
*/
public function __set($name, $value)
public function setInnerHtml(string $value): void
{
if ('innerHTML' !== $name) {
$trace = debug_backtrace();
trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], \E_USER_NOTICE);

return;
}

// first, empty the element
if (isset($this->childNodes)) {

Check failure on line 42 in src/JSLikeHTMLElement.php

View workflow job for this annotation

GitHub Actions / CS Fixer & PHPStan (7.4)

Property DOMNode::$childNodes (DOMNodeList) in isset() is not nullable.
for ($x = $this->childNodes->length - 1; $x >= 0; --$x) {
$this->removeChild($this->childNodes->item($x));
}
Expand Down Expand Up @@ -81,7 +67,7 @@
$f = new \DOMDocument();

// Using <htmlfragment> will generate a warning, but so will bad HTML
// (and by this point, bad HTML is what we've got).
// (and by element point, bad HTML is what we've got).
// We use it (and suppress the warning) because an HTML fragment will
// be wrapped around <html><body> tags which we don't really want to keep.
// Note: despite the warning, if loadHTML succeeds it will return true.
Expand All @@ -102,42 +88,18 @@
}

/**
* Used for getting innerHTML like it's done in JavaScript:.
*
* ```php
* $string = $div->innerHTML;
* ```
* Gets inner HTML.
*/
public function __get($name)
public function getInnerHtml(): string
{
if ('innerHTML' === $name) {
$inner = '';
$inner = '';

if (isset($this->childNodes)) {
foreach ($this->childNodes as $child) {
$inner .= $this->ownerDocument->saveXML($child);
}
if (isset($this->childNodes)) {

Check failure on line 97 in src/JSLikeHTMLElement.php

View workflow job for this annotation

GitHub Actions / CS Fixer & PHPStan (7.4)

Property DOMNode::$childNodes (DOMNodeList) in isset() is not nullable.
foreach ($this->childNodes as $child) {
$inner .= $this->ownerDocument->saveXML($child);
}

return $inner;
}

$trace = debug_backtrace();
trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], \E_USER_NOTICE);
}

public function __toString()
{
return '[' . $this->tagName . ']';
}

public function getInnerHtml()
{
return $this->__get('innerHTML');
}

public function setInnerHtml($value)
{
return $this->__set('innerHTML', $value);
return $inner;
}
}
Loading