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