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