Commit e8c263c4 authored by catch's avatar catch

Issue #2112239 by amateescu: Convert base field and property definitions.

parent 31c48739
......@@ -11,6 +11,7 @@
use Drupal\Core\Entity\Plugin\DataType\EntityReference;
use Drupal\Core\Language\Language;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\TypedDataInterface;
/**
......@@ -227,7 +228,7 @@ public function getDefinition() {
else {
$type = 'entity:' . $this->entityType();
}
return array('type' => $type);
return DataDefinition::create($type);
}
/**
......
......@@ -338,15 +338,8 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
// See https://drupal.org/node/2114707.
$class = $this->factory->getPluginClass($entity_type, $this->getDefinition($entity_type));
$base_definitions = $class::baseFieldDefinitions($entity_type);
foreach ($base_definitions as &$base_definition) {
// Support old-style field types to avoid that all base field
// definitions need to be changed.
// @todo: Remove after https://drupal.org/node/2047229.
$base_definition['type'] = preg_replace('/(.+)_field/', 'field_item:$1', $base_definition['type']);
}
$this->entityFieldInfo[$entity_type] = array(
'definitions' => $base_definitions,
'definitions' => $class::baseFieldDefinitions($entity_type),
// Contains definitions of optional (per-bundle) fields.
'optional' => array(),
// An array keyed by bundle name containing the optional fields added
......@@ -360,13 +353,9 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
$result = $this->moduleHandler->invokeAll('entity_field_info', array($entity_type));
$this->entityFieldInfo[$entity_type] = NestedArray::mergeDeep($this->entityFieldInfo[$entity_type], $result);
// Enforce field definitions to be objects.
// Automatically set the field name for non-configurable fields.
foreach (array('definitions', 'optional') as $key) {
foreach ($this->entityFieldInfo[$entity_type][$key] as $field_name => &$definition) {
if (is_array($definition)) {
$definition = FieldDefinition::createFromOldStyleDefinition($definition);
}
// Automatically set the field name for non-configurable fields.
if ($definition instanceof FieldDefinition) {
$definition->setFieldName($field_name);
}
......
......@@ -64,7 +64,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['constraints']['EntityType'], $this->id);
$this->target = entity_load($this->definition->getConstraint('EntityType'), $this->id);
}
return $this->target;
}
......@@ -101,7 +101,7 @@ public function setValue($value, $notify = TRUE) {
if (!isset($value) || $value instanceof EntityInterface) {
$this->target = $value;
}
elseif (!is_scalar($value) || empty($this->definition['constraints']['EntityType'])) {
elseif (!is_scalar($value) || (($constraints = $this->definition->getConstraints()) && empty($constraints['EntityType']))) {
throw new \InvalidArgumentException('Value is not a valid entity.');
}
else {
......
......@@ -7,9 +7,8 @@
namespace Drupal\Core\Entity\Plugin\DataType;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\DataReferenceBase;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the 'language_reference' data type.
......@@ -32,9 +31,7 @@ class LanguageReference extends DataReferenceBase {
* {@inheritdoc}
*/
public function getTargetDefinition() {
return array(
'type' => 'language',
);
return DataDefinition::create('language');
}
/**
......
......@@ -29,8 +29,7 @@ public function validate($value, Constraint $constraint) {
}
$referenced_entity = $value->get('entity')->getTarget();
if (!$referenced_entity) {
$definition = $value->getDefinition();
$type = $definition['settings']['target_type'];
$type = $value->getDefinition()->getSetting('target_type');
$this->context->addViolation($constraint->message, array('%type' => $type, '%id' => $id));
}
}
......
......@@ -204,7 +204,7 @@ public function addField($field, $type, $langcode) {
// Check for a valid relationship.
if (isset($propertyDefinitions[$relationship_specifier]) && $entity->{$specifier}->get('entity') instanceof EntityReference) {
// If it is, use the entity type.
$entity_type = $propertyDefinitions[$relationship_specifier]['constraints']['EntityType'];
$entity_type = $propertyDefinitions[$relationship_specifier]->getConstraint('EntityType');
$entity_info = $entity_manager->getDefinition($entity_type);
// Add the new entity base table using the table and sql column.
$join_condition= '%alias.' . $entity_info['entity_keys']['id'] . " = $table.$sql_column";
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\field\FieldInstanceInterface;
use Drupal\field\FieldInterface;
......@@ -35,11 +36,12 @@ class ConfigEntityReferenceItemBase extends EntityReferenceItem implements Confi
* {@inheritdoc}
*/
public function getPropertyDefinitions() {
$target_type = $this->definition['settings']['target_type'];
$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($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
$key .= isset($settings['target_bundle']) ? $settings['target_bundle'] : '';
if (!isset(static::$propertyDefinitions[$key])) {
// Call the parent to define the target_id and entity properties.
......@@ -49,25 +51,18 @@ public function getPropertyDefinitions() {
// revisions.
$target_type_info = \Drupal::entityManager()->getDefinition($target_type);
if (!empty($target_type_info['entity_keys']['revision']) && !empty($target_type_info['revision_table'])) {
static::$propertyDefinitions[$key]['revision_id'] = array(
'type' => 'integer',
'label' => t('Revision ID'),
'constraints' => array(
'Range' => array('min' => 0),
),
);
static::$propertyDefinitions[$key]['revision_id'] = DataDefinition::create('integer')
->setLabel(t('Revision ID'))
->setConstraints(array('Range' => array('min' => 0)));
}
static::$propertyDefinitions[$key]['label'] = array(
'type' => 'string',
'label' => t('Label (auto-create)'),
'computed' => TRUE,
);
static::$propertyDefinitions[$key]['access'] = array(
'type' => 'boolean',
'label' => t('Access'),
'computed' => TRUE,
);
static::$propertyDefinitions[$key]['label'] = DataDefinition::create('string')
->setLabel(t('Label (auto-create)'))
->setComputed(TRUE);
static::$propertyDefinitions[$key]['access'] = DataDefinition::create('boolean')
->setLabel(t('Access'))
->setComputed(TRUE);
}
return static::$propertyDefinitions[$key];
}
......
......@@ -14,7 +14,7 @@
/**
* A class for defining entity fields.
*/
class FieldDefinition extends ListDefinition implements FieldDefinitionInterface, \ArrayAccess {
class FieldDefinition extends ListDefinition implements FieldDefinitionInterface {
/**
* Creates a new field definition.
......@@ -22,7 +22,7 @@ class FieldDefinition extends ListDefinition implements FieldDefinitionInterface
* @param string $type
* The type of the field.
*
* @return \Drupal\Core\Field\FieldDefinition
* @return static
* A new field definition object.
*/
public static function create($type) {
......@@ -42,7 +42,7 @@ public function getFieldName() {
* @param string $name
* The field name to set.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setFieldName($name) {
......@@ -73,7 +73,7 @@ public function getFieldSettings() {
* @param array $settings
* The value to set.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setFieldSettings(array $settings) {
......@@ -85,8 +85,7 @@ public function setFieldSettings(array $settings) {
* {@inheritdoc}
*/
public function getFieldSetting($setting_name) {
$settings = $this->getFieldSettings();
return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
return $this->getItemDefinition()->getSetting($setting_name);
}
/**
......@@ -97,13 +96,12 @@ public function getFieldSetting($setting_name) {
* @param mixed $value
* The value to set.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setFieldSetting($setting_name, $value) {
$settings = $this->getFieldSettings();
$settings[$setting_name] = $value;
return $this->setFieldSettings($settings);
$this->getItemDefinition()->setSetting($setting_name, $value);
return $this;
}
/**
......@@ -126,7 +124,7 @@ public function isFieldTranslatable() {
* @param bool $translatable
* Whether the field is translatable.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setTranslatable($translatable) {
......@@ -191,7 +189,7 @@ public function isFieldMultiple() {
* @param bool $required
* Whether the field is required.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setFieldRequired($required) {
......@@ -211,7 +209,7 @@ public function isFieldQueryable() {
* @param bool $queryable
* Whether the field is queryable.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setFieldQueryable($queryable) {
......@@ -227,7 +225,7 @@ public function setFieldQueryable($queryable) {
* @param array $constraints
* The constraints to set.
*
* @return self
* @return static
* The object itself for chaining.
*/
public function setPropertyConstraints($name, array $constraints) {
......@@ -251,77 +249,4 @@ public function getFieldDefaultValue(EntityInterface $entity) {
return $this->getFieldSetting('default_value');
}
/**
* Allows creating field definition objects from old style definition arrays.
*
* @todo: Remove once https://drupal.org/node/2112239 is in.
*/
public static function createFromOldStyleDefinition(array $definition) {
unset($definition['list']);
// Separate the list item definition from the list definition.
$list_definition = $definition;
unset($list_definition['type']);
// Constraints, class and settings apply to the list item.
unset($list_definition['constraints']);
unset($list_definition['class']);
unset($list_definition['settings']);
$field_definition = new FieldDefinition($list_definition);
if (isset($definition['list_class'])) {
$field_definition->setClass($definition['list_class']);
}
else {
$type_definition = \Drupal::typedData()->getDefinition($definition['type']);
if (isset($type_definition['list_class'])) {
$field_definition->setClass($type_definition['list_class']);
}
}
if (isset($definition['translatable'])) {
$field_definition->setTranslatable($definition['translatable']);
unset($definition['translatable']);
}
// Take care of the item definition now.
// Required applies to the field definition only.
unset($definition['required']);
$item_definition = new DataDefinition($definition);
$field_definition->setItemDefinition($item_definition);
return $field_definition;
}
/**
* {@inheritdoc}
*
* This is for BC support only.
* @todo: Remove once https://drupal.org/node/2112239 is in.
*/
public function &offsetGet($offset) {
if ($offset == 'type') {
// What previously was "type" is now the type of the list item.
$type = &$this->itemDefinition->offsetGet('type');
return $type;
}
if (!isset($this->definition[$offset])) {
$this->definition[$offset] = NULL;
}
return $this->definition[$offset];
}
/**
* {@inheritdoc}
*
* This is for BC support only.
* @todo: Remove once https://drupal.org/node/2112239 is in.
*/
public function offsetSet($offset, $value) {
if ($offset == 'type') {
// What previously was "type" is now the type of the list item.
$this->itemDefinition->setDataType($value);
}
else {
$this->definition[$offset] = $value;
}
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\Core\TypedData\Plugin\DataType\Map;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\user;
......@@ -23,14 +24,14 @@
abstract class FieldItemBase extends Map implements FieldItemInterface {
/**
* Overrides \Drupal\Core\TypedData\TypedData::__construct().
* {@inheritdoc}
*/
public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
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) {
if (!empty($definition['computed'])) {
if ($definition->isComputed()) {
$this->properties[$name] = \Drupal::typedData()->getPropertyInstance($this, $name);
}
}
......@@ -185,20 +186,6 @@ public function onChange($property_name) {
}
}
/**
* {@inheritdoc}
*/
public function getConstraints() {
$constraints = parent::getConstraints();
// If property constraints are present add in a ComplexData constraint for
// applying them.
if (!empty($this->definition['property_constraints'])) {
$constraints[] = \Drupal::typedData()->getValidationConstraintManager()
->create('ComplexData', $this->definition['property_constraints']);
}
return $constraints;
}
/**
* {@inheritdoc}
*/
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\Core\TypedData\Plugin\DataType\ItemList;
use Drupal\Core\Language\Language;
......@@ -40,7 +41,7 @@ class FieldItemList extends ItemList implements FieldItemListInterface {
/**
* {@inheritdoc}
*/
public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) {
public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) {
parent::__construct($definition, $name, $parent);
// Always initialize one empty item as most times a value for at least one
// item will be present. That way prototypes created by
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the 'boolean' entity field type.
......@@ -34,13 +35,11 @@ class BooleanItem extends FieldItemBase {
* Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
*/
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['value'] = array(
'type' => 'boolean',
'label' => t('Boolean value'),
);
static::$propertyDefinitions['value'] = DataDefinition::create('boolean')
->setLabel(t('Boolean value'));
}
return static::$propertyDefinitions;
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the 'email' entity field type.
......@@ -36,10 +37,8 @@ class EmailItem extends FieldItemBase {
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['value'] = array(
'type' => 'email',
'label' => t('E-mail value'),
);
static::$propertyDefinitions['value'] = DataDefinition::create('email')
->setLabel(t('E-mail value'));
}
return static::$propertyDefinitions;
}
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the 'entity_reference' entity field type.
......@@ -41,45 +42,41 @@ class EntityReferenceItem extends FieldItemBase {
* Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
*/
public function getPropertyDefinitions() {
$target_type = $this->definition['settings']['target_type'];
$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($this->definition['settings']['target_bundle']) ? $this->definition['settings']['target_bundle'] : '';
$key .= isset($settings['target_bundle']) ? $settings['target_bundle'] : '';
if (!isset(static::$propertyDefinitions[$key])) {
$target_type_info = \Drupal::entityManager()->getDefinition($target_type);
if (is_subclass_of($target_type_info['class'], '\Drupal\Core\Entity\ContentEntityInterface')) {
static::$propertyDefinitions[$key]['target_id'] = array(
// @todo: Lookup the entity type's ID data type and use it here.
// https://drupal.org/node/2107249
'type' => 'integer',
'label' => t('Entity ID'),
'constraints' => array(
// @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'] = array(
'type' => 'string',
'label' => t('Entity ID'),
);
static::$propertyDefinitions[$key]['target_id'] = DataDefinition::create('string')
->setLabel(t('Entity ID'));
}
static::$propertyDefinitions[$key]['entity'] = array(
'type' => 'entity_reference',
'constraints' => array(
'EntityType' => $this->definition['settings']['target_type'],
),
'label' => t('Entity'),
'description' => t('The referenced entity'),
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.
'computed' => TRUE,
'read-only' => FALSE,
);
if (isset($this->definition['settings']['target_bundle'])) {
static::$propertyDefinitions[$key]['entity']['constraints']['Bundle'] = $this->definition['settings']['target_bundle'];
->setComputed(TRUE)
->setReadOnly(FALSE)
->setConstraints(array(
'EntityType' => $settings['target_type'],
));
if (isset($settings['target_bundle'])) {
static::$propertyDefinitions[$key]['entity']->addConstraint('Bundle', $settings['target_bundle']);
}
}
return static::$propertyDefinitions[$key];
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the 'float' entity field type.
......@@ -36,10 +37,8 @@ class FloatItem extends FieldItemBase {
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['value'] = array(
'type' => 'float',
'label' => t('Float value'),
);
static::$propertyDefinitions['value'] = DataDefinition::create('float')
->setLabel(t('Float value'));
}
return static::$propertyDefinitions;
}
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Language\Language;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the 'language' entity field item.
......@@ -41,18 +42,15 @@ class LanguageItem extends FieldItemBase {
*/
public function getPropertyDefinitions() {
if (!isset(static::$propertyDefinitions)) {
static::$propertyDefinitions['value'] = array(
'type' => 'string',
'label' => t('Language code'),
);
static::$propertyDefinitions['language'] = array(
'type' => 'language_reference',
'label' => t('Language object'),
'description' => t('The referenced language'),
// The language object is retrieved via the language code.
'computed' => TRUE,
'read-only' => FALSE,
);
static::$propertyDefinitions['value'] = DataDefinition::create('string')
->setLabel(t('Language code'));
static::$propertyDefinitions['language'] = DataDefinition::create('language_reference')
->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;
}
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
/**
* Defines the 'uri' entity field type.
......@@ -34,13 +35,11 @@ class UriItem extends FieldItemBase {
* Implements ComplexDataInterface::getPropertyDefinitions().