Commit 5fc86b00 authored by alexpott's avatar alexpott

Issue #1868004 by fago, das-peter, Berdir, EclipseGc, fubhy the cat, dixon_:...

Issue #1868004 by fago, das-peter, Berdir, EclipseGc, fubhy the cat, dixon_: Improve the TypedData API usage of EntityNG.
parent 1c9bd127
...@@ -53,15 +53,11 @@ public function get($property_name) { ...@@ -53,15 +53,11 @@ public function get($property_name) {
* Implements Drupal\Core\TypedData\ComplexDataInterface::set(). * Implements Drupal\Core\TypedData\ComplexDataInterface::set().
*/ */
public function set($property_name, $value, $notify = TRUE) { public function set($property_name, $value, $notify = TRUE) {
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
// Set the data into the configuration array but behave according to the // Set the data into the configuration array but behave according to the
// interface specification when we've got a null value. // interface specification when we've got a null value.
if (isset($value)) { if (isset($value)) {
$this->value[$property_name] = $value; $this->value[$property_name] = $value;
return $this->get($property_name); $property = $this->get($property_name);
} }
else { else {
// In these objects, when clearing the value, the property is gone. // In these objects, when clearing the value, the property is gone.
...@@ -69,8 +65,12 @@ public function set($property_name, $value, $notify = TRUE) { ...@@ -69,8 +65,12 @@ public function set($property_name, $value, $notify = TRUE) {
$property = $this->get($property_name); $property = $this->get($property_name);
unset($this->value[$property_name]); unset($this->value[$property_name]);
$property->setValue($value); $property->setValue($value);
return $property;
} }
// Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
return $property;
} }
/** /**
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\TypedData\TranslatableInterface; use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\user\UserInterface;
use IteratorAggregate; use IteratorAggregate;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
...@@ -425,62 +424,66 @@ public function getNGEntity() { ...@@ -425,62 +424,66 @@ public function getNGEntity() {
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::getType(). * {@inheritdoc}
*/ */
public function getType() { public function getType() {
// @todo: Incorporate the entity type here by making entities proper // @todo: This does not make much sense, so remove once TypedDataInterface
// typed data. See http://drupal.org/node/1868004. // is removed. See https://drupal.org/node/2002138.
return 'entity'; if ($this->bundle() != $this->entityType()) {
return 'entity:' . $this->entityType() . ':' . $this->bundle();
}
return 'entity:' . $this->entityType();
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition(). * {@inheritdoc}
*/ */
public function getDefinition() { public function getDefinition() {
// @todo: This does not make much sense, so remove once TypedDataInterface
// is removed. See https://drupal.org/node/2002138.
return array( return array(
'type' => $this->getType() 'type' => $this->getType()
); );
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::getValue(). * {@inheritdoc}
*/ */
public function getValue() { public function getValue() {
// @todo: Implement by making entities proper typed data. See // @todo: This does not make much sense, so remove once TypedDataInterface
// http://drupal.org/node/1868004. // is removed. See https://drupal.org/node/2002138.
return $this->getPropertyValues();
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
*/ */
public function setValue($value, $notify = TRUE) { public function setValue($value, $notify = TRUE) {
// @todo: Implement by making entities proper typed data. See // @todo: This does not make much sense, so remove once TypedDataInterface
// http://drupal.org/node/1868004. // is removed. See https://drupal.org/node/2002138.
$this->setPropertyValues($value);
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::getString(). * {@inheritdoc}
*/ */
public function getString() { public function getString() {
// @todo: Implement by making entities proper typed data. See return $this->label();
// http://drupal.org/node/1868004.
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints(). * {@inheritdoc}
*/ */
public function getConstraints() { public function getConstraints() {
// @todo: Implement by making entities proper typed data. See
// http://drupal.org/node/1868004.
return array(); return array();
} }
/** /**
* Implements \Drupal\Core\TypedData\TypedDataInterface::validate(). * {@inheritdoc}
*/ */
public function validate() { public function validate() {
// @todo: Implement by making entities proper typed data. See // @todo: Add the typed data manager as proper dependency.
// http://drupal.org/node/1868004. return \Drupal::typedData()->getValidator()->validate($this);
} }
/** /**
......
...@@ -184,6 +184,7 @@ public function __set($name, $value) { ...@@ -184,6 +184,7 @@ public function __set($name, $value) {
// out of sync. That way, the next field object instantiated by EntityNG // out of sync. That way, the next field object instantiated by EntityNG
// will hold the updated value. // will hold the updated value.
unset($this->decorated->fields[$name]); unset($this->decorated->fields[$name]);
$this->decorated->onChange($name);
} }
/** /**
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Core\TypedData\AccessibleInterface; use Drupal\Core\TypedData\AccessibleInterface;
use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\ComplexDataInterface;
use Drupal\Core\TypedData\IdentifiableInterface;
use Drupal\Core\TypedData\TranslatableInterface; use Drupal\Core\TypedData\TranslatableInterface;
/** /**
...@@ -27,16 +28,7 @@ ...@@ -27,16 +28,7 @@
* @see \Drupal\Core\TypedData\TypedDataManager * @see \Drupal\Core\TypedData\TypedDataManager
* @see \Drupal\Core\Field\FieldInterface * @see \Drupal\Core\Field\FieldInterface
*/ */
interface EntityInterface extends ComplexDataInterface, AccessibleInterface, TranslatableInterface { interface EntityInterface extends IdentifiableInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface {
/**
* Returns the entity identifier (the entity's machine name or numeric ID).
*
* @return
* The identifier of the entity, or NULL if the entity does not yet have
* an identifier.
*/
public function id();
/** /**
* Returns the entity UUID (Universally Unique Identifier). * Returns the entity UUID (Universally Unique Identifier).
......
...@@ -167,15 +167,6 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans ...@@ -167,15 +167,6 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans
$this->init(); $this->init();
} }
/**
* Gets the typed data type of the entity.
*
* @return string
*/
public function getType() {
return $this->entityType;
}
/** /**
* Initialize the object. Invoked upon construction and wake up. * Initialize the object. Invoked upon construction and wake up.
*/ */
...@@ -458,7 +449,7 @@ protected function getDefaultLanguage() { ...@@ -458,7 +449,7 @@ protected function getDefaultLanguage() {
} }
if (empty($this->language)) { if (empty($this->language)) {
// Make sure we return a proper language object. // Make sure we return a proper language object.
$this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED)); $this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE));
} }
} }
return $this->language; return $this->language;
...@@ -841,12 +832,4 @@ public function label($langcode = NULL) { ...@@ -841,12 +832,4 @@ public function label($langcode = NULL) {
return $label; return $label;
} }
/**
* {@inheritdoc}
*/
public function validate() {
// @todo: Add the typed data manager as proper dependency.
return \Drupal::typedData()->getValidator()->validate($this);
}
} }
...@@ -77,10 +77,6 @@ public function getValue($include_computed = FALSE) { ...@@ -77,10 +77,6 @@ public function getValue($include_computed = FALSE) {
* Overrides \Drupal\Core\TypedData\ItemList::setValue(). * Overrides \Drupal\Core\TypedData\ItemList::setValue().
*/ */
public function setValue($values, $notify = TRUE) { public function setValue($values, $notify = TRUE) {
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
if (!isset($values) || $values === array()) { if (!isset($values) || $values === array()) {
$this->list = $values; $this->list = $values;
} }
...@@ -108,6 +104,10 @@ public function setValue($values, $notify = TRUE) { ...@@ -108,6 +104,10 @@ public function setValue($values, $notify = TRUE) {
} }
} }
} }
// Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
} }
/** /**
......
...@@ -49,10 +49,6 @@ public function setValue($values, $notify = TRUE) { ...@@ -49,10 +49,6 @@ public function setValue($values, $notify = TRUE) {
$keys = array_keys($this->getPropertyDefinitions()); $keys = array_keys($this->getPropertyDefinitions());
$values = array($keys[0] => $values); $values = array($keys[0] => $values);
} }
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
$this->values = $values; $this->values = $values;
// Update any existing property objects. // Update any existing property objects.
foreach ($this->properties as $name => $property) { foreach ($this->properties as $name => $property) {
...@@ -63,6 +59,10 @@ public function setValue($values, $notify = TRUE) { ...@@ -63,6 +59,10 @@ public function setValue($values, $notify = TRUE) {
$property->setValue($value, FALSE); $property->setValue($value, FALSE);
unset($this->values[$name]); unset($this->values[$name]);
} }
// Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
} }
/** /**
...@@ -83,10 +83,6 @@ public function __get($name) { ...@@ -83,10 +83,6 @@ public function __get($name) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function set($property_name, $value, $notify = TRUE) { public function set($property_name, $value, $notify = TRUE) {
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
// For defined properties there is either a property object or a plain // For defined properties there is either a property object or a plain
// value that needs to be updated. // value that needs to be updated.
if (isset($this->properties[$property_name])) { if (isset($this->properties[$property_name])) {
...@@ -97,6 +93,10 @@ public function set($property_name, $value, $notify = TRUE) { ...@@ -97,6 +93,10 @@ public function set($property_name, $value, $notify = TRUE) {
else { else {
$this->values[$property_name] = $value; $this->values[$property_name] = $value;
} }
// Directly notify ourselves.
if ($notify) {
$this->onChange($property_name);
}
} }
/** /**
...@@ -135,8 +135,10 @@ public function onChange($property_name) { ...@@ -135,8 +135,10 @@ public function onChange($property_name) {
} }
// Remove the plain value, such that any further __get() calls go via the // Remove the plain value, such that any further __get() calls go via the
// updated property object. // updated property object.
if (isset($this->properties[$property_name])) {
unset($this->values[$property_name]); unset($this->values[$property_name]);
} }
}
/** /**
* {@inheritdoc} * {@inheritdoc}
......
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver.
*/
namespace Drupal\Core\Entity\Plugin\DataType\Deriver;
use Drupal\Component\Plugin\Derivative\DerivativeInterface;
/**
* Provides data type plugins for each existing entity type and bundle.
*/
class EntityDeriver implements DerivativeInterface {
/**
* List of derivative definitions.
*
* @var array
*/
protected $derivatives = array();
/**
* {@inheritdoc}
*/
public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
return $this->derivatives[$derivative_id];
}
$this->getDerivativeDefinitions($base_plugin_definition);
if (isset($this->derivatives[$derivative_id])) {
return $this->derivatives[$derivative_id];
}
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions(array $base_plugin_definition) {
// Also keep the 'entity' defined as is.
$this->derivatives[''] = $base_plugin_definition;
// Add definitions for each entity type and bundle.
foreach (entity_get_info() as $entity_type => $info) {
$this->derivatives[$entity_type] = array(
'label' => $info['label'],
'class' => $info['class'],
'constraints' => array('EntityType' => $entity_type),
) + $base_plugin_definition;
// Incorporate the bundles as entity:$entity_type:$bundle, if any.
foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) {
if ($bundle !== $entity_type) {
$this->derivatives[$entity_type . ':' . $bundle] = array(
'label' => $bundle_info['label'],
'class' => $info['class'],
'constraints' => array(
'EntityType' => $entity_type,
'Bundle' => $bundle,
),
) + $base_plugin_definition;
}
}
}
return $this->derivatives;
}
}
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
/** /**
* @file * @file
* Contains \Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative. * Contains \Drupal\Core\Entity\Plugin\DataType\Deriver\FieldItemDeriver.
*/ */
namespace Drupal\Core\Entity\Plugin\DataType; namespace Drupal\Core\Entity\Plugin\DataType\Deriver;
use Drupal\Component\Plugin\Derivative\DerivativeInterface; use Drupal\Component\Plugin\Derivative\DerivativeInterface;
/** /**
* Provides data type plugins for each existing field type plugin. * Provides data type plugins for each existing field type plugin.
*/ */
class FieldDataTypeDerivative implements DerivativeInterface { class FieldItemDeriver implements DerivativeInterface {
/** /**
* List of derivative definitions. * List of derivative definitions.
......
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Plugin\DataType\Entity.
*/
namespace Drupal\Core\Entity\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the base plugin for deriving data types for entity types.
*
* Note that the class only registers the plugin, and is actually never used.
* \Drupal\Core\Entity\Entity is available for use as base class.
*
* @DataType(
* id = "entity",
* label = @Translation("Entity"),
* description = @Translation("All kind of entities, e.g. nodes, comments or users."),
* derivative = "\Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver"
* )
*/
abstract class Entity {
}
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Plugin\DataType\EntityReference.
*/
namespace Drupal\Core\Entity\Plugin\DataType;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\DataReferenceBase;
/**
* Defines an 'entity_reference' data type.
*
* This serves as 'entity' property of entity reference field items and gets
* its value set from the parent, i.e. LanguageItem.
*
* The plain value of this reference is the entity object, i.e. an instance of
* \Drupal\Core\Entity\EntityInterface. For setting the value the entity object
* or the entity ID may be passed, whereas passing the ID is only supported if
* an 'entity type' constraint is specified.
*
* Some supported constraints (below the definition's 'constraints' key) are:
* - EntityType: The entity type. Required.
* - Bundle: (optional) The bundle or an array of possible bundles.
*
* @DataType(
* id = "entity_reference",
* label = @Translation("Entity reference")
* )
*/
class EntityReference extends DataReferenceBase {
/**
* The entity ID.
*
* @var integer|string
*/
protected $id;
/**
* {@inheritdoc}
*/
public function getTargetDefinition() {
$definition = array(
'type' => 'entity',
);
if (isset($this->definition['constraints']['EntityType'])) {
$definition['type'] .= ':' . $this->definition['constraints']['EntityType'];
}
if (isset($this->definition['constraints']['Bundle']) && is_string($this->definition['constraints']['Bundle'])) {
$definition['type'] .= ':' . $this->definition['constraints']['Bundle'];
}
return $definition;
}
/**
* {@inheritdoc}
*/
public function getTarget() {
if (!isset($this->target) && isset($this->id)) {
// If we have a valid reference, return the entity object which is typed
// data itself.
$this->target = entity_load($this->definition['constraints']['EntityType'], $this->id);
}
return $this->target;
}
/**
* {@inheritdoc}
*/
public function getTargetIdentifier() {
if (isset($this->id)) {
return $this->id;
}