comparison core/lib/Drupal/Core/Field/FieldConfigBase.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
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 }