commit b442dd3528d6db5e92bde96e92985a4d45a1b71d Author: fago Date: Sun Feb 10 11:54:35 2013 +0100 Extract genric list item from field class. diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php index 49418a0..9c8cb5e 100644 --- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php +++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php @@ -10,7 +10,7 @@ use Drupal\Core\Entity\Field\FieldInterface; use Drupal\user\Plugin\Core\Entity\User; use Drupal\Core\TypedData\ContextAwareInterface; -use Drupal\Core\TypedData\ContextAwareTypedData; +use Drupal\Core\TypedData\ItemList; use Drupal\Core\TypedData\TypedDataInterface; use ArrayIterator; use IteratorAggregate; @@ -27,7 +27,7 @@ * * @see \Drupal\Core\Entity\Field\FieldInterface */ -class Field extends ContextAwareTypedData implements IteratorAggregate, FieldInterface { +class Field extends ItemList implements IteratorAggregate, FieldInterface { /** * Numerically indexed array of field items, implementing the @@ -50,7 +50,7 @@ public function __construct(array $definition, $name = NULL, ContextAwareInterfa } /** - * Overrides \Drupal\Core\TypedData\TypedData::getValue(). + * Overrides \Drupal\Core\TypedData\ItemList::getValue(). */ public function getValue() { if (isset($this->list)) { @@ -68,147 +68,6 @@ public function getValue() { } /** - * Overrides \Drupal\Core\TypedData\TypedData::setValue(). - * - * @param array|null $values - * An array of values of the field items, or NULL to unset the field. - */ - public function setValue($values) { - if (!isset($values) || $values === array()) { - $this->list = $values; - } - else { - // Support passing in only the value of the first item. - if (!is_array($values) || !is_numeric(current(array_keys($values)))) { - $values = array(0 => $values); - } - - // Clear the values of properties for which no value has been passed. - if (isset($this->list)) { - $this->list = array_intersect_key($this->list, $values); - } - - // Set the values. - foreach ($values as $delta => $value) { - if (!is_numeric($delta)) { - throw new InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.'); - } - elseif (!isset($this->list[$delta])) { - $this->list[$delta] = $this->createItem($delta, $value); - } - else { - $this->list[$delta]->setValue($value); - } - } - } - } - - /** - * Overrides \Drupal\Core\TypedData\TypedData::getString(). - */ - public function getString() { - $strings = array(); - if (isset($this->list)) { - foreach ($this->list as $item) { - $strings[] = $item->getString(); - } - return implode(', ', array_filter($strings)); - } - } - - /** - * Overrides \Drupal\Core\TypedData\TypedData::getConstraints(). - */ - public function getConstraints() { - // Apply the constraints to the list items only. - return array(); - } - - /** - * Implements \ArrayAccess::offsetExists(). - */ - public function offsetExists($offset) { - return isset($this->list) && array_key_exists($offset, $this->list); - } - - /** - * Implements \ArrayAccess::offsetUnset(). - */ - public function offsetUnset($offset) { - if (isset($this->list)) { - unset($this->list[$offset]); - } - } - - /** - * Implements \ArrayAccess::offsetGet(). - */ - public function offsetGet($offset) { - if (!is_numeric($offset)) { - throw new InvalidArgumentException('Unable to get a value with a non-numeric delta in a list.'); - } - // Allow getting not yet existing items as well. - // @todo: Maybe add a public createItem() method in addition? - elseif (!isset($this->list[$offset])) { - $this->list[$offset] = $this->createItem($offset); - } - return $this->list[$offset]; - } - - /** - * Helper for creating a list item object. - * - * @return \Drupal\Core\TypedData\TypedDataInterface - */ - protected function createItem($offset = 0, $value = NULL) { - return typed_data()->getPropertyInstance($this, $offset, $value); - } - - /** - * Implements \Drupal\Core\TypedData\ListInterface::getItemDefinition(). - */ - public function getItemDefinition() { - return array('list' => FALSE) + $this->definition; - } - - /** - * Implements \ArrayAccess::offsetSet(). - */ - public function offsetSet($offset, $value) { - if (!isset($offset)) { - // The [] operator has been used so point at a new entry. - $offset = $this->list ? max(array_keys($this->list)) + 1 : 0; - } - if (is_numeric($offset)) { - // Support setting values via typed data objects. - if ($value instanceof TypedDataInterface) { - $value = $value->getValue(); - } - $this->offsetGet($offset)->setValue($value); - } - else { - throw new InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.'); - } - } - - /** - * Implements \IteratorAggregate::getIterator(). - */ - public function getIterator() { - if (isset($this->list)) { - return new ArrayIterator($this->list); - } - return new ArrayIterator(array()); - } - - /** - * Implements \Countable::count(). - */ - public function count() { - return isset($this->list) ? count($this->list) : 0; - } - - /** * Implements \Drupal\Core\Entity\Field\FieldInterface::getPropertyDefinition(). */ public function getPropertyDefinition($name) { @@ -258,34 +117,6 @@ public function __unset($property_name) { } /** - * Implements \Drupal\Core\TypedData\ListInterface::isEmpty(). - */ - public function isEmpty() { - if (isset($this->list)) { - foreach ($this->list as $item) { - if (!$item->isEmpty()) { - return FALSE; - } - } - } - return TRUE; - } - - /** - * Magic method: Implements a deep clone. - */ - public function __clone() { - if (isset($this->list)) { - foreach ($this->list as $delta => $item) { - $this->list[$delta] = clone $item; - if ($item instanceof ContextAwareInterface) { - $this->list[$delta]->setContext($delta, $this); - } - } - } - } - - /** * Implements \Drupal\Core\TypedData\AccessibleInterface::access(). */ public function access($operation = 'view', User $account = NULL) { diff --git a/core/lib/Drupal/Core/TypedData/ItemList.php b/core/lib/Drupal/Core/TypedData/ItemList.php new file mode 100644 index 0000000..97e4ab4 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/ItemList.php @@ -0,0 +1,204 @@ +list; + } + + /** + * Overrides \Drupal\Core\TypedData\TypedData::setValue(). + * + * @param array|null $values + * An array of values of the field items, or NULL to unset the field. + */ + public function setValue($values) { + if (!isset($values) || $values === array()) { + $this->list = $values; + } + else { + // Support passing in only the value of the first item. + if (!is_array($values) || !is_numeric(current(array_keys($values)))) { + $values = array(0 => $values); + } + + // Clear the values of properties for which no value has been passed. + if (isset($this->list)) { + $this->list = array_intersect_key($this->list, $values); + } + + // Set the values. + foreach ($values as $delta => $value) { + if (!is_numeric($delta)) { + throw new InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.'); + } + elseif (!isset($this->list[$delta])) { + $this->list[$delta] = $this->createItem($delta, $value); + } + else { + $this->list[$delta]->setValue($value); + } + } + } + } + + /** + * Overrides \Drupal\Core\TypedData\TypedData::getString(). + */ + public function getString() { + $strings = array(); + if (isset($this->list)) { + foreach ($this->list as $item) { + $strings[] = $item->getString(); + } + return implode(', ', array_filter($strings)); + } + } + + /** + * Overrides \Drupal\Core\TypedData\TypedData::getConstraints(). + */ + public function getConstraints() { + // Apply the constraints to the list items only. + return array(); + } + + /** + * Implements \ArrayAccess::offsetExists(). + */ + public function offsetExists($offset) { + return isset($this->list) && array_key_exists($offset, $this->list); + } + + /** + * Implements \ArrayAccess::offsetUnset(). + */ + public function offsetUnset($offset) { + if (isset($this->list)) { + unset($this->list[$offset]); + } + } + + /** + * Implements \ArrayAccess::offsetGet(). + */ + public function offsetGet($offset) { + if (!is_numeric($offset)) { + throw new InvalidArgumentException('Unable to get a value with a non-numeric delta in a list.'); + } + // Allow getting not yet existing items as well. + // @todo: Maybe add a public createItem() method in addition? + elseif (!isset($this->list[$offset])) { + $this->list[$offset] = $this->createItem($offset); + } + return $this->list[$offset]; + } + + /** + * Helper for creating a list item object. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + */ + protected function createItem($offset = 0, $value = NULL) { + return typed_data()->getPropertyInstance($this, $offset, $value); + } + + /** + * Implements \Drupal\Core\TypedData\ListInterface::getItemDefinition(). + */ + public function getItemDefinition() { + return array('list' => FALSE) + $this->definition; + } + + /** + * Implements \ArrayAccess::offsetSet(). + */ + public function offsetSet($offset, $value) { + if (!isset($offset)) { + // The [] operator has been used so point at a new entry. + $offset = $this->list ? max(array_keys($this->list)) + 1 : 0; + } + if (is_numeric($offset)) { + // Support setting values via typed data objects. + if ($value instanceof TypedDataInterface) { + $value = $value->getValue(); + } + $this->offsetGet($offset)->setValue($value); + } + else { + throw new InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.'); + } + } + + /** + * Implements \IteratorAggregate::getIterator(). + */ + public function getIterator() { + if (isset($this->list)) { + return new ArrayIterator($this->list); + } + return new ArrayIterator(array()); + } + + /** + * Implements \Countable::count(). + */ + public function count() { + return isset($this->list) ? count($this->list) : 0; + } + + /** + * Implements \Drupal\Core\TypedData\ListInterface::isEmpty(). + */ + public function isEmpty() { + if (isset($this->list)) { + foreach ($this->list as $item) { + if (!$item->isEmpty()) { + return FALSE; + } + } + } + return TRUE; + } + + /** + * Magic method: Implements a deep clone. + */ + public function __clone() { + if (isset($this->list)) { + foreach ($this->list as $delta => $item) { + $this->list[$delta] = clone $item; + if ($item instanceof ContextAwareInterface) { + $this->list[$delta]->setContext($delta, $this); + } + } + } + } +} diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index 8b5306d..5723f7c 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -191,14 +191,20 @@ public function getInstance(array $options) { * @see \Drupal\Core\TypedData\TypedDataManager::create() */ public function getPropertyInstance(ContextAwareInterface $object, $property_name, $value = NULL) { - $key = $object->getRoot()->getType() . ':' . $object->getPropertyPath() . '.'; - // If we are creating list items, we always use 0 in the key as all list - // items look the same. - $key .= is_numeric($property_name) ? 0 : $property_name; + if ($root = $object->getRoot()) { + $key = $root->getType() . ':' . $object->getPropertyPath() . '.'; + // If we are creating list items, we always use 0 in the key as all list + // items look the same. + $key .= is_numeric($property_name) ? 0 : $property_name; } + else { + // Missing context, thus we cannot determine a unique key for prototyping. + // Fall back to create a new prototype on each call. + $key = FALSE; + } // Make sure we have a prototype. Then, clone the prototype and set object // specific values, i.e. the value and the context. - if (!isset($this->prototypes[$key])) { + if (!isset($this->prototypes[$key]) || !$key) { // Create the initial prototype. For that we need to fetch the definition // of the to be created property instance from the parent. if ($object instanceof ComplexDataInterface) { diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 223af2e..f868f26 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2194,6 +2194,7 @@ function system_data_type_info() { 'label' => t('String'), 'class' => '\Drupal\Core\TypedData\Type\String', 'primitive type' => Primitive::STRING, + 'list class' => '\Drupal\Core\TypedData\ItemList', ), 'integer' => array( 'label' => t('Integer'),