Newer
Older
<?php
/**
* @file
Alex Pott
committed
* Contains \Drupal\Core\TypedData\Plugin\DataType\Map.
Alex Pott
committed
namespace Drupal\Core\TypedData\Plugin\DataType;
catch
committed
use Drupal\Core\TypedData\TypedData;
use Drupal\Core\TypedData\ComplexDataInterface;
/**
* The "map" data type.
*
* The "map" data type represent a simple complex data type, e.g. for
* representing associative arrays. It can also serve as base class for any
* complex data type.
*
* By default there is no metadata for contained properties. Extending classes
* may want to override MapDataDefinition::getPropertyDefinitions() to define
* it.
Alex Pott
committed
*
Angie Byron
committed
* @ingroup typed_data
*
Alex Pott
committed
* @DataType(
* id = "map",
* label = @Translation("Map"),
* definition_class = "\Drupal\Core\TypedData\MapDataDefinition"
Alex Pott
committed
* )
catch
committed
class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface {
/**
* The data definition.
*
* @var \Drupal\Core\TypedData\ComplexDataDefinitionInterface
*/
protected $definition;
/**
* An array of values for the contained properties.
*
* @var array
*/
protected $values = array();
/**
* The array of properties.
* @var \Drupal\Core\TypedData\TypedDataInterface[]
protected $properties = array();
Angie Byron
committed
* {@inheritdoc}
Angie Byron
committed
public function getValue() {
// Update the values and return them.
foreach ($this->properties as $name => $property) {
$definition = $property->getDataDefinition();
Angie Byron
committed
if (!$definition->isComputed()) {
catch
committed
$value = $property->getValue();
// Only write NULL values if the whole map is not NULL.
if (isset($this->values) || isset($value)) {
$this->values[$name] = $value;
}
}
}
return $this->values;
}
/**
* Overrides \Drupal\Core\TypedData\TypedData::setValue().
*
* @param array|null $values
* An array of property values.
*/
catch
committed
public function setValue($values, $notify = TRUE) {
if (isset($values) && !is_array($values)) {
throw new \InvalidArgumentException("Invalid values given. Values must be represented as an associative array.");
}
$this->values = $values;
catch
committed
// Update any existing property objects.
foreach ($this->properties as $name => $property) {
Alex Pott
committed
$value = isset($values[$name]) ? $values[$name] : NULL;
catch
committed
$property->setValue($value, FALSE);
Alex Pott
committed
// Remove the value from $this->values to ensure it does not contain any
// value for computed properties.
unset($this->values[$name]);
catch
committed
}
// Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
* {@inheritdoc}
*/
public function getString() {
$strings = array();
foreach ($this->getProperties() as $property) {
$strings[] = $property->getString();
}
// Remove any empty strings resulting from empty items.
Alex Pott
committed
return implode(', ', array_filter($strings, '\Drupal\Component\Utility\Unicode::strlen'));
}
/**
* {@inheritdoc}
*/
public function get($property_name) {
if (!isset($this->properties[$property_name])) {
catch
committed
$value = NULL;
if (isset($this->values[$property_name])) {
$value = $this->values[$property_name];
}
// If the property is unknown, this will throw an exception.
Alex Bronstein
committed
$this->properties[$property_name] = $this->getTypedDataManager()->getPropertyInstance($this, $property_name, $value);
}
return $this->properties[$property_name];
}
/**
Alex Pott
committed
* {@inheritdoc}
catch
committed
public function set($property_name, $value, $notify = TRUE) {
Alex Pott
committed
// Separate the writing in a protected method, such that onChange
// implementations can make use of it.
$this->writePropertyValue($property_name, $value);
$this->onChange($property_name, $notify);
return $this;
}
/**
* Writes the value of a property without handling changes.
*
* Implementations of onChange() should use this method instead of set() in
* order to avoid onChange() being triggered again.
*
* @param string $property_name
* The name of the property to be written.
* @param $value
* The value to set.
*/
protected function writePropertyValue($property_name, $value) {
if ($this->definition->getPropertyDefinition($property_name)) {
Alex Pott
committed
$this->get($property_name)->setValue($value, FALSE);
}
else {
catch
committed
// Just set the plain value, which allows adding a new entry to the map.
$this->values[$property_name] = $value;
}
}
/**
* {@inheritdoc}
*/
public function getProperties($include_computed = FALSE) {
$properties = array();
foreach ($this->definition->getPropertyDefinitions() as $name => $definition) {
if ($include_computed || !$definition->isComputed()) {
$properties[$name] = $this->get($name);
}
}
return $properties;
}
/**
public function toArray() {
$values = array();
foreach ($this->getProperties() as $name => $property) {
$values[$name] = $property->getValue();
}
return $values;
}
/**
* {@inheritdoc}
*/
public function getIterator() {
return new \ArrayIterator($this->getProperties());
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
catch
committed
foreach ($this->properties as $property) {
$definition = $property->getDataDefinition();
if (!$definition->isComputed() && $property->getValue() !== NULL) {
return FALSE;
}
}
catch
committed
if (isset($this->values)) {
foreach ($this->values as $name => $value) {
if (isset($value) && !isset($this->properties[$name])) {
return FALSE;
}
}
}
return TRUE;
}
/**
* Magic method: Implements a deep clone.
*/
public function __clone() {
catch
committed
foreach ($this->properties as $name => $property) {
$this->properties[$name] = clone $property;
catch
committed
$this->properties[$name]->setContext($name, $this);
}
}
/**
Alex Pott
committed
* {@inheritdoc}
*
* @param bool $notify
* (optional) Whether to forward the notification to the parent. Defaults to
* TRUE. By passing FALSE, overrides of this method can re-use the logic
* of parent classes without triggering notification.
catch
committed
*/
Alex Pott
committed
public function onChange($property_name, $notify = TRUE) {
catch
committed
// Notify the parent of changes.
Alex Pott
committed
if ($notify && isset($this->parent)) {
catch
committed
$this->parent->onChange($this->name);
/**
* {@inheritdoc}
*/
public function applyDefaultValue($notify = TRUE) {
// Apply the default value of all properties.
foreach ($this->getProperties() as $property) {
$property->applyDefaultValue(FALSE);
}
return $this;
}