Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / web / core / lib / Drupal / Core / Field / BaseFieldDefinition.php
1 <?php
2
3 namespace Drupal\Core\Field;
4
5 use Drupal\Core\Cache\UnchangingCacheableDependencyTrait;
6 use Drupal\Core\Entity\FieldableEntityInterface;
7 use Drupal\Core\Field\Entity\BaseFieldOverride;
8 use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
9 use Drupal\Core\TypedData\ListDataDefinition;
10 use Drupal\Core\TypedData\OptionsProviderInterface;
11
12 /**
13  * A class for defining entity fields.
14  */
15 class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionInterface, FieldStorageDefinitionInterface, RequiredFieldStorageDefinitionInterface {
16
17   use UnchangingCacheableDependencyTrait;
18   use FieldInputValueNormalizerTrait;
19
20   /**
21    * The field type.
22    *
23    * @var string
24    */
25   protected $type;
26
27   /**
28    * An array of field property definitions.
29    *
30    * @var \Drupal\Core\TypedData\DataDefinitionInterface[]
31    *
32    * @see \Drupal\Core\TypedData\ComplexDataDefinitionInterface::getPropertyDefinitions()
33    */
34   protected $propertyDefinitions;
35
36   /**
37    * The field schema.
38    *
39    * @var array
40    */
41   protected $schema;
42
43   /**
44    * @var array
45    */
46   protected $indexes = [];
47
48   /**
49    * Creates a new field definition.
50    *
51    * @param string $type
52    *   The type of the field.
53    *
54    * @return static
55    *   A new field definition object.
56    */
57   public static function create($type) {
58     $field_definition = new static([]);
59     $field_definition->type = $type;
60     $field_definition->itemDefinition = FieldItemDataDefinition::create($field_definition);
61     // Create a definition for the items, and initialize it with the default
62     // settings for the field type.
63     $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
64     $default_settings = $field_type_manager->getDefaultStorageSettings($type) + $field_type_manager->getDefaultFieldSettings($type);
65     $field_definition->itemDefinition->setSettings($default_settings);
66     return $field_definition;
67   }
68
69   /**
70    * Creates a new field definition based upon a field storage definition.
71    *
72    * In cases where one needs a field storage definitions to act like full
73    * field definitions, this creates a new field definition based upon the
74    * (limited) information available. That way it is possible to use the field
75    * definition in places where a full field definition is required; e.g., with
76    * widgets or formatters.
77    *
78    * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
79    *   The field storage definition to base the new field definition upon.
80    *
81    * @return $this
82    */
83   public static function createFromFieldStorageDefinition(FieldStorageDefinitionInterface $definition) {
84     return static::create($definition->getType())
85       ->setCardinality($definition->getCardinality())
86       ->setConstraints($definition->getConstraints())
87       ->setCustomStorage($definition->hasCustomStorage())
88       ->setDescription($definition->getDescription())
89       ->setLabel($definition->getLabel())
90       ->setName($definition->getName())
91       ->setProvider($definition->getProvider())
92       ->setRevisionable($definition->isRevisionable())
93       ->setSettings($definition->getSettings())
94       ->setTargetEntityTypeId($definition->getTargetEntityTypeId())
95       ->setTranslatable($definition->isTranslatable());
96   }
97
98   /**
99    * {@inheritdoc}
100    */
101   public static function createFromItemType($item_type) {
102     // The data type of a field item is in the form of "field_item:$field_type".
103     $parts = explode(':', $item_type, 2);
104     return static::create($parts[1]);
105   }
106
107   /**
108    * {@inheritdoc}
109    */
110   public function getName() {
111     return $this->definition['field_name'];
112   }
113
114   /**
115    * Sets the field name.
116    *
117    * @param string $name
118    *   The field name to set.
119    *
120    * @return static
121    *   The object itself for chaining.
122    */
123   public function setName($name) {
124     $this->definition['field_name'] = $name;
125     return $this;
126   }
127
128   /**
129    * {@inheritdoc}
130    */
131   public function getType() {
132     return $this->type;
133   }
134
135   /**
136    * {@inheritdoc}
137    */
138   public function getSettings() {
139     return $this->getItemDefinition()->getSettings();
140   }
141
142   /**
143    * {@inheritdoc}
144    *
145    * Note that the method does not unset existing settings not specified in the
146    * incoming $settings array.
147    *
148    * For example:
149    * @code
150    *   // Given these are the default settings.
151    *   $field_definition->getSettings() === [
152    *     'fruit' => 'apple',
153    *     'season' => 'summer',
154    *   ];
155    *   // Change only the 'fruit' setting.
156    *   $field_definition->setSettings(['fruit' => 'banana']);
157    *   // The 'season' setting persists unchanged.
158    *   $field_definition->getSettings() === [
159    *     'fruit' => 'banana',
160    *     'season' => 'summer',
161    *   ];
162    * @endcode
163    *
164    * For clarity, it is preferred to use setSetting() if not all available
165    * settings are supplied.
166    */
167   public function setSettings(array $settings) {
168     // Assign settings individually, in order to keep the current values
169     // of settings not specified in $settings.
170     foreach ($settings as $setting_name => $setting) {
171       $this->getItemDefinition()->setSetting($setting_name, $setting);
172     }
173     return $this;
174   }
175
176   /**
177    * {@inheritdoc}
178    */
179   public function getSetting($setting_name) {
180     return $this->getItemDefinition()->getSetting($setting_name);
181   }
182
183   /**
184    * {@inheritdoc}
185    */
186   public function setSetting($setting_name, $value) {
187     $this->getItemDefinition()->setSetting($setting_name, $value);
188     return $this;
189   }
190
191   /**
192    * {@inheritdoc}
193    */
194   public function getProvider() {
195     return isset($this->definition['provider']) ? $this->definition['provider'] : NULL;
196   }
197
198   /**
199    * Sets the name of the provider of this field.
200    *
201    * @param string $provider
202    *   The provider name to set.
203    *
204    * @return $this
205    */
206   public function setProvider($provider) {
207     $this->definition['provider'] = $provider;
208     return $this;
209   }
210
211   /**
212    * {@inheritdoc}
213    */
214   public function isTranslatable() {
215     return !empty($this->definition['translatable']);
216   }
217
218   /**
219    * Sets whether the field is translatable.
220    *
221    * @param bool $translatable
222    *   Whether the field is translatable.
223    *
224    * @return $this
225    *   The object itself for chaining.
226    */
227   public function setTranslatable($translatable) {
228     $this->definition['translatable'] = $translatable;
229     return $this;
230   }
231
232   /**
233    * {@inheritdoc}
234    */
235   public function isRevisionable() {
236     // Multi-valued base fields are always considered revisionable, just like
237     // configurable fields.
238     return !empty($this->definition['revisionable']) || $this->isMultiple();
239   }
240
241   /**
242    * Sets whether the field is revisionable.
243    *
244    * @param bool $revisionable
245    *   Whether the field is revisionable.
246    *
247    * @return $this
248    *   The object itself for chaining.
249    */
250   public function setRevisionable($revisionable) {
251     $this->definition['revisionable'] = $revisionable;
252     return $this;
253   }
254
255   /**
256    * {@inheritdoc}
257    */
258   public function getCardinality() {
259     // @todo: Allow to control this.
260     return isset($this->definition['cardinality']) ? $this->definition['cardinality'] : 1;
261   }
262
263   /**
264    * Sets the maximum number of items allowed for the field.
265    *
266    * Possible values are positive integers or
267    * FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
268    *
269    * Note that if the entity type that this base field is attached to is
270    * revisionable and the field has a cardinality higher than 1, the field is
271    * considered revisionable by default.
272    *
273    * @param int $cardinality
274    *   The field cardinality.
275    *
276    * @return $this
277    */
278   public function setCardinality($cardinality) {
279     $this->definition['cardinality'] = $cardinality;
280     return $this;
281   }
282
283   /**
284    * {@inheritdoc}
285    */
286   public function isMultiple() {
287     $cardinality = $this->getCardinality();
288     return ($cardinality == static::CARDINALITY_UNLIMITED) || ($cardinality > 1);
289   }
290
291   /**
292    * {@inheritdoc}
293    */
294   public function isQueryable() {
295     @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);
296     return !$this->hasCustomStorage();
297   }
298
299   /**
300    * Sets whether the field is queryable.
301    *
302    * @param bool $queryable
303    *   Whether the field is queryable.
304    *
305    * @return static
306    *   The object itself for chaining.
307    *
308    * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use
309    *   \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage() instead.
310    *
311    * @see https://www.drupal.org/node/2856563
312    */
313   public function setQueryable($queryable) {
314     @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);
315     $this->definition['queryable'] = $queryable;
316     return $this;
317   }
318
319   /**
320    * Sets constraints for a given field item property.
321    *
322    * Note: this overwrites any existing property constraints. If you need to
323    * add to the existing constraints, use
324    * \Drupal\Core\Field\BaseFieldDefinition::addPropertyConstraints()
325    *
326    * @param string $name
327    *   The name of the property to set constraints for.
328    * @param array $constraints
329    *   The constraints to set.
330    *
331    * @return static
332    *   The object itself for chaining.
333    */
334   public function setPropertyConstraints($name, array $constraints) {
335     $item_constraints = $this->getItemDefinition()->getConstraints();
336     $item_constraints['ComplexData'][$name] = $constraints;
337     $this->getItemDefinition()->setConstraints($item_constraints);
338     return $this;
339   }
340
341   /**
342    * Adds constraints for a given field item property.
343    *
344    * Adds a constraint to a property of a base field item. e.g.
345    * @code
346    * // Limit the field item's value property to the range 0 through 10.
347    * // e.g. $node->size->value.
348    * $field->addPropertyConstraints('value', [
349    *   'Range' => [
350    *     'min' => 0,
351    *     'max' => 10,
352    *   ]
353    * ]);
354    * @endcode
355    *
356    * If you want to add a validation constraint that applies to the
357    * \Drupal\Core\Field\FieldItemList, use BaseFieldDefinition::addConstraint()
358    * instead.
359    *
360    * Note: passing a new set of options for an existing property constraint will
361    * overwrite with the new options.
362    *
363    * @param string $name
364    *   The name of the property to set constraints for.
365    * @param array $constraints
366    *   The constraints to set.
367    *
368    * @return static
369    *   The object itself for chaining.
370    *
371    * @see \Drupal\Core\Field\BaseFieldDefinition::addConstraint()
372    */
373   public function addPropertyConstraints($name, array $constraints) {
374     $item_constraints = $this->getItemDefinition()->getConstraint('ComplexData') ?: [];
375     if (isset($item_constraints[$name])) {
376       // Add the new property constraints, overwriting as required.
377       $item_constraints[$name] = $constraints + $item_constraints[$name];
378     }
379     else {
380       $item_constraints[$name] = $constraints;
381     }
382     $this->getItemDefinition()->addConstraint('ComplexData', $item_constraints);
383     return $this;
384   }
385
386   /**
387    * Sets the display options for the field in forms or rendered entities.
388    *
389    * This enables generic rendering of the field with widgets / formatters,
390    * including automated support for "In place editing", and with optional
391    * configurability in the "Manage display" / "Manage form display" UI screens.
392    *
393    * Unless this method is called, the field remains invisible (or requires
394    * ad-hoc rendering logic).
395    *
396    * @param string $display_context
397    *   The display context. Either 'view' or 'form'.
398    * @param array $options
399    *   An array of display options. Refer to
400    *   \Drupal\Core\Field\FieldDefinitionInterface::getDisplayOptions() for
401    *   a list of supported keys. The options should include at least a 'weight',
402    *   or specify 'type' = 'hidden'. The 'default_widget' / 'default_formatter'
403    *   for the field type will be used if no 'type' is specified.
404    *
405    * @return static
406    *   The object itself for chaining.
407    */
408   public function setDisplayOptions($display_context, array $options) {
409     $this->definition['display'][$display_context]['options'] = $options;
410     return $this;
411   }
412
413   /**
414    * Sets whether the display for the field can be configured.
415    *
416    * @param string $display_context
417    *   The display context. Either 'view' or 'form'.
418    * @param bool $configurable
419    *   Whether the display options can be configured (e.g., via the "Manage
420    *   display" / "Manage form display" UI screens). If TRUE, the options
421    *   specified via getDisplayOptions() act as defaults.
422    *
423    * @return static
424    *   The object itself for chaining.
425    */
426   public function setDisplayConfigurable($display_context, $configurable) {
427     // If no explicit display options have been specified, default to 'hidden'.
428     if (empty($this->definition['display'][$display_context])) {
429       $this->definition['display'][$display_context]['options'] = ['region' => 'hidden'];
430     }
431     $this->definition['display'][$display_context]['configurable'] = $configurable;
432     return $this;
433   }
434
435   /**
436    * {@inheritdoc}
437    */
438   public function getDisplayOptions($display_context) {
439     return isset($this->definition['display'][$display_context]['options']) ? $this->definition['display'][$display_context]['options'] : NULL;
440   }
441
442   /**
443    * {@inheritdoc}
444    */
445   public function isDisplayConfigurable($display_context) {
446     return isset($this->definition['display'][$display_context]['configurable']) ? $this->definition['display'][$display_context]['configurable'] : FALSE;
447   }
448
449   /**
450    * {@inheritdoc}
451    */
452   public function getDefaultValueLiteral() {
453     return isset($this->definition['default_value']) ? $this->definition['default_value'] : [];
454   }
455
456   /**
457    * {@inheritdoc}
458    */
459   public function getDefaultValueCallback() {
460     return isset($this->definition['default_value_callback']) ? $this->definition['default_value_callback'] : NULL;
461   }
462
463   /**
464    * {@inheritdoc}
465    */
466   public function getDefaultValue(FieldableEntityInterface $entity) {
467     // Allow custom default values function.
468     if ($callback = $this->getDefaultValueCallback()) {
469       $value = call_user_func($callback, $entity, $this);
470     }
471     else {
472       $value = $this->getDefaultValueLiteral();
473     }
474     $value = $this->normalizeValue($value, $this->getMainPropertyName());
475     // Allow the field type to process default values.
476     $field_item_list_class = $this->getClass();
477     return $field_item_list_class::processDefaultValue($value, $entity, $this);
478   }
479
480   /**
481    * {@inheritdoc}
482    */
483   public function setDefaultValue($value) {
484     if ($value === NULL) {
485       $value = [];
486     }
487     // Unless the value is an empty array, we may need to transform it.
488     if (!is_array($value) || !empty($value)) {
489       if (!is_array($value)) {
490         $value = [[$this->getMainPropertyName() => $value]];
491       }
492       elseif (is_array($value) && !is_numeric(array_keys($value)[0])) {
493         $value = [0 => $value];
494       }
495     }
496     $this->definition['default_value'] = $value;
497     return $this;
498   }
499
500   /**
501    * {@inheritdoc}
502    */
503   public function setDefaultValueCallback($callback) {
504     if (isset($callback) && !is_string($callback)) {
505       throw new \InvalidArgumentException('Default value callback must be a string, like "function_name" or "ClassName::methodName"');
506     }
507     $this->definition['default_value_callback'] = $callback;
508     return $this;
509   }
510
511   /**
512    * Returns the initial value for the field.
513    *
514    * @return array
515    *   The initial value for the field, as a numerically indexed array of items,
516    *   each item being a property/value array (array() for no default value).
517    */
518   public function getInitialValue() {
519     return $this->normalizeValue($this->definition['initial_value'], $this->getMainPropertyName());
520   }
521
522   /**
523    * Sets an initial value for the field.
524    *
525    * @param mixed $value
526    *   The initial value for the field. This can be either:
527    *   - a literal, in which case it will be assigned to the first property of
528    *     the first item;
529    *   - a numerically indexed array of items, each item being a property/value
530    *     array;
531    *   - a non-numerically indexed array, in which case the array is assumed to
532    *     be a property/value array and used as the first item;
533    *   - an empty array for no initial value.
534    *
535    * @return $this
536    */
537   public function setInitialValue($value) {
538     // @todo Implement initial value support for multi-value fields in
539     //   https://www.drupal.org/node/2883851.
540     if ($this->isMultiple()) {
541       throw new FieldException('Multi-value fields can not have an initial value.');
542     }
543
544     $this->definition['initial_value'] = $this->normalizeValue($value, $this->getMainPropertyName());
545     return $this;
546   }
547
548   /**
549    * Returns the name of the field that will be used for getting initial values.
550    *
551    * @return string|null
552    *   The field name.
553    */
554   public function getInitialValueFromField() {
555     return isset($this->definition['initial_value_from_field']) ? $this->definition['initial_value_from_field'] : NULL;
556   }
557
558   /**
559    * Sets a field that will be used for getting initial values.
560    *
561    * @param string $field_name
562    *   The name of the field that will be used for getting initial values.
563    * @param mixed $default_value
564    *   (optional) The default value for the field, in case the inherited value
565    *   is NULL. This can be either:
566    *   - a literal, in which case it will be assigned to the first property of
567    *     the first item;
568    *   - a numerically indexed array of items, each item being a property/value
569    *     array;
570    *   - a non-numerically indexed array, in which case the array is assumed to
571    *     be a property/value array and used as the first item;
572    *   - an empty array for no initial value.
573    *   If the field being added is required or an entity key, it is recommended
574    *   to provide a default value.
575    *
576    * @return $this
577    */
578   public function setInitialValueFromField($field_name, $default_value = NULL) {
579     $this->definition['initial_value_from_field'] = $field_name;
580     $this->setInitialValue($default_value);
581     return $this;
582   }
583
584   /**
585    * {@inheritdoc}
586    */
587   public function getOptionsProvider($property_name, FieldableEntityInterface $entity) {
588     // If the field item class implements the interface, create an orphaned
589     // runtime item object, so that it can be used as the options provider
590     // without modifying the entity being worked on.
591     if (is_subclass_of($this->getItemDefinition()->getClass(), OptionsProviderInterface::class)) {
592       $items = $entity->get($this->getName());
593       return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
594     }
595     // @todo: Allow setting custom options provider, see
596     // https://www.drupal.org/node/2002138.
597   }
598
599   /**
600    * {@inheritdoc}
601    */
602   public function getPropertyDefinition($name) {
603     if (!isset($this->propertyDefinitions)) {
604       $this->getPropertyDefinitions();
605     }
606     if (isset($this->propertyDefinitions[$name])) {
607       return $this->propertyDefinitions[$name];
608     }
609   }
610
611   /**
612    * {@inheritdoc}
613    */
614   public function getPropertyDefinitions() {
615     if (!isset($this->propertyDefinitions)) {
616       $class = $this->getItemDefinition()->getClass();
617       $this->propertyDefinitions = $class::propertyDefinitions($this);
618     }
619     return $this->propertyDefinitions;
620   }
621
622   /**
623    * {@inheritdoc}
624    */
625   public function getPropertyNames() {
626     return array_keys($this->getPropertyDefinitions());
627   }
628
629   /**
630    * {@inheritdoc}
631    */
632   public function getMainPropertyName() {
633     $class = $this->getItemDefinition()->getClass();
634     return $class::mainPropertyName();
635   }
636
637   /**
638    * Helper to retrieve the field item class.
639    *
640    * @deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Use
641    *   \Drupal\Core\TypedData\ListDataDefinition::getClass() instead.
642    */
643   protected function getFieldItemClass() {
644     @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);
645     if ($class = $this->getItemDefinition()->getClass()) {
646       return $class;
647     }
648     else {
649       $type_definition = \Drupal::typedDataManager()
650         ->getDefinition($this->getItemDefinition()->getDataType());
651       return $type_definition['class'];
652     }
653   }
654
655   /**
656    * {@inheritdoc}
657    */
658   public function __sleep() {
659     // Do not serialize the statically cached property definitions.
660     $vars = get_object_vars($this);
661     unset($vars['propertyDefinitions'], $vars['typedDataManager']);
662     return array_keys($vars);
663   }
664
665   /**
666    * {@inheritdoc}
667    */
668   public function getTargetEntityTypeId() {
669     return isset($this->definition['entity_type']) ? $this->definition['entity_type'] : NULL;
670   }
671
672   /**
673    * Sets the ID of the type of the entity this field is attached to.
674    *
675    * @param string $entity_type_id
676    *   The name of the target entity type to set.
677    *
678    * @return $this
679    */
680   public function setTargetEntityTypeId($entity_type_id) {
681     $this->definition['entity_type'] = $entity_type_id;
682     return $this;
683   }
684
685   /**
686    * {@inheritdoc}
687    */
688   public function getTargetBundle() {
689     return isset($this->definition['bundle']) ? $this->definition['bundle'] : NULL;
690   }
691
692   /**
693    * Sets the bundle this field is defined for.
694    *
695    * @param string|null $bundle
696    *   The bundle, or NULL if the field is not bundle-specific.
697    *
698    * @return $this
699    */
700   public function setTargetBundle($bundle) {
701     $this->definition['bundle'] = $bundle;
702     return $this;
703   }
704
705   /**
706    * {@inheritdoc}
707    */
708   public function getSchema() {
709     if (!isset($this->schema)) {
710       // Get the schema from the field item class.
711       $definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType());
712       $class = $definition['class'];
713       $schema = $class::schema($this);
714       // Fill in default values.
715       $schema += [
716         'columns' => [],
717         'unique keys' => [],
718         'indexes' => [],
719         'foreign keys' => [],
720       ];
721
722       // Merge custom indexes with those specified by the field type. Custom
723       // indexes prevail.
724       $schema['indexes'] = $this->indexes + $schema['indexes'];
725
726       $this->schema = $schema;
727     }
728
729     return $this->schema;
730   }
731
732   /**
733    * {@inheritdoc}
734    */
735   public function getColumns() {
736     $schema = $this->getSchema();
737     // A typical use case for the method is to iterate on the columns, while
738     // some other use cases rely on identifying the first column with the key()
739     // function. Since the schema is persisted in the Field object, we take care
740     // of resetting the array pointer so that the former does not interfere with
741     // the latter.
742     reset($schema['columns']);
743     return $schema['columns'];
744   }
745
746   /**
747    * {@inheritdoc}
748    */
749   public function hasCustomStorage() {
750     return !empty($this->definition['custom_storage']) || $this->isComputed();
751   }
752
753   /**
754    * {@inheritdoc}
755    */
756   public function isBaseField() {
757     return TRUE;
758   }
759
760   /**
761    * Sets the storage behavior for this field.
762    *
763    * @param bool $custom_storage
764    *   Pass FALSE if the storage takes care of storing the field,
765    *   TRUE otherwise.
766    *
767    * @return $this
768    *
769    * @throws \LogicException
770    *   Thrown if custom storage is to be set to FALSE for a computed field.
771    */
772   public function setCustomStorage($custom_storage) {
773     if (!$custom_storage && $this->isComputed()) {
774       throw new \LogicException("Entity storage cannot store a computed field.");
775     }
776     $this->definition['custom_storage'] = $custom_storage;
777     return $this;
778   }
779
780   /**
781    * {@inheritdoc}
782    */
783   public function getFieldStorageDefinition() {
784     return $this;
785   }
786
787   /**
788    * {@inheritdoc}
789    */
790   public function getUniqueStorageIdentifier() {
791     return $this->getTargetEntityTypeId() . '-' . $this->getName();
792   }
793
794   /**
795    * {@inheritdoc}
796    */
797   public function getUniqueIdentifier() {
798     // If we have a specified target bundle, we're dealing with a bundle base
799     // field definition, so we need to include it in the unique identifier.
800     if ($this->getTargetBundle()) {
801       return $this->getTargetEntityTypeId() . '-' . $this->getTargetBundle() . '-' . $this->getName();
802     }
803
804     return $this->getUniqueStorageIdentifier();
805   }
806
807   /**
808    * {@inheritdoc}
809    */
810   public function isDeleted() {
811     return !empty($this->definition['deleted']);
812   }
813
814   /**
815    * Sets whether the field storage is deleted.
816    *
817    * @param bool $deleted
818    *   Whether the field storage is deleted.
819    *
820    * @return $this
821    */
822   public function setDeleted($deleted) {
823     $this->definition['deleted'] = $deleted;
824     return $this;
825   }
826
827   /**
828    * {@inheritdoc}
829    */
830   public function getConfig($bundle) {
831     $override = BaseFieldOverride::loadByName($this->getTargetEntityTypeId(), $bundle, $this->getName());
832     if ($override) {
833       return $override;
834     }
835     return BaseFieldOverride::createFromBaseFieldDefinition($this, $bundle);
836   }
837
838   /**
839    * {@inheritdoc}
840    */
841   public function isStorageRequired() {
842     if (isset($this->definition['storage_required'])) {
843       return (bool) $this->definition['storage_required'];
844     }
845
846     // Default to the 'required' property of the base field.
847     return $this->isRequired();
848   }
849
850   /**
851    * Sets whether the field storage is required.
852    *
853    * @param bool $required
854    *   Whether the field storage is required.
855    *
856    * @return static
857    *   The object itself for chaining.
858    */
859   public function setStorageRequired($required) {
860     $this->definition['storage_required'] = $required;
861     return $this;
862   }
863
864   /**
865    * Magic method: Implements a deep clone.
866    */
867   public function __clone() {
868     parent::__clone();
869
870     // The itemDefinition (\Drupal\Core\Field\TypedData\FieldItemDataDefinition)
871     // has a property fieldDefinition, which is a recursive reference to the
872     // parent BaseFieldDefinition, therefore the reference to the old object has
873     // to be overwritten with a reference to the cloned one.
874     $this->itemDefinition->setFieldDefinition($this);
875     // Reset the static cache of the field property definitions in order to
876     // ensure that the clone will reference different field property definitions
877     // objects.
878     $this->propertyDefinitions = NULL;
879   }
880
881   /**
882    * {@inheritdoc}
883    */
884   public function isInternal() {
885     // All fields are not internal unless explicitly set.
886     return !empty($this->definition['internal']);
887   }
888
889 }