diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php index 256076f..171c972 100644 --- a/core/lib/Drupal/Core/Config/Schema/Mapping.php +++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php @@ -108,7 +108,13 @@ public function setPropertyValues($values) { } /** - * Implements Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition(). + * Gets the definition of a contained property. + * + * @param string $name + * The name of property. + * + * @return array|FALSE + * The definition of the property or FALSE if the property does not exist. */ public function getPropertyDefinition($name) { if (isset($this->definition['mapping'][$name])) { @@ -120,7 +126,11 @@ public function getPropertyDefinition($name) { } /** - * Implements Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). + * Gets an array of property definitions of contained properties. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface[] + * An array of property definitions of contained properties, keyed by + * property name. */ public function getPropertyDefinitions() { $list = array(); diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 1572129..f0855ef 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -9,9 +9,9 @@ use Drupal\Component\Utility\String; use Drupal\Core\Entity\Plugin\DataType\EntityReference; +use Drupal\Core\Entity\TypedData\EntityDataDefinition; use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\TypedData\TypedDataInterface; /** @@ -66,7 +66,7 @@ /** * Local cache for field definitions. * - * @see ContentEntityBase::getPropertyDefinitions() + * @see ContentEntityBase::getFieldDefinitions() * * @var array */ @@ -211,16 +211,12 @@ public function preSaveRevision(EntityStorageControllerInterface $storage_contro /** * {@inheritdoc} */ - public function getDefinition() { - // @todo: This does not make much sense, so remove once TypedDataInterface - // is removed. See https://drupal.org/node/2002138. + public function getDataDefinition() { + $definition = EntityDataDefinition::create($this->getEntityTypeId()); if ($this->bundle() != $this->getEntityTypeId()) { - $type = 'entity:' . $this->getEntityTypeId() . ':' . $this->bundle(); + $definition->setBundles(array($this->bundle())); } - else { - $type = 'entity:' . $this->getEntityTypeId(); - } - return DataDefinition::create($type); + return $definition; } /** @@ -378,7 +374,7 @@ public function uuid() { * {@inheritdoc} */ public function hasField($field_name) { - return (bool) $this->getPropertyDefinition($field_name); + return (bool) $this->getFieldDefinition($field_name); } /** @@ -404,7 +400,7 @@ protected function getTranslatedField($name, $langcode) { // Populate $this->fields to speed-up further look-ups and to keep track of // fields objects, possibly holding changes to field values. if (!isset($this->fields[$name][$langcode])) { - $definition = $this->getPropertyDefinition($name); + $definition = $this->getFieldDefinition($name); if (!$definition) { throw new \InvalidArgumentException('Field ' . String::checkPlain($name) . ' is unknown.'); } @@ -454,7 +450,7 @@ public function set($name, $value, $notify = TRUE) { */ public function getProperties($include_computed = FALSE) { $properties = array(); - foreach ($this->getPropertyDefinitions() as $name => $definition) { + foreach ($this->getFieldDefinitions() as $name => $definition) { if ($include_computed || !$definition->isComputed()) { $properties[$name] = $this->get($name); } @@ -472,9 +468,9 @@ public function getIterator() { /** * {@inheritdoc} */ - public function getPropertyDefinition($name) { + public function getFieldDefinition($name) { if (!isset($this->fieldDefinitions)) { - $this->getPropertyDefinitions(); + $this->getFieldDefinitions(); } if (isset($this->fieldDefinitions[$name])) { return $this->fieldDefinitions[$name]; @@ -487,7 +483,7 @@ public function getPropertyDefinition($name) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { + public function getFieldDefinitions() { if (!isset($this->fieldDefinitions)) { $bundle = $this->bundle != $this->entityTypeId ? $this->bundle : NULL; $this->fieldDefinitions = \Drupal::entityManager()->getFieldDefinitions($this->entityTypeId, $bundle); @@ -566,7 +562,7 @@ public function language() { */ protected function setDefaultLangcode() { // Get the language code if the property exists. - if ($this->getPropertyDefinition('langcode') && ($item = $this->get('langcode')) && isset($item->language)) { + if ($this->hasField('langcode') && ($item = $this->get('langcode')) && isset($item->language)) { $this->defaultLangcode = $item->language->id; } if (empty($this->defaultLangcode)) { @@ -611,7 +607,7 @@ public function onChange($name) { /** * {@inheritdoc} * - * @return \Drupal\Core\Entity\EntityInterface + * @return \Drupal\Core\Entity\ContentEntityInterface */ public function getTranslation($langcode) { // Ensure we always use the default language code when dealing with the @@ -734,7 +730,7 @@ public function addTranslation($langcode, array $values = array()) { $this->translations[$langcode]['status'] = static::TRANSLATION_CREATED; $translation = $this->getTranslation($langcode); - $definitions = $translation->getPropertyDefinitions(); + $definitions = $translation->getFieldDefinitions(); foreach ($values as $name => $value) { if (isset($definitions[$name]) && $definitions[$name]->isTranslatable()) { @@ -750,7 +746,7 @@ public function addTranslation($langcode, array $values = array()) { */ public function removeTranslation($langcode) { if (isset($this->translations[$langcode]) && $langcode != Language::LANGCODE_DEFAULT && $langcode != $this->defaultLangcode) { - foreach ($this->getPropertyDefinitions() as $name => $definition) { + foreach ($this->getFieldDefinitions() as $name => $definition) { if ($definition->isTranslatable()) { unset($this->values[$name][$langcode]); unset($this->fields[$name][$langcode]); @@ -804,7 +800,7 @@ public function updateOriginalValues() { if (!$this->fields) { return; } - foreach ($this->getPropertyDefinitions() as $name => $definition) { + foreach ($this->getFieldDefinitions() as $name => $definition) { if (!$definition->isComputed() && !empty($this->fields[$name])) { foreach ($this->fields[$name] as $langcode => $item) { $item->filterEmptyItems(); @@ -826,9 +822,9 @@ public function &__get($name) { if (isset($this->fields[$name][$this->activeLangcode])) { return $this->fields[$name][$this->activeLangcode]; } - // Inline getPropertyDefinition() to speed up things. + // Inline getFieldDefinition() to speed up things. if (!isset($this->fieldDefinitions)) { - $this->getPropertyDefinitions(); + $this->getFieldDefinitions(); } if (isset($this->fieldDefinitions[$name])) { $return = $this->getTranslatedField($name, $this->activeLangcode); @@ -930,7 +926,7 @@ public function __clone() { // Avoid deep-cloning when we are initializing a translation object, since // it will represent the same entity, only with a different active language. if (!$this->translationInitialize) { - $definitions = $this->getPropertyDefinitions(); + $definitions = $this->getFieldDefinitions(); foreach ($this->fields as $name => $values) { $this->fields[$name] = array(); // Untranslatable fields may have multiple references for the same field diff --git a/core/lib/Drupal/Core/Entity/ContentEntityFormController.php b/core/lib/Drupal/Core/Entity/ContentEntityFormController.php index cad2511..0383533 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityFormController.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityFormController.php @@ -139,7 +139,8 @@ public function buildEntity(array $form, array &$form_state) { // edited by this form. Values of fields handled by field API are copied // by field_attach_extract_form_values() below. $values_excluding_fields = $entity_type->isFieldable() ? array_diff_key($form_state['values'], field_info_instances($entity_type_id, $entity->bundle())) : $form_state['values']; - $definitions = $entity->getPropertyDefinitions(); + $definitions = $entity->getFieldDefinitions(); + foreach ($values_excluding_fields as $key => $value) { if (isset($definitions[$key])) { $entity->$key = $value; diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php index 862b23f..59f596c 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php @@ -72,4 +72,25 @@ public static function baseFieldDefinitions($entity_type); */ public function hasField($field_name); + /** + * Gets the definition of a contained field. + * + * @param string $name + * The name of the field. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface|false + * The definition of the field or FALSE if the field does not exist. + */ + public function getFieldDefinition($name); + + /** + * Gets an array of field definitions of all contained fields. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * An array of field definitions, keyed by field name. + * + * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() + */ + public function getFieldDefinitions(); + } diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index d100546..5684a9d 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -374,14 +374,6 @@ public function getFieldDefinitions($entity_type_id, $bundle = NULL) { /** * {@inheritdoc} */ - public function getFieldDefinitionsByConstraints($entity_type, array $constraints) { - // @todo: Add support for specifying multiple bundles. - return $this->getFieldDefinitions($entity_type, isset($constraints['Bundle']) ? $constraints['Bundle'] : NULL); - } - - /** - * {@inheritdoc} - */ public function clearCachedFieldDefinitions() { unset($this->entityFieldInfo); unset($this->fieldDefinitions); diff --git a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php index 3dde8e9..1cb7ab4 100644 --- a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php @@ -38,7 +38,6 @@ public function getEntityTypeLabels(); * An array of entity field definitions, keyed by field name. * * @see \Drupal\Core\TypedData\TypedDataManager::create() - * @see \Drupal\Core\Entity\EntityManager::getFieldDefinitionsByConstraints() */ public function getFieldDefinitions($entity_type_id, $bundle = NULL); @@ -70,30 +69,6 @@ public function getAccessController($entity_type); public function getAdminRouteInfo($entity_type_id, $bundle); /** - * Gets an array of entity field definitions based on validation constraints. - * - * @param string $entity_type - * The entity type to get field definitions for. - * @param array $constraints - * An array of entity constraints as used for entities in typed data - * definitions, i.e. an array optionally including a 'Bundle' key. - * For example the constraints used by an entity reference could be: - * - * @code - * array( - * 'Bundle' => 'article', - * ) - * @endcode - * - * @return array - * An array of field definitions of entity fields, keyed by field - * name. - * - * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() - */ - public function getFieldDefinitionsByConstraints($entity_type, array $constraints); - - /** * Creates a new storage controller instance. * * @param string $entity_type diff --git a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php index 6a1c8f8..350dd9d 100644 --- a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php @@ -667,7 +667,7 @@ protected function savePropertyData(EntityInterface $entity, $table_key = 'data_ protected function mapToStorageRecord(EntityInterface $entity, $table_key = 'base_table') { $record = new \stdClass(); $values = array(); - $definitions = $entity->getPropertyDefinitions(); + $definitions = $entity->getFieldDefinitions(); $schema = drupal_get_schema($this->entityType->get($table_key)); $is_new = $entity->isNew(); diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php index 1d9a00f..785cde9 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php @@ -17,7 +17,8 @@ * 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" + * derivative = "\Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver", + * definition_class = "\Drupal\Core\Entity\TypedData\EntityDataDefinition" * ) */ 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 index 69aef4a..a4e8940 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php @@ -18,16 +18,22 @@ * * 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. + * or the entity ID may be passed. * - * 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. + * Note that the definition of the referenced entity's type is required, whereas + * defining referencable entity bundle(s) is optional. A reference defining the + * type and bundle of the referenced entity can be created as following: + * @code + * $definition = \Drupal\Core\Entity\EntityDefinition::create($entity_type) + * ->addConstraint('Bundle', $bundle); + * \Drupal\Core\TypedData\DataReferenceDefinition::create('entity') + * ->setTargetDefinition($definition); + * @endcode * * @DataType( * id = "entity_reference", - * label = @Translation("Entity reference") + * label = @Translation("Entity reference"), + * definition_class = "\Drupal\Core\TypedData\DataReferenceDefinition" * ) */ class EntityReference extends DataReferenceBase { @@ -40,19 +46,13 @@ class EntityReference extends DataReferenceBase { protected $id; /** - * {@inheritdoc} + * Returns the definition of the referenced entity. + * + * @return \Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface + * The reference target's definition. */ 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; + return $this->definition->getTargetDefinition(); } /** @@ -62,7 +62,7 @@ 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->getConstraint('EntityType'), $this->id); + $this->target = entity_load($this->getTargetDefinition()->getEntityTypeId(), $this->id); } return $this->target; } @@ -99,7 +99,7 @@ public function setValue($value, $notify = TRUE) { if (!isset($value) || $value instanceof EntityInterface) { $this->target = $value; } - elseif (!is_scalar($value) || (($constraints = $this->definition->getConstraints()) && empty($constraints['EntityType']))) { + elseif (!is_scalar($value) || $this->getTargetDefinition()->getEntityTypeId() === NULL) { throw new \InvalidArgumentException('Value is not a valid entity.'); } else { diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php index 766d21b..bc269c5 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php @@ -29,7 +29,7 @@ public function validate($value, Constraint $constraint) { } $referenced_entity = $value->get('entity')->getTarget(); if (!$referenced_entity) { - $type = $value->getDefinition()->getSetting('target_type'); + $type = $value->getFieldDefinition()->getSetting('target_type'); $this->context->addViolation($constraint->message, array('%type' => $type, '%id' => $id)); } } diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php index 0621500..7308431 100644 --- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php +++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php @@ -144,7 +144,7 @@ public function addField($field, $type, $langcode) { $entity = $entity_manager ->getStorageController($entity_type_id) ->create($values); - $propertyDefinitions = $entity->$field_name->getPropertyDefinitions(); + $propertyDefinitions = $entity->$field_name->getFieldDefinition()->getPropertyDefinitions(); // If the column is not yet known, ie. the // $node->field_image->entity case then use first property as @@ -198,14 +198,14 @@ public function addField($field, $type, $langcode) { $entity = $entity_manager ->getStorageController($entity_type_id) ->create($values); - $propertyDefinitions = $entity->$specifier->getPropertyDefinitions(); + $propertyDefinitions = $entity->$specifier->getFieldDefinition()->getPropertyDefinitions(); $relationship_specifier = $specifiers[$key + 1]; $next_index_prefix = $relationship_specifier; } // Check for a valid relationship. if (isset($propertyDefinitions[$relationship_specifier]) && $entity->get($specifier)->first()->get('entity') instanceof EntityReference) { // If it is, use the entity type. - $entity_type_id = $propertyDefinitions[$relationship_specifier]->getConstraint('EntityType'); + $entity_type_id = $propertyDefinitions[$relationship_specifier]->getTargetDefinition()->getEntityTypeId(); $entity_type = $entity_manager->getDefinition($entity_type_id); // Add the new entity base table using the table and sql column. $join_condition= '%alias.' . $entity_type->getKey('id') . " = $table.$sql_column"; diff --git a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php new file mode 100644 index 0000000..87c6866 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php @@ -0,0 +1,127 @@ +setEntityTypeId($entity_type_id); + } + return $definition; + } + + /** + * {@inheritdoc} + */ + public static function createFromDataType($data_type) { + $parts = explode(':', $data_type); + if ($parts[0] != 'entity') { + throw new \InvalidArgumentException('Data type must be in the form of "entity:ENTITY_TYPE:BUNDLE."'); + } + $definition = static::create(); + // Set the passed entity type and bundle. + if (isset($parts[1])) { + $definition->setEntityTypeId($parts[1]); + } + if (isset($parts[2])) { + $definition->setBundles(array($parts[2])); + } + return $definition; + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + if (!isset($this->propertyDefinitions)) { + if ($entity_type_id = $this->getEntityTypeId()) { + // @todo: Add support for handling multiple bundles. + // See https://drupal.org/node/2169813. + $bundles = $this->getBundles(); + $bundle = is_array($bundles) && count($bundles) == 1 ? reset($bundles) : NULL; + $this->propertyDefinitions = \Drupal::entityManager()->getFieldDefinitions($entity_type_id, $bundle); + } + else { + // No entity type given. + $this->propertyDefinitions = array(); + } + } + return $this->propertyDefinitions; + } + + /** + * {@inheritdoc} + */ + public function getDataType() { + $type = 'entity'; + if ($entity_type = $this->getEntityTypeId()) { + $type .= ':' . $entity_type; + // Append the bundle only if we know it for sure. + if (($bundles = $this->getBundles()) && count($bundles) == 1) { + $type .= ':' . reset($bundles); + } + } + return $type; + } + + /** + * {@inheritdoc} + */ + public function getEntityTypeId() { + return $this->getConstraint('EntityType'); + } + + /** + * {@inheritdoc} + */ + public function setEntityTypeId($entity_type_id) { + return $this->addConstraint('EntityType', $entity_type_id); + } + + /** + * {@inheritdoc} + */ + public function getBundles() { + $bundle = $this->getConstraint('Bundle'); + return is_string($bundle) ? array($bundle) : $bundle; + } + + /** + * {@inheritdoc} + */ + public function setBundles(array $bundles = NULL) { + if (isset($bundles)) { + $this->addConstraint('Bundle', $bundles); + } + else { + // Remove the constraint. + $constraints = $this->getConstraints(); + unset($constraints['Bundle']); + $this->setConstraints($constraints); + } + return $this; + } + +} diff --git a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinitionInterface.php b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinitionInterface.php new file mode 100644 index 0000000..4d0a6c7 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinitionInterface.php @@ -0,0 +1,52 @@ +type = $type; + $field_definition->itemDefinition = FieldItemDataDefinition::create($field_definition); // Create a definition for the items, and initialize it with the default // settings for the field type. // @todo Cleanup in https://drupal.org/node/2116341. - $item_definition = DataDefinition::create('field_item:' . $type); $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); $default_settings = $field_type_manager->getDefaultSettings($type) + $field_type_manager->getDefaultInstanceSettings($type); - $item_definition->setSettings($default_settings); + $field_definition->itemDefinition->setSettings($default_settings); + return $field_definition; + } - return new static(array(), $item_definition); + /** + * {@inheritdoc} + */ + public static function createFromItemType($item_type) { + // The data type of a field item is in the form of "field_item:$field_type". + $parts = explode(':', $item_type, 2); + return static::create($parts[1]); } /** @@ -75,10 +101,7 @@ public function setName($name) { * {@inheritdoc} */ public function getType() { - $data_type = $this->getItemDefinition()->getDataType(); - // Cut of the leading field_item: prefix from 'field_item:FIELD_TYPE'. - $parts = explode(':', $data_type); - return $parts[1]; + return $this->type; } /** @@ -128,13 +151,6 @@ public function setSetting($setting_name, $value) { /** * {@inheritdoc} */ - public function getPropertyNames() { - return array_keys(\Drupal::typedDataManager()->create($this->getItemDefinition())->getPropertyDefinitions()); - } - - /** - * {@inheritdoc} - */ public function isTranslatable() { return !empty($this->definition['translatable']); } @@ -288,6 +304,71 @@ public function getDefaultValue(EntityInterface $entity) { /** * {@inheritdoc} */ + public function getPropertyDefinition($name) { + if (!isset($this->propertyDefinitions)) { + $this->getPropertyDefinitions(); + } + if (isset($this->propertyDefinitions[$name])) { + return $this->propertyDefinitions[$name]; + } + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + if (!isset($this->propertyDefinitions)) { + $class = $this->getFieldItemClass(); + $this->propertyDefinitions = $class::propertyDefinitions($this); + } + return $this->propertyDefinitions; + } + + /** + * {@inheritdoc} + */ + public function getPropertyNames() { + return array_keys($this->getPropertyDefinitions()); + } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + $class = $this->getFieldItemClass(); + return $class::mainPropertyName(); + } + + /** + * Helper to retrieve the field item class. + * + * @todo: Remove once getClass() adds in defaults. See + * https://drupal.org/node/2116341. + */ + protected function getFieldItemClass() { + if ($class = $this->getItemDefinition()->getClass()) { + return $class; + } + else { + $type_definition = \Drupal::typedDataManager() + ->getDefinition($this->getItemDefinition()->getDataType()); + return $type_definition['class']; + } + } + + /** + * {@inheritdoc} + */ + public function __sleep() { + // Do not serialize the statically cached property definitions. + $vars = get_object_vars($this); + unset($vars['propertyDefinitions']); + return array_keys($vars); + } + + /** + * {@inheritdoc} + */ public function getTargetEntityTypeId() { return isset($this->definition['entity_type']) ? $this->definition['entity_type'] : NULL; } diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php index 8146d9e..e7a457e 100644 --- a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php +++ b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php @@ -8,7 +8,7 @@ namespace Drupal\Core\Field; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\TypedData\ListDefinitionInterface; +use Drupal\Core\TypedData\ListDataDefinitionInterface; /** * Defines an interface for entity field definitions. @@ -52,7 +52,7 @@ * based on that abstract definition, even though that abstract definition can * differ from the concrete definition of any particular node's body field. */ -interface FieldDefinitionInterface extends ListDefinitionInterface { +interface FieldDefinitionInterface extends ListDataDefinitionInterface { /** * Value indicating a field accepts an unlimited number of values. @@ -104,22 +104,6 @@ public function getSettings(); public function getSetting($setting_name); /** - * Returns the names of the field's subproperties. - * - * A field is a list of items, and each item can contain one or more - * properties. All items for a given field contain the same property names, - * but the values can be different for each item. - * - * For example, an email field might just contain a single 'value' property, - * while a link field might contain 'title' and 'url' properties, and a text - * field might contain 'value', 'summary', and 'format' properties. - * - * @return array - * The property names. - */ - public function getPropertyNames(); - - /** * Returns whether the field is translatable. * * @return bool @@ -257,6 +241,54 @@ public function isMultiple(); public function getDefaultValue(EntityInterface $entity); /** + * Gets the definition of a contained property. + * + * @param string $name + * The name of property. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface|null + * The definition of the property or NULL if the property does not exist. + */ + public function getPropertyDefinition($name); + + /** + * Gets an array of property definitions of contained properties. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface[] + * An array of property definitions of contained properties, keyed by + * property name. + */ + public function getPropertyDefinitions(); + + /** + * Returns the names of the field's subproperties. + * + * A field is a list of items, and each item can contain one or more + * properties. All items for a given field contain the same property names, + * but the values can be different for each item. + * + * For example, an email field might just contain a single 'value' property, + * while a link field might contain 'title' and 'url' properties, and a text + * field might contain 'value', 'summary', and 'format' properties. + * + * @return array + * The property names. + */ + public function getPropertyNames(); + + /** + * Returns the name of the main property, if any. + * + * Some field items consist mainly of one main property, e.g. the value of a + * text field or the @code target_id @endcode of an entity reference. If the + * field item has no main property, the method returns NULL. + * + * @return string|null + * The name of the value property, or NULL if there is none. + */ + public function getMainPropertyName(); + + /** * Returns the ID of the type of the entity this field is attached to. * * This method should not be confused with EntityInterface::entityType() diff --git a/core/lib/Drupal/Core/Field/FieldItemBase.php b/core/lib/Drupal/Core/Field/FieldItemBase.php index 125b964..403dc25 100644 --- a/core/lib/Drupal/Core/Field/FieldItemBase.php +++ b/core/lib/Drupal/Core/Field/FieldItemBase.php @@ -17,7 +17,7 @@ * An entity field item. * * Entity field items making use of this base class have to implement - * ComplexDataInterface::getPropertyDefinitions(). + * the static method propertyDefinitions(). * * @see \Drupal\Core\Field\FieldItemInterface */ @@ -26,11 +26,18 @@ /** * {@inheritdoc} */ + public static function mainPropertyName() { + return 'value'; + } + + /** + * {@inheritdoc} + */ public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) { parent::__construct($definition, $name, $parent); // Initialize computed properties by default, such that they get cloned // with the whole item. - foreach ($this->getPropertyDefinitions() as $name => $definition) { + foreach ($this->definition->getPropertyDefinitions() as $name => $definition) { if ($definition->isComputed()) { $this->properties[$name] = \Drupal::typedDataManager()->getPropertyInstance($this, $name); } @@ -91,7 +98,7 @@ public function setValue($values, $notify = TRUE) { // Treat the values as property value of the first property, if no array is // given. if (isset($values) && !is_array($values)) { - $keys = array_keys($this->getPropertyDefinitions()); + $keys = array_keys($this->definition->getPropertyDefinitions()); $values = array($keys[0] => $values); } $this->values = $values; @@ -211,11 +218,4 @@ public function delete() { } */ public function deleteRevision() { } - /** - * {@inheritdoc} - */ - public function getMainPropertyName() { - return 'value'; - } - } diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php index bb1c5e5..899fbad 100644 --- a/core/lib/Drupal/Core/Field/FieldItemInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php @@ -24,6 +24,31 @@ interface FieldItemInterface extends ComplexDataInterface { /** + * Defines field item properties. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface[] + * An array of property definitions of contained properties, keyed by + * property name. + * + * @see \Drupal\Core\Field\FieldDefinition + */ + public static function propertyDefinitions(FieldDefinitionInterface $field_definition); + + /** + * Returns the name of the main property, if any. + * + * Some field items consist mainly of one main property, e.g. the value of a + * text field or the @code target_id @endcode of an entity reference. If the + * field item has no main property, the method returns NULL. + * + * @return string|null + * The name of the value property, or NULL if there is none. + * + * @see \Drupal\Core\Field\FieldDefinition + */ + public static function mainPropertyName(); + + /** * Returns the schema for the field. * * This method is static because the field schema information is needed on @@ -40,7 +65,7 @@ * following key/value pairs: * - columns: An array of Schema API column specifications, keyed by column * name. The columns need to be a subset of the properties defined in - * getPropertyDefinitions(). It is recommended to avoid having the column + * propertyDefinitions(). It is recommended to avoid having the column * definitions depend on field settings when possible. No assumptions * should be made on how storage engines internally use the original * column name to structure their storage. @@ -171,20 +196,4 @@ public function delete(); */ public function deleteRevision(); - /** - * Returns the name of the main property, if any. - * - * Some field items consist mainly of one main property, e.g. the value of a - * text field or the @code target_id @endcode of an entity reference. If the - * field item has no main property, the method returns NULL. - * - * @return string|null - * The name of the value property, or NULL if there is none. - * - * @todo: Move this to ComplexDataInterface once we improved Typed data to do - * not enforce having all methods on the data objects. - * https://drupal.org/node/2002134 - */ - public function getMainPropertyName(); - } diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php index 8afca40..78cd645 100644 --- a/core/lib/Drupal/Core/Field/FieldItemList.php +++ b/core/lib/Drupal/Core/Field/FieldItemList.php @@ -157,20 +157,6 @@ public function setValue($values, $notify = TRUE) { /** * {@inheritdoc} */ - public function getPropertyDefinition($name) { - return $this->first()->getPropertyDefinition($name); - } - - /** - * {@inheritdoc} - */ - public function getPropertyDefinitions() { - return $this->first()->getPropertyDefinitions(); - } - - /** - * {@inheritdoc} - */ public function __get($property_name) { return $this->first()->__get($property_name); } diff --git a/core/lib/Drupal/Core/Field/FieldItemListInterface.php b/core/lib/Drupal/Core/Field/FieldItemListInterface.php index 0af2245..abbf970 100644 --- a/core/lib/Drupal/Core/Field/FieldItemListInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemListInterface.php @@ -124,20 +124,6 @@ public function __isset($property_name); public function __unset($property_name); /** - * Gets the definition of a property of the first field item. - * - * @see \Drupal\Core\Field\FieldItemInterface::getPropertyDefinition() - */ - public function getPropertyDefinition($name); - - /** - * Gets an array of property definitions of the first field item. - * - * @see \Drupal\Core\Field\FieldItemInterface::getPropertyDefinitions() - */ - public function getPropertyDefinitions(); - - /** * Defines custom presave behavior for field values. * * This method is called before either insert() or update() methods, and diff --git a/core/lib/Drupal/Core/Field/Plugin/DataType/Deriver/FieldItemDeriver.php b/core/lib/Drupal/Core/Field/Plugin/DataType/Deriver/FieldItemDeriver.php index d6b6778..8d0ef20 100644 --- a/core/lib/Drupal/Core/Field/Plugin/DataType/Deriver/FieldItemDeriver.php +++ b/core/lib/Drupal/Core/Field/Plugin/DataType/Deriver/FieldItemDeriver.php @@ -77,6 +77,8 @@ public function getDerivativeDefinition($derivative_id, array $base_plugin_defin */ public function getDerivativeDefinitions(array $base_plugin_definition) { foreach ($this->fieldTypePluginManager->getDefinitions() as $plugin_id => $definition) { + $definition['definition_class'] = '\Drupal\Core\Field\TypedData\FieldItemDataDefinition'; + $definition['list_definition_class'] = '\Drupal\Core\Field\FieldDefinition'; $this->derivatives[$plugin_id] = $definition; } return $this->derivatives; diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php index 1d9884f..334a5a6 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php @@ -24,23 +24,13 @@ class BooleanItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see BooleanItem::getPropertyDefinitions() - * - * @var array + * {@inheritdoc} */ - static $propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('boolean') + ->setLabel(t('Boolean value')); - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). - */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('boolean') - ->setLabel(t('Boolean value')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DateItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DateItem.php index c1276dd..4fe58fe 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DateItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DateItem.php @@ -9,6 +9,7 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemBase; +use Drupal\Core\TypedData\DataDefinition; /** * Defines the 'date' entity field type. @@ -23,26 +24,13 @@ class DateItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see DateItem::getPropertyDefinitions() - * - * @var array + * {@inheritdoc} */ - static $propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('date') + ->setLabel(t('Date value')); - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). - */ - public function getPropertyDefinitions() { - - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = array( - 'type' => 'date', - 'label' => t('Date value'), - ); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php index 9e68719..93fc622 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php @@ -24,24 +24,13 @@ class EmailItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see EmailItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** - * Implements ComplexDataInterface::getPropertyDefinitions(). + * {@inheritdoc} */ - public function getPropertyDefinitions() { + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('email') + ->setLabel(t('E-mail value')); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('email') - ->setLabel(t('E-mail value')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php index 31a7d8e..58a5961 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php @@ -7,9 +7,11 @@ namespace Drupal\Core\Field\Plugin\Field\FieldType; +use Drupal\Core\Entity\TypedData\EntityDataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemBase; use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\DataReferenceDefinition; /** * Defines the 'entity_reference' entity field type. @@ -31,56 +33,46 @@ class EntityReferenceItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see EntityReferenceItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). + * {@inheritdoc} */ - public function getPropertyDefinitions() { - $settings = $this->definition->getSettings(); - $target_type = $settings['target_type']; - - // Definitions vary by entity type and bundle, so key them accordingly. - $key = $target_type . ':'; - $key .= isset($settings['target_bundle']) ? $settings['target_bundle'] : ''; - - if (!isset(static::$propertyDefinitions[$key])) { - $target_type_info = \Drupal::entityManager()->getDefinition($target_type); - if ($target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) { - // @todo: Lookup the entity type's ID data type and use it here. - // https://drupal.org/node/2107249 - static::$propertyDefinitions[$key]['target_id'] = DataDefinition::create('integer') - ->setLabel(t('Entity ID')) - ->setConstraints(array( - 'Range' => array('min' => 0), - )); - } - else { - static::$propertyDefinitions[$key]['target_id'] = DataDefinition::create('string') - ->setLabel(t('Entity ID')); - } + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $settings = $field_definition->getSettings(); + $target_type_info = \Drupal::entityManager()->getDefinition($settings['target_type']); - static::$propertyDefinitions[$key]['entity'] = DataDefinition::create('entity_reference') - ->setLabel(t('Entity')) - ->setDescription(t('The referenced entity')) - // The entity object is computed out of the entity ID. - ->setComputed(TRUE) - ->setReadOnly(FALSE) + if ($target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) { + // @todo: Lookup the entity type's ID data type and use it here. + // https://drupal.org/node/2107249 + $target_id_definition = DataDefinition::create('integer') + ->setLabel(t('Entity ID')) ->setConstraints(array( - 'EntityType' => $settings['target_type'], + 'Range' => array('min' => 0), )); - - if (isset($settings['target_bundle'])) { - static::$propertyDefinitions[$key]['entity']->addConstraint('Bundle', $settings['target_bundle']); - } } - return static::$propertyDefinitions[$key]; + else { + $target_id_definition = DataDefinition::create('string') + ->setLabel(t('Entity ID')); + } + $properties['target_id'] = $target_id_definition; + $properties['entity'] = DataReferenceDefinition::create('entity') + ->setLabel(t('Entity')) + ->setDescription(t('The referenced entity')) + // The entity object is computed out of the entity ID. + ->setComputed(TRUE) + ->setReadOnly(FALSE) + ->setTargetDefinition(EntityDataDefinition::create($settings['target_type'])); + + if (isset($settings['target_bundle'])) { + $properties['entity']->getTargetDefinition()->addConstraint('Bundle', $settings['target_bundle']); + } + + return $properties; + } + + /** + * {@inheritdoc} + */ + public static function mainPropertyName() { + return 'target_id'; } /** @@ -197,13 +189,6 @@ public function onChange($property_name) { /** * {@inheritdoc} */ - public function getMainPropertyName() { - return 'target_id'; - } - - /** - * {@inheritdoc} - */ public function isEmpty() { // Avoid loading the entity by first checking the 'target_id'. $target_id = $this->target_id; @@ -240,5 +225,4 @@ public function preSave() { public function hasUnsavedEntity() { return $this->target_id === NULL && ($entity = $this->entity) && $entity->isNew(); } - } diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php index 045af1c..c53f639 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php @@ -24,24 +24,13 @@ class FloatItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see IntegerItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). + * {@inheritdoc} */ - public function getPropertyDefinitions() { + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('float') + ->setLabel(t('Float value')); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('float') - ->setLabel(t('Float value')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php index ec49cdb..0a7a8cf 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php @@ -24,24 +24,13 @@ class IntegerItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see IntegerItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('integer') + ->setLabel(t('Integer value')); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('integer') - ->setLabel(t('Integer value')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php index 3bae65b..f764710 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php @@ -11,6 +11,7 @@ use Drupal\Core\Field\FieldItemBase; use Drupal\Core\Language\Language; use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\DataReferenceDefinition; /** * Defines the 'language' entity field item. @@ -30,30 +31,20 @@ class LanguageItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see LanguageItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). + * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('Language code')); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Language code')); - static::$propertyDefinitions['language'] = DataDefinition::create('language_reference') - ->setLabel(t('Language object')) - ->setDescription(t('The referenced language')) + $properties['language'] = DataReferenceDefinition::create('language') + ->setLabel(t('Language object')) + ->setDescription(t('The referenced language')) // The language object is retrieved via the language code. - ->setComputed(TRUE) - ->setReadOnly(FALSE); - } - return static::$propertyDefinitions; + ->setComputed(TRUE) + ->setReadOnly(FALSE); + + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php index 698e5b8..50f38ed 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php @@ -9,6 +9,7 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemBase; +use Drupal\Core\TypedData\DataDefinition; /** * Defines the 'map' entity field type. @@ -16,7 +17,7 @@ * @FieldType( * id = "map", * label = @Translation("Map"), - * description = @Translation("An entity field containing a map value."), + * description = @Translation("An entity field for storing a serialized array of values."), * configurable = FALSE * ) */ @@ -25,6 +26,16 @@ class MapItem extends FieldItemBase { /** * {@inheritdoc} */ + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Serialized values')); + + return $properties; + } + + /** + * {@inheritdoc} + */ public static function schema(FieldDefinitionInterface $field_definition) { return array( 'columns' => array( diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php index c5f6c77..5a32aa6 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php @@ -27,24 +27,13 @@ class StringItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see StringItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Text value')); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('Text value')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php index d8c0b32..0fa6820 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php @@ -30,23 +30,13 @@ class UriItem extends StringItem { /** - * Field definitions of the contained properties. - * - * @see self::getPropertyDefinitions() - * - * @var array + * {@inheritdoc} */ - static $propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('uri') + ->setLabel(t('URI value')); - /** - * Implements ComplexDataInterface::getPropertyDefinitions(). - */ - public function getPropertyDefinitions() { - if (!isset(self::$propertyDefinitions)) { - self::$propertyDefinitions['value'] = DataDefinition::create('uri') - ->setLabel(t('URI value')); - } - return self::$propertyDefinitions; + return $properties; } /** diff --git a/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php b/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php new file mode 100644 index 0000000..dbf81c6 --- /dev/null +++ b/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php @@ -0,0 +1,81 @@ +getItemDefinition(); + } + + /** + * Creates a new field item definition. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition the item definition belongs to. + * + * @return static + */ + public static function create($field_definition) { + $definition['type'] = 'field_item:' . $field_definition->getType(); + $item_definition = new static($definition); + $item_definition->fieldDefinition = $field_definition; + return $item_definition; + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinition($name) { + return $this->fieldDefinition->getPropertyDefinition($name); + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + return $this->fieldDefinition->getPropertyDefinitions(); + } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + return $this->fieldDefinition->getMainPropertyName(); + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Annotation/DataType.php b/core/lib/Drupal/Core/TypedData/Annotation/DataType.php index c95063c..880ec65 100644 --- a/core/lib/Drupal/Core/TypedData/Annotation/DataType.php +++ b/core/lib/Drupal/Core/TypedData/Annotation/DataType.php @@ -62,6 +62,14 @@ class DataType extends Plugin { public $description; /** + * The definition class to use for defining data of this type. + * Must implement the \Drupal\Core\TypedData\DataDefinitionInterface. + * + * @var string + */ + public $definition_class = '\Drupal\Core\TypedData\DataDefinition'; + + /** * The typed data class used for wrapping multiple data items of the type. * Must implement the \Drupal\Core\TypedData\ListInterface. * @@ -70,6 +78,14 @@ class DataType extends Plugin { public $list_class = '\Drupal\Core\TypedData\Plugin\DataType\ItemList'; /** + * The definition class to use for defining a list of items of this type. + * Must implement the \Drupal\Core\TypedData\ListDataDefinitionInterface. + * + * @var string + */ + public $list_definition_class = '\Drupal\Core\TypedData\ListDataDefinition'; + + /** * The pre-defined primitive type that this data type maps to. * * If set, it must be a constant defined by \Drupal\Core\TypedData\Primitive diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php new file mode 100644 index 0000000..1fa5dab --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php @@ -0,0 +1,56 @@ +propertyDefinitions)) { + $this->getPropertyDefinitions(); + } + if (isset($this->propertyDefinitions[$name])) { + return $this->propertyDefinitions[$name]; + } + } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + return NULL; + } + + /** + * {@inheritdoc} + */ + public function __sleep() { + // Do not serialize the cached property definitions. + $vars = get_object_vars($this); + unset($vars['propertyDefinitions']); + return array_keys($vars); + } + +} diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionInterface.php new file mode 100644 index 0000000..efa5fdf --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionInterface.php @@ -0,0 +1,49 @@ +definition = $definition; + public function __construct(array $values = array()) { + $this->definition = $values; } /** @@ -110,7 +117,7 @@ public function setDescription($description) { * {@inheritdoc} */ public function isList() { - return ($this instanceof ListDefinitionInterface); + return ($this instanceof ListDataDefinitionInterface); } /** diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php index e026fe8..0aae838 100644 --- a/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php +++ b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php @@ -14,11 +14,42 @@ * For example, a plugin could describe its parameters using data definitions * in order to specify what kind of data is required for it. * + * Definitions that describe lists or complex data have to implement the + * respective interfaces, such that the metadata about contained list items or + * properties can be retrieved from the definition. + * * @see \Drupal\Core\TypedData\DataDefinition + * @see \Drupal\Core\TypedData\ListDefinitionInterface + * @see \Drupal\Core\TypedData\ComplexDataDefinitionInterface + * @see \Drupal\Core\TypedData\DataReferenceDefinitionInterface + * @see \Drupal\Core\TypedData\TypedDataInterface */ interface DataDefinitionInterface { /** + * Creates a new data definition object. + * + * This method is typically used by + * \Drupal\Core\TypedData\TypedDataManager::createDataDefinition() to build a + * definition object for an arbitrary data type. When the definition class is + * known, it is recommended to directly use the static create() method on that + * class instead; e.g.: + * @code + * $map_definition = \Drupal\Core\TypedData\MapDataDefinition::create(); + * @endcode + * + * @param string $data_type + * The data type, for which a data definition should be created. + * + * @throws \InvalidArgumentException + * If an unsupported data type gets passed to the class; e.g., 'string' to a + * definition class handling 'entity:* data types. + * + * @return static + */ + public static function createFromDataType($data_type); + + /** * Returns the data type of the data. * * @return string diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php index 5a2d597..12b930e 100644 --- a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php +++ b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php @@ -10,9 +10,14 @@ /** * Base class for typed data references. * - * Implementing classes have to implement at least - * \Drupal\Core\TypedData\DataReferenceInterface::getTargetDefinition() and + * Data types based on this base class need to be named + * "{TARGET_TYPE}_reference", whereas {TARGET_TYPE} is the referenced data type. + * For example, an entity reference data type would have to be named + * "entity_reference". + * Beside that, implementing classes have to implement at least * \Drupal\Core\TypedData\DataReferenceInterface::getTargetIdentifier(). + * + * @see \Drupal\Core\TypedData\DataReferenceDefinition */ abstract class DataReferenceBase extends TypedData implements DataReferenceInterface { @@ -43,7 +48,7 @@ public function getValue() { * {@inheritdoc} */ public function setValue($value, $notify = TRUE) { - $this->target = \Drupal::typedDataManager()->create($this->getTargetDefinition(), $value); + $this->target = \Drupal::typedDataManager()->create($this->definition->getTargetDefinition(), $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/DataReferenceDefinition.php b/core/lib/Drupal/Core/TypedData/DataReferenceDefinition.php new file mode 100644 index 0000000..9c58657 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/DataReferenceDefinition.php @@ -0,0 +1,70 @@ +setTargetDefinition(\Drupal::typedDataManager()->createDataDefinition($type)); + } + + /** + * {@inheritdoc} + */ + public static function createFromDataType($data_type) { + if (substr($data_type, -strlen('_reference')) != '_reference') { + throw new \InvalidArgumentException('Data type must be of the form "{TARGET_TYPE}_reference"'); + } + // Cut of the _reference suffix. + return static::create(substr($data_type, 0, strlen($data_type) - strlen('_reference'))); + } + + /** + * {@inheritdoc} + */ + public function getTargetDefinition() { + return $this->targetDefinition; + } + + /** + * Sets the definition of the referenced data. + * + * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition + * The target definition to set. + * + * @return $this + */ + public function setTargetDefinition(DataDefinitionInterface $definition) { + $this->targetDefinition = $definition; + return $this; + } + +} diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/DataReferenceDefinitionInterface.php new file mode 100644 index 0000000..334cc9b --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/DataReferenceDefinitionInterface.php @@ -0,0 +1,26 @@ +itemDefinition = DataDefinition::create('any'); + return $definition; + } + + /** + * {@inheritdoc} + */ + public static function createFromItemType($item_type) { + return new static(array(), \Drupal::typedDataManager()->createDataDefinition($item_type)); } /** * {@inheritdoc} - * - * @param */ - public function __construct(array $definition = array(), DataDefinitionInterface $item_definition = NULL) { - parent::__construct($definition); - $this->itemDefinition = isset($item_definition) ? $item_definition : DataDefinition::create('any'); + public function __construct(array $values = array(), DataDefinitionInterface $item_definition = NULL) { + $this->definition = $values; + $this->itemDefinition = $item_definition; } /** diff --git a/core/lib/Drupal/Core/TypedData/ListDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/ListDataDefinitionInterface.php similarity index 30% rename from core/lib/Drupal/Core/TypedData/ListDefinitionInterface.php rename to core/lib/Drupal/Core/TypedData/ListDataDefinitionInterface.php index c07d60e..67d2cc1 100644 --- a/core/lib/Drupal/Core/TypedData/ListDefinitionInterface.php +++ b/core/lib/Drupal/Core/TypedData/ListDataDefinitionInterface.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\Core\TypedData\ListDefinitionInterface. + * Contains \Drupal\Core\TypedData\ListDataDefinitionInterface. */ namespace Drupal\Core\TypedData; @@ -12,8 +12,34 @@ * * This interface is present on a data definition if it describes a list. The * actual lists implement the \Drupal\Core\TypedData\ListInterface. + * + * @see \Drupal\Core\TypedData\ListDefinition + * @see \Drupal\Core\TypedData\ListInterface */ -interface ListDefinitionInterface extends DataDefinitionInterface { +interface ListDataDefinitionInterface extends DataDefinitionInterface { + + /** + * Creates a new list data definition for items of the given data type. + * + * This method is typically used by + * \Drupal\Core\TypedData\TypedDataManager::createListDataDefinition() to + * build a definition object for an arbitrary item type. When the definition + * class is known, it is recommended to directly use the static create() + * method on that class instead; e.g.: + * @code + * $list_definition = \Drupal\Core\TypedData\ListDataDefinition::create('string'); + * @endcode + * + * @param string $item_type + * The item type, for which a list data definition should be created. + * + * @throws \InvalidArgumentException + * If an unsupported data type gets passed to the class; e.g., 'string' to a + * definition class handling lists of 'field_item:* data types. + * + * @return static + */ + public static function createFromItemType($item_type); /** * Gets the data definition of an item of the list. diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php index 3f8972b..e8803b3 100644 --- a/core/lib/Drupal/Core/TypedData/ListInterface.php +++ b/core/lib/Drupal/Core/TypedData/ListInterface.php @@ -15,6 +15,8 @@ * * When implementing this interface which extends Traversable, make sure to list * IteratorAggregate or Iterator before this interface in the implements clause. + * + * @see \Drupal\Core\TypedData\ListDefinitionInterface */ interface ListInterface extends TypedDataInterface, \ArrayAccess, \Countable, \Traversable { diff --git a/core/lib/Drupal/Core/TypedData/MapDataDefinition.php b/core/lib/Drupal/Core/TypedData/MapDataDefinition.php new file mode 100644 index 0000000..9b90697 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/MapDataDefinition.php @@ -0,0 +1,92 @@ +propertyDefinitions)) { + $this->propertyDefinitions = array(); + } + return $this->propertyDefinitions; + } + + /** + * Sets the definition of a map property. + * + * @param string $name + * The name of the property to define. + * @param \Drupal\Core\TypedData\DataDefinitionInterface|null $definition + * (optional) The property definition to set, or NULL to unset it. + * + * @return $this + */ + public function setPropertyDefinition($name, DataDefinitionInterface $definition = NULL) { + if (isset($definition)) { + $this->propertyDefinitions[$name] = $definition; + } + else { + unset($this->propertyDefinitions[$name]); + } + return $this; + } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + return $this->mainPropertyName; + } + + /** + * Sets the main property name. + * + * @param string|null $name + * The name of the main property, or NULL if there is none. + * + * @return $this + */ + public function setMainPropertyName($name) { + $this->mainPropertyName = $name; + return $this; + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php index d2b1a06..e15945b 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php @@ -22,7 +22,8 @@ * * @DataType( * id = "list", - * label = @Translation("List of items") + * label = @Translation("List of items"), + * definition_class = "\Drupal\Core\TypedData\ListDataDefinition" * ) */ class ItemList extends TypedData implements \IteratorAggregate, ListInterface { diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/LanguageReference.php similarity index 61% rename from core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php rename to core/lib/Drupal/Core/TypedData/Plugin/DataType/LanguageReference.php index f0c352c..9fbaa21 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/LanguageReference.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/LanguageReference.php @@ -2,18 +2,17 @@ /** * @file - * Contains \Drupal\Core\Entity\Plugin\DataType\LanguageReference. + * Contains \Drupal\Core\TypedData\Plugin\DataType\LanguageReference. */ -namespace Drupal\Core\Entity\Plugin\DataType; +namespace Drupal\Core\TypedData\Plugin\DataType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\TypedData\DataReferenceBase; /** * Defines the 'language_reference' data type. * - * This serves as 'language' property of entity reference field items and gets + * This serves as 'language' property of language 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 @@ -22,7 +21,8 @@ * * @DataType( * id = "language_reference", - * label = @Translation("Language reference") + * label = @Translation("Language reference"), + * definition_class = "\Drupal\Core\TypedData\DataReferenceDefinition" * ) */ class LanguageReference extends DataReferenceBase { @@ -30,15 +30,9 @@ class LanguageReference extends DataReferenceBase { /** * {@inheritdoc} */ - public function getTargetDefinition() { - return DataDefinition::create('language'); - } - - /** - * {@inheritdoc} - */ public function getTargetIdentifier() { $language = $this->getTarget(); return isset($language) ? $language->id() : NULL; } + } diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php index ab66442..d895632 100644 --- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php +++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php @@ -7,7 +7,6 @@ namespace Drupal\Core\TypedData\Plugin\DataType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\ComplexDataInterface; @@ -23,12 +22,20 @@ * * @DataType( * id = "map", - * label = @Translation("Map") + * label = @Translation("Map"), + * definition_class = "\Drupal\Core\TypedData\MapDataDefinition" * ) */ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface { /** + * The data definition. + * + * @var \Drupal\Core\TypedData\ComplexDataDefinitionInterface + */ + protected $definition; + + /** * An array of values for the contained properties. * * @var array @@ -36,21 +43,21 @@ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface protected $values = array(); /** - * The array of properties, each implementing the TypedDataInterface. + * The array of properties. * - * @var array + * @var \Drupal\Core\TypedData\TypedDataInterface[] */ protected $properties = array(); /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). + * Gets an array of property definitions of contained properties. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface[] + * An array of property definitions of contained properties, keyed by + * property name. */ - public function getPropertyDefinitions() { - $definitions = array(); - foreach ($this->values as $name => $value) { - $definitions[$name] = DataDefinition::create('any'); - } - return $definitions; + protected function getPropertyDefinitions() { + return $this->definition->getPropertyDefinitions(); } /** @@ -59,7 +66,7 @@ public function getPropertyDefinitions() { public function getValue($include_computed = FALSE) { // Update the values and return them. foreach ($this->properties as $name => $property) { - $definition = $property->getDefinition(); + $definition = $property->getDataDefinition(); if ($include_computed || !$definition->isComputed()) { $value = $property->getValue(); // Only write NULL values if the whole map is not NULL. @@ -128,7 +135,7 @@ public function get($property_name) { * Implements \Drupal\Core\TypedData\ComplexDataInterface::set(). */ public function set($property_name, $value, $notify = TRUE) { - if ($this->getPropertyDefinition($property_name)) { + if ($this->definition->getPropertyDefinition($property_name)) { $this->get($property_name)->setValue($value, $notify); } else { @@ -146,7 +153,7 @@ public function set($property_name, $value, $notify = TRUE) { */ public function getProperties($include_computed = FALSE) { $properties = array(); - foreach ($this->getPropertyDefinitions() as $name => $definition) { + foreach ($this->definition->getPropertyDefinitions() as $name => $definition) { if ($include_computed || !$definition->isComputed()) { $properties[$name] = $this->get($name); } @@ -182,24 +189,11 @@ public function getIterator() { } /** - * 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::isEmpty(). */ public function isEmpty() { foreach ($this->properties as $property) { - $definition = $property->getDefinition(); + $definition = $property->getDataDefinition(); if (!$definition->isComputed() && $property->getValue() !== NULL) { return FALSE; } diff --git a/core/lib/Drupal/Core/TypedData/TypedData.php b/core/lib/Drupal/Core/TypedData/TypedData.php index 1597c93..d113675 100644 --- a/core/lib/Drupal/Core/TypedData/TypedData.php +++ b/core/lib/Drupal/Core/TypedData/TypedData.php @@ -79,7 +79,7 @@ public function getPluginDefinition() { /** * {@inheritdoc} */ - public function getDefinition() { + public function getDataDefinition() { return $this->definition; } diff --git a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php index 4d7b066..b709a81 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataInterface.php @@ -11,6 +11,8 @@ /** * Interface for typed data objects. + * + * @see \Drupal\Core\TypedData\DataDefinitionInterface */ interface TypedDataInterface { @@ -20,7 +22,7 @@ * @return \Drupal\Core\TypedData\DataDefinitionInterface * The data definition object. */ - public function getDefinition(); + public function getDataDefinition(); /** * Gets the data value. diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index e060cd3..f8c9ab4 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -133,6 +133,56 @@ public function create(DataDefinitionInterface $definition, $value = NULL, $name } /** + * Creates a new data definition object. + * + * While data definitions objects may be created directly if the definition + * class used by a data type is known, this method allows the creation of data + * definitions for any given data type. + * + * E.g., if a definition for a map is to be created, the following code + * could be used instead of calling this method with the argument 'map': + * @code + * $map_definition = \Drupal\Core\TypedData\MapDataDefinition::create(); + * @endcode + * + * @param string $data_type + * The data type, for which a data definition should be created. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface + * A data definition for the given data type. + * + * @see \Drupal\Core\TypedData\TypedDataManager::createListDataDefinition() + */ + public function createDataDefinition($data_type) { + $type_definition = $this->getDefinition($data_type); + if (!isset($type_definition)) { + throw new \InvalidArgumentException(format_string('Invalid data type %plugin_id has been given.', array('%plugin_id' => $data_type))); + } + $class = $type_definition['definition_class']; + return $class::createFromDataType($data_type); + } + + /** + * Creates a new list data definition for items of the given data type. + * + * @param string $item_type + * The item type, for which a list data definition should be created. + * + * @return \Drupal\Core\TypedData\ListDataDefinitionInterface + * A list definition for items of the given data type. + * + * @see \Drupal\Core\TypedData\TypedDataManager::createDataDefinition() + */ + public function createListDataDefinition($item_type) { + $type_definition = $this->getDefinition($item_type); + if (!isset($type_definition)) { + throw new \InvalidArgumentException(format_string('Invalid data type %plugin_id has been given.', array('%plugin_id' => $item_type))); + } + $class = $type_definition['list_definition_class']; + return $class::createFromItemType($item_type); + } + + /** * Implements \Drupal\Component\Plugin\PluginManagerInterface::getInstance(). * * @param array $options @@ -188,10 +238,10 @@ public function getInstance(array $options) { * @see \Drupal\Core\TypedData\TypedDataManager::create() */ public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL) { - $definition = $object->getRoot()->getDefinition(); + $definition = $object->getRoot()->getDataDefinition(); // If the definition is a list, we need to look at the data type and the // settings of its item definition. - if ($definition instanceof ListDefinition) { + if ($definition instanceof ListDataDefinition) { $definition = $definition->getItemDefinition(); } $key = $definition->getDataType(); @@ -209,7 +259,7 @@ public function getPropertyInstance(TypedDataInterface $object, $property_name, // Create the initial prototype. For that we need to fetch the definition // of the to be created property instance from the parent. if ($object instanceof ComplexDataInterface) { - $definition = $object->getPropertyDefinition($property_name); + $definition = $object->getDataDefinition()->getPropertyDefinition($property_name); } elseif ($object instanceof ListInterface) { $definition = $object->getItemDefinition(); @@ -365,6 +415,12 @@ public function getConstraints(DataDefinitionInterface $definition) { if (is_subclass_of($class,'Drupal\Core\TypedData\AllowedValuesInterface')) { $constraints[] = $validation_manager->create('AllowedValues', array()); } + // Add any constraints about referenced data. + if ($definition instanceof DataReferenceDefinitionInterface) { + foreach ($definition->getTargetDefinition()->getConstraints() as $name => $options) { + $constraints[] = $validation_manager->create($name, $options); + } + } return $constraints; } diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php index af0e38e..da5263a 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php @@ -30,7 +30,7 @@ public function validate($value, Constraint $constraint) { // If the data is complex, we have to validate its main property. if ($typed_data instanceof ComplexDataInterface) { - $name = $typed_data->getMainPropertyName(); + $name = $typed_data->getDataDefinition()->getMainPropertyName(); if (!isset($name)) { throw new \LogicException('Cannot validate allowed values for complex data without a main property.'); } diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index fe0c572..606eac7 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -413,7 +413,7 @@ function comment_new_page_count($num_comments, $new_replies, EntityInterface $en function comment_entity_view_alter(&$build, EntityInterface $entity, EntityViewDisplayInterface $display) { // Add the comment page number to the cache key if render caching is enabled. if (isset($build['#cache']) && isset($build['#cache']['keys']) && \Drupal::request()->query->has('page')) { - foreach ($entity->getPropertyDefinitions() as $field_name => $definition) { + foreach ($entity->getFieldDefinitions() as $field_name => $definition) { if (isset($build[$field_name]) && $definition->getType() === 'comment') { $display_options = $display->getComponent($field_name); $pager_id = $display_options['settings']['pager_id']; @@ -887,7 +887,7 @@ function comment_translation_configuration_element_submit($form, &$form_state) { /** * Implements hook_entity_load(). * - * @see \Drupal\comment\Plugin\Field\FieldType\CommentItem::getPropertyDefinitions() + * @see \Drupal\comment\Plugin\Field\FieldType\CommentItem::propertyDefinitions() */ function comment_entity_load($entities, $entity_type) { if (!\Drupal::service('comment.manager')->getFields($entity_type)) { diff --git a/core/modules/comment/comment.tokens.inc b/core/modules/comment/comment.tokens.inc index ecff337..a4c9af1 100644 --- a/core/modules/comment/comment.tokens.inc +++ b/core/modules/comment/comment.tokens.inc @@ -257,7 +257,7 @@ function comment_tokens($type, $tokens, array $data = array(), array $options = case 'comment-count': $count = 0; $fields = array_keys(\Drupal::service('comment.manager')->getFields($entity->getEntityTypeId())); - $definitions = array_keys($entity->getPropertyDefinitions()); + $definitions = array_keys($entity->getFieldDefinitions()); $valid_fields = array_intersect($fields, $definitions); foreach ($valid_fields as $field_name) { $count += $entity->get($field_name)->comment_count; diff --git a/core/modules/comment/lib/Drupal/comment/CommentFieldNameItem.php b/core/modules/comment/lib/Drupal/comment/CommentFieldNameItem.php index a90495d..0f6eae2 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentFieldNameItem.php +++ b/core/modules/comment/lib/Drupal/comment/CommentFieldNameItem.php @@ -7,6 +7,7 @@ namespace Drupal\comment; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\Plugin\Field\FieldType\StringItem; use Drupal\Core\TypedData\DataDefinition; @@ -16,26 +17,15 @@ class CommentFieldNameItem extends StringItem { /** - * Definitions of the contained properties. - * - * @see self::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('String value')) + ->setClass('\Drupal\comment\CommentFieldNameValue') + ->setComputed(TRUE); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('String value')) - ->setClass('\Drupal\comment\CommentFieldNameValue') - ->setComputed(TRUE); - } - return static::$propertyDefinitions; + return $properties; } } diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php index a4312c0..9911726 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php @@ -226,7 +226,7 @@ public function form(array $form, array &$form_state) { // Add internal comment properties. $original = $comment->getUntranslated(); foreach (array('cid', 'pid', 'entity_id', 'entity_type', 'field_id', 'uid', 'langcode') as $key) { - $key_name = key($comment->$key->first()->getPropertyDefinitions()); + $key_name = key($comment->$key->getFieldDefinition()->getPropertyDefinitions()); $form[$key] = array('#type' => 'value', '#value' => $original->$key->{$key_name}); } diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php index a43e338..ae4f4cb 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/Field/FieldType/CommentItem.php @@ -7,8 +7,8 @@ namespace Drupal\comment\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\ConfigFieldItemBase; /** @@ -33,39 +33,31 @@ class CommentItem extends ConfigFieldItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - public static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['status'] = DataDefinition::create('integer') - ->setLabel(t('Comment status value')); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['status'] = DataDefinition::create('integer') + ->setLabel(t('Comment status value')); - static::$propertyDefinitions['cid'] = DataDefinition::create('integer') - ->setLabel(t('Last comment ID')); + $properties['cid'] = DataDefinition::create('integer') + ->setLabel(t('Last comment ID')); - static::$propertyDefinitions['last_comment_timestamp'] = DataDefinition::create('integer') - ->setLabel(t('Last comment timestamp')) - ->setDescription(t('The time that the last comment was created.')); + $properties['last_comment_timestamp'] = DataDefinition::create('integer') + ->setLabel(t('Last comment timestamp')) + ->setDescription(t('The time that the last comment was created.')); - static::$propertyDefinitions['last_comment_name'] = DataDefinition::create('string') - ->setLabel(t('Last comment name')) - ->setDescription(t('The name of the user posting the last comment.')); + $properties['last_comment_name'] = DataDefinition::create('string') + ->setLabel(t('Last comment name')) + ->setDescription(t('The name of the user posting the last comment.')); - static::$propertyDefinitions['last_comment_uid'] = DataDefinition::create('integer') - ->setLabel(t('Last comment user ID')); + $properties['last_comment_uid'] = DataDefinition::create('integer') + ->setLabel(t('Last comment user ID')); - static::$propertyDefinitions['comment_count'] = DataDefinition::create('integer') - ->setLabel(t('Number of comments')) - ->setDescription(t('The number of comments.')); - } - return static::$propertyDefinitions; + $properties['comment_count'] = DataDefinition::create('integer') + ->setLabel(t('Number of comments')) + ->setDescription(t('The number of comments.')); + + return $properties; } /** diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php index 62341ee..ad21904 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php @@ -65,13 +65,13 @@ function testSchemaMapping() { // Check type detection on elements with undefined types. $config = config_typed()->get('config_test.someschema'); - $definition = $config['testitem']->getDefinition(); + $definition = $config['testitem']->getDataDefinition(); $expected = array(); $expected['label'] = 'Test item'; $expected['class'] = '\Drupal\Core\TypedData\Plugin\DataType\String'; $expected['type'] = 'string'; $this->assertEqual($definition, $expected, 'Automatic type detection on string item worked.'); - $definition = $config['testlist']->getDefinition(); + $definition = $config['testlist']->getDataDefinition(); $expected = array(); $expected['label'] = 'Test list'; $expected['class'] = '\Drupal\Core\Config\Schema\Property'; @@ -132,7 +132,7 @@ function testSchemaMapping() { // Most complex case, get metadata for actual configuration element. $effects = config_typed()->get('image.style.medium')->get('effects'); - $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDefinition(); + $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDataDefinition(); // This should be the schema for image.effect.image_scale, reuse previous one. $expected['type'] = 'image.effect.image_scale'; @@ -164,7 +164,7 @@ function testSchemaMappingWithParents() { // Test fetching parent one level up. $entry = $config_data->get('one_level'); - $definition = $entry['testitem']->getDefinition(); + $definition = $entry['testitem']->getDataDefinition(); $expected = array( 'type' => 'config_test.someschema.with_parents.key_1', 'label' => 'Test item nested one level', @@ -174,7 +174,7 @@ function testSchemaMappingWithParents() { // Test fetching parent two levels up. $entry = $config_data->get('two_levels'); - $definition = $entry['wrapper']['testitem']->getDefinition(); + $definition = $entry['wrapper']['testitem']->getDataDefinition(); $expected = array( 'type' => 'config_test.someschema.with_parents.key_2', 'label' => 'Test item nested two levels', @@ -184,7 +184,7 @@ function testSchemaMappingWithParents() { // Test fetching parent three levels up. $entry = $config_data->get('three_levels'); - $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDefinition(); + $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDataDefinition(); $expected = array( 'type' => 'config_test.someschema.with_parents.key_3', 'label' => 'Test item nested three levels', @@ -202,13 +202,13 @@ function testSchemaData() { $property = $meta->get('name'); $this->assertTrue($property instanceof StringInterface, 'Got the right wrapper fo the site name property.'); $this->assertEqual($property->getValue(), 'Drupal', 'Got the right string value for site name data.'); - $definition = $property->getDefinition(); + $definition = $property->getDataDefinition(); $this->assertTrue($definition['translatable'], 'Got the right translatability setting for site name data.'); $property = $meta->get('page')->get('front'); $this->assertTrue($property instanceof StringInterface, 'Got the right wrapper fo the page.front property.'); $this->assertEqual($property->getValue(), 'user', 'Got the right value for page.front data.'); - $definition = $property->getDefinition(); + $definition = $property->getDataDefinition(); $this->assertTrue(empty($definition['translatable']), 'Got the right translatability setting for page.front data.'); // Check nested array of properties. diff --git a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php index d5f77c5..7168d26 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/ConfigMapperManager.php @@ -133,7 +133,7 @@ protected function findTranslatable(TypedDataInterface $element) { return FALSE; } else { - $definition = $element->getDefinition(); + $definition = $element->getDataDefinition(); return isset($definition['translatable']) && $definition['translatable']; } } diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php index 22e6783..5948f7a 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php @@ -264,7 +264,7 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d foreach ($schema as $key => $element) { // Make the specific element key, "$base_key.$key". $element_key = implode('.', array_filter(array($base_key, $key))); - $definition = $element->getDefinition() + array('label' => $this->t('N/A')); + $definition = $element->getDataDefinition() + array('label' => $this->t('N/A')); if ($element instanceof Element) { // Build sub-structure and include it with a wrapper in the form // if there are any translatable elements there. @@ -299,7 +299,7 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d } } else { - $definition = $element->getDefinition(); + $definition = $element->getDataDefinition(); // Invoke hook_config_translation_type_info_alter() implementations to // alter the configuration types. diff --git a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php index 5f4afe5..860941b 100644 --- a/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php +++ b/core/modules/config_translation/tests/Drupal/config_translation/Tests/ConfigMapperManagerTest.php @@ -164,7 +164,7 @@ public function providerTestHasTranslatable() { protected function getElement(array $definition) { $element = $this->getMock('Drupal\Core\TypedData\TypedDataInterface'); $element->expects($this->any()) - ->method('getDefinition') + ->method('getDataDefinition') ->will($this->returnValue($definition)); return $element; } diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index f2aa2bb..19e4ea6 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -634,7 +634,7 @@ function content_translation_form_alter(array &$form, array &$form_state) { // Handle fields shared between translations when there is at least one // translation available or a new one is being created. if (!$entity->isNew() && (!isset($translations[$form_langcode]) || count($translations) > 1)) { - foreach ($entity->getPropertyDefinitions() as $property_name => $definition) { + foreach ($entity->getFieldDefinitions() as $property_name => $definition) { if (isset($form[$property_name])) { $form[$property_name]['#multilingual'] = $definition->isTranslatable(); } diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldType/DateTimeItem.php index 43aa550..1e15fad 100644 --- a/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldType/DateTimeItem.php +++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/Field/FieldType/DateTimeItem.php @@ -40,29 +40,20 @@ class DateTimeItem extends ConfigFieldItemBase implements PrepareCacheInterface const DATETIME_TYPE_DATETIME = 'datetime'; /** - * Field definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('datetime_iso8601') - ->setLabel(t('Date value')); - - static::$propertyDefinitions['date'] = DataDefinition::create('datetime_computed') - ->setLabel(t('Computed date')) - ->setDescription(t('The computed DateTime object.')) - ->setComputed(TRUE) - ->setClass('\Drupal\datetime\DateTimeComputed') - ->setSetting('date source', 'value'); - } - - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('datetime_iso8601') + ->setLabel(t('Date value')); + + $properties['date'] = DataDefinition::create('datetime_computed') + ->setLabel(t('Computed date')) + ->setDescription(t('The computed DateTime object.')) + ->setComputed(TRUE) + ->setClass('\Drupal\datetime\DateTimeComputed') + ->setSetting('date source', 'value'); + + return $properties; } /** diff --git a/core/modules/edit/edit.module b/core/modules/edit/edit.module index ad20007..3e64e03 100644 --- a/core/modules/edit/edit.module +++ b/core/modules/edit/edit.module @@ -132,7 +132,7 @@ function edit_preprocess_field(&$variables) { // Fields that are not part of the entity (i.e. dynamically injected "pseudo // fields") and computed fields are not editable. - $definition = $entity->getPropertyDefinition($element['#field_name']); + $definition = $entity->getFieldDefinition($element['#field_name']); if ($definition && !$definition->isComputed()) { $variables['attributes']['data-edit-field-id'] = $entity->getEntityTypeId() . '/' . $entity->id() . '/' . $element['#field_name'] . '/' . $element['#language'] . '/' . $element['#view_mode']; } diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module index 31d5624..f1a9840 100644 --- a/core/modules/editor/editor.module +++ b/core/modules/editor/editor.module @@ -559,14 +559,14 @@ function _editor_get_file_uuids_by_field(EntityInterface $entity) { * The names of the fields on this entity that have text processing enabled. */ function _editor_get_processed_text_fields(ContentEntityInterface $entity) { - $properties = $entity->getPropertyDefinitions(); - if (empty($properties)) { + $field_definitions = $entity->getFieldDefinitions(); + if (empty($field_definitions)) { return array(); } // Find all configurable fields, because only they could have a // text_processing setting. - $configurable_fields = array_keys(array_filter($properties, function ($definition) { + $configurable_fields = array_keys(array_filter($field_definitions, function ($definition) { return $definition->isConfigurable(); })); if (empty($configurable_fields)) { diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php index f2eb699..f9643b0 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php @@ -76,40 +76,25 @@ public function getSettableOptions(AccountInterface $account = NULL) { } /** - * Definitions of the contained properties. - * - * @see ConfigurableEntityReferenceItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - $settings = $this->definition->getSettings(); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $settings = $field_definition->getSettings(); $target_type = $settings['target_type']; - // Definitions vary by entity type and bundle, so key them accordingly. - $key = $target_type . ':'; - $key .= isset($settings['target_bundle']) ? $settings['target_bundle'] : ''; - - if (!isset(static::$propertyDefinitions[$key])) { - // Call the parent to define the target_id and entity properties. - parent::getPropertyDefinitions(); - - // Only add the revision ID property if the target entity type supports - // revisions. - $target_type_info = \Drupal::entityManager()->getDefinition($target_type); - if ($target_type_info->hasKey('revision') && $target_type_info->getRevisionTable()) { - static::$propertyDefinitions[$key]['revision_id'] = DataDefinition::create('integer') - ->setLabel(t('Revision ID')) - ->setConstraints(array('Range' => array('min' => 0))); - } + // Call the parent to define the target_id and entity properties. + $properties = parent::propertyDefinitions($field_definition); + + // Only add the revision ID property if the target entity type supports + // revisions. + $target_type_info = \Drupal::entityManager()->getDefinition($target_type); + if ($target_type_info->hasKey('revision') && $target_type_info->getRevisionTable()) { + $properties['revision_id'] = DataDefinition::create('integer') + ->setLabel(t('Revision ID')) + ->setConstraints(array('Range' => array('min' => 0))); } - return static::$propertyDefinitions[$key]; + return $properties; } /** diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php index f7b74e4..c3c38cd 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php @@ -102,7 +102,7 @@ public static function settingsForm(FieldDefinitionInterface $field_definition) $target_type_info = \Drupal::entityManager()->getDefinition($target_type); if ($target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) { - // @todo Use Entity::getPropertyDefinitions() when all entity types are + // @todo Use Entity::getFieldDefinitions() when all entity types are // converted to the new Field API. $fields = drupal_map_assoc(drupal_schema_fields_sql($entity_type->getBaseTable())); foreach (field_info_instances($target_type) as $bundle_instances) { diff --git a/core/modules/field/field.deprecated.inc b/core/modules/field/field.deprecated.inc index e74d8bd..3014656 100644 --- a/core/modules/field/field.deprecated.inc +++ b/core/modules/field/field.deprecated.inc @@ -335,7 +335,7 @@ function field_attach_form(EntityInterface $entity, &$form, &$form_state, $langc function field_attach_form_validate(ContentEntityInterface $entity, $form, &$form_state, array $options = array()) { $has_violations = FALSE; foreach ($entity as $field_name => $field) { - $definition = $field->getDefinition(); + $definition = $field->getFieldDefinition(); if ($definition->isConfigurable() && (empty($options['field_name']) || $options['field_name'] == $field_name)) { $field_violations = $field->validate(); if (count($field_violations)) { diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php index cef84e5..418fd31 100644 --- a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php +++ b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php @@ -11,7 +11,8 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; -use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\Field\FieldDefinition; +use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\field\FieldException; use Drupal\field\FieldInterface; @@ -182,6 +183,15 @@ class FieldConfig extends ConfigEntityBase implements FieldInterface { protected $schema; /** + * An array of field property definitions. + * + * @var \Drupal\Core\TypedData\DataDefinitionInterface[] + * + * @see \Drupal\Core\TypedData\ComplexDataDefinitionInterface::getPropertyDefinitions() + */ + protected $propertyDefinitions; + + /** * The data definition of a field item. * * @var \Drupal\Core\TypedData\DataDefinition @@ -433,8 +443,7 @@ public static function postDelete(EntityStorageControllerInterface $storage_cont public function getSchema() { if (!isset($this->schema)) { // Get the schema from the field item class. - $definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->type); - $class = $definition['class']; + $class = $this->getFieldItemClass(); $schema = $class::schema($this); // Fill in default values for optional entries. $schema += array('indexes' => array(), 'foreign keys' => array()); @@ -535,14 +544,6 @@ public function getSetting($setting_name) { /** * {@inheritdoc} */ - public function getPropertyNames() { - $schema = $this->getSchema(); - return array_keys($schema['columns']); - } - - /** - * {@inheritdoc} - */ public function isTranslatable() { return $this->translatable; } @@ -712,6 +713,24 @@ public function __wakeup() { /** * {@inheritdoc} */ + public static function createFromDataType($type) { + // Forward to the field definition class for creating new data definitions + // via the typed manager. + return FieldDefinition::createFromDataType($type); + } + + /** + * {@inheritdoc} + */ + public static function createFromItemType($item_type) { + // Forward to the field definition class for creating new data definitions + // via the typed manager. + return FieldDefinition::createFromItemType($item_type); + } + + /** + * {@inheritdoc} + */ public function getDataType() { return 'list'; } @@ -766,10 +785,65 @@ public function getConstraint($constraint_name) { */ public function getItemDefinition() { if (!isset($this->itemDefinition)) { - $this->itemDefinition = DataDefinition::create('field_item:' . $this->type) + $this->itemDefinition = FieldItemDataDefinition::create($this) ->setSettings($this->getSettings()); } return $this->itemDefinition; } + /** + * {@inheritdoc} + */ + public function getPropertyDefinition($name) { + if (!isset($this->propertyDefinitions)) { + $this->getPropertyDefinitions(); + } + if (isset($this->propertyDefinitions[$name])) { + return $this->propertyDefinitions[$name]; + } + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + if (!isset($this->propertyDefinitions)) { + $class = $this->getFieldItemClass(); + $this->propertyDefinitions = $class::propertyDefinitions($this); + } + return $this->propertyDefinitions; + } + + /** + * {@inheritdoc} + */ + public function getPropertyNames() { + return array_keys($this->getPropertyDefinitions()); + } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + $class = $this->getFieldItemClass(); + return $class::mainPropertyName(); + } + + /** + * Helper to retrieve the field item class. + * + * @todo: Remove once getClass() adds in defaults. See + * https://drupal.org/node/2116341. + */ + protected function getFieldItemClass() { + if ($class = $this->getItemDefinition()->getClass()) { + return $class; + } + else { + $type_definition = \Drupal::typedDataManager() + ->getDefinition($this->getItemDefinition()->getDataType()); + return $type_definition['class']; + } + } + } diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php index acc01fa..445dc23 100644 --- a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php +++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php @@ -10,8 +10,9 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Field\FieldDefinition; +use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\field\FieldException; -use Drupal\Core\TypedData\DataDefinition; use Drupal\field\FieldInstanceInterface; /** @@ -485,14 +486,6 @@ public function getSetting($setting_name) { /** * {@inheritdoc} */ - public function getPropertyNames() { - $schema = $this->field->getSchema(); - return array_keys($schema['columns']); - } - - /** - * {@inheritdoc} - */ public function isTranslatable() { return $this->field->translatable; } @@ -640,6 +633,24 @@ public function __wakeup() { $this->__construct($values); } + /** + * {@inheritdoc} + */ + public static function createFromDataType($type) { + // Forward to the field definition class for creating new data definitions + // via the typed manager. + return FieldDefinition::createFromDataType($type); + } + + /** + * {@inheritdoc} + */ + public static function createFromItemType($item_type) { + // Forward to the field definition class for creating new data definitions + // via the typed manager. + return FieldDefinition::createFromItemType($item_type); + } + public function getDataType() { return 'list'; } @@ -691,7 +702,7 @@ public function getConstraint($constraint_name) { */ public function getItemDefinition() { if (!isset($this->itemDefinition)) { - $this->itemDefinition = DataDefinition::create('field_item:' . $this->field->type) + $this->itemDefinition = FieldItemDataDefinition::create($this) ->setSettings($this->getSettings()); } return $this->itemDefinition; @@ -700,6 +711,34 @@ public function getItemDefinition() { /** * {@inheritdoc} */ + public function getPropertyDefinition($name) { + return $this->field->getPropertyDefinition($name); + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + return $this->field->getPropertyDefinitions(); + } + + /** + * {@inheritdoc} + */ + public function getPropertyNames() { + return $this->field->getPropertyNames(); + } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + return $this->field->getMainPropertyName(); + } + + /** + * {@inheritdoc} + */ public function getSchema() { return $this->field->getSchema(); } diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/HiddenTestItem.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/HiddenTestItem.php index d3597fd..700efde 100644 --- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/HiddenTestItem.php +++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/HiddenTestItem.php @@ -7,8 +7,8 @@ namespace Drupal\field_test\Plugin\Field\FieldType; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\TypedData\DataDefinition; -use Drupal\field_test\Plugin\Field\FieldType\TestItem; /** * Defines the 'hidden_test' entity field item. @@ -25,23 +25,13 @@ class HiddenTestItem extends TestItem { /** - * Property definitions of the contained properties. - * - * @see TestItem::getPropertyDefinitions() - * - * @var array + * {@inheritdoc} */ - static $propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('integer') + ->setLabel(t('Test integer value')); - /** - * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions(). - */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('integer') - ->setLabel(t('Test integer value')); - } - return static::$propertyDefinitions; + return $properties; } } diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/ShapeItem.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/ShapeItem.php index 15d05cd..63487c1 100644 --- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/ShapeItem.php +++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/ShapeItem.php @@ -7,8 +7,8 @@ namespace Drupal\field_test\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\ConfigFieldItemBase; /** @@ -28,26 +28,16 @@ class ShapeItem extends ConfigFieldItemBase { /** - * Property definitions of the contained properties. - * - * @see ShapeItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['shape'] = DataDefinition::create('string') - ->setLabel(t('Shape')); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['shape'] = DataDefinition::create('string') + ->setLabel(t('Shape')); - static::$propertyDefinitions['color'] = DataDefinition::create('string') - ->setLabel(t('Color')); - } - return static::$propertyDefinitions; + $properties['color'] = DataDefinition::create('string') + ->setLabel(t('Color')); + + return $properties; } /** diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/TestItem.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/TestItem.php index be3955f..d2d769a 100644 --- a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/TestItem.php +++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Field/FieldType/TestItem.php @@ -35,23 +35,13 @@ class TestItem extends ConfigFieldItemBase implements PrepareCacheInterface { /** - * Property definitions of the contained properties. - * - * @see TestItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('integer') - ->setLabel(t('Test integer value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('integer') + ->setLabel(t('Test integer value')); + + return $properties; } /** diff --git a/core/modules/file/lib/Drupal/file/Plugin/Field/FieldType/FileItem.php b/core/modules/file/lib/Drupal/file/Plugin/Field/FieldType/FileItem.php index 0be4a99..81c4dff 100644 --- a/core/modules/file/lib/Drupal/file/Plugin/Field/FieldType/FileItem.php +++ b/core/modules/file/lib/Drupal/file/Plugin/Field/FieldType/FileItem.php @@ -20,6 +20,7 @@ * label = @Translation("File"), * description = @Translation("This field stores the ID of a file as an integer value."), * settings = { + * "target_type" = "file", * "display_field" = "0", * "display_default" = "0", * "uri_scheme" = "" @@ -38,15 +39,6 @@ class FileItem extends EntityReferenceItem implements ConfigFieldItemInterface { /** - * Property definitions of the contained properties. - * - * @see FileItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public static function schema(FieldDefinitionInterface $field_definition) { @@ -87,19 +79,16 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - $this->definition->setSetting('target_type', 'file'); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties = parent::propertyDefinitions($field_definition); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions = parent::getPropertyDefinitions(); + $properties['display'] = DataDefinition::create('boolean') + ->setLabel(t('Flag to control whether this file should be displayed when viewing content')); - static::$propertyDefinitions['display'] = DataDefinition::create('boolean') - ->setLabel(t('Flag to control whether this file should be displayed when viewing content')); + $properties['description'] = DataDefinition::create('string') + ->setLabel(t('A description of the file')); - static::$propertyDefinitions['description'] = DataDefinition::create('string') - ->setLabel(t('A description of the file')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php index 09987f2..5442d17 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php +++ b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldType/ImageItem.php @@ -7,8 +7,8 @@ namespace Drupal\image\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; use Drupal\file\Plugin\Field\FieldType\FileItem; /** @@ -19,6 +19,7 @@ * label = @Translation("Image"), * description = @Translation("This field stores the ID of an image file as an integer value."), * settings = { + * "target_type" = "file", * "uri_scheme" = "", * "default_image" = { * "fid" = NULL, @@ -117,25 +118,22 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - $this->definition->setSetting('target_type', 'file'); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties = parent::propertyDefinitions($field_definition); - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions = parent::getPropertyDefinitions(); + $properties['alt'] = DataDefinition::create('string') + ->setLabel(t("Alternative image text, for the image's 'alt' attribute.")); - static::$propertyDefinitions['alt'] = DataDefinition::create('string') - ->setLabel(t("Alternative image text, for the image's 'alt' attribute.")); + $properties['title'] = DataDefinition::create('string') + ->setLabel(t("Image title text, for the image's 'title' attribute.")); - static::$propertyDefinitions['title'] = DataDefinition::create('string') - ->setLabel(t("Image title text, for the image's 'title' attribute.")); + $properties['width'] = DataDefinition::create('integer') + ->setLabel(t('The width of the image in pixels.')); - static::$propertyDefinitions['width'] = DataDefinition::create('integer') - ->setLabel(t('The width of the image in pixels.')); + $properties['height'] = DataDefinition::create('integer') + ->setLabel(t('The height of the image in pixels.')); - static::$propertyDefinitions['height'] = DataDefinition::create('integer') - ->setLabel(t('The height of the image in pixels.')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldType/LinkItem.php b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldType/LinkItem.php index bc28594..17853c3 100644 --- a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldType/LinkItem.php +++ b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldType/LinkItem.php @@ -8,8 +8,9 @@ namespace Drupal\link\Plugin\Field\FieldType; use Drupal\Core\Field\ConfigFieldItemBase; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\MapDataDefinition; /** * Plugin implementation of the 'link' field type. @@ -28,27 +29,19 @@ class LinkItem extends ConfigFieldItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['url'] = DataDefinition::create('uri') - ->setLabel(t('URL')); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['url'] = DataDefinition::create('uri') + ->setLabel(t('URL')); + + $properties['title'] = DataDefinition::create('string') + ->setLabel(t('Link text')); - static::$propertyDefinitions['title'] = DataDefinition::create('string') - ->setLabel(t('Link text')); + $properties['attributes'] = MapDataDefinition::create() + ->setLabel(t('Attributes')); - static::$propertyDefinitions['attributes'] = DataDefinition::create('map') - ->setLabel(t('Attributes')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php index dc83b6d..c0095f1 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleTypedConfig.php @@ -170,7 +170,7 @@ protected function getArrayTranslation(ArrayElement $element, array $options) { */ protected function translateElement(\Drupal\Core\TypedData\TypedDataInterface $element, array $options) { if ($this->canTranslate($options['source'], $options['target'])) { - $definition = $element->getDefinition(); + $definition = $element->getDataDefinition(); $value = $element->getValue(); if ($value && !empty($definition['translatable'])) { $context = isset($definition['locale context']) ? $definition['locale context'] : ''; diff --git a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/DecimalItem.php b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/DecimalItem.php index 42588e8..bba5591 100644 --- a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/DecimalItem.php +++ b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/DecimalItem.php @@ -7,8 +7,8 @@ namespace Drupal\number\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; use Drupal\Component\Utility\MapArray; /** @@ -37,12 +37,11 @@ class DecimalItem extends NumberItemBase { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('Decimal value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Decimal value')); + + return $properties; } /** diff --git a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/FloatItem.php b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/FloatItem.php index 5765147..9e545c5 100644 --- a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/FloatItem.php +++ b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/FloatItem.php @@ -7,8 +7,8 @@ namespace Drupal\number\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; /** * Plugin implementation of the 'number_float' field type. @@ -32,12 +32,11 @@ class FloatItem extends NumberItemBase { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('float') - ->setLabel(t('Float value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('float') + ->setLabel(t('Float value')); + + return $properties; } /** diff --git a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/IntegerItem.php b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/IntegerItem.php index 6c44d76..e9eecde 100644 --- a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/IntegerItem.php +++ b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/IntegerItem.php @@ -7,8 +7,8 @@ namespace Drupal\number\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; /** * Plugin implementation of the 'number_integer' field type. @@ -32,12 +32,11 @@ class IntegerItem extends NumberItemBase { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('integer') - ->setLabel(t('Integer value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('integer') + ->setLabel(t('Integer value')); + + return $properties; } /** diff --git a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/NumberItemBase.php b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/NumberItemBase.php index 22f2d59..c8f29b8 100644 --- a/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/NumberItemBase.php +++ b/core/modules/number/lib/Drupal/number/Plugin/Field/FieldType/NumberItemBase.php @@ -15,13 +15,6 @@ abstract class NumberItemBase extends ConfigFieldItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public function instanceSettingsForm(array $form, array &$form_state) { diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListBooleanItem.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListBooleanItem.php index 558a103..b283d7f 100644 --- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListBooleanItem.php +++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListBooleanItem.php @@ -29,13 +29,6 @@ class ListBooleanItem extends ListItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public static function schema(FieldDefinitionInterface $field_definition) { @@ -52,12 +45,11 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('boolean') - ->setLabel(t('Boolean value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('boolean') + ->setLabel(t('Boolean value')); + + return $properties; } } diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListFloatItem.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListFloatItem.php index f8d0adb..cfd9251 100644 --- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListFloatItem.php +++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListFloatItem.php @@ -29,13 +29,6 @@ class ListFloatItem extends ListItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public static function schema(FieldDefinitionInterface $field_definition) { @@ -52,12 +45,11 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('float') - ->setLabel(t('Float value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('float') + ->setLabel(t('Float value')); + + return $properties; } } diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListIntegerItem.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListIntegerItem.php index 9c6e7d7..ea28a94 100644 --- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListIntegerItem.php +++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListIntegerItem.php @@ -29,13 +29,6 @@ class ListIntegerItem extends ListItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public static function schema(FieldDefinitionInterface $field_definition) { @@ -52,12 +45,11 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('integer') - ->setLabel(t('Integer value')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('integer') + ->setLabel(t('Integer value')); + + return $properties; } } diff --git a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListTextItem.php b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListTextItem.php index 1e27eac..11757d2 100644 --- a/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListTextItem.php +++ b/core/modules/options/lib/Drupal/options/Plugin/Field/FieldType/ListTextItem.php @@ -29,13 +29,6 @@ class ListTextItem extends ListItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public static function schema(FieldDefinitionInterface $field_definition) { @@ -53,13 +46,13 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - $constraints = array('Length' => array('max' => 255)); - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('Text value')) - ->setConstraints($constraints); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $constraints = array('Length' => array('max' => 255)); + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Text value')) + ->setConstraints($constraints); + + return $properties; } + } diff --git a/core/modules/path/lib/Drupal/path/Plugin/Field/FieldType/PathItem.php b/core/modules/path/lib/Drupal/path/Plugin/Field/FieldType/PathItem.php index 54411a6..8125ff9 100644 --- a/core/modules/path/lib/Drupal/path/Plugin/Field/FieldType/PathItem.php +++ b/core/modules/path/lib/Drupal/path/Plugin/Field/FieldType/PathItem.php @@ -24,26 +24,14 @@ class PathItem extends FieldItemBase { /** - * Definitions of the contained properties. - * - * @see PathItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['alias'] = DataDefinition::create('string') + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['alias'] = DataDefinition::create('string') ->setLabel(t('Path alias')); - - static::$propertyDefinitions['pid'] = DataDefinition::create('string') + $properties['pid'] = DataDefinition::create('string') ->setLabel(t('Path id')); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index a4a19e2..01cb430 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -313,7 +313,7 @@ function rdf_preprocess_node(&$variables) { $comment_count_mapping = $mapping->getPreparedFieldMapping('comment_count'); if (!empty($comment_count_mapping['properties'])) { $fields = array_keys(\Drupal::service('comment.manager')->getFields('node')); - $definitions = array_keys($variables['node']->getPropertyDefinitions()); + $definitions = array_keys($variables['node']->getFieldDefinitions()); $valid_fields = array_intersect($fields, $definitions); $count = 0; foreach ($valid_fields as $field_name) { diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutPathItem.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutPathItem.php index 1010000..10dbed5 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutPathItem.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutPathItem.php @@ -7,6 +7,7 @@ namespace Drupal\shortcut; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\Plugin\Field\FieldType\StringItem; use Drupal\Core\TypedData\DataDefinition; @@ -16,25 +17,14 @@ class ShortcutPathItem extends StringItem { /** - * Definitions of the contained properties. - * - * @see self::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('String value')) - ->setComputed(TRUE) - ->setClass('\Drupal\shortcut\ShortcutPathValue'); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('String value')) + ->setComputed(TRUE) + ->setClass('\Drupal\shortcut\ShortcutPathValue'); + return $properties; } } 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 2ea38e9..eece832 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php @@ -9,10 +9,12 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Field\FieldDefinition; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Language\Language; -use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\ComplexDataDefinitionInterface; +use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\TypedDataInterface; @@ -26,7 +28,7 @@ class EntityFieldTest extends EntityUnitTestBase { * * @var array */ - public static $modules = array('filter', 'text', 'node'); + public static $modules = array('filter', 'text', 'node', 'user'); public static function getInfo() { return array( @@ -360,30 +362,55 @@ protected function checkIntrospection($entity_type) { $this->assertEqual($definitions['user_id']->getType(), 'entity_reference', $entity_type .': User field found.'); $this->assertEqual($definitions['field_test_text']->getType(), 'text', $entity_type .': Test-text-field field found.'); + // Test deriving further metadata. + $this->assertTrue($definitions['name'] instanceof FieldDefinitionInterface); + $field_item_definition = $definitions['name']->getItemDefinition(); + $this->assertTrue($field_item_definition instanceof ComplexDataDefinitionInterface); + $this->assertEqual($field_item_definition->getDataType(), 'field_item:string'); + $value_definition = $field_item_definition->getPropertyDefinition('value'); + $this->assertTrue($value_definition instanceof DataDefinitionInterface); + $this->assertEqual($value_definition->getDataType(), 'string'); + + // Test deriving metadata from references. + $entity_definition = \Drupal\Core\Entity\TypedData\EntityDataDefinition::create($entity_type); + $reference_definition = $entity_definition->getPropertyDefinition('langcode') + ->getPropertyDefinition('language') + ->getTargetDefinition(); + $this->assertEqual($reference_definition->getDataType(), 'language'); + + $reference_definition = $entity_definition->getPropertyDefinition('user_id') + ->getPropertyDefinition('entity') + ->getTargetDefinition(); + + $this->assertTrue($reference_definition instanceof \Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface, 'Definition of the referenced user retrieved.'); + $this->assertEqual($reference_definition->getEntityTypeId(), 'user', 'Referenced entity is of type "user".'); + + // Test propagating down. + $name_definition = $reference_definition->getPropertyDefinition('name'); + $this->assertTrue($name_definition instanceof FieldDefinitionInterface); + $this->assertEqual($name_definition->getPropertyDefinition('value')->getDataType(), 'string'); + // Test introspecting an entity object. // @todo: Add bundles and test bundles as well. $entity = entity_create($entity_type); - $definitions = $entity->getPropertyDefinitions(); + $definitions = $entity->getFieldDefinitions(); $this->assertEqual($definitions['name']->getType(), 'string', $entity_type .': Name field found.'); $this->assertEqual($definitions['user_id']->getType(), 'entity_reference', $entity_type .': User field found.'); $this->assertEqual($definitions['field_test_text']->getType(), 'text', $entity_type .': Test-text-field field found.'); - $name_properties = $entity->name->getPropertyDefinitions(); + $name_properties = $entity->name->getFieldDefinition()->getPropertyDefinitions(); $this->assertEqual($name_properties['value']->getDataType(), 'string', $entity_type .': String value property of the name found.'); - $userref_properties = $entity->user_id->getPropertyDefinitions(); + $userref_properties = $entity->user_id->getFieldDefinition()->getPropertyDefinitions(); $this->assertEqual($userref_properties['target_id']->getDataType(), 'integer', $entity_type .': Entity id property of the user found.'); $this->assertEqual($userref_properties['entity']->getDataType(), 'entity_reference', $entity_type .': Entity reference property of the user found.'); - $textfield_properties = $entity->field_test_text->getPropertyDefinitions(); + $textfield_properties = $entity->field_test_text->getFieldDefinition()->getPropertyDefinitions(); $this->assertEqual($textfield_properties['value']->getDataType(), 'string', $entity_type .': String value property of the test-text field found.'); $this->assertEqual($textfield_properties['format']->getDataType(), 'filter_format', $entity_type .': String format field of the test-text field found.'); $this->assertEqual($textfield_properties['processed']->getDataType(), 'string', $entity_type .': String processed property of the test-text field found.'); - // @todo: Once the user entity has definitions, continue testing getting - // them from the $userref_values['entity'] property. - // Make sure provided contextual information is right. $this->assertIdentical($entity->getRoot(), $entity, 'Entity is root object.'); $this->assertEqual($entity->getPropertyPath(), ''); @@ -446,7 +473,7 @@ protected function assertIterator($entity_type) { } $properties = $entity->getProperties(); - $this->assertEqual(array_keys($properties), array_keys($entity->getPropertyDefinitions()), format_string('%entity_type: All properties returned.', array('%entity_type' => $entity_type))); + $this->assertEqual(array_keys($properties), array_keys($entity->getDataDefinition()->getPropertyDefinitions()), format_string('%entity_type: All properties returned.', array('%entity_type' => $entity_type))); $this->assertEqual($properties, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all properties.', array('%entity_type' => $entity_type))); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php new file mode 100644 index 0000000..3e0fe10 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php @@ -0,0 +1,136 @@ + 'Entity typed data definitions', + 'description' => 'Tests reading and deriving metadata of entity and field data types.', + 'group' => 'Typed Data API', + ); + } + + public function setUp() { + parent::setup(); + $this->typedDataManager = $this->container->get('typed_data_manager'); + } + + /** + * Tests deriving metadata about fields. + */ + public function testFields() { + $field_definition = FieldDefinition::create('integer'); + // Fields are lists of complex data. + $this->assertTrue($field_definition instanceof ListDataDefinitionInterface); + $this->assertFalse($field_definition instanceof ComplexDataDefinitionInterface); + $field_item_definition = $field_definition->getItemDefinition(); + $this->assertFalse($field_item_definition instanceof ListDataDefinitionInterface); + $this->assertTrue($field_item_definition instanceof ComplexDataDefinitionInterface); + + // Derive metadata about field item properties. + $this->assertEqual(array_keys($field_item_definition->getPropertyDefinitions()), array('value')); + $this->assertEqual($field_item_definition->getPropertyDefinition('value')->getDataType(), 'integer'); + $this->assertEqual($field_item_definition->getMainPropertyName(), 'value'); + $this->assertNull($field_item_definition->getPropertyDefinition('invalid')); + + // Test accessing field item property metadata via the field definition. + $this->assertTrue($field_definition instanceof FieldDefinitionInterface); + $this->assertEqual(array_keys($field_definition->getPropertyDefinitions()), array('value')); + $this->assertEqual($field_definition->getPropertyDefinition('value')->getDataType(), 'integer'); + $this->assertEqual($field_definition->getMainPropertyName(), 'value'); + $this->assertNull($field_definition->getPropertyDefinition('invalid')); + + // Test using the definition factory for field item lists and field items. + $field_item = $this->typedDataManager->createDataDefinition('field_item:integer'); + $this->assertFalse($field_item instanceof ListDataDefinitionInterface); + $this->assertTrue($field_item instanceof ComplexDataDefinitionInterface); + // Comparison should ignore the internal static cache, so compare the + // serialized objects instead. + $this->assertEqual(serialize($field_item_definition), serialize($field_item)); + + $field_definition2 = $this->typedDataManager->createListDataDefinition('field_item:integer'); + $this->assertTrue($field_definition2 instanceof ListDataDefinitionInterface); + $this->assertFalse($field_definition2 instanceof ComplexDataDefinitionInterface); + $this->assertEqual(serialize($field_definition), serialize($field_definition2)); + } + + /** + * Tests deriving metadata about entities. + */ + public function testEntities() { + $entity_definition = EntityDataDefinition::create('node'); + // Entities are complex data. + $this->assertFalse($entity_definition instanceof ListDataDefinitionInterface); + $this->assertTrue($entity_definition instanceof ComplexDataDefinitionInterface); + + $field_definitions = $entity_definition->getPropertyDefinitions(); + // Comparison should ignore the internal static cache, so compare the + // serialized objects instead. + $this->assertEqual(serialize($field_definitions), serialize(\Drupal::entityManager()->getFieldDefinitions('node'))); + $this->assertEqual($entity_definition->getPropertyDefinition('title')->getItemDefinition()->getDataType(), 'field_item:text'); + $this->assertNull($entity_definition->getMainPropertyName()); + $this->assertNull($entity_definition->getPropertyDefinition('invalid')); + + $entity_definition2 = $this->typedDataManager->createDataDefinition('entity:node'); + $this->assertFalse($entity_definition2 instanceof ListDataDefinitionInterface); + $this->assertTrue($entity_definition2 instanceof ComplexDataDefinitionInterface); + $this->assertEqual(serialize($entity_definition), serialize($entity_definition2)); + + // Test that the definition factory creates the right definitions for all + // entity data types variants. + $this->assertEqual($this->typedDataManager->createDataDefinition('entity'), EntityDataDefinition::create()); + $this->assertEqual($this->typedDataManager->createDataDefinition('entity:node'), EntityDataDefinition::create('node')); + } + + /** + * Tests deriving metadata from entity references. + */ + public function testEntityReferences() { + $reference_definition = DataReferenceDefinition::create('entity'); + $this->assertTrue($reference_definition instanceof DataReferenceDefinitionInterface); + + // Test retrieving metadata about the referenced data. + $this->assertEqual($reference_definition->getTargetDefinition()->getDataType(), 'entity'); + $this->assertTrue($reference_definition->getTargetDefinition() instanceof \Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface); + + // Test that the definition factory creates the right definition object. + $reference_definition2 = $this->typedDataManager->createDataDefinition('entity_reference'); + $this->assertTrue($reference_definition2 instanceof DataReferenceDefinitionInterface); + $this->assertEqual($reference_definition2, $reference_definition); + } + +} diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataDefinitionTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataDefinitionTest.php new file mode 100644 index 0000000..aa9d3c1 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataDefinitionTest.php @@ -0,0 +1,110 @@ + 'Typed data definitions', + 'description' => 'Tests reading and deriving metadata of core data types.', + 'group' => 'Typed Data API', + ); + } + + public function setUp() { + parent::setup(); + $this->typedDataManager = $this->container->get('typed_data_manager'); + } + + /** + * Tests deriving metadata about list items. + */ + public function testLists() { + $list_definition = ListDataDefinition::create('string'); + $this->assertTrue($list_definition instanceof ListDataDefinitionInterface); + $item_definition = $list_definition->getItemDefinition(); + $this->assertTrue($item_definition instanceof DataDefinitionInterface); + $this->assertEqual($item_definition->getDataType(), 'string'); + + // Test using the definition factory. + $list_definition2 = $this->typedDataManager->createListDataDefinition('string'); + $this->assertTrue($list_definition2 instanceof ListDataDefinitionInterface); + $this->assertEqual($list_definition, $list_definition2); + + // Test creating the definition of data with type 'list', which is the same + // as creating a definition of a list of items of type 'any'. + $list_definition = $this->typedDataManager->createDataDefinition('list'); + $this->assertTrue($list_definition instanceof ListDataDefinitionInterface); + $this->assertEqual($list_definition->getDataType(), 'list'); + $this->assertEqual($list_definition->getItemDefinition()->getDataType(), 'any'); + } + + /** + * Tests deriving metadata about maps. + */ + public function testMaps() { + $map_definition = MapDataDefinition::create() + ->setPropertyDefinition('one', DataDefinition::create('string')) + ->setPropertyDefinition('two', DataDefinition::create('string')) + ->setPropertyDefinition('three', DataDefinition::create('string')); + + $this->assertTrue($map_definition instanceof ComplexDataDefinitionInterface); + + // Test retrieving metadata about contained properties. + $this->assertEqual(array_keys($map_definition->getPropertyDefinitions()), array('one', 'two', 'three')); + $this->assertEqual($map_definition->getPropertyDefinition('one')->getDataType(), 'string'); + $this->assertNull($map_definition->getMainPropertyName()); + $this->assertNull($map_definition->getPropertyDefinition('invalid')); + + // Test using the definition factory. + $map_definition2 = $this->typedDataManager->createDataDefinition('map'); + $this->assertTrue($map_definition2 instanceof ComplexDataDefinitionInterface); + $map_definition2->setPropertyDefinition('one', DataDefinition::create('string')) + ->setPropertyDefinition('two', DataDefinition::create('string')) + ->setPropertyDefinition('three', DataDefinition::create('string')); + $this->assertEqual($map_definition, $map_definition2); + } + + /** + * Tests deriving metadata from data references. + */ + public function testDataReferences() { + $language_reference_definition = DataReferenceDefinition::create('language'); + $this->assertTrue($language_reference_definition instanceof DataReferenceDefinitionInterface); + + // Test retrieving metadata about the referenced data. + $this->assertEqual($language_reference_definition->getTargetDefinition()->getDataType(), 'language'); + + // Test using the definition factory. + $language_reference_definition2 = $this->typedDataManager->createDataDefinition('language_reference'); + $this->assertTrue($language_reference_definition2 instanceof DataReferenceDefinitionInterface); + $this->assertEqual($language_reference_definition, $language_reference_definition2); + } + +} diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php index eeb6bb5..34a896c 100644 --- a/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/TypedDataTest.php @@ -9,7 +9,9 @@ use Drupal\Core\Field\FieldDefinition; use Drupal\Core\TypedData\DataDefinition; -use Drupal\Core\TypedData\ListDefinition; +use Drupal\Core\TypedData\ListDataDefinition; +use Drupal\Core\TypedData\MapDataDefinition; +use Drupal\Core\TypedData\Plugin\DataType\Map; use Drupal\simpletest\DrupalUnitTestBase; use Drupal\Core\Datetime\DrupalDateTime; @@ -318,7 +320,7 @@ public function testGetAndSet() { public function testTypedDataLists() { // Test working with an existing list of strings. $value = array('one', 'two', 'three'); - $typed_data = $this->createTypedData(ListDefinition::create('string'), $value); + $typed_data = $this->createTypedData(ListDataDefinition::create('string'), $value); $this->assertEqual($typed_data->getValue(), $value, 'List value has been set.'); // Test iterating. $count = 0; @@ -410,9 +412,12 @@ public function testTypedDataMaps() { 'two' => 'zwei', 'three' => 'drei', ); - $typed_data = $this->createTypedData(array( - 'type' => 'map', - ), $value); + $definition = MapDataDefinition::create() + ->setPropertyDefinition('one', DataDefinition::create('string')) + ->setPropertyDefinition('two', DataDefinition::create('string')) + ->setPropertyDefinition('three', DataDefinition::create('string')); + + $typed_data = $this->createTypedData($definition, $value); // Test iterating. $count = 0; @@ -423,10 +428,10 @@ public function testTypedDataMaps() { $this->assertEqual($count, 3); // Test retrieving metadata. - $this->assertEqual(array_keys($typed_data->getPropertyDefinitions()), array_keys($value)); - $definition = $typed_data->getPropertyDefinition('one'); - $this->assertEqual($definition->getDataType(), 'any'); - $this->assertFalse($typed_data->getPropertyDefinition('invalid')); + $this->assertEqual(array_keys($typed_data->getDataDefinition()->getPropertyDefinitions()), array_keys($value)); + $definition = $typed_data->getDataDefinition()->getPropertyDefinition('one'); + $this->assertEqual($definition->getDataType(), 'string'); + $this->assertNull($typed_data->getDataDefinition()->getPropertyDefinition('invalid')); // Test getting and setting properties. $this->assertEqual($typed_data->get('one')->getValue(), 'eins'); @@ -450,8 +455,11 @@ public function testTypedDataMaps() { $this->assertEqual($typed_data->get('two')->getValue(), 'zwei'); $this->assertEqual($typed_data->get('three')->getValue(), 'drei'); + // Test setting a not defined property. It shouldn't show up in the + // properties, but be kept in the values. $typed_data->setValue(array('foo' => 'bar')); - $this->assertEqual(array_keys($typed_data->getProperties()), array('foo')); + $this->assertEqual(array_keys($typed_data->getProperties()), array('one', 'two', 'three')); + $this->assertEqual(array_keys($typed_data->getValue()), array('foo', 'one', 'two', 'three')); // Test getting the string representation. $typed_data->setValue(array('one' => 'eins', 'two' => '', 'three' => 'drei')); @@ -492,10 +500,11 @@ public function testTypedDataMaps() { $this->pass('Exception thrown:' . $e->getMessage()); } - // Test adding a new entry to the map. + // Test adding a new property to the map. + $typed_data->getDataDefinition()->setPropertyDefinition('zero', DataDefinition::create('any')); $typed_data->set('zero', 'null'); $this->assertEqual($typed_data->get('zero')->getValue(), 'null'); - $definition = $typed_data->getPropertyDefinition('zero'); + $definition = $typed_data->get('zero')->getDataDefinition(); $this->assertEqual($definition->getDataType(), 'any', 'Definition for a new map entry returned.'); } diff --git a/core/modules/system/lib/Drupal/system/Tests/Validation/ComplexDataConstraintValidatorTest.php b/core/modules/system/lib/Drupal/system/Tests/Validation/ComplexDataConstraintValidatorTest.php index 2b0af2f..baabdb8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Validation/ComplexDataConstraintValidatorTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Validation/ComplexDataConstraintValidatorTest.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Validation; use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\MapDataDefinition; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -42,7 +43,8 @@ public function setUp() { */ public function testValidation() { // Create a definition that specifies some ComplexData constraint. - $definition = DataDefinition::create('map') + $definition = MapDataDefinition::create() + ->setPropertyDefinition('key', DataDefinition::create('integer')) ->addConstraint('ComplexData', array( 'key' => array( 'AllowedValues' => array(1, 2, 3) @@ -71,7 +73,8 @@ public function testValidation() { $violations = $typed_data->validate(); $this->assertEqual($violations->count(), 0, 'Constraint on non-existing key is ignored.'); - $definition = DataDefinition::create('map') + $definition = MapDataDefinition::create() + ->setPropertyDefinition('key', DataDefinition::create('integer')) ->addConstraint('ComplexData', array( 'key' => array( 'NotNull' => array() diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php index 2733515..db80f4b 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php @@ -21,6 +21,7 @@ * label = @Translation("Term Reference"), * description = @Translation("This field stores a reference to a taxonomy term."), * settings = { + * "target_type" = "taxonomy_term", * "options_list_callback" = NULL, * "allowed_values" = { * { @@ -89,14 +90,6 @@ public function getSettableOptions(AccountInterface $account = NULL) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - $this->definition['settings']['target_type'] = 'taxonomy_term'; - return parent::getPropertyDefinitions(); - } - - /** - * {@inheritdoc} - */ public static function schema(FieldDefinitionInterface $field_definition) { return array( 'columns' => array( diff --git a/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldType/TelephoneItem.php b/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldType/TelephoneItem.php index 67d7bdf..e710ded 100644 --- a/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldType/TelephoneItem.php +++ b/core/modules/telephone/lib/Drupal/telephone/Plugin/Field/FieldType/TelephoneItem.php @@ -8,8 +8,8 @@ namespace Drupal\telephone\Plugin\Field\FieldType; use Drupal\Core\Field\ConfigFieldItemBase; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; /** * Plugin implementation of the 'telephone' field type. @@ -25,13 +25,6 @@ class TelephoneItem extends ConfigFieldItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ public static function schema(FieldDefinitionInterface $field_definition) { @@ -49,12 +42,11 @@ public static function schema(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('Telephone number')); - } - return static::$propertyDefinitions; + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Telephone number')); + + return $properties; } /** diff --git a/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextItemBase.php b/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextItemBase.php index 158c416..9cac637 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextItemBase.php +++ b/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextItemBase.php @@ -8,6 +8,7 @@ namespace Drupal\text\Plugin\Field\FieldType; use Drupal\Core\Field\ConfigFieldItemBase; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\PrepareCacheInterface; use Drupal\Core\TypedData\DataDefinition; @@ -17,31 +18,23 @@ abstract class TextItemBase extends ConfigFieldItemBase implements PrepareCacheInterface { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions['value'] = DataDefinition::create('string') - ->setLabel(t('Text value')); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('string') + ->setLabel(t('Text value')); - static::$propertyDefinitions['format'] = DataDefinition::create('filter_format') - ->setLabel(t('Text format')); + $properties['format'] = DataDefinition::create('filter_format') + ->setLabel(t('Text format')); - static::$propertyDefinitions['processed'] = DataDefinition::create('string') - ->setLabel(t('Processed text')) - ->setDescription(t('The text value with the text format applied.')) - ->setComputed(TRUE) - ->setClass('\Drupal\text\TextProcessed') - ->setSetting('text source', 'value'); - } - return static::$propertyDefinitions; + $properties['processed'] = DataDefinition::create('string') + ->setLabel(t('Processed text')) + ->setDescription(t('The text value with the text format applied.')) + ->setComputed(TRUE) + ->setClass('\Drupal\text\TextProcessed') + ->setSetting('text source', 'value'); + + return $properties; } /** @@ -73,7 +66,7 @@ public function getCacheData() { // the sanitized value in the filter cache separately. $text_processing = $this->getSetting('text_processing'); if (!$text_processing || filter_format_allowcache($this->get('format')->getValue())) { - foreach ($this->getPropertyDefinitions() as $property => $definition) { + foreach ($this->definition->getPropertyDefinitions() as $property => $definition) { if ($definition->getClass() == '\Drupal\text\TextProcessed') { $data[$property] = $this->get($property)->getValue(); } @@ -92,7 +85,7 @@ public function onChange($property_name) { } // Unset processed properties that are affected by the change. - foreach ($this->getPropertyDefinitions() as $property => $definition) { + foreach ($this->definition->getPropertyDefinitions() as $property => $definition) { if ($definition->getClass() == '\Drupal\text\TextProcessed') { if ($property_name == 'format' || ($definition->getSetting('text source') == $property_name)) { $this->set($property, NULL, FALSE); diff --git a/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextWithSummaryItem.php b/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextWithSummaryItem.php index 3942510..5fe30fc 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextWithSummaryItem.php +++ b/core/modules/text/lib/Drupal/text/Plugin/Field/FieldType/TextWithSummaryItem.php @@ -7,8 +7,8 @@ namespace Drupal\text\Plugin\Field\FieldType; -use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; /** * Plugin implementation of the 'text_with_summary' field type. @@ -28,30 +28,22 @@ class TextWithSummaryItem extends TextItemBase { /** - * Definitions of the contained properties. - * - * @var array - */ - static $propertyDefinitions; - - /** * {@inheritdoc} */ - public function getPropertyDefinitions() { - if (!isset(static::$propertyDefinitions)) { - static::$propertyDefinitions = parent::getPropertyDefinitions(); + public static function propertyDefinitions(FieldDefinitionInterface $field_definition) { + $properties = parent::propertyDefinitions($field_definition); + + $properties['summary'] = DataDefinition::create('string') + ->setLabel(t('Summary text value')); - static::$propertyDefinitions['summary'] = DataDefinition::create('string') - ->setLabel(t('Summary text value')); + $properties['summary_processed'] = DataDefinition::create('string') + ->setLabel(t('Processed summary text')) + ->setDescription(t('The summary text value with the text format applied.')) + ->setComputed(TRUE) + ->setClass('\Drupal\text\TextProcessed') + ->setSetting('text source', 'summary'); - static::$propertyDefinitions['summary_processed'] = DataDefinition::create('string') - ->setLabel(t('Processed summary text')) - ->setDescription(t('The summary text value with the text format applied.')) - ->setComputed(TRUE) - ->setClass('\Drupal\text\TextProcessed') - ->setSetting('text source', 'summary'); - } - return static::$propertyDefinitions; + return $properties; } /** diff --git a/core/modules/user/lib/Drupal/user/Tests/UserValidationTest.php b/core/modules/user/lib/Drupal/user/Tests/UserValidationTest.php index 8b54b67..754a08f 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserValidationTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserValidationTest.php @@ -112,7 +112,7 @@ function testValidation() { $violations = $user->validate(); // @todo There are two violations because EmailItem::getConstraints() // overlaps with the implicit constraint of the 'email' property type used - // in EmailItem::getPropertyDefinitions(). Resolve this in + // in EmailItem::propertyDefinitions(). Resolve this in // https://drupal.org/node/2023465. $this->assertEqual(count($violations), 2, 'Violations found when email is too long'); $this->assertEqual($violations[0]->getPropertyPath(), 'mail.0.value'); diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php index 965f676..1ea7ee2 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php @@ -1009,10 +1009,10 @@ public function initTranslation($langcode) { } /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::getDefinition(). + * Implements \Drupal\Core\TypedData\TypedDataInterface::getDataDefinition(). */ - public function getDefinition() { - return $this->storage->getDefinition(); + public function getDataDefinition() { + return $this->storage->getDataDefinition(); } /** diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index 60622f0..eaae25a 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -541,23 +541,6 @@ public function testGetFieldDefinitionsInvalidDefinition() { } /** - * Tests the getFieldDefinitionsByConstraints() method. - * - * @covers ::getFieldDefinitionsByConstraints() - */ - public function testGetFieldDefinitionsByConstraints() { - $field_definition = $this->setUpEntityWithFieldDefinition(); - - $this->moduleHandler->expects($this->exactly(2)) - ->method('invokeAll') - ->will($this->returnValue(array())); - - $expected = array('id' => $field_definition); - $this->assertSame($expected, $this->entityManager->getFieldDefinitionsByConstraints('test_entity_type', array())); - $this->assertSame($expected, $this->entityManager->getFieldDefinitionsByConstraints('test_entity_type', array('Bundle' => 'test_entity_bundle'))); - } - - /** * Prepares an entity that defines a field definition. * * @param bool $custom_invoke_all diff --git a/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php b/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php index 39b73cf..c90ed93 100644 --- a/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php @@ -84,7 +84,7 @@ public function setUp() { * Tests field name methods. */ public function testFieldName() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $field_name = $this->randomName(); $definition->setName($field_name); $this->assertEquals($field_name, $definition->getName()); @@ -94,7 +94,7 @@ public function testFieldName() { * Tests field label methods. */ public function testFieldLabel() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $label = $this->randomName(); $definition->setLabel($label); $this->assertEquals($label, $definition->getLabel()); @@ -104,7 +104,7 @@ public function testFieldLabel() { * Tests field description methods. */ public function testFieldDescription() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $description = $this->randomName(); $definition->setDescription($description); $this->assertEquals($description, $definition->getDescription()); @@ -122,12 +122,13 @@ public function testFieldType() { * Tests field settings methods. */ public function testFieldSettings() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $setting = $this->randomName(); $value = $this->randomName(); $definition->setSetting($setting, $value); $this->assertEquals($value, $definition->getSetting($setting)); - $this->assertEquals(array($setting => $value), $definition->getSettings()); + $default_settings = $this->fieldTypeDefinition['settings'] + $this->fieldTypeDefinition['instance_settings']; + $this->assertEquals(array($setting => $value) + $default_settings, $definition->getSettings()); } /** @@ -146,7 +147,7 @@ public function testDefaultFieldSettings() { * Tests field default value. */ public function testFieldDefaultValue() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $setting = 'default_value'; $value = $this->randomName(); $definition->setSetting($setting, $value); @@ -160,7 +161,7 @@ public function testFieldDefaultValue() { * Tests field translatable methods. */ public function testFieldTranslatable() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $this->assertFalse($definition->isTranslatable()); $definition->setTranslatable(TRUE); $this->assertTrue($definition->isTranslatable()); @@ -172,7 +173,7 @@ public function testFieldTranslatable() { * Tests field cardinality. */ public function testFieldCardinality() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $this->assertEquals(1, $definition->getCardinality()); // @todo: Add more tests when this can be controlled. } @@ -181,7 +182,7 @@ public function testFieldCardinality() { * Tests required. */ public function testFieldRequired() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $this->assertFalse($definition->isRequired()); $definition->setRequired(TRUE); $this->assertTrue($definition->isRequired()); @@ -193,7 +194,7 @@ public function testFieldRequired() { * Tests configurable. */ public function testFieldConfigurable() { - $definition = new FieldDefinition(); + $definition = FieldDefinition::create($this->fieldType); $this->assertFalse($definition->isConfigurable()); }