Last active
January 14, 2022 15:41
-
-
Save WinterSilence/fe4022567888ea29f5ba65cee7a8b9a0 to your computer and use it in GitHub Desktop.
Extended DOMElement for generate HTML tags
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* HTML tag. | |
*/ | |
class Tag extends DOMElement implements TagInterface | |
{ | |
public function __construct(string $name, string $value = '') | |
{ | |
parent::__construct($name, $value); | |
} | |
/** | |
* @param iterable $attributes the attributes, attribute name/value pairs. | |
*/ | |
public function setAttributes(iterable $attributes): self | |
{ | |
if ($this->hasAttributes()) { | |
$this->resetAttributes(); | |
} | |
foreach ($attributes as $name => $value) { | |
$this->setAttribute($name, $value); | |
} | |
return $this; | |
} | |
/** | |
* | |
*/ | |
public function setAttribute($name, $value): DOMAttr | |
{ | |
// @todo support passing arrays in $value to set `data-*` and `aria-*` attributes | |
return parent::setAttribute($name, $this->normalizeAttribute($name, $value)); | |
} | |
/** | |
* Returns encoded value. | |
* | |
* @param mixed $value the value to encode | |
*/ | |
protected function encodeValue($value): string | |
{ | |
return (string) json_encode( | |
$value, | |
JSON_FORCE_OBJECT | |
| JSON_NUMERIC_CHECK | |
| JSON_PARTIAL_OUTPUT_ON_ERROR | |
| JSON_PRESERVE_ZERO_FRACTION | |
| JSON_UNESCAPED_SLASHES | |
| JSON_UNESCAPED_UNICODE | |
| JSON_THROW_ON_ERROR | |
); | |
} | |
/** | |
* Returns normalized value of attribute. | |
* | |
* @param string $name the attribute name | |
* @param mixed $value the attribute value | |
*/ | |
protected function normalizeAttribute(string $name, $value): string | |
{ | |
if (is_object($value)) { | |
if (method_exists($value, '__toString')) { | |
$value = (string) $value; | |
} else { | |
$value = (array) $value; | |
} | |
} | |
if (is_array($value)) { | |
if (empty($value)) { | |
$value = ''; | |
} elseif ($name === 'style') { | |
if (!isset($value[0])) { | |
foreach ($value as $key => $val) { | |
$value[$key] = $key . ': ' . str_replace('"', "'", $this->encodeValue($val)); | |
} | |
} | |
$value = implode('; ', $value); | |
} else { | |
$value = implode(' ', array_filter($value)); | |
} | |
} | |
return is_string($value) ? $value : $this->encodeValue($value); | |
} | |
/** | |
* Removes all attributes of tag. | |
*/ | |
public function resetAttributes(): self | |
{ | |
foreach ($this->attributes as $attribute) { | |
$this->removeAttributeNode($attribute); | |
} | |
return $this; | |
} | |
/** | |
* Sets inner content(text or HTML) of tag. | |
*/ | |
public function setContent(...$values): self | |
{ | |
$this->removeContent(); | |
foreach ($values as $value) { | |
if (is_callable($value)) { | |
$value = call_user_func($value, $this, $this->ownerDocument); | |
} | |
if ($value instanceof DOMElement) { | |
$this->appendChild($value); | |
} elseif ($value instanceof SimpleXMLElement) { | |
$this->appendChild(dom_import_simplexml($value)); | |
} else { | |
$value = (string) $value; | |
// Dirty, but fast solution to detect HTML tags | |
if (strpos($value, '<') !== false && strpos($value, '>') !== false) { | |
// HTML: | |
$fragment = $this->ownerDocument->createDocumentFragment(); | |
$fragment->appendXML($value); | |
$this->appendChild($fragment); | |
} else { | |
// Text: | |
$this->appendChild($this->ownerDocument->createTextNode($value)); | |
} | |
} | |
} | |
return $this; | |
} | |
public function removeContent(): self | |
{ | |
foreach ($this->childNodes as $child) { | |
$this->removeChild($child); | |
} | |
return $this; | |
} | |
public function __toString(): string | |
{ | |
return (string) $this->ownerDocument->saveHTML($this); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* HTML tag factory. | |
*/ | |
class TagFactory | |
{ | |
/** | |
* @var DOMDocument the HTML document | |
*/ | |
protected $document; | |
/** | |
* @param bool $html5 if `TRUE`, then generate HTML 5 document, else, HTML 4 document | |
*/ | |
public function __construct(bool $html5 = true) | |
{ | |
$dom = new DOMImplementation(); | |
if ($html5) { | |
$docType = $dom->createDocumentType('html'); | |
} else { | |
$docType = $dom->createDocumentType( | |
'HTML', | |
'-//W3C//DTD HTML 4.01 Transitional//EN', | |
'http://www.w3.org/TR/html4/loose.dtd' | |
); | |
} | |
$this->document = $dom->createDocument('', 'html', $docType); | |
$this->document->registerNodeClass(DOMElement::class, Tag::class); | |
// @todo | |
// $this->document->registerNodeClass(DOMAttr::class, TagAttribute::class); | |
} | |
/** | |
* Creates new `TagInterface` instance. | |
* | |
* @param string $name the tag name | |
* @param iterable $attributes the tag attributes | |
* @param string|DOMElement|SimpleXMLElement|TagInterface|callable|null $content the inner text/HTML, callback syntax: | |
* `function (TagInterface $tag, DOMDocument $document): TagInterface|string` | |
* @return TagInterface | |
*/ | |
public function createTag(string $name, iterable $attributes = [], $content = null): TagInterface | |
{ | |
// @todo remove tag from document instead cloning | |
$document = $this->document->cloneNode(); | |
$tag = $document->documentElement->appendChild($document->createElement($name)); | |
$tag->setAttributes($attributes); | |
if ($content !== null) { | |
$tag->setContent($content); | |
} | |
return $tag; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Interface of HTML tags. | |
*/ | |
interface TagInterface | |
{ | |
public function setAttributes(iterable $attributes); | |
/** | |
* @sstring|DOMElement|SimpleXMLElement|TagInterface|callable|null | |
*/ | |
public function setContent($content); | |
public function __toString(): string; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment