Upgraded drupal core with security updates
[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     // @todo Cleanup in https://www.drupal.org/node/2116341.
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       ->setQueryable($definition->isQueryable())
93       ->setRevisionable($definition->isRevisionable())
94       ->setSettings($definition->getSettings())
95       ->setTargetEntityTypeId($definition->getTargetEntityTypeId())
96       ->setTranslatable($definition->isTranslatable());
97   }
98
99   /**
100    * {@inheritdoc}
101    */
102   public static function createFromItemType($item_type) {
103     // The data type of a field item is in the form of "field_item:$field_type".
104     $parts = explode(':', $item_type, 2);
105     return static::create($parts[1]);
106   }
107
108   /**
109    * {@inheritdoc}
110    */
111   public function getName() {
112     return $this->definition['field_name'];
113   }
114
115   /**
116    * Sets the field name.
117    *
118    * @param string $name
119    *   The field name to set.
120    *
121    * @return static
122    *   The object itself for chaining.
123    */
124   public function setName($name) {
125     $this->definition['field_name'] = $name;
126     return $this;
127   }
128
129   /**
130    * {@inheritdoc}
131    */
132   public function getType() {
133     return $this->type;
134   }
135
136   /**
137    * {@inheritdoc}
138    */
139   public function getSettings() {
140     return $this->getItemDefinition()->getSettings();
141   }
142
143   /**
144    * {@inheritdoc}
145    *
146    * Note that the method does not unset existing settings not specified in the
147    * incoming $settings array.
148    *
149    * For example:
150    * @code
151    *   // Given these are the default settings.
152    *   $field_definition->getSettings() === [
153    *     'fruit' => 'apple',
154    *     'season' => 'summer',
155    *   ];
156    *   // Change only the 'fruit' setting.
157    *   $field_definition->setSettings(['fruit' => 'banana']);
158    *   // The 'season' setting persists unchanged.
159    *   $field_definition->getSettings() === [
160    *     'fruit' => 'banana',
161    *     'season' => 'summer',
162    *   ];
163    * @endcode
164    *
165    * For clarity, it is preferred to use setSetting() if not all available
166    * settings are supplied.
167    */
168   public function setSettings(array $settings) {
169     // Assign settings individually, in order to keep the current values
170     // of settings not specified in $settings.
171     foreach ($settings as $setting_name => $setting) {
172       $this->getItemDefinition()->setSetting($setting_name, $setting);
173     }
174     return $this;
175   }
176
177   /**
178    * {@inheritdoc}
179    */
180   public function getSetting($setting_name) {
181     return $this->getItemDefinition()->getSetting($setting_name);
182   }
183
184   /**
185    * {@inheritdoc}
186    */
187   public function setSetting($setting_name, $value) {
188     $this->getItemDefinition()->setSetting($setting_name, $value);
189     return $this;
190   }
191
192   /**
193    * {@inheritdoc}
194    */
195   public function getProvider() {
196     return isset($this->definition['provider']) ? $this->definition['provider'] : NULL;
197   }
198
199   /**
200    * Sets the name of the provider of this field.
201    *
202    * @param string $provider
203    *   The provider name to set.
204    *
205    * @return $this
206    */
207   public function setProvider($provider) {
208     $this->definition['provider'] = $provider;
209     return $this;
210   }
211
212   /**
213    * {@inheritdoc}
214    */
215   public function isTranslatable() {
216     return !empty($this->definition['translatable']);
217   }
218
219   /**
220    * Sets whether the field is translatable.
221    *
222    * @param bool $translatable
223    *   Whether the field is translatable.
224    *
225    * @return $this
226    *   The object itself for chaining.
227    */
228   public function setTranslatable($translatable) {
229     $this->definition['translatable'] = $translatable;
230     return $this;
231   }
232
233   /**
234    * {@inheritdoc}
235    */
236   public function isRevisionable() {
237     return !empty($this->definition['revisionable']);
238   }
239
240   /**
241    * Sets whether the field is revisionable.
242    *
243    * @param bool $revisionable
244    *   Whether the field is revisionable.
245    *
246    * @return $this
247    *   The object itself for chaining.
248    */
249   public function setRevisionable($revisionable) {
250     $this->definition['revisionable'] = $revisionable;
251     return $this;
252   }
253
254   /**
255    * {@inheritdoc}
256    */
257   public function getCardinality() {
258     // @todo: Allow to control this.
259     return isset($this->definition['cardinality']) ? $this->definition['cardinality'] : 1;
260   }
261
262   /**
263    * Sets the maximum number of items allowed for the field.
264    *
265    * Possible values are positive integers or
266    * FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
267    *
268    * @param int $cardinality
269    *   The field cardinality.
270    *
271    * @return $this
272    */
273   public function setCardinality($cardinality) {
274     $this->definition['cardinality'] = $cardinality;
275     return $this;
276   }
277
278   /**
279    * {@inheritdoc}
280    */
281   public function isMultiple() {
282     $cardinality = $this->getCardinality();
283     return ($cardinality == static::CARDINALITY_UNLIMITED) || ($cardinality > 1);
284   }
285
286   /**
287    * {@inheritdoc}
288    */
289   public function isQueryable() {
290     return isset($this->definition['queryable']) ? $this->definition['queryable'] : !$this->isComputed();
291   }
292
293   /**
294    * Sets whether the field is queryable.
295    *
296    * @param bool $queryable
297    *   Whether the field is queryable.
298    *
299    * @return static
300    *   The object itself for chaining.
301    */
302   public function setQueryable($queryable) {
303     $this->definition['queryable'] = $queryable;
304     return $this;
305   }
306
307   /**
308    * Sets constraints for a given field item property.
309    *
310    * Note: this overwrites any existing property constraints. If you need to
311    * add to the existing constraints, use
312    * \Drupal\Core\Field\BaseFieldDefinition::addPropertyConstraints()
313    *
314    * @param string $name
315    *   The name of the property to set constraints for.
316    * @param array $constraints
317    *   The constraints to set.
318    *
319    * @return static
320    *   The object itself for chaining.
321    */
322   public function setPropertyConstraints($name, array $constraints) {
323     $item_constraints = $this->getItemDefinition()->getConstraints();
324     $item_constraints['ComplexData'][$name] = $constraints;
325     $this->getItemDefinition()->setConstraints($item_constraints);
326     return $this;
327   }
328
329   /**
330    * Adds constraints for a given field item property.
331    *
332    * Adds a constraint to a property of a base field item. e.g.
333    * @code
334    * // Limit the field item's value property to the range 0 through 10.
335    * // e.g. $node->size->value.
336    * $field->addPropertyConstraints('value', [
337    *   'Range' => [
338    *     'min' => 0,
339    *     'max' => 10,
340    *   ]
341    * ]);
342    * @endcode
343    *
344    * If you want to add a validation constraint that applies to the
345    * \Drupal\Core\Field\FieldItemList, use BaseFieldDefinition::addConstraint()
346    * instead.
347    *
348    * Note: passing a new set of options for an existing property constraint will
349    * overwrite with the new options.
350    *
351    * @param string $name
352    *   The name of the property to set constraints for.
353    * @param array $constraints
354    *   The constraints to set.
355    *
356    * @return static
357    *   The object itself for chaining.
358    *
359    * @see \Drupal\Core\Field\BaseFieldDefinition::addConstraint()
360    */
361   public function addPropertyConstraints($name, array $constraints) {
362     $item_constraints = $this->getItemDefinition()->getConstraint('ComplexData') ?: [];
363     if (isset($item_constraints[$name])) {
364       // Add the new property constraints, overwriting as required.
365       $item_constraints[$name] = $constraints + $item_constraints[$name];
366     }
367     else {
368       $item_constraints[$name] = $constraints;
369     }
370     $this->getItemDefinition()->addConstraint('ComplexData', $item_constraints);
371     return $this;
372   }
373
374   /**
375    * Sets the display options for the field in forms or rendered entities.
376    *
377    * This enables generic rendering of the field with widgets / formatters,
378    * including automated support for "In place editing", and with optional
379    * configurability in the "Manage display" / "Manage form display" UI screens.
380    *
381    * Unless this method is called, the field remains invisible (or requires
382    * ad-hoc rendering logic).
383    *
384    * @param string $display_context
385    *   The display context. Either 'view' or 'form'.
386    * @param array $options
387    *   An array of display options. Refer to
388    *   \Drupal\Core\Field\FieldDefinitionInterface::getDisplayOptions() for
389    *   a list of supported keys. The options should include at least a 'weight',
390    *   or specify 'type' = 'hidden'. The 'default_widget' / 'default_formatter'
391    *   for the field type will be used if no 'type' is specified.
392    *
393    * @return static
394    *   The object itself for chaining.
395    */
396   public function setDisplayOptions($display_context, array $options) {
397     $this->definition['display'][$display_context]['options'] = $options;
398     return $this;
399   }
400
401   /**
402    * Sets whether the display for the field can be configured.
403    *
404    * @param string $display_context
405    *   The display context. Either 'view' or 'form'.
406    * @param bool $configurable
407    *   Whether the display options can be configured (e.g., via the "Manage
408    *   display" / "Manage form display" UI screens). If TRUE, the options
409    *   specified via getDisplayOptions() act as defaults.
410    *
411    * @return static
412    *   The object itself for chaining.
413    */
414   public function setDisplayConfigurable($display_context, $configurable) {
415     // If no explicit display options have been specified, default to 'hidden'.
416     if (empty($this->definition['display'][$display_context])) {
417       $this->definition['display'][$display_context]['options'] = ['region' => 'hidden'];
418     }
419     $this->definition['display'][$display_context]['configurable'] = $configurable;
420     return $this;
421   }
422
423   /**
424    * {@inheritdoc}
425    */
426   public function getDisplayOptions($display_context) {
427     return isset($this->definition['display'][$display_context]['options']) ? $this->definition['display'][$display_context]['options'] : NULL;
428   }
429
430   /**
431    * {@inheritdoc}
432    */
433   public function isDisplayConfigurable($display_context) {
434     return isset($this->definition['display'][$display_context]['configurable']) ? $this->definition['display'][$display_context]['configurable'] : FALSE;
435   }
436
437   /**
438    * {@inheritdoc}
439    */
440   public function getDefaultValueLiteral() {
441     return isset($this->definition['default_value']) ? $this->definition['default_value'] : [];
442   }
443
444   /**
445    * {@inheritdoc}
446    */
447   public function getDefaultValueCallback() {
448     return isset($this->definition['default_value_callback']) ? $this->definition['default_value_callback'] : NULL;
449   }
450
451   /**
452    * {@inheritdoc}
453    */
454   public function getDefaultValue(FieldableEntityInterface $entity) {
455     // Allow custom default values function.
456     if ($callback = $this->getDefaultValueCallback()) {
457       $value = call_user_func($callback, $entity, $this);
458     }
459     else {
460       $value = $this->getDefaultValueLiteral();
461     }
462     // Normalize into the "array keyed by delta" format.
463     if (isset($value) && !is_array($value)) {
464       $properties = $this->getPropertyNames();
465       $property = reset($properties);
466       $value = [
467         [$property => $value],
468       ];
469     }
470     // Allow the field type to process default values.
471     $field_item_list_class = $this->getClass();
472     return $field_item_list_class::processDefaultValue($value, $entity, $this);
473   }
474
475   /**
476    * {@inheritdoc}
477    */
478   public function setDefaultValue($value) {
479     if ($value === NULL) {
480       $value = [];
481     }
482     // Unless the value is an empty array, we may need to transform it.
483     if (!is_array($value) || !empty($value)) {
484       if (!is_array($value)) {
485         $value = [[$this->getMainPropertyName() => $value]];
486       }
487       elseif (is_array($value) && !is_numeric(array_keys($value)[0])) {
488         $value = [0 => $value];
489       }
490     }
491     $this->definition['default_value'] = $value;
492     return $this;
493   }
494
495   /**
496    * {@inheritdoc}
497    */
498   public function setDefaultValueCallback($callback) {
499     if (isset($callback) && !is_string($callback)) {
500       throw new \InvalidArgumentException('Default value callback must be a string, like "function_name" or "ClassName::methodName"');
501     }
502     $this->definition['default_value_callback'] = $callback;
503     return $this;
504   }
505
506   /**
507    * {@inheritdoc}
508    */
509   public function getOptionsProvider($property_name, FieldableEntityInterface $entity) {
510     // If the field item class implements the interface, create an orphaned
511     // runtime item object, so that it can be used as the options provider
512     // without modifying the entity being worked on.
513     if (is_subclass_of($this->getFieldItemClass(), OptionsProviderInterface::class)) {
514       $items = $entity->get($this->getName());
515       return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
516     }
517     // @todo: Allow setting custom options provider, see
518     // https://www.drupal.org/node/2002138.
519   }
520
521   /**
522    * {@inheritdoc}
523    */
524   public function getPropertyDefinition($name) {
525     if (!isset($this->propertyDefinitions)) {
526       $this->getPropertyDefinitions();
527     }
528     if (isset($this->propertyDefinitions[$name])) {
529       return $this->propertyDefinitions[$name];
530     }
531   }
532
533   /**
534    * {@inheritdoc}
535    */
536   public function getPropertyDefinitions() {
537     if (!isset($this->propertyDefinitions)) {
538       $class = $this->getFieldItemClass();
539       $this->propertyDefinitions = $class::propertyDefinitions($this);
540     }
541     return $this->propertyDefinitions;
542   }
543
544   /**
545    * {@inheritdoc}
546    */
547   public function getPropertyNames() {
548     return array_keys($this->getPropertyDefinitions());
549   }
550
551   /**
552    * {@inheritdoc}
553    */
554   public function getMainPropertyName() {
555     $class = $this->getFieldItemClass();
556     return $class::mainPropertyName();
557   }
558
559   /**
560    * Helper to retrieve the field item class.
561    *
562    * @todo: Remove once getClass() adds in defaults. See
563    * https://www.drupal.org/node/2116341.
564    */
565   protected function getFieldItemClass() {
566     if ($class = $this->getItemDefinition()->getClass()) {
567       return $class;
568     }
569     else {
570       $type_definition = \Drupal::typedDataManager()
571         ->getDefinition($this->getItemDefinition()->getDataType());
572       return $type_definition['class'];
573     }
574   }
575
576   /**
577    * {@inheritdoc}
578    */
579   public function __sleep() {
580     // Do not serialize the statically cached property definitions.
581     $vars = get_object_vars($this);
582     unset($vars['propertyDefinitions']);
583     return array_keys($vars);
584   }
585
586   /**
587    * {@inheritdoc}
588    */
589   public function getTargetEntityTypeId() {
590     return isset($this->definition['entity_type']) ? $this->definition['entity_type'] : NULL;
591   }
592
593   /**
594    * Sets the ID of the type of the entity this field is attached to.
595    *
596    * @param string $entity_type_id
597    *   The name of the target entity type to set.
598    *
599    * @return $this
600    */
601   public function setTargetEntityTypeId($entity_type_id) {
602     $this->definition['entity_type'] = $entity_type_id;
603     return $this;
604   }
605
606   /**
607    * {@inheritdoc}
608    */
609   public function getTargetBundle() {
610     return isset($this->definition['bundle']) ? $this->definition['bundle'] : NULL;
611   }
612
613   /**
614    * Sets the bundle this field is defined for.
615    *
616    * @param string|null $bundle
617    *   The bundle, or NULL if the field is not bundle-specific.
618    *
619    * @return $this
620    */
621   public function setTargetBundle($bundle) {
622     $this->definition['bundle'] = $bundle;
623     return $this;
624   }
625
626   /**
627    * {@inheritdoc}
628    */
629   public function getSchema() {
630     if (!isset($this->schema)) {
631       // Get the schema from the field item class.
632       $definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType());
633       $class = $definition['class'];
634       $schema = $class::schema($this);
635       // Fill in default values.
636       $schema += [
637         'columns' => [],
638         'unique keys' => [],
639         'indexes' => [],
640         'foreign keys' => [],
641       ];
642
643       // Merge custom indexes with those specified by the field type. Custom
644       // indexes prevail.
645       $schema['indexes'] = $this->indexes + $schema['indexes'];
646
647       $this->schema = $schema;
648     }
649
650     return $this->schema;
651   }
652
653   /**
654    * {@inheritdoc}
655    */
656   public function getColumns() {
657     $schema = $this->getSchema();
658     // A typical use case for the method is to iterate on the columns, while
659     // some other use cases rely on identifying the first column with the key()
660     // function. Since the schema is persisted in the Field object, we take care
661     // of resetting the array pointer so that the former does not interfere with
662     // the latter.
663     reset($schema['columns']);
664     return $schema['columns'];
665   }
666
667   /**
668    * {@inheritdoc}
669    */
670   public function hasCustomStorage() {
671     return !empty($this->definition['custom_storage']) || $this->isComputed();
672   }
673
674   /**
675    * {@inheritdoc}
676    */
677   public function isBaseField() {
678     return TRUE;
679   }
680
681   /**
682    * Sets the storage behavior for this field.
683    *
684    * @param bool $custom_storage
685    *   Pass FALSE if the storage takes care of storing the field,
686    *   TRUE otherwise.
687    *
688    * @return $this
689    *
690    * @throws \LogicException
691    *   Thrown if custom storage is to be set to FALSE for a computed field.
692    */
693   public function setCustomStorage($custom_storage) {
694     if (!$custom_storage && $this->isComputed()) {
695       throw new \LogicException("Entity storage cannot store a computed field.");
696     }
697     $this->definition['custom_storage'] = $custom_storage;
698     return $this;
699   }
700
701   /**
702    * {@inheritdoc}
703    */
704   public function getFieldStorageDefinition() {
705     return $this;
706   }
707
708   /**
709    * {@inheritdoc}
710    */
711   public function getUniqueStorageIdentifier() {
712     return $this->getTargetEntityTypeId() . '-' . $this->getName();
713   }
714
715   /**
716    * {@inheritdoc}
717    */
718   public function getConfig($bundle) {
719     $override = BaseFieldOverride::loadByName($this->getTargetEntityTypeId(), $bundle, $this->getName());
720     if ($override) {
721       return $override;
722     }
723     return BaseFieldOverride::createFromBaseFieldDefinition($this, $bundle);
724   }
725
726   /**
727    * {@inheritdoc}
728    */
729   public function isStorageRequired() {
730     if (isset($this->definition['storage_required'])) {
731       return (bool) $this->definition['storage_required'];
732     }
733
734     // Default to the 'required' property of the base field.
735     return $this->isRequired();
736   }
737
738   /**
739    * Sets whether the field storage is required.
740    *
741    * @param bool $required
742    *   Whether the field storage is required.
743    *
744    * @return static
745    *   The object itself for chaining.
746    */
747   public function setStorageRequired($required) {
748     $this->definition['storage_required'] = $required;
749     return $this;
750   }
751
752 }