diff --git a/core/lib/Drupal/Core/Fault/FaultException.php b/core/lib/Drupal/Core/Fault/FaultException.php deleted file mode 100644 index 5d324a7..0000000 --- a/core/lib/Drupal/Core/Fault/FaultException.php +++ /dev/null @@ -1,12 +0,0 @@ - 'socks')); * $attributes['class'] = array('black-cat', 'white-cat'); @@ -34,6 +35,7 @@ * When printing out individual attributes to customize them within a Twig * template, use the "without" filter to prevent attributes that have already * been printed from being printed again. For example: + * * @code * * {# Produces #} @@ -43,11 +45,14 @@ * \Drupal\Component\Utility\String::checkPlain(). */ class Attribute extends \ArrayObject { - - public function __construct(array $array = []) { + /** + * Returns Drupal\Core\Template\Attribute object. + */ + public function __construct($array = []) { + assert('is_array($array) || (is_object($array) && $array instanceof Traversable)', 'invalidParam'); parent::__construct([]); - foreach($array as $name => $value) { + foreach ($array as $name => $value) { $this[$name] = $value; } } @@ -76,9 +81,9 @@ protected function createAttributeValue($name, $value) { // http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name assert('preg_match(\'/^([\\w_:][\\w\\d\\-_:\\.]*)*$/\', $name)', 'invalidAttributeName'); - // If the value is already an AttributeValueBase object, return it + // If the value is already an AttributeValue object or null, return it // straight away. - if ($value instanceOf AttributeValueBase) { + if ($value === NULL || $value instanceOf AttributeValueInterface) { return $value; } // Some attributes have known W3C patterns concerning their values. @@ -90,15 +95,12 @@ protected function createAttributeValue($name, $value) { 'hidden', 'multiple', 'novalidate', 'readonly', 'required', 'reversed', 'spellcheck', 'checked', 'defer', 'disabled', 'draggable', 'dropzone', 'autoplay', 'selected']) || is_bool($value)) { - $value = new AttributeBoolean($name, $value); + $value = new AttributeBoolean($name, $value); } - elseif (is_array($value) || $value instanceof \Traversable ) { + elseif (is_array($value) || $value instanceof \Traversable) { $value = new AttributeArray($name, $value); } - else if (is_null($value)) { - $value = NULL; - } - else if (!is_object($value) || method_exists($value, '__toString')) { + elseif (!is_object($value) || method_exists($value, '__toString')) { $value = new AttributeString($name, $value); } else { @@ -106,7 +108,7 @@ protected function createAttributeValue($name, $value) { } // Assert the conversion was successful. - assert('$value === NULL || $value instanceof \\Drupal\\Core\\Template\\AttributeValueBase', 'invalidReturn'); + assert('$value === NULL || $value instanceof \\Drupal\\Core\\Template\\AttributeValueInterface', 'invalidReturn'); return $value; } @@ -183,13 +185,7 @@ public function removeClass() { // With no class attribute, there is no need to remove. if (isset($this['class'])) { foreach (func_get_args() as $arg) { - if (!is_array($arg)) { - $arg = explode(' ', $arg); - } - - foreach($arg as $a) { - unset($this['class'][$a]); - } + unset($this['class'][$arg]); } } return $this; @@ -214,7 +210,7 @@ public function hasClass($class) { public function __toString() { $return = ''; foreach ($this as $name => $value) { - if($value === NULL) { + if ($value === NULL) { continue; } @@ -229,8 +225,8 @@ public function __toString() { /** * Implements the magic __clone() method. */ - public function __clone() { - // storage is private, so call it this way. + public function __clone() { + // Storage is private, so call it this way. $clone = $this->getArrayCopy(); foreach ($clone as $name => $value) { @@ -248,6 +244,7 @@ public function __clone() { * Returns the whole array. * * Since making this a child of ArrayObject this becomes a BC wrapper. + * * @deprecated */ public function storage() { diff --git a/core/lib/Drupal/Core/Template/AttributeArray.php b/core/lib/Drupal/Core/Template/AttributeArray.php index d9ae14c..790a271 100644 --- a/core/lib/Drupal/Core/Template/AttributeArray.php +++ b/core/lib/Drupal/Core/Template/AttributeArray.php @@ -20,6 +20,7 @@ * $attributes['class'][] = 'cat'; * @endcode * Incorrect: + * * @code * $attributes = new Attribute(); * $attributes['class'][] = 'cat'; @@ -27,117 +28,55 @@ * * @see \Drupal\Core\Template\Attribute */ -class AttributeArray extends AttributeValueBase implements \ArrayAccess, \IteratorAggregate, \Countable { - - /** - * Ensures empty array as a result of array_filter will not print '$name=""'. - * - * @see \Drupal\Core\Template\AttributeArray::__toString() - * @see \Drupal\Core\Template\AttributeValueBase::render() - */ - const RENDER_EMPTY_ATTRIBUTE = FALSE; - +class AttributeArray extends \ArrayObject implements AttributeValueInterface { /** * Delimiter for the implosion of the array. * * Space is default for BC. */ const DELIMITER = ' '; - - protected $value = []; - /** - * Bind the value passed to the constructor and make all elements a string. - * - * @param array $value The array to put into storage. + * Constructs a \Drupal\Core\Template\AttributeString object. */ - protected function setValue($value) { - foreach ($value as $key => $v) { - $this->value[$key] = trim(strval($v)); - } - } + public function __construct($name, $array = []) { + assert('is_array($array) || $array instanceof \\Traversable', 'invalidParam'); + assert('\\Drupal\\Core\\Fault\\Assertion::validCaller(\'Drupal\\Core\\Template\\Attribute\')', 'invalidCaller'); - /** - * Filter the value of an incoming array element, set its datatype to string. - * - * @param $value Element Value. - * byReference for use as a callback for array_walk. - */ - protected function filterValue( &$value ) { - $value = trim(strval($value)); - } + parent::__construct([]); + $this->name = $name; + foreach ($array as $key => $value) { + $this[$key] = $value; + } + } /** - * Implements ArrayAccess::offsetGet(). + * Implements AttributeValueInterface::value. */ - public function offsetGet($offset) { - return $this->value[$offset]; + public function value() { + return $this->getArrayCopy(); } - /** - * Implements ArrayAccess::offsetSet(). + * Overrides ArrayAccess::offsetSet(). */ public function offsetSet($offset, $value) { $value = trim(strval($value)); - - if (isset($offset)) { - $this->value[$offset] = $value; - } - else { - $this->value[] = $value; + if ($value !== '') { + parent::offsetSet($offset, $value); } } - /** - * Implements ArrayAccess::offsetUnset(). + * Implements AttributeValueInterface::render(). */ - public function offsetUnset($offset) { - unset($this->value[$offset]); - } - - /** - * Implements ArrayAccess::offsetExists(). - */ - public function offsetExists($offset) { - return isset($this->value[$offset]); + public function render() { + if (count($this) > 0) { + return $this->name . '="' . strval($this) . '"'; + } } - /** * Implements the magic __toString() method. */ public function __toString() { - return String::checkPlain(implode(static::DELIMITER, $this->value)); - } - - /** - * Implements IteratorAggregate::getIterator(). - */ - public function getIterator() { - return new \ArrayIterator($this->value); - } - - /** - * Implements Countable::count - */ - public function count() { - return count($this->value); - } - - /** - * Exchange the array for another one. - * - * @see ArrayObject::exchangeArray - * - * @param array $input - * The array input to replace the internal value. - * - * @return array - * The old array value. - */ - public function exchangeArray(array $input) { - $old = $this->value; - $this->setValue($input); - return $old; + return String::checkPlain(implode(static::DELIMITER, $this->getArrayCopy())); } } diff --git a/core/lib/Drupal/Core/Template/AttributeBoolean.php b/core/lib/Drupal/Core/Template/AttributeBoolean.php index 81a249a..e6d963e 100644 --- a/core/lib/Drupal/Core/Template/AttributeBoolean.php +++ b/core/lib/Drupal/Core/Template/AttributeBoolean.php @@ -7,8 +7,6 @@ namespace Drupal\Core\Template; -use Drupal\Component\Utility\String; - /** * A class that defines a type of boolean HTML attribute. * @@ -29,24 +27,32 @@ * * @see \Drupal\Core\Template\Attribute */ -class AttributeBoolean extends AttributeValueBase { - - protected function setValue($value) { +class AttributeBoolean implements AttributeValueInterface { + /** + * Returns a Drupal\Core\Template\AttributeBoolean. + */ + public function __construct($name, $value) { + assert('\\Drupal\\Core\\Fault\\Assertion::validCaller(\'Drupal\\Core\\Template\\Attribute\')', 'invalidCaller'); + $this->name = $name; $this->value = (boolean) $value; } - /** - * Overrides AttributeValueBase::render(). + * Implements AttributeValueInterface::render(). */ public function render() { - return $this->__toString(); + return $this->value ? "{$this->name}=\"{$this->name}\"" : ''; + } + /** + * Returns the raw value. + */ + public function value() { + return $this->value; } - /** * Implements the magic __toString() method. */ public function __toString() { - return $this->value === FALSE ? '' : String::checkPlain($this->name); + return $this->value ? "{$this->name}" : ''; } } diff --git a/core/lib/Drupal/Core/Template/AttributeNamedClass.php b/core/lib/Drupal/Core/Template/AttributeNamedClass.php index 67c40be..0d777a5 100644 --- a/core/lib/Drupal/Core/Template/AttributeNamedClass.php +++ b/core/lib/Drupal/Core/Template/AttributeNamedClass.php @@ -1,10 +1,16 @@ value = []; - foreach ($value as $v) { - $this[] = trim(strval($v)); + elseif (empty($value)) { + $value = []; } - } - - protected function setOne($value) { - // HTML classes are case sensitive, but CSS class selectors are not - // Forgetting this quirk can lead to enormous debugging headaches - // when it surfaces. - if (!empty($value)) { - // If an attempt is made to assign a dupe with a different case, warn. - assert('!isset($this->value[strtolower($value)]) || $value === $this->value[strtolower($value)]', 'cssCaseInsensitive'); - // Assert valid - assert('preg_match(\'/^((?!\d)(?!\-\-)(?!\-\d)([\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]+))$/u\', $value)', 'invalidIdentifier'); - $this->value[strtolower($value)] = $value; - } + parent::__construct('class', $value); } - + /** + * {@inheritdoc} + */ public function offsetSet($offset, $value) { + if (is_array($value)) { - foreach($value as $v) { + foreach ($value as $v) { $this[] = $v; } } - elseif (strpos($value, self::DELIMITER) !== false) { - $val = explode(self::DELIMITER, $value); - foreach($val as $v) { + elseif (strpos($value, self::DELIMITER) !== FALSE) { + $value = explode(self::DELIMITER, $value); + foreach ($value as $v) { $this[] = $v; } } - elseif(!empty($value)) { - $this->setOne($value); + elseif (!empty($value)) { + // If an attempt is made to assign a dupe with a different case, warn. + assert('!(isset($this[$value]) && $this[$value] !== $value)', 'cssCaseInsensitive'); + // Now before accepting assert valid. + assert('preg_match(\'/^((?!\d)(?!\-\-)(?!\-\d)([\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]+))$/u\', $value)', 'invalidIdentifier'); + + parent::offsetSet(strtolower($value), $value); } } + /** + * {@inheritdoc} + */ + public function offsetGet($offset) { + return parent::offsetGet(strtolower($offset)); + } /** - * Implements ArrayAccess::offsetUnset(). + * Overrides ArrayAccess::offsetUnset(). + * + * Accepts a space delimited set of classes to unset as well as + * normal argument. */ public function offsetUnset($offset) { - assert('is_string($offset);', 'notString'); - if (strpos($offset, self::DELIMITER) !== 0) { - $off = explode(self::DELIMITER, $offset); - foreach ( $off as $o ) { - unset($this->value[strtolower($o)]); + if (is_array($offset)) { + foreach ($offset as $o) { + unset($this[$o]); + } + } + else { + $offset = strtolower($offset); + if (strpos($offset, self::DELIMITER) !== 0) { + $offset = explode(self::DELIMITER, $offset); + foreach ($offset as $o) { + if (isset($this[$o])) { + parent::offsetUnset($o); + } + } + } + else { + if (isset($this[$offset])) { + parent::offsetUnset($offset); + } } } - unset($this->value[strtolower($offset)]); } - + /** + * Overrides AttributeArray::offsetExists(). + * + * In addition to the normal search, this also checks a space delimited + * list of classes and returns true only if all match. + */ public function offsetExists($offset) { - assert('is_string($offset);', 'notString'); - return isset($this->value[strtolower($offset)]); + assert('is_string($offset)', 'notString'); + $offset = strtolower($offset); + if (strpos($offset, self::DELIMITER) !== 0) { + $offset = explode(self::DELIMITER, $offset); + + foreach ($offset as $o) { + if ($o !== '' && !parent::offsetExists($o)) { + return FALSE; + } + } + return TRUE; + } + else { + return parent::offsetExists($offset); + } } } diff --git a/core/lib/Drupal/Core/Template/AttributeString.php b/core/lib/Drupal/Core/Template/AttributeString.php index 8b8feb7..4e2bb6f 100644 --- a/core/lib/Drupal/Core/Template/AttributeString.php +++ b/core/lib/Drupal/Core/Template/AttributeString.php @@ -24,16 +24,33 @@ * * @see \Drupal\Core\Template\Attribute */ -class AttributeString extends AttributeValueBase { - - public function setValue( $value ) { - $this->value = (string) $value; +class AttributeString implements AttributeValueInterface { + /** + * Constructs a \Drupal\Core\Template\AttributeString object. + */ + public function __construct($name, $value) { + assert('\\Drupal\\Core\\Fault\\Assertion::validCaller(\'Drupal\\Core\\Template\\Attribute\')', 'invalidCaller'); + $this->name = $name; + $this->value = trim((string) $value); + $this->safeValue = String::checkPlain($this->value); + } + /** + * Implements AttributeValueInterface::render. + */ + public function render() { + return "{$this->name}=\"{$this->safeValue}\""; + } + /** + * Returns the raw value. + */ + public function value() { + return $this->value; } /** * Implements the magic __toString() method. */ public function __toString() { - return String::checkPlain($this->value); + return $this->safeValue; } } diff --git a/core/lib/Drupal/Core/Template/AttributeValueInterface.php b/core/lib/Drupal/Core/Template/AttributeValueInterface.php new file mode 100644 index 0000000..b905e94 --- /dev/null +++ b/core/lib/Drupal/Core/Template/AttributeValueInterface.php @@ -0,0 +1,31 @@ + array('a/class'), + 'class' => array('a-class'), ); $expected_links = ''; $expected_links .= '