summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2013-07-05 19:43:36 +0100
committerAlex Pott2013-07-05 19:43:36 +0100
commit5fc86b002978fc160b98e703b4f5c2bdc2e99792 (patch)
tree9492963f5fb293f460cfd82f8559a239dda3ef9f
parent1c9bd12778c7e14444ef2ee5525514e441c61152 (diff)
Issue #1868004 by fago, das-peter, Berdir, EclipseGc, fubhy the cat, dixon_: Improve the TypedData API usage of EntityNG.
-rw-r--r--core/lib/Drupal/Core/Config/Schema/Mapping.php12
-rw-r--r--core/lib/Drupal/Core/Entity/Entity.php43
-rw-r--r--core/lib/Drupal/Core/Entity/EntityBCDecorator.php1
-rw-r--r--core/lib/Drupal/Core/Entity/EntityInterface.php12
-rw-r--r--core/lib/Drupal/Core/Entity/EntityNG.php19
-rw-r--r--core/lib/Drupal/Core/Entity/Field/Field.php8
-rw-r--r--core/lib/Drupal/Core/Entity/Field/FieldItemBase.php20
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php67
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php (renamed from core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php)6
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php28
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php129
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php54
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php227
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php10
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php23
-rw-r--r--core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php39
-rw-r--r--core/lib/Drupal/Core/Entity/Query/Sql/Tables.php16
-rw-r--r--core/lib/Drupal/Core/TypedData/ComplexDataInterface.php2
-rw-r--r--core/lib/Drupal/Core/TypedData/DataDefinitionException.php15
-rw-r--r--core/lib/Drupal/Core/TypedData/DataReferenceBase.php67
-rw-r--r--core/lib/Drupal/Core/TypedData/DataReferenceInterface.php38
-rw-r--r--core/lib/Drupal/Core/TypedData/IdentifiableInterface.php22
-rw-r--r--core/lib/Drupal/Core/TypedData/ItemList.php8
-rw-r--r--core/lib/Drupal/Core/TypedData/ListInterface.php2
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php8
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php6
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php6
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php59
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php18
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php7
-rw-r--r--core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php6
-rw-r--r--core/lib/Drupal/Core/TypedData/PrimitiveBase.php4
-rw-r--r--core/lib/Drupal/Core/TypedData/TypedData.php4
-rw-r--r--core/lib/Drupal/Core/TypedData/TypedDataManager.php20
-rw-r--r--core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php2
-rw-r--r--core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php5
-rw-r--r--core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php2
-rw-r--r--core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php4
-rw-r--r--core/modules/comment/comment.module2
-rw-r--r--core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php5
-rw-r--r--core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php15
-rw-r--r--core/modules/file/lib/Drupal/file/Type/FileItem.php13
-rw-r--r--core/modules/image/lib/Drupal/image/Type/ImageItem.php17
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php2
-rw-r--r--core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php4
-rw-r--r--core/modules/node/node.module2
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php93
47 files changed, 705 insertions, 467 deletions
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
index b7bddb3..9701df0 100644
--- a/core/lib/Drupal/Core/Config/Schema/Mapping.php
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -53,15 +53,11 @@ class Mapping extends ArrayElement implements ComplexDataInterface {
* Implements Drupal\Core\TypedData\ComplexDataInterface::set().
*/
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
// interface specification when we've got a null value.
if (isset($value)) {
$this->value[$property_name] = $value;
- return $this->get($property_name);
+ $property = $this->get($property_name);
}
else {
// In these objects, when clearing the value, the property is gone.
@@ -69,8 +65,12 @@ class Mapping extends ArrayElement implements ComplexDataInterface {
$property = $this->get($property_name);
unset($this->value[$property_name]);
$property->setValue($value);
- return $property;
}
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
+ return $property;
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 7712bf1..33a62ce 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -11,7 +11,6 @@ use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Language\Language;
use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\Core\TypedData\TypedDataInterface;
-use Drupal\user\UserInterface;
use IteratorAggregate;
use Drupal\Core\Session\AccountInterface;
@@ -425,62 +424,66 @@ class Entity implements IteratorAggregate, EntityInterface {
}
/**
- * Implements \Drupal\Core\TypedData\TypedDataInterface::getType().
+ * {@inheritdoc}
*/
public function getType() {
- // @todo: Incorporate the entity type here by making entities proper
- // typed data. See http://drupal.org/node/1868004.
- return 'entity';
+ // @todo: This does not make much sense, so remove once TypedDataInterface
+ // is removed. See https://drupal.org/node/2002138.
+ 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() {
+ // @todo: This does not make much sense, so remove once TypedDataInterface
+ // is removed. See https://drupal.org/node/2002138.
return array(
'type' => $this->getType()
);
}
/**
- * Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
+ * {@inheritdoc}
*/
public function getValue() {
- // @todo: Implement by making entities proper typed data. See
- // http://drupal.org/node/1868004.
+ // @todo: This does not make much sense, so remove once TypedDataInterface
+ // is removed. See https://drupal.org/node/2002138.
+ return $this->getPropertyValues();
}
/**
* Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
*/
public function setValue($value, $notify = TRUE) {
- // @todo: Implement by making entities proper typed data. See
- // http://drupal.org/node/1868004.
+ // @todo: This does not make much sense, so remove once TypedDataInterface
+ // is removed. See https://drupal.org/node/2002138.
+ $this->setPropertyValues($value);
}
/**
- * Implements \Drupal\Core\TypedData\TypedDataInterface::getString().
+ * {@inheritdoc}
*/
public function getString() {
- // @todo: Implement by making entities proper typed data. See
- // http://drupal.org/node/1868004.
+ return $this->label();
}
/**
- * Implements \Drupal\Core\TypedData\TypedDataInterface::getConstraints().
+ * {@inheritdoc}
*/
public function getConstraints() {
- // @todo: Implement by making entities proper typed data. See
- // http://drupal.org/node/1868004.
return array();
}
/**
- * Implements \Drupal\Core\TypedData\TypedDataInterface::validate().
+ * {@inheritdoc}
*/
public function validate() {
- // @todo: Implement by making entities proper typed data. See
- // http://drupal.org/node/1868004.
+ // @todo: Add the typed data manager as proper dependency.
+ return \Drupal::typedData()->getValidator()->validate($this);
}
/**
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index 52d3f6f..a3ffcb9 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -184,6 +184,7 @@ class EntityBCDecorator implements IteratorAggregate, EntityInterface {
// out of sync. That way, the next field object instantiated by EntityNG
// will hold the updated value.
unset($this->decorated->fields[$name]);
+ $this->decorated->onChange($name);
}
/**
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index cdb4cd3..e965b8e 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -9,6 +9,7 @@ namespace Drupal\Core\Entity;
use Drupal\Core\TypedData\AccessibleInterface;
use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\IdentifiableInterface;
use Drupal\Core\TypedData\TranslatableInterface;
/**
@@ -27,16 +28,7 @@ use Drupal\Core\TypedData\TranslatableInterface;
* @see \Drupal\Core\TypedData\TypedDataManager
* @see \Drupal\Core\Field\FieldInterface
*/
-interface EntityInterface extends 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();
+interface EntityInterface extends IdentifiableInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface {
/**
* Returns the entity UUID (Universally Unique Identifier).
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 3d0c5c6..a6768e8 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -168,15 +168,6 @@ class EntityNG extends Entity {
}
/**
- * 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.
*/
protected function init() {
@@ -458,7 +449,7 @@ class EntityNG extends Entity {
}
if (empty($this->language)) {
// 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;
@@ -841,12 +832,4 @@ class EntityNG extends Entity {
return $label;
}
- /**
- * {@inheritdoc}
- */
- public function validate() {
- // @todo: Add the typed data manager as proper dependency.
- return \Drupal::typedData()->getValidator()->validate($this);
- }
-
}
diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php
index 3948ddf..fdbc943 100644
--- a/core/lib/Drupal/Core/Entity/Field/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Field.php
@@ -77,10 +77,6 @@ class Field extends ItemList implements FieldInterface {
* Overrides \Drupal\Core\TypedData\ItemList::setValue().
*/
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()) {
$this->list = $values;
}
@@ -108,6 +104,10 @@ class Field extends ItemList implements FieldInterface {
}
}
}
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index cb243d5..84eb341 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -49,10 +49,6 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
$keys = array_keys($this->getPropertyDefinitions());
$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;
// Update any existing property objects.
foreach ($this->properties as $name => $property) {
@@ -63,6 +59,10 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
$property->setValue($value, FALSE);
unset($this->values[$name]);
}
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
/**
@@ -83,10 +83,6 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
* {@inheritdoc}
*/
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
// value that needs to be updated.
if (isset($this->properties[$property_name])) {
@@ -97,6 +93,10 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
else {
$this->values[$property_name] = $value;
}
+ // Directly notify ourselves.
+ if ($notify) {
+ $this->onChange($property_name);
+ }
}
/**
@@ -135,7 +135,9 @@ abstract class FieldItemBase extends Map implements FieldItemInterface {
}
// Remove the plain value, such that any further __get() calls go via the
// updated property object.
- unset($this->values[$property_name]);
+ if (isset($this->properties[$property_name])) {
+ unset($this->values[$property_name]);
+ }
}
/**
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
new file mode 100644
index 0000000..67ebea6
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/EntityDeriver.php
@@ -0,0 +1,67 @@
+<?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;
+ }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php
index 346b656..2a304df 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldDataTypeDerivative.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Deriver/FieldItemDeriver.php
@@ -2,17 +2,17 @@
/**
* @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;
/**
* Provides data type plugins for each existing field type plugin.
*/
-class FieldDataTypeDerivative implements DerivativeInterface {
+class FieldItemDeriver implements DerivativeInterface {
/**
* List of derivative definitions.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
new file mode 100644
index 0000000..9976232
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php
@@ -0,0 +1,28 @@
+<?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 {
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
new file mode 100644
index 0000000..4741c19
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
@@ -0,0 +1,129 @@
+<?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;
+ }
+ elseif ($entity = $this->getValue()) {
+ return $entity->id();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue() {
+ // Entities are already typed data, so just return that.
+ return $this->getTarget();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setValue($value, $notify = TRUE) {
+ unset($this->target);
+ unset($this->id);
+
+ // Both the entity ID and the entity object may be passed as value. The
+ // reference may also be unset by passing NULL as value.
+ if (!isset($value) || $value instanceof EntityInterface) {
+ // Ensure we reference a NG Entity object.
+ if (isset($value)) {
+ $value = $value->getNGEntity();
+ }
+ $this->target = $value;
+ }
+ elseif (!is_scalar($value) || empty($this->definition['constraints']['EntityType'])) {
+ throw new \InvalidArgumentException('Value is not a valid entity.');
+ }
+ else {
+ $this->id = $value;
+ }
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getString() {
+ if ($entity = $this->getValue()) {
+ return $entity->label();
+ }
+ return '';
+ }
+}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
index 7f756ad..3e67f7e 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReferenceItem.php
@@ -13,10 +13,13 @@ use Drupal\Core\Entity\Field\FieldItemBase;
use Drupal\Core\TypedData\TypedDataInterface;
/**
- * Defines the 'entity_reference' entity field item.
+ * Defines the 'entity_reference_item' entity field item.
*
- * Required settings (below the definition's 'settings' key) are:
- * - target_type: The entity type to reference.
+ * Supported settings (below the definition's 'settings' key) are:
+ * - target_type: The entity type to reference. Required.
+ * - target_bundle: (optional): If set, restricts the entity bundles which may
+ * may be referenced. May be set to an single bundle, or to an array of
+ * allowed bundles.
*
* @DataType(
* id = "entity_reference_field",
@@ -40,11 +43,12 @@ class EntityReferenceItem extends FieldItemBase {
* Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
*/
public function getPropertyDefinitions() {
- // Definitions vary by entity type, so key them by entity type.
- $target_type = $this->definition['settings']['target_type'];
+ // Definitions vary by entity type and bundle, so key them accordingly.
+ $key = $this->definition['settings']['target_type'] . ':';
+ $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
- if (!isset(self::$propertyDefinitions[$target_type])) {
- static::$propertyDefinitions[$target_type]['target_id'] = array(
+ if (!isset(static::$propertyDefinitions[$key])) {
+ static::$propertyDefinitions[$key]['target_id'] = array(
// @todo: Lookup the entity type's ID data type and use it here.
'type' => 'integer',
'label' => t('Entity ID'),
@@ -52,20 +56,22 @@ class EntityReferenceItem extends FieldItemBase {
'Range' => array('min' => 0),
),
);
- static::$propertyDefinitions[$target_type]['entity'] = array(
- 'type' => 'entity',
+ static::$propertyDefinitions[$key]['entity'] = array(
+ 'type' => 'entity_reference',
'constraints' => array(
- 'EntityType' => $target_type,
+ 'EntityType' => $this->definition['settings']['target_type'],
),
'label' => t('Entity'),
'description' => t('The referenced entity'),
// The entity object is computed out of the entity ID.
'computed' => TRUE,
'read-only' => FALSE,
- 'settings' => array('id source' => 'target_id'),
);
+ if (isset($this->definition['settings']['target_bundle'])) {
+ static::$propertyDefinitions[$key]['entity']['constraints']['Bundle'] = $this->definition['settings']['target_bundle'];
+ }
}
- return static::$propertyDefinitions[$target_type];
+ return static::$propertyDefinitions[$key];
}
/**
@@ -96,12 +102,14 @@ class EntityReferenceItem extends FieldItemBase {
* Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
*/
public function setValue($values, $notify = TRUE) {
- // Treat the values as value of the entity property, if no array is
- // given as this handles entity IDs and objects.
if (isset($values) && !is_array($values)) {
- // Directly update the property instead of invoking the parent, so that
- // the entity property can take care of updating the ID property.
+ // Directly update the property instead of invoking the parent, so it can
+ // handle objects and IDs.
$this->properties['entity']->setValue($values, $notify);
+ // If notify was FALSE, ensure the target_id property gets synched.
+ if (!$notify) {
+ $this->set('target_id', $this->properties['entity']->getTargetIdentifier(), FALSE);
+ }
}
else {
// Make sure that the 'entity' property gets set as 'target_id'.
@@ -111,4 +119,18 @@ class EntityReferenceItem extends FieldItemBase {
parent::setValue($values, $notify);
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onChange($property_name) {
+ // Make sure that the target ID and the target property stay in sync.
+ if ($property_name == 'target_id') {
+ $this->properties['entity']->setValue($this->target_id, FALSE);
+ }
+ elseif ($property_name == 'entity') {
+ $this->set('target_id', $this->properties['entity']->getTargetIdentifier(), FALSE);
+ }
+ parent::onChange($property_name);
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php
deleted file mode 100644
index e2561a9..0000000
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityWrapper.php
+++ /dev/null
@@ -1,227 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\Plugin\DataType\EntityWrapper.
- */
-
-namespace Drupal\Core\Entity\Plugin\DataType;
-
-use Drupal\Core\TypedData\Annotation\DataType;
-use Drupal\Core\Annotation\Translation;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\TypedData\ComplexDataInterface;
-use Drupal\Core\TypedData\TypedData;
-use Drupal\Core\TypedData\TypedDataInterface;
-use ArrayIterator;
-use IteratorAggregate;
-use InvalidArgumentException;
-
-/**
- * Defines an 'entity' data type, e.g. the computed 'entity' property of entity references.
- *
- * This object wraps the regular entity object and implements the
- * ComplexDataInterface by forwarding most of its methods to the wrapped entity
- * (if set).
- *
- * The plain value of this wrapper 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.
- *
- * Supported constraints (below the definition's 'constraints' key) are:
- * - EntityType: The entity type.
- * - Bundle: The bundle or an array of possible bundles.
- *
- * Supported settings (below the definition's 'settings' key) are:
- * - id source: If used as computed property, the ID property used to load
- * the entity object.
- *
- * @DataType(
- * id = "entity",
- * label = @Translation("Entity"),
- * description = @Translation("All kind of entities, e.g. nodes, comments or users.")
- * )
- */
-class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataInterface {
-
- /**
- * The referenced entity type.
- *
- * @var string
- */
- protected $entityType;
-
- /**
- * The entity ID if no 'id source' is used.
- *
- * @var string
- */
- protected $id;
-
- /**
- * If set, a new entity to create and reference.
- *
- * @var \Drupal\Core\Entity\EntityInterface
- */
- protected $newEntity;
-
- /**
- * Overrides TypedData::__construct().
- */
- public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) {
- parent::__construct($definition, $name, $parent);
- $this->entityType = isset($this->definition['constraints']['EntityType']) ? $this->definition['constraints']['EntityType'] : NULL;
- }
-
- /**
- * Overrides \Drupal\Core\TypedData\TypedData::getValue().
- */
- public function getValue() {
- if (isset($this->newEntity)) {
- return $this->newEntity;
- }
- if (!empty($this->definition['settings']['id source'])) {
- $this->id = $this->parent->__get($this->definition['settings']['id source']);
- }
- return $this->id ? entity_load($this->entityType, $this->id) : NULL;
- }
-
- /**
- * Overrides \Drupal\Core\TypedData\TypedData::setValue().
- *
- * Both the entity ID and the entity object may be passed as value.
- */
- public function setValue($value, $notify = TRUE) {
- // Support passing in the entity object. If it's not yet saved we have
- // to store the whole entity such that it could be saved later on.
- if ($value instanceof EntityInterface && $value->isNew()) {
- $this->newEntity = $value;
- $this->entityType = $value->entityType();
- $value = 0;
- }
- elseif ($value instanceof EntityInterface) {
- $this->entityType = $value->entityType();
- $value = $value->id();
- unset($this->newEntity);
- }
- elseif (isset($value) && !(is_scalar($value) && !empty($this->definition['constraints']['EntityType']))) {
- throw new InvalidArgumentException('Value is not a valid entity.');
- }
- // Update the 'id source' property, if given.
- if (!empty($this->definition['settings']['id source'])) {
- $this->parent->__set($this->definition['settings']['id source'], $value, $notify);
- }
- else {
- // Notify the parent of any changes to be made.
- if ($notify && isset($this->parent)) {
- $this->parent->onChange($this->name);
- }
- $this->id = $value;
- }
- }
-
- /**
- * Overrides \Drupal\Core\TypedData\TypedData::getString().
- */
- public function getString() {
- if ($entity = $this->getValue()) {
- return $entity->label();
- }
- return '';
- }
-
- /**
- * Implements \IteratorAggregate::getIterator().
- */
- public function getIterator() {
- if ($entity = $this->getValue()) {
- return $entity->getIterator();
- }
- return new ArrayIterator(array());
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::get().
- */
- public function get($property_name) {
- // @todo: Allow navigating through the tree without data as well.
- if ($entity = $this->getValue()) {
- return $entity->get($property_name);
- }
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::set().
- */
- public function set($property_name, $value, $notify = TRUE) {
- $this->get($property_name)->setValue($value, FALSE);
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::getProperties().
- */
- public function getProperties($include_computed = FALSE) {
- if ($entity = $this->getValue()) {
- return $entity->getProperties($include_computed);
- }
- return array();
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition().
- */
- public function getPropertyDefinition($name) {
- $definitions = $this->getPropertyDefinitions();
- if (isset($definitions[$name])) {
- return $definitions[$name];
- }
- else {
- return FALSE;
- }
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
- */
- public function getPropertyDefinitions() {
- // @todo: Support getting definitions if multiple bundles are specified.
- return \Drupal::entityManager()->getFieldDefinitionsByConstraints($this->entityType, $this->definition['constraints']);
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
- */
- public function getPropertyValues() {
- if ($entity = $this->getValue()) {
- return $entity->getPropertyValues();
- }
- return array();
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues().
- */
- public function setPropertyValues($values) {
- if ($entity = $this->getValue()) {
- $entity->setPropertyValues($values);
- }
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::isEmpty().
- */
- public function isEmpty() {
- return !$this->getValue();
- }
-
- /**
- * Implements \Drupal\Core\TypedData\ComplexDataInterface::onChange().
- */
- public function onChange($property_name) {
- // Notify the parent of changes.
- if (isset($this->parent)) {
- $this->parent->onChange($this->name);
- }
- }
-}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
index 73309d9..71fa264 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/FieldItem.php
@@ -9,18 +9,20 @@ namespace Drupal\Core\Entity\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
-use Drupal\Component\Plugin\PluginBase;
/**
- * Defines the base plugin definition for field type typed data types.
+ * Defines the base plugin for deriving data types for field types.
+ *
+ * Note that the class only register the plugin, and is actually never used.
+ * \Drupal\Core\Entity\Field\FieldItemBase is available for use as base class.
*
* @DataType(
* id = "field_item",
* label = @Translation("Field item"),
* list_class = "\Drupal\Core\Entity\Field\Field",
- * derivative = "Drupal\Core\Entity\Plugin\DataType\FieldDataTypeDerivative"
+ * derivative = "Drupal\Core\Entity\Plugin\DataType\Deriver\FieldItemDeriver"
* )
*/
-class FieldItem extends PluginBase {
+abstract class FieldItem {
}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
index 5338556..68526f5 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageItem.php
@@ -42,19 +42,18 @@ class LanguageItem extends FieldItemBase {
* Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
*/
public function getPropertyDefinitions() {
-
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['value'] = array(
'type' => 'string',
'label' => t('Language code'),
);
static::$propertyDefinitions['language'] = array(
- 'type' => 'language',
+ 'type' => 'language_reference',
'label' => t('Language object'),
+ 'description' => t('The referenced language'),
// The language object is retrieved via the language code.
'computed' => TRUE,
'read-only' => FALSE,
- 'settings' => array('langcode source' => 'value'),
);
}
return static::$propertyDefinitions;
@@ -71,6 +70,10 @@ class LanguageItem extends FieldItemBase {
// the language property can take care of updating the language code
// property.
$this->properties['language']->setValue($values, $notify);
+ // If notify was FALSE, ensure the value property gets synched.
+ if (!$notify) {
+ $this->set('value', $this->properties['language']->getTargetIdentifier(), FALSE);
+ }
}
else {
// Make sure that the 'language' property gets set as 'value'.
@@ -89,4 +92,18 @@ class LanguageItem extends FieldItemBase {
$this->setValue(array('value' => Language::LANGCODE_NOT_SPECIFIED), $notify);
return $this;
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onChange($property_name) {
+ // Make sure that the value and the language property stay in sync.
+ if ($property_name == 'value') {
+ $this->properties['language']->setValue($this->value, FALSE);
+ }
+ elseif ($property_name == 'language') {
+ $this->set('value', $this->properties['language']->getTargetIdentifier(), FALSE);
+ }
+ parent::onChange($property_name);
+ }
}
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php
new file mode 100644
index 0000000..8d143a7
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\DataType\LanguageReference.
+ */
+
+namespace Drupal\Core\Entity\Plugin\DataType;
+
+use Drupal\Core\TypedData\DataReferenceBase;
+use Drupal\Core\TypedData\Annotation\DataType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the 'language_reference' data type.
+ *
+ * This serves as 'language' property of entity reference field items and gets
+ * its value set from the parent, i.e. LanguageItem.
+ *
+ * The plain value is the language object, i.e. an instance of
+ * \Drupal\Core\Language\Language. For setting the value the language object or
+ * the language code as string may be passed.
+ *
+ * @DataType(
+ * id = "language_reference",
+ * label = @Translation("Language reference")
+ * )
+ */
+class LanguageReference extends DataReferenceBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTargetDefinition() {
+ return array(
+ 'type' => 'language',
+ );
+ }
+}
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index f346129..2f7156a 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -8,6 +8,7 @@
namespace Drupal\Core\Entity\Query\Sql;
use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\Core\Entity\Plugin\DataType\EntityReference;
use Drupal\Core\Entity\Query\QueryException;
use Drupal\field\Plugin\Core\Entity\Field;
@@ -140,13 +141,12 @@ class Tables {
$propertyDefinitions = $entity->{$field['field_name']}->getPropertyDefinitions();
// If the column is not yet known, ie. the
- // $node->field_image->entity case then use the id source as the
- // column.
- if (!$column && isset($propertyDefinitions[$relationship_specifier]['settings']['id source'])) {
- // If this is a valid relationship, use the id source.
- // Otherwise, the code executing the relationship will throw an
- // exception anyways so no need to do it here.
- $column = $propertyDefinitions[$relationship_specifier]['settings']['id source'];
+ // $node->field_image->entity case then use first property as
+ // column, i.e. target_id or fid.
+ // Otherwise, the code executing the relationship will throw an
+ // exception anyways so no need to do it here.
+ if (!$column && isset($propertyDefinitions[$relationship_specifier]) && $entity->{$field['field_name']}->get('entity') instanceof EntityReference) {
+ $column = current(array_keys($propertyDefinitions));
}
// Prepare the next index prefix.
$next_index_prefix = "$relationship_specifier.$column";
@@ -193,7 +193,7 @@ class Tables {
$next_index_prefix = $relationship_specifier;
}
// Check for a valid relationship.
- if (isset($propertyDefinitions[$relationship_specifier]['constraints']['EntityType']) && isset($propertyDefinitions[$relationship_specifier]['settings']['id source'])) {
+ if (isset($propertyDefinitions[$relationship_specifier]) && $entity->{$specifier}->get('entity') instanceof EntityReference) {
// If it is, use the entity type.
$entity_type = $propertyDefinitions[$relationship_specifier]['constraints']['EntityType'];
$entity_info = entity_get_info($entity_type);
diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
index 595064e..a681ffe 100644
--- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php
@@ -128,7 +128,7 @@ interface ComplexDataInterface extends Traversable, TypedDataInterface {
/**
* React to changes to a child property.
*
- * Note that this is invoked before any changes are applied.
+ * Note that this is invoked after any changes have been applied.
*
* @param $property_name
* The name of the property which is changed.
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionException.php b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php
new file mode 100644
index 0000000..2a23315
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\MissingContextException.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Exception thrown when a data definition lacks required information.
+ */
+class DataDefinitionException extends \Exception {
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
new file mode 100644
index 0000000..8e67a24
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataReferenceBase.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Base class for typed data references.
+ *
+ * Implementing classes have to implement at least
+ * \Drupal\Core\TypedData\DataReferenceInterface::getTargetDefinition() and
+ * \Drupal\Core\TypedData\DataReferenceInterface::getTargetIdentifier().
+ */
+abstract class DataReferenceBase extends TypedData implements DataReferenceInterface {
+
+ /**
+ * The referenced data.
+ *
+ * @var \Drupal\Core\TypedData\TypedDataInterface
+ */
+ protected $target;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTarget() {
+ return $this->target;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue() {
+ if ($target = $this->getTarget()) {
+ return $target->getValue();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setValue($value, $notify = TRUE) {
+ $this->target = \Drupal::typedData()->create($this->getTargetDefinition(), $value);
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getString() {
+ return (string) $this->getType() . ':' . $this->getTargetIdentifier();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTargetIdentifier() {
+ $target = $this->getTarget();
+ return isset($target) ? $target->id() : NULL;
+ }
+}
diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php b/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php
new file mode 100644
index 0000000..501f9d2
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/DataReferenceInterface.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\DataReferenceInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for typed data references.
+ */
+interface DataReferenceInterface {
+
+ /**
+ * Gets the data definition of the referenced data.
+ *
+ * @return array
+ * The data definition of the referenced data.
+ */
+ public function getTargetDefinition();
+
+ /**
+ * Gets the referenced data.
+ *
+ * @return \Drupal\Core\TypedData\TypedDataInterface|null
+ * The referenced typed data object, or NULL if the reference is unset.
+ */
+ public function getTarget();
+
+ /**
+ * Gets the identifier of the referenced data.
+ *
+ * @return int|string|null
+ * The identifier of the referenced data, or NULL if the reference is unset.
+ */
+ public function getTargetIdentifier();
+}
diff --git a/core/lib/Drupal/Core/TypedData/IdentifiableInterface.php b/core/lib/Drupal/Core/TypedData/IdentifiableInterface.php
new file mode 100644
index 0000000..09f8c92
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/IdentifiableInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\TypedData\IdentifiableInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for identifiable typed data.
+ */
+interface IdentifiableInterface {
+
+ /**
+ * Returns the identifier.
+ *
+ * @return string|int|null
+ * The object identifier, or NULL if the object does not yet have an identifier.
+ */
+ public function id();
+}
diff --git a/core/lib/Drupal/Core/TypedData/ItemList.php b/core/lib/Drupal/Core/TypedData/ItemList.php
index ee69432..9b39e83 100644
--- a/core/lib/Drupal/Core/TypedData/ItemList.php
+++ b/core/lib/Drupal/Core/TypedData/ItemList.php
@@ -42,10 +42,6 @@ class ItemList extends TypedData implements \IteratorAggregate, ListInterface {
* An array of values of the field items, or NULL to unset the field.
*/
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()) {
$this->list = $values;
}
@@ -72,6 +68,10 @@ class ItemList extends TypedData implements \IteratorAggregate, ListInterface {
}
}
}
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
/**
diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php
index 2711cd4..451e1af 100644
--- a/core/lib/Drupal/Core/TypedData/ListInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ListInterface.php
@@ -41,7 +41,7 @@ interface ListInterface extends TypedDataInterface, ArrayAccess, Countable, Trav
/**
* React to changes to a child item.
*
- * Note that this is invoked before any changes are applied.
+ * Note that this is invoked after any changes have been applied.
*
* @param $delta
* The delta of the item which is changed.
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
index 908f040..16ac5d6 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Binary.php
@@ -59,10 +59,6 @@ class Binary extends PrimitiveBase implements BinaryInterface {
* Supports a PHP file resource or a (absolute) stream resource URI as value.
*/
public function setValue($value, $notify = TRUE) {
- // Notify the parent of any changes to be made.
- if ($notify && isset($this->parent)) {
- $this->parent->onChange($this->name);
- }
if (!isset($value)) {
$this->handle = NULL;
$this->uri = NULL;
@@ -76,6 +72,10 @@ class Binary extends PrimitiveBase implements BinaryInterface {
else {
$this->handle = $value;
}
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
/**
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
index 59bbe8a..906b4eb 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DateTimeIso8601.php
@@ -36,8 +36,12 @@ class DateTimeIso8601 extends String implements DateTimeInterface {
/**
* {@inheritdoc}
*/
- public function setDateTime(DrupalDateTime $dateTime) {
+ public function setDateTime(DrupalDateTime $dateTime, $notify = TRUE) {
$this->value = $dateTime->format('c');
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php
index d83261f..9e67026 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/DurationIso8601.php
@@ -37,10 +37,14 @@ class DurationIso8601 extends String implements DurationInterface {
/**
* {@inheritdoc}
*/
- public function setDuration(\DateInterval $duration) {
+ public function setDuration(\DateInterval $duration, $notify = TRUE) {
// Generate an ISO 8601 formatted string as supported by
// DateInterval::__construct() and setValue().
$this->value = $duration->format('%rP%yY%mM%dDT%hH%mM%sS');
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
index fdb7e59..87d0bdf 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Language.php
@@ -11,6 +11,7 @@ use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use InvalidArgumentException;
use Drupal\Core\Language\Language as LanguageObject;
+use Drupal\Core\TypedData\IdentifiableInterface;
use Drupal\Core\TypedData\TypedData;
/**
@@ -20,39 +21,36 @@ use Drupal\Core\TypedData\TypedData;
* \Drupal\Core\Language\Language. For setting the value the language object or
* the language code as string may be passed.
*
- * Optionally, this class may be used as computed property, see the supported
- * settings below. E.g., it is used as 'language' property of language items.
- *
- * Supported settings (below the definition's 'settings' key) are:
- * - langcode source: If used as computed property, the langcode property used
- * to load the language object.
- *
* @DataType(
* id = "language",
* label = @Translation("Language"),
* description = @Translation("A language object.")
* )
*/
-class Language extends TypedData {
+class Language extends TypedData implements IdentifiableInterface {
/**
- * The language code of the language if no 'langcode source' is used.
+ * The id of the language.
*
* @var string
*/
- protected $langcode;
+ protected $id;
+
+ /**
+ * @var \Drupal\Core\Language
+ */
+ protected $language;
/**
* Overrides TypedData::getValue().
+ *
+ * @return \Drupal\Core\Language\Language|null
*/
public function getValue() {
- if (!empty($this->definition['settings']['langcode source'])) {
- $this->id = $this->parent->__get($this->definition['settings']['langcode source']);
- }
- if ($this->id) {
- $language = language_load($this->id);
- return $language ?: new LanguageObject(array('id' => $this->id));
+ if (!isset($this->language) && $this->id) {
+ $this->language = language_load($this->id);
}
+ return $this->language;
}
/**
@@ -63,21 +61,19 @@ class Language extends TypedData {
public function setValue($value, $notify = TRUE) {
// Support passing language objects.
if (is_object($value)) {
- $value = $value->id;
+ $this->id = $value->id;
+ $this->language = $value;
}
elseif (isset($value) && !is_scalar($value)) {
throw new InvalidArgumentException('Value is no valid langcode or language object.');
}
- // Update the 'langcode source' property, if given.
- if (!empty($this->definition['settings']['langcode source'])) {
- $this->parent->__set($this->definition['settings']['langcode source'], $value, $notify);
- }
else {
- // Notify the parent of any changes to be made.
- if ($notify && isset($this->parent)) {
- $this->parent->onChange($this->name);
- }
$this->id = $value;
+ $this->language = NULL;
+ }
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
}
}
@@ -88,4 +84,17 @@ class Language extends TypedData {
$language = $this->getValue();
return $language ? $language->name : '';
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function id() {
+ if (isset($this->id)) {
+ return $this->id;
+ }
+ elseif (isset($this->language)) {
+ return $this->language->id;
+ }
+ }
+
}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
index a033322..180003c 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
@@ -84,10 +84,6 @@ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface
if (isset($values) && !is_array($values)) {
throw new \InvalidArgumentException("Invalid values given. Values must be represented as an associative array.");
}
- // Notify the parent of any changes to be made.
- if ($notify && isset($this->parent)) {
- $this->parent->onChange($this->name);
- }
$this->values = $values;
// Update any existing property objects.
@@ -98,6 +94,10 @@ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface
}
$property->setValue($value, FALSE);
}
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
/**
@@ -131,16 +131,16 @@ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface
* Implements \Drupal\Core\TypedData\ComplexDataInterface::set().
*/
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);
- }
if ($this->getPropertyDefinition($property_name)) {
- $this->get($property_name)->setValue($value);
+ $this->get($property_name)->setValue($value, $notify);
}
else {
// Just set the plain value, which allows adding a new entry to the map.
$this->values[$property_name] = $value;
+ // Directly notify ourselves.
+ if ($notify) {
+ $this->onChange($property_name, $value);
+ }
}
}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php
index b0ec72a..c91fcd2 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/TimeSpan.php
@@ -43,7 +43,7 @@ class TimeSpan extends Integer implements DurationInterface {
/**
* {@inheritdoc}
*/
- public function setDuration(\DateInterval $duration) {
+ public function setDuration(\DateInterval $duration, $notify = TRUE) {
// Note that this applies the assumption of 12 month's a 30 days and
// each year having 365 days. There is no accurate conversion for time spans
// exceeding a day.
@@ -53,6 +53,11 @@ class TimeSpan extends Integer implements DurationInterface {
($duration->h * 60 * 60) +
($duration->i * 60) +
$duration->s;
+
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
index 18c99dc..c0cad02 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Timestamp.php
@@ -41,7 +41,11 @@ class Timestamp extends Integer implements DateTimeInterface {
/**
* {@inheritdoc}
*/
- public function setDateTime(DrupalDateTime $dateTime) {
+ public function setDateTime(DrupalDateTime $dateTime, $notify = TRUE) {
$this->value = $dateTime->getTimestamp();
+ // Notify the parent of any changes.
+ if ($notify && isset($this->parent)) {
+ $this->parent->onChange($this->name);
+ }
}
}
diff --git a/core/lib/Drupal/Core/TypedData/PrimitiveBase.php b/core/lib/Drupal/Core/TypedData/PrimitiveBase.php
index 1ba9319..dae6dbe 100644
--- a/core/lib/Drupal/Core/TypedData/PrimitiveBase.php
+++ b/core/lib/Drupal/Core/TypedData/PrimitiveBase.php
@@ -30,10 +30,10 @@ abstract class PrimitiveBase extends TypedData implements PrimitiveInterface {
* {@inheritdoc}
*/
public function setValue($value, $notify = TRUE) {
- // Notify the parent of any changes to be made.
+ $this->value = $value;
+ // Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
- $this->value = $value;
}
}
diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php
index 8bfa215..f54f8ed 100644
--- a/core/lib/Drupal/Core/TypedData/TypedData.php
+++ b/core/lib/Drupal/Core/TypedData/TypedData.php
@@ -97,11 +97,11 @@ abstract class TypedData implements TypedDataInterface, PluginInspectionInterfac
* Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
*/
public function setValue($value, $notify = TRUE) {
- // Notify the parent of any changes to be made.
+ $this->value = $value;
+ // Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
- $this->value = $value;
}
/**
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index f0e8034..5c48fb0 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -219,18 +219,16 @@ class TypedDataManager extends DefaultPluginManager {
* @todo: Add type-hinting to $object once entities implement the
* TypedDataInterface.
*/
- public function getPropertyInstance($object, $property_name, $value = NULL) {
- 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;
+ public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL) {
+ $definition = $object->getRoot()->getDefinition();
+ $key = $definition['type'];
+ if (isset($definition['settings'])) {
+ $key .= ':' . implode(',', $definition['settings']);
}
+ $key .= ':' . $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;
// Make sure we have a prototype. Then, clone the prototype and set object
// specific values, i.e. the value and the context.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php
index f6ea289..ebd844b 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraint.php
@@ -20,7 +20,7 @@ use Drupal\Core\Annotation\Translation;
* @Plugin(
* id = "Bundle",
* label = @Translation("Bundle", context = "Validation"),
- * type = "entity"
+ * type = { "entity", "entity_reference" }
* )
*/
class BundleConstraint extends Constraint {
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php
index a84251e..42f09ca 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/BundleConstraintValidator.php
@@ -18,10 +18,7 @@ class BundleConstraintValidator extends ConstraintValidator {
/**
* Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
*/
- public function validate($typed_data, Constraint $constraint) {
- // If the entity is contained in a reference, unwrap it first.
- $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE;
-
+ public function validate($entity, Constraint $constraint) {
if (!empty($entity) && !in_array($entity->bundle(), $constraint->getBundleOption())) {
$this->context->addViolation($constraint->message, array('%bundle', implode(', ', $constraint->getBundleOption())));
}
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php
index 1d38ae5..d480fa1 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraint.php
@@ -20,7 +20,7 @@ use Drupal\Core\Annotation\Translation;
* @Plugin(
* id = "EntityType",
* label = @Translation("Entity type", context = "Validation"),
- * type = "entity"
+ * type = { "entity", "entity_reference" }
* )
*/
class EntityTypeConstraint extends Constraint {
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
index 31c7cb2..304a85c 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
@@ -19,9 +19,7 @@ class EntityTypeConstraintValidator extends ConstraintValidator {
/**
* Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
*/
- public function validate($typed_data, Constraint $constraint) {
- // If the entity is contained in a reference, unwrap it first.
- $entity = isset($typed_data) && !($typed_data instanceof EntityInterface) ? $typed_data->getValue() : FALSE;
+ public function validate($entity, Constraint $constraint) {
if (!empty($entity) && $entity->entityType() != $constraint->type) {
$this->context->addViolation($constraint->message, array('%type' => $constraint->type));
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 604cb93..8ba44d1 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1482,7 +1482,7 @@ function comment_preprocess_block(&$variables) {
function comment_prepare_author(Comment $comment) {
// The account has been pre-loaded by CommentRenderController::buildContent().
$account = $comment->uid->entity;
- if (!$account) {
+ if (empty($account->uid->value)) {
$account = entity_create('user', array('uid' => 0, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value));
}
return $account->getBCEntity();
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php
index 1f5e457..b26b0a5 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/Views/TranslationLinkTest.php
@@ -46,6 +46,11 @@ class TranslationLinkTest extends ContentTranslationTestBase {
parent::setUp();
+ // Assign user 1 a language code so that the entity can be translated.
+ $user = user_load(1);
+ $user->langcode = 'en';
+ $user->save();
+
ViewTestData::importTestViews(get_class($this), array('content_translation_test_views'));
}
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
index 7229a9a..ff4472f 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
@@ -57,14 +57,15 @@ class ConfigEntityReferenceItemBase extends EntityReferenceItem implements Confi
* {@inheritdoc}
*/
public function getPropertyDefinitions() {
- // Definitions vary by entity type, so key them by entity type.
- $target_type = $this->definition['settings']['target_type'];
+ // Definitions vary by entity type and bundle, so key them accordingly.
+ $key = $this->definition['settings']['target_type'] . ':';
+ $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
- if (!isset(self::$propertyDefinitions[$target_type])) {
+ if (!isset(static::$propertyDefinitions[$key])) {
// Call the parent to define the target_id and entity properties.
parent::getPropertyDefinitions();
- static::$propertyDefinitions[$target_type]['revision_id'] = array(
+ static::$propertyDefinitions[$key]['revision_id'] = array(
// @todo: Lookup the entity type's ID data type and use it here.
'type' => 'integer',
'label' => t('Revision ID'),
@@ -72,18 +73,18 @@ class ConfigEntityReferenceItemBase extends EntityReferenceItem implements Confi
'Range' => array('min' => 0),
),
);
- static::$propertyDefinitions[$target_type]['label'] = array(
+ static::$propertyDefinitions[$key]['label'] = array(
'type' => 'string',
'label' => t('Label (auto-create)'),
'computed' => TRUE,
);
- static::$propertyDefinitions[$target_type]['access'] = array(
+ static::$propertyDefinitions[$key]['access'] = array(
'type' => 'boolean',
'label' => t('Access'),
'computed' => TRUE,
);
}
- return static::$propertyDefinitions[$target_type];
+ return static::$propertyDefinitions[$key];
}
/**
diff --git a/core/modules/file/lib/Drupal/file/Type/FileItem.php b/core/modules/file/lib/Drupal/file/Type/FileItem.php
index 9b2cc4c..c8f1a9c 100644
--- a/core/modules/file/lib/Drupal/file/Type/FileItem.php
+++ b/core/modules/file/lib/Drupal/file/Type/FileItem.php
@@ -28,20 +28,23 @@ class FileItem extends ConfigEntityReferenceItemBase {
*/
public function getPropertyDefinitions() {
$this->definition['settings']['target_type'] = 'file';
+ // Definitions vary by entity type and bundle, so key them accordingly.
+ $key = $this->definition['settings']['target_type'] . ':';
+ $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
- if (!isset(static::$propertyDefinitions)) {
- static::$propertyDefinitions = parent::getPropertyDefinitions();
+ if (!isset(static::$propertyDefinitions[$key])) {
+ static::$propertyDefinitions[$key] = parent::getPropertyDefinitions();
- static::$propertyDefinitions['display'] = array(
+ static::$propertyDefinitions[$key]['display'] = array(
'type' => 'boolean',
'label' => t('Flag to control whether this file should be displayed when viewing content.'),
);
- static::$propertyDefinitions['description'] = array(
+ static::$propertyDefinitions[$key]['description'] = array(
'type' => 'string',
'label' => t('A description of the file.'),
);
}
- return static::$propertyDefinitions;
+ return static::$propertyDefinitions[$key];
}
}
diff --git a/core/modules/image/lib/Drupal/image/Type/ImageItem.php b/core/modules/image/lib/Drupal/image/Type/ImageItem.php
index 7d441fd..3b86fe4 100644
--- a/core/modules/image/lib/Drupal/image/Type/ImageItem.php
+++ b/core/modules/image/lib/Drupal/image/Type/ImageItem.php
@@ -28,28 +28,31 @@ class ImageItem extends ConfigEntityReferenceItemBase {
*/
public function getPropertyDefinitions() {
$this->definition['settings']['target_type'] = 'file';
+ // Definitions vary by entity type and bundle, so key them accordingly.
+ $key = $this->definition['settings']['target_type'] . ':';
+ $key .= isset($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
- if (!isset(static::$propertyDefinitions)) {
- static::$propertyDefinitions = parent::getPropertyDefinitions();
+ if (!isset(static::$propertyDefinitions[$key])) {
+ static::$propertyDefinitions[$key] = parent::getPropertyDefinitions();
- static::$propertyDefinitions['alt'] = array(
+ static::$propertyDefinitions[$key]['alt'] = array(
'type' => 'string',
'label' => t("Alternative image text, for the image's 'alt' attribute."),
);
- static::$propertyDefinitions['title'] = array(
+ static::$propertyDefinitions[$key]['title'] = array(
'type' => 'string',
'label' => t("Image title text, for the image's 'title' attribute."),
);
- static::$propertyDefinitions['width'] = array(
+ static::$propertyDefinitions[$key]['width'] = array(
'type' => 'integer',
'label' => t('The width of the image in pixels.'),
);
- static::$propertyDefinitions['height'] = array(
+ static::$propertyDefinitions[$key]['height'] = array(
'type' => 'integer',
'label' => t('The height of the image in pixels.'),
);
}
- return static::$propertyDefinitions;
+ return static::$propertyDefinitions[$key];
}
}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
index c55927f..b53ba51 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
@@ -97,6 +97,7 @@ class LocaleContentTest extends WebTestBase {
$this->drupalPost("admin/structure/types/manage/{$type2->type}", $edit, t('Save content type'));
$this->assertRaw(t('The content type %type has been updated.', array('%type' => $type2->name)));
$this->drupalLogout();
+ drupal_static_reset('language_list');
// Verify language selection is not present on the node add form.
$this->drupalLogin($web_user);
@@ -153,6 +154,7 @@ class LocaleContentTest extends WebTestBase {
$edit = array();
$edit['predefined_langcode'] = 'ar';
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+ drupal_static_reset('language_list');
// Install Spanish language.
$edit = array();
diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
index b914837..d0fbb8c 100644
--- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
+++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
@@ -419,8 +419,10 @@ class MenuTest extends MenuWebTestBase {
public function testMenuBundles() {
$this->drupalLogin($this->big_user);
$menu = $this->addCustomMenu();
+ // Clear the entity info cache to ensure the static caches are rebuilt.
+ entity_info_cache_clear();
$bundles = entity_get_bundles('menu_link');
- $this->assertTrue($bundles[$menu->id()]);
+ $this->assertTrue(isset($bundles[$menu->id()]));
$menus = menu_list_system_menus();
$menus[$menu->id()] = $menu->label();
ksort($menus);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index db4614a..3a1acb4 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -2164,7 +2164,7 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) {
// If no language code was provided, default to the node's langcode.
if (empty($langcode)) {
- $langcode = $node->langcode;
+ $langcode = $node->language()->id;
// If the Language module is enabled, try to use the language from content
// negotiation.
if (module_exists('language')) {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index e8878be..7bc9107 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -339,7 +339,7 @@ class EntityFieldTest extends EntityUnitTestBase {
public function testIntrospection() {
// All entity variations have to have the same results.
foreach (entity_test_entity_types() as $entity_type) {
- $this->assertIntrospection($entity_type);
+ $this->checkIntrospection($entity_type);
}
}
@@ -349,17 +349,11 @@ class EntityFieldTest extends EntityUnitTestBase {
* @param string $entity_type
* The entity type to run the tests with.
*/
- protected function assertIntrospection($entity_type) {
- // Test getting metadata upfront, i.e. without having an entity object.
- $definition = array(
- 'type' => 'entity',
- 'constraints' => array(
- 'EntityType' => $entity_type,
- ),
- 'label' => 'Test entity',
- );
- $wrapped_entity = $this->container->get('typed_data')->create($definition);
- $definitions = $wrapped_entity->getPropertyDefinitions($definition);
+ protected function checkIntrospection($entity_type) {
+ // Test getting metadata upfront.
+ // @todo: Make this work without having to create entity objects.
+ $entity = entity_create($entity_type, array());
+ $definitions = $entity->getPropertyDefinitions();
$this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.');
$this->assertEqual($definitions['user_id']['type'], 'entity_reference_field', $entity_type .': User field found.');
$this->assertEqual($definitions['field_test_text']['type'], 'field_item:text', $entity_type .': Test-text-field field found.');
@@ -378,7 +372,7 @@ class EntityFieldTest extends EntityUnitTestBase {
$userref_properties = $entity->user_id->getPropertyDefinitions();
$this->assertEqual($userref_properties['target_id']['type'], 'integer', $entity_type .': Entity id property of the user found.');
- $this->assertEqual($userref_properties['entity']['type'], 'entity', $entity_type .': Entity reference property of the user found.');
+ $this->assertEqual($userref_properties['entity']['type'], 'entity_reference', $entity_type .': Entity reference property of the user found.');
$textfield_properties = $entity->field_test_text->getPropertyDefinitions();
$this->assertEqual($textfield_properties['value']['type'], 'string', $entity_type .': String value property of the test-text field found.');
@@ -470,21 +464,12 @@ class EntityFieldTest extends EntityUnitTestBase {
*/
protected function assertDataStructureInterfaces($entity_type) {
$entity = $this->createTestEntity($entity_type);
- $entity->save();
- $entity_definition = array(
- 'type' => 'entity',
- 'constraints' => array(
- 'EntityType' => $entity_type,
- ),
- 'label' => 'Test entity',
- );
- $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $entity);
// Test using the whole tree of typed data by navigating through the tree of
// contained properties and getting all contained strings, limited by a
// certain depth.
$strings = array();
- $this->getContainedStrings($wrapped_entity, 0, $strings);
+ $this->getContainedStrings($entity, 0, $strings);
// @todo: Once the user entity has defined properties this should contain
// the user name and other user entity strings as well.
@@ -527,22 +512,39 @@ class EntityFieldTest extends EntityUnitTestBase {
}
/**
+ * Makes sure data types are correctly derived for all entity types.
+ */
+ public function testDataTypes() {
+ $types = \Drupal::typedData()->getDefinitions();
+ foreach (entity_test_entity_types() as $entity_type) {
+ $this->assertTrue($types['entity:' . $entity_type]['class'], 'Entity data type registed.');
+ }
+ // Check bundle types are provided as well.
+ entity_test_create_bundle('bundle');
+ $types = \Drupal::typedData()->getDefinitions();
+ $this->assertTrue($types['entity:entity_test:bundle']['class'], 'Entity bundle data type registed.');
+ }
+
+ /**
* Tests validation constraints provided by the Entity API.
*/
public function testEntityConstraintValidation() {
$entity = $this->createTestEntity('entity_test');
$entity->save();
- $entity_definition = array(
- 'type' => 'entity',
- 'constraints' => array(
- 'EntityType' => 'entity_test',
+ // Create a reference field item and let it reference the entity.
+ $definition = array(
+ 'type' => 'entity_reference_field',
+ 'settings' => array(
+ 'target_type' => 'entity_test',
),
'label' => 'Test entity',
);
- $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $entity);
+ $reference_field_item = \Drupal::TypedData()->create($definition);
+ $reference = $reference_field_item->get('entity');
+ $reference->setValue($entity);
// Test validation the typed data object.
- $violations = $wrapped_entity->validate();
+ $violations = $reference->validate();
$this->assertEqual($violations->count(), 0);
// Test validating an entity of the wrong type.
@@ -552,30 +554,31 @@ class EntityFieldTest extends EntityUnitTestBase {
'type' => 'page',
'uid' => $user->id(),
));
- // @todo: EntityWrapper can only handle entities with an id.
- $node->save();
- $wrapped_entity->setValue($node);
- $violations = $wrapped_entity->validate();
+ $reference->setValue($node);
+ $violations = $reference->validate();
$this->assertEqual($violations->count(), 1);
// Test bundle validation.
- $entity_definition = array(
- 'type' => 'entity',
- 'constraints' => array(
- 'EntityType' => 'node',
- 'Bundle' => 'article',
+ $definition = array(
+ 'type' => 'entity_reference_field',
+ 'settings' => array(
+ 'target_type' => 'node',
+ 'target_bundle' => 'article',
),
- 'label' => 'Test node',
);
- $wrapped_entity = $this->container->get('typed_data')->create($entity_definition, $node);
-
- $violations = $wrapped_entity->validate();
+ $reference_field_item = \Drupal::TypedData()->create($definition);
+ $reference = $reference_field_item->get('entity');
+ $reference->setValue($node);
+ $violations = $reference->validate();
$this->assertEqual($violations->count(), 1);
- $node->type = 'article';
+ $node = entity_create('node', array(
+ 'type' => 'article',
+ 'uid' => $user->id(),
+ ));
$node->save();
- $wrapped_entity->setValue($node);
- $violations = $wrapped_entity->validate();
+ $reference->setValue($node);
+ $violations = $reference->validate();
$this->assertEqual($violations->count(), 0);
}