diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:30:08 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:30:08 +0000 |
commit | 4ce65d59ca91871cfd126497158200a818720bce (patch) | |
tree | e277def01fc7eba7dbc21c4a4ae5576e8aa2cf1f /vendor/ipl/html/src/Attribute.php | |
parent | Initial commit. (diff) | |
download | icinga-php-library-4ce65d59ca91871cfd126497158200a818720bce.tar.xz icinga-php-library-4ce65d59ca91871cfd126497158200a818720bce.zip |
Adding upstream version 0.13.1.upstream/0.13.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ipl/html/src/Attribute.php')
-rw-r--r-- | vendor/ipl/html/src/Attribute.php | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/vendor/ipl/html/src/Attribute.php b/vendor/ipl/html/src/Attribute.php new file mode 100644 index 0000000..c42485a --- /dev/null +++ b/vendor/ipl/html/src/Attribute.php @@ -0,0 +1,328 @@ +<?php + +namespace ipl\Html; + +use InvalidArgumentException; + +/** + * HTML Attribute + * + * Every single HTML attribute is (or should be) an instance of this class. + * This guarantees that every attribute is safe and escaped correctly. + * + * Usually attributes are not instantiated directly, but created through an HTML + * element's exposed methods. + */ +class Attribute +{ + /** @var string */ + protected $name; + + /** @var string The separator used if value is an array */ + protected $separator = ' '; + + /** @var string|array|bool|null */ + protected $value; + + /** + * Create a new HTML attribute from the given name and value + * + * @param string $name The name of the attribute + * @param string|bool|array|null $value The value of the attribute + * + * @throws InvalidArgumentException If the name of the attribute contains special characters + */ + public function __construct($name, $value = null) + { + $this->setName($name)->setValue($value); + } + + /** + * Create a new HTML attribute from the given name and value + * + * @param string $name The name of the attribute + * @param string|bool|array|null $value The value of the attribute + * + * @return static + * + * @throws InvalidArgumentException If the name of the attribute contains special characters + */ + public static function create($name, $value) + { + return new static($name, $value); + } + + /** + * Create a new empty HTML attribute from the given name + * + * The value of the attribute will be null after construction. + * + * @param string $name The name of the attribute + * + * @return static + * + * @throws InvalidArgumentException If the name of the attribute contains special characters + */ + public static function createEmpty($name) + { + return new static($name, null); + } + + /** + * Escape the name of an attribute + * + * Makes sure that the name of an attribute really is a string. + * + * @param string $name + * + * @return string + */ + public static function escapeName($name) + { + return (string) $name; + } + + /** + * Escape the value of an attribute + * + * If the value is an array, returns the string representation + * of all array elements joined with the specified glue string. + * + * Values are escaped according to the HTML5 double-quoted attribute value syntax: + * {@link https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 }. + * + * @param string|array $value + * @param string $glue Glue string to join elements if value is an array + * + * @return string + */ + public static function escapeValue($value, $glue = ' ') + { + if (is_array($value)) { + $value = implode($glue, $value); + } + + // We force double-quoted attribute value syntax so let's start by escaping double quotes + $value = str_replace('"', '"', $value); + + // In addition, values must not contain ambiguous ampersands + $value = preg_replace_callback( + '/&[0-9A-Z]+;/i', + function ($match) { + $subject = $match[0]; + + if (htmlspecialchars_decode($subject, ENT_COMPAT | ENT_HTML5) === $subject) { + // Ambiguous ampersand + return str_replace('&', '&', $subject); + } + + return $subject; + }, + $value + ); + + return $value; + } + + /** + * Get the name of the attribute + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the name of the attribute + * + * @param string $name + * + * @return $this + * + * @throws InvalidArgumentException If the name contains special characters + */ + protected function setName($name) + { + if (! preg_match('/^[a-z][a-z0-9:-]*$/i', $name)) { + throw new InvalidArgumentException(sprintf( + 'Attribute names with special characters are not yet allowed: %s', + $name + )); + } + + $this->name = $name; + + return $this; + } + + /** + * Get the separator by which multiple values are concatenated with + * + * @return string + */ + public function getSeparator(): string + { + return $this->separator; + } + + /** + * Set the separator to concatenate multiple values with + * + * @param string $separator + * + * @return $this + */ + public function setSeparator(string $separator): self + { + $this->separator = $separator; + + return $this; + } + + /** + * Get the value of the attribute + * + * @return string|bool|array|null + */ + public function getValue() + { + return $this->value; + } + + /** + * Set the value of the attribute + * + * @param string|bool|array|null $value + * + * @return $this + */ + public function setValue($value) + { + $this->value = $value; + + return $this; + } + + /** + * Add the given value(s) to the attribute + * + * @param string|array $value The value(s) to add + * + * @return $this + */ + public function addValue($value) + { + $this->value = array_merge((array) $this->value, (array) $value); + + return $this; + } + + /** + * Remove the given value(s) from the attribute + * + * The current value is set to null if it matches the value to remove + * or is in the array of values to remove. + * + * If the current value is an array, all elements are removed which + * match the value(s) to remove. + * + * Does nothing if there is no such value to remove. + * + * @param string|array $value The value(s) to remove + * + * @return $this + */ + public function removeValue($value) + { + $value = (array) $value; + + $current = $this->getValue(); + + if (is_array($current)) { + $this->setValue(array_diff($current, $value)); + } elseif (in_array($current, $value, true)) { + $this->setValue(null); + } + + return $this; + } + + /** + * Test and return true if the attribute is boolean, false otherwise + * + * @return bool + */ + public function isBoolean() + { + return is_bool($this->value); + } + + /** + * Test and return true if the attribute is empty, false otherwise + * + * Null and the empty array will be considered empty. + * + * @return bool + */ + public function isEmpty() + { + return $this->value === null || $this->value === []; + } + + /** + * Render the attribute to HTML + * + * If the value of the attribute is of type boolean, it will be rendered as + * {@link http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes boolean attribute}. + * Note that in this case if the value of the attribute is false, the empty string will be returned. + * + * If the value of the attribute is null or an empty array, + * the empty string will be returned as well. + * + * Escaping of the attribute's value takes place automatically using {@link Attribute::escapeValue()}. + * + * @return string + */ + public function render() + { + if ($this->isEmpty()) { + return ''; + } + + if ($this->isBoolean()) { + if ($this->value) { + return $this->renderName(); + } + + return ''; + } else { + return sprintf( + '%s="%s"', + $this->renderName(), + $this->renderValue() + ); + } + } + + /** + * Render the name of the attribute to HTML + * + * @return string + */ + public function renderName() + { + return static::escapeName($this->name); + } + + /** + * Render the value of the attribute to HTML + * + * @return string + */ + public function renderValue() + { + return static::escapeValue($this->value, $this->separator); + } +} |