Pull merge.
[yaffs-website] / web / core / lib / Drupal / Core / Field / BaseFieldDefinition.php
index c7bb23306d51a4616a05b9b1a56ab98255b39ef5..0947bb132471d1c14ae8403d8ec0a368c2b14148 100644 (file)
@@ -15,6 +15,7 @@ use Drupal\Core\TypedData\OptionsProviderInterface;
 class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionInterface, FieldStorageDefinitionInterface, RequiredFieldStorageDefinitionInterface {
 
   use UnchangingCacheableDependencyTrait;
+  use FieldInputValueNormalizerTrait;
 
   /**
    * The field type.
@@ -59,7 +60,6 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
     $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://www.drupal.org/node/2116341.
     $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
     $default_settings = $field_type_manager->getDefaultStorageSettings($type) + $field_type_manager->getDefaultFieldSettings($type);
     $field_definition->itemDefinition->setSettings($default_settings);
@@ -89,7 +89,6 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
       ->setLabel($definition->getLabel())
       ->setName($definition->getName())
       ->setProvider($definition->getProvider())
-      ->setQueryable($definition->isQueryable())
       ->setRevisionable($definition->isRevisionable())
       ->setSettings($definition->getSettings())
       ->setTargetEntityTypeId($definition->getTargetEntityTypeId())
@@ -234,7 +233,9 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
    * {@inheritdoc}
    */
   public function isRevisionable() {
-    return !empty($this->definition['revisionable']);
+    // Multi-valued base fields are always considered revisionable, just like
+    // configurable fields.
+    return !empty($this->definition['revisionable']) || $this->isMultiple();
   }
 
   /**
@@ -265,6 +266,10 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
    * Possible values are positive integers or
    * FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
    *
+   * Note that if the entity type that this base field is attached to is
+   * revisionable and the field has a cardinality higher than 1, the field is
+   * considered revisionable by default.
+   *
    * @param int $cardinality
    *   The field cardinality.
    *
@@ -287,7 +292,8 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
    * {@inheritdoc}
    */
   public function isQueryable() {
-    return isset($this->definition['queryable']) ? $this->definition['queryable'] : !$this->isComputed();
+    @trigger_error('BaseFieldDefinition::isQueryable() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\Field\BaseFieldDefinition::hasCustomStorage(). See https://www.drupal.org/node/2856563.', E_USER_DEPRECATED);
+    return !$this->hasCustomStorage();
   }
 
   /**
@@ -298,8 +304,14 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
    *
    * @return static
    *   The object itself for chaining.
+   *
+   * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use
+   *   \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage() instead.
+   *
+   * @see https://www.drupal.org/node/2856563
    */
   public function setQueryable($queryable) {
+    @trigger_error('BaseFieldDefinition::setQueryable() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage(). See https://www.drupal.org/node/2856563.', E_USER_DEPRECATED);
     $this->definition['queryable'] = $queryable;
     return $this;
   }
@@ -459,14 +471,7 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
     else {
       $value = $this->getDefaultValueLiteral();
     }
-    // Normalize into the "array keyed by delta" format.
-    if (isset($value) && !is_array($value)) {
-      $properties = $this->getPropertyNames();
-      $property = reset($properties);
-      $value = [
-        [$property => $value],
-      ];
-    }
+    $value = $this->normalizeValue($value, $this->getMainPropertyName());
     // Allow the field type to process default values.
     $field_item_list_class = $this->getClass();
     return $field_item_list_class::processDefaultValue($value, $entity, $this);
@@ -503,6 +508,79 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
     return $this;
   }
 
