Upgraded drupal core with security updates
[yaffs-website] / web / core / lib / Drupal / Core / Field / FieldConfigBase.php
1 <?php
2
3 namespace Drupal\Core\Field;
4
5 use Drupal\Core\Config\Entity\ConfigEntityBase;
6 use Drupal\Core\Entity\EntityStorageInterface;
7 use Drupal\Core\Entity\FieldableEntityInterface;
8 use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
9
10 /**
11  * Base class for configurable field definitions.
12  */
13 abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigInterface {
14
15   /**
16    * The field ID.
17    *
18    * The ID consists of 3 parts: the entity type, bundle and the field name.
19    *
20    * Example: node.article.body, user.user.field_main_image.
21    *
22    * @var string
23    */
24   protected $id;
25
26   /**
27    * The field name.
28    *
29    * @var string
30    */
31   protected $field_name;
32
33   /**
34    * The field type.
35    *
36    * This property is denormalized from the field storage for optimization of
37    * the "entity and render cache hits" critical paths. If not present in the
38    * $values passed to create(), it is populated from the field storage in
39    * postCreate(), and saved in config records so that it is present on
40    * subsequent loads.
41    *
42    * @var string
43    */
44   protected $field_type;
45
46   /**
47    * The name of the entity type the field is attached to.
48    *
49    * @var string
50    */
51   protected $entity_type;
52
53   /**
54    * The name of the bundle the field is attached to.
55    *
56    * @var string
57    */
58   protected $bundle;
59
60   /**
61    * The human-readable label for the field.
62    *
63    * This will be used as the title of Form API elements for the field in entity
64    * edit forms, or as the label for the field values in displayed entities.
65    *
66    * If not specified, this defaults to the field_name (mostly useful for fields
67    * created in tests).
68    *
69    * @var string
70    */
71   protected $label;
72
73   /**
74    * The field description.
75    *
76    * A human-readable description for the field when used with this bundle.
77    * For example, the description will be the help text of Form API elements for
78    * this field in entity edit forms.
79    *
80    * @var string
81    */
82   protected $description = '';
83
84   /**
85    * Field-type specific settings.
86    *
87    * An array of key/value pairs. The keys and default values are defined by the
88    * field type.
89    *
90    * @var array
91    */
92   protected $settings = [];
93
94   /**
95    * Flag indicating whether the field is required.
96    *
97    * TRUE if a value for this field is required when used with this bundle,
98    * FALSE otherwise. Currently, required-ness is only enforced at the Form API
99    * level in entity edit forms, not during direct API saves.
100    *
101    * @var bool
102    */
103   protected $required = FALSE;
104
105   /**
106    * Flag indicating whether the field is translatable.
107    *
108    * Defaults to TRUE.
109    *
110    * @var bool
111    */
112   protected $translatable = TRUE;
113
114   /**
115    * Default field value.
116    *
117    * The default value is used when an entity is created, either:
118    * - through an entity creation form; the form elements for the field are
119    *   prepopulated with the default value.
120    * - through direct API calls (i.e. $entity->save()); the default value is
121    *   added if the $entity object provides no explicit entry (actual values or
122    *   "the field is empty") for the field.
123    *
124    * The default value is expressed as a numerically indexed array of items,
125    * each item being an array of key/value pairs matching the set of 'columns'
126    * defined by the "field schema" for the field type, as exposed in
127    * hook_field_schema(). If the number of items exceeds the cardinality of the
128    * field, extraneous items will be ignored.
129    *
130    * This property is overlooked if the $default_value_callback is non-empty.
131    *
132    * Example for a integer field:
133    * @code
134    * array(
135    *   array('value' => 1),
136    *   array('value' => 2),
137    * )
138    * @endcode
139    *
140    * @var array
141    */
142   protected $default_value = [];
143
144   /**
145    * The name of a callback function that returns default values.
146    *
147    * The function will be called with the following arguments:
148    * - \Drupal\Core\Entity\FieldableEntityInterface $entity
149    *   The entity being created.
150    * - \Drupal\Core\Field\FieldDefinitionInterface $definition
151    *   The field definition.
152    * It should return an array of default values, in the same format as the
153    * $default_value property.
154    *
155    * This property takes precedence on the list of fixed values specified in the
156    * $default_value property.
157    *
158    * @var string
159    */
160   protected $default_value_callback = '';
161
162   /**
163    * The field storage object.
164    *
165    * @var \Drupal\Core\Field\FieldStorageDefinitionInterface
166    */
167   protected $fieldStorage;
168
169   /**
170    * The data definition of a field item.
171    *
172    * @var \Drupal\Core\Field\TypedData\FieldItemDataDefinition
173    */
174   protected $itemDefinition;
175
176   /**
177    * Array of constraint options keyed by constraint plugin ID.
178    *
179    * @var array
180    */
181   protected $constraints = [];
182
183   /**
184    * Array of property constraint options keyed by property ID. The values are
185    * associative array of constraint options keyed by constraint plugin ID.
186    *
187    * @var array[]
188    */
189   protected $propertyConstraints = [];
190
191   /**
192    * {@inheritdoc}
193    */
194   public function id() {
195     return $this->entity_type . '.' . $this->bundle . '.' . $this->field_name;
196   }
197
198   /**
199    * {@inheritdoc}
200    */
201   public function getName() {
202     return $this->field_name;
203   }
204
205   /**
206    * {@inheritdoc}
207    */
208   public function getType() {
209     return $this->field_type;
210   }
211
212   /**
213    * {@inheritdoc}
214    */
215   public function getTargetEntityTypeId() {
216     return $this->entity_type;
217   }
218
219   /**
220    * {@inheritdoc}
221    */
222   public function getTargetBundle() {
223     return $this->bundle;
224   }
225
226   /**
227    * {@inheritdoc}
228    */
229   public function calculateDependencies() {
230     parent::calculateDependencies();
231     // Add dependencies from the field type plugin. We can not use
232     // self::calculatePluginDependencies() because instantiation of a field item
233     // plugin requires a parent entity.
234     /** @var $field_type_manager \Drupal\Core\Field\FieldTypePluginManagerInterface */
235     $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
236     $definition = $field_type_manager->getDefinition($this->getType());
237     $this->addDependency('module', $definition['provider']);
238     // Plugins can declare additional dependencies in their definition.
239     if (isset($definition['config_dependencies'])) {
240       $this->addDependencies($definition['config_dependencies']);
241     }
242     // Let the field type plugin specify its own dependencies.
243     // @see \Drupal\Core\Field\FieldItemInterface::calculateDependencies()
244     $this->addDependencies($definition['class']::calculateDependencies($this));
245
246     // Create dependency on the bundle.
247     $bundle_config_dependency = $this->entityManager()->getDefinition($this->entity_type)->getBundleConfigDependency($this->bundle);
248     $this->addDependency($bundle_config_dependency['type'], $bundle_config_dependency['name']);
249
250     return $this;
251   }
252
253   /**
254    * {@inheritdoc}
255    */
256   public function onDependencyRemoval(array $dependencies) {
257     $changed = parent::onDependencyRemoval($dependencies);
258     $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
259     $definition = $field_type_manager->getDefinition($this->getType());
260     if ($definition['class']::onDependencyRemoval($this, $dependencies)) {
261       $changed = TRUE;
262     }
263     return $changed;
264   }
265
266
267   /**
268    * {@inheritdoc}
269    */
270   public function postCreate(EntityStorageInterface $storage) {
271     parent::postCreate($storage);
272     // If it was not present in the $values passed to create(), (e.g. for
273     // programmatic creation), populate the denormalized field_type property
274     // from the field storage, so that it gets saved in the config record.
275     if (empty($this->field_type)) {
276       $this->field_type = $this->getFieldStorageDefinition()->getType();
277     }
278   }
279
280   /**
281    * {@inheritdoc}
282    */
283   public function postSave(EntityStorageInterface $storage, $update = TRUE) {
284     // Clear the cache.
285     $this->entityManager()->clearCachedFieldDefinitions();
286
287     // Invalidate the render cache for all affected entities.
288     $entity_type = $this->getFieldStorageDefinition()->getTargetEntityTypeId();
289     if ($this->entityManager()->hasHandler($entity_type, 'view_builder')) {
290       $this->entityManager()->getViewBuilder($entity_type)->resetCache();
291     }
292   }
293
294   /**
295    * {@inheritdoc}
296    */
297   public function getLabel() {
298     return $this->label();
299   }
300
301   /**
302    * {@inheritdoc}
303    */
304   public function setLabel($label) {
305     $this->label = $label;
306     return $this;
307   }
308
309   /**
310    * {@inheritdoc}
311    */
312   public function getDescription() {
313     return $this->description;
314   }
315
316   /**
317    * {@inheritdoc}
318    */
319   public function setDescription($description) {
320     $this->description = $description;
321     return $this;
322   }
323
324   /**
325    * {@inheritdoc}
326    */
327   public function isTranslatable() {
328     // A field can be enabled for translation only if translation is supported.
329     return $this->translatable && $this->getFieldStorageDefinition()->isTranslatable();
330   }
331
332   /**
333    * {@inheritdoc}
334    */
335   public function setTranslatable($translatable) {
336     $this->translatable = $translatable;
337     return $this;
338   }
339
340   /**
341    * {@inheritdoc}
342    */
343   public function getSettings() {
344     return $this->settings + $this->getFieldStorageDefinition()->getSettings();
345   }
346
347   /**
348    * {@inheritdoc}
349    */
350   public function setSettings(array $settings) {
351     $this->settings = $settings + $this->settings;
352     return $this;
353   }
354
355   /**
356    * {@inheritdoc}
357    */
358   public function getSetting($setting_name) {
359     if (array_key_exists($setting_name, $this->settings)) {
360       return $this->settings[$setting_name];
361     }
362     else {
363       return $this->getFieldStorageDefinition()->getSetting($setting_name);
364     }
365   }
366
367   /**
368    * {@inheritdoc}
369    */
370   public function setSetting($setting_name, $value) {
371     $this->settings[$setting_name] = $value;
372     return $this;
373   }
374
375   /**
376    * {@inheritdoc}
377    */
378   public function isRequired() {
379     return $this->required;
380   }
381
382   /**
383    * [@inheritdoc}
384    */
385   public function setRequired($required) {
386     $this->required = $required;
387     return $this;
388   }
389
390   /**
391    * {@inheritdoc}
392    */
393   public function getDefaultValue(FieldableEntityInterface $entity) {
394     // Allow custom default values function.
395     if ($callback = $this->getDefaultValueCallback()) {
396       $value = call_user_func($callback, $entity, $this);
397     }
398     else {
399       $value = $this->getDefaultValueLiteral();
400     }
401     // Allow the field type to process default values.
402     $field_item_list_class = $this->getClass();
403     return $field_item_list_class::processDefaultValue($value, $entity, $this);
404   }
405
406   /**
407    * {@inheritdoc}
408    */
409   public function getDefaultValueLiteral() {
410     return $this->default_value;
411   }
412
413   /**
414    * {@inheritdoc}
415    */
416   public function setDefaultValue($value) {
417     if (!is_array($value)) {
418       if ($value === NULL) {
419         $value = [];
420       }
421       $key = $this->getFieldStorageDefinition()->getPropertyNames()[0];
422       // Convert to the multi value format to support fields with a cardinality
423       // greater than 1.
424       $value = [
425         [$key => $value],
426       ];
427     }
428     $this->default_value = $value;
429     return $this;
430   }
431
432   /**
433    * {@inheritdoc}
434    */
435   public function getDefaultValueCallback() {
436     return $this->default_value_callback;
437   }
438
439   /**
440    * {@inheritdoc}
441    */
442   public function setDefaultValueCallback($callback) {
443     $this->default_value_callback = $callback;
444     return $this;
445   }
446
447   /**
448    * Implements the magic __sleep() method.
449    *
450    * Using the Serialize interface and serialize() / unserialize() methods
451    * breaks entity forms in PHP 5.4.
452    * @todo Investigate in https://www.drupal.org/node/2074253.
453    */
454   public function __sleep() {
455     // Only serialize necessary properties, excluding those that can be
456     // recalculated.
457     $properties = get_object_vars($this);
458     unset($properties['fieldStorage'], $properties['itemDefinition'], $properties['original']);
459     return array_keys($properties);
460   }
461
462   /**
463    * {@inheritdoc}
464    */
465   public static function createFromItemType($item_type) {
466     // Forward to the field definition class for creating new data definitions
467     // via the typed manager.
468     return BaseFieldDefinition::createFromItemType($item_type);
469   }
470
471   /**
472    * {@inheritdoc}
473    */
474   public static function createFromDataType($type) {
475     // Forward to the field definition class for creating new data definitions
476     // via the typed manager.
477     return BaseFieldDefinition::createFromDataType($type);
478   }
479
480   /**
481    * {@inheritdoc}
482    */
483   public function getDataType() {
484     return 'list';
485   }
486
487   /**
488    * {@inheritdoc}
489    */
490   public function isList() {
491     return TRUE;
492   }
493
494   /**
495    * {@inheritdoc}
496    */
497   public function getClass() {
498     // Derive list class from the field type.
499     $type_definition = \Drupal::service('plugin.manager.field.field_type')
500       ->getDefinition($this->getType());
501     return $type_definition['list_class'];
502   }
503
504   /**
505    * {@inheritdoc}
506    */
507   public function getConstraints() {
508     return \Drupal::typedDataManager()->getDefaultConstraints($this) + $this->constraints;
509   }
510
511   /**
512    * {@inheritdoc}
513    */
514   public function getConstraint($constraint_name) {
515     $constraints = $this->getConstraints();
516     return isset($constraints[$constraint_name]) ? $constraints[$constraint_name] : NULL;
517   }
518
519   /**
520    * {@inheritdoc}
521    */
522   public function getItemDefinition() {
523     if (!isset($this->itemDefinition)) {
524       $this->itemDefinition = FieldItemDataDefinition::create($this)
525         ->setSettings($this->getSettings());
526
527       // Add any custom property constraints, overwriting as required.
528       $item_constraints = $this->itemDefinition->getConstraint('ComplexData') ?: [];
529       foreach ($this->propertyConstraints as $name => $constraints) {
530         if (isset($item_constraints[$name])) {
531           $item_constraints[$name] = $constraints + $item_constraints[$name];
532         }
533         else {
534           $item_constraints[$name] = $constraints;
535         }
536         $this->itemDefinition->addConstraint('ComplexData', $item_constraints);
537       }
538     }
539
540     return $this->itemDefinition;
541   }
542
543   /**
544    * {@inheritdoc}
545    */
546   public function getConfig($bundle) {
547     return $this;
548   }
549
550   /**
551    * {@inheritdoc}
552    */
553   public function setConstraints(array $constraints) {
554     $this->constraints = $constraints;
555     return $this;
556   }
557
558   /**
559    * {@inheritdoc}
560    */
561   public function addConstraint($constraint_name, $options = NULL) {
562     $this->constraints[$constraint_name] = $options;
563     return $this;
564   }
565
566   /**
567    * {@inheritdoc}
568    */
569   public function setPropertyConstraints($name, array $constraints) {
570     $this->propertyConstraints[$name] = $constraints;
571
572     // Reset the field item definition so the next time it is instantiated it
573     // will receive the new constraints.
574     $this->itemDefinition = NULL;
575
576     return $this;
577   }
578
579   /**
580    * {@inheritdoc}
581    */
582   public function addPropertyConstraints($name, array $constraints) {
583     foreach ($constraints as $constraint_name => $options) {
584       $this->propertyConstraints[$name][$constraint_name] = $options;
585     }
586
587     // Reset the field item definition so the next time it is instantiated it
588     // will receive the new constraints.
589     $this->itemDefinition = NULL;
590
591     return $this;
592   }
593
594 }