+  /**
+   * Returns the initial value for the field.
+   *
+   * @return array
+   *   The initial value for the field, as a numerically indexed array of items,
+   *   each item being a property/value array (array() for no default value).
+   */
+  public function getInitialValue() {
+    return $this->normalizeValue($this->definition['initial_value'], $this->getMainPropertyName());
+  }
+
+  /**
+   * Sets an initial value for the field.
+   *
+   * @param mixed $value
+   *   The initial value for the field. This can be either:
+   *   - a literal, in which case it will be assigned to the first property of
+   *     the first item;
+   *   - a numerically indexed array of items, each item being a property/value
+   *     array;
+   *   - a non-numerically indexed array, in which case the array is assumed to
+   *     be a property/value array and used as the first item;
+   *   - an empty array for no initial value.
+   *
+   * @return $this
+   */
+  public function setInitialValue($value) {
+    // @todo Implement initial value support for multi-value fields in
+    //   https://www.drupal.org/node/2883851.
+    if ($this->isMultiple()) {
+      throw new FieldException('Multi-value fields can not have an initial value.');
+    }
+
+    $this->definition['initial_value'] = $this->normalizeValue($value, $this->getMainPropertyName());
+    return $this;
+  }
+
+  /**
+   * Returns the name of the field that will be used for getting initial values.
+   *
+   * @return string|null
+   *   The field name.
+   */
+  public function getInitialValueFromField() {
+    return isset($this->definition['initial_value_from_field']) ? $this->definition['initial_value_from_field'] : NULL;
+  }
+
+  /**
+   * Sets a field that will be used for getting initial values.
+   *
+   * @param string $field_name
+   *   The name of the field that will be used for getting initial values.
+   * @param mixed $default_value
+   *   (optional) The default value for the field, in case the inherited value
+   *   is NULL. This can be either:
+   *   - a literal, in which case it will be assigned to the first property of
+   *     the first item;
+   *   - a numerically indexed array of items, each item being a property/value
+   *     array;
+   *   - a non-numerically indexed array, in which case the array is assumed to
+   *     be a property/value array and used as the first item;
+   *   - an empty array for no initial value.
+   *   If the field being added is required or an entity key, it is recommended
+   *   to provide a default value.
+   *
+   * @return $this
+   */
+  public function setInitialValueFromField($field_name, $default_value = NULL) {
+    $this->definition['initial_value_from_field'] = $field_name;
+    $this->setInitialValue($default_value);
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -510,7 +588,7 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
     // If the field item class implements the interface, create an orphaned
     // runtime item object, so that it can be used as the options provider
     // without modifying the entity being worked on.
-    if (is_subclass_of($this->getFieldItemClass(), OptionsProviderInterface::class)) {
+    if (is_subclass_of($this->getItemDefinition()->getClass(), OptionsProviderInterface::class)) {
       $items = $entity->get($this->getName());
       return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
     }
@@ -535,7 +613,7 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
    */
   public function getPropertyDefinitions() {
     if (!isset($this->propertyDefinitions)) {
-      $class = $this->getFieldItemClass();
+      $class = $this->getItemDefinition()->getClass();
       $this->propertyDefinitions = $class::propertyDefinitions($this);
     }
     return $this->propertyDefinitions;
@@ -552,17 +630,18 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
    * {@inheritdoc}
    */
   public function getMainPropertyName() {
-    $class = $this->getFieldItemClass();
+    $class = $this->getItemDefinition()->getClass();
     return $class::mainPropertyName();
   }
 
   /**
    * Helper to retrieve the field item class.
    *
-   * @todo: Remove once getClass() adds in defaults. See
-   * https://www.drupal.org/node/2116341.
+   * @deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Use
+   *   \Drupal\Core\TypedData\ListDataDefinition::getClass() instead.
    */
   protected function getFieldItemClass() {
+    @trigger_error('BaseFieldDefinition::getFieldItemClass() is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\TypedData\ListDataDefinition::getClass(). See https://www.drupal.org/node/2933964.', E_USER_DEPRECATED);
     if ($class = $this->getItemDefinition()->getClass()) {
       return $class;
     }
@@ -579,7 +658,7 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
   public function __sleep() {
     // Do not serialize the statically cached property definitions.
     $vars = get_object_vars($this);
-    unset($vars['propertyDefinitions']);
+    unset($vars['propertyDefinitions'], $vars['typedDataManager']);
     return array_keys($vars);
   }
 
@@ -712,6 +791,39 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
     return $this->getTargetEntityTypeId() . '-' . $this->getName();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getUniqueIdentifier() {
+    // If we have a specified target bundle, we're dealing with a bundle base
+    // field definition, so we need to include it in the unique identifier.
+    if ($this->getTargetBundle()) {
+      return $this->getTargetEntityTypeId() . '-' . $this->getTargetBundle() . '-' . $this->getName();
+    }
+
+    return $this->getUniqueStorageIdentifier();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isDeleted() {
+    return !empty($this->definition['deleted']);
+  }
+
+  /**
+   * Sets whether the field storage is deleted.
+   *
+   * @param bool $deleted
+   *   Whether the field storage is deleted.
+   *
+   * @return $this
+   */
+  public function setDeleted($deleted) {
+    $this->definition['deleted'] = $deleted;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -749,4 +861,29 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
     return $this;
   }
 
+  /**
+   * Magic method: Implements a deep clone.
+   */
+  public function __clone() {
+    parent::__clone();
+
+    // The itemDefinition (\Drupal\Core\Field\TypedData\FieldItemDataDefinition)
+    // has a property fieldDefinition, which is a recursive reference to the
+    // parent BaseFieldDefinition, therefore the reference to the old object has
+    // to be overwritten with a reference to the cloned one.
+    $this->itemDefinition->setFieldDefinition($this);
+    // Reset the static cache of the field property definitions in order to
+    // ensure that the clone will reference different field property definitions
+    // objects.
+    $this->propertyDefinitions = NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isInternal() {
+    // All fields are not internal unless explicitly set.
+    return !empty($this->definition['internal']);
+  }
+
 }