Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Entity/EntityFieldManager.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Core\Entity; | |
4 | |
5 use Drupal\Core\Cache\Cache; | |
6 use Drupal\Core\Cache\CacheBackendInterface; | |
7 use Drupal\Core\Cache\UseCacheBackendTrait; | |
8 use Drupal\Core\Extension\ModuleHandlerInterface; | |
9 use Drupal\Core\Field\BaseFieldDefinition; | |
10 use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; | |
11 use Drupal\Core\Language\LanguageManagerInterface; | |
12 use Drupal\Core\StringTranslation\StringTranslationTrait; | |
13 use Drupal\Core\TypedData\TypedDataManagerInterface; | |
14 | |
15 /** | |
16 * Manages the discovery of entity fields. | |
17 * | |
18 * This includes field definitions, base field definitions, and field storage | |
19 * definitions. | |
20 */ | |
21 class EntityFieldManager implements EntityFieldManagerInterface { | |
22 | |
23 use UseCacheBackendTrait; | |
24 use StringTranslationTrait; | |
25 | |
26 /** | |
27 * Extra fields by bundle. | |
28 * | |
29 * @var array | |
30 */ | |
31 protected $extraFields = []; | |
32 | |
33 /** | |
34 * Static cache of base field definitions. | |
35 * | |
36 * @var array | |
37 */ | |
38 protected $baseFieldDefinitions; | |
39 | |
40 /** | |
41 * Static cache of field definitions per bundle and entity type. | |
42 * | |
43 * @var array | |
44 */ | |
45 protected $fieldDefinitions; | |
46 | |
47 /** | |
48 * Static cache of field storage definitions per entity type. | |
49 * | |
50 * Elements of the array: | |
51 * - $entity_type_id: \Drupal\Core\Field\BaseFieldDefinition[] | |
52 * | |
53 * @var array | |
54 */ | |
55 protected $fieldStorageDefinitions; | |
56 | |
57 /** | |
58 * An array keyed by entity type. Each value is an array whose keys are | |
59 * field names and whose value is an array with two entries: | |
60 * - type: The field type. | |
61 * - bundles: The bundles in which the field appears. | |
62 * | |
63 * @return array | |
64 */ | |
65 protected $fieldMap = []; | |
66 | |
67 /** | |
68 * An array keyed by field type. Each value is an array whose key are entity | |
69 * types including arrays in the same form that $fieldMap. | |
70 * | |
71 * It helps access the mapping between types and fields by the field type. | |
72 * | |
73 * @var array | |
74 */ | |
75 protected $fieldMapByFieldType = []; | |
76 | |
77 /** | |
78 * The typed data manager. | |
79 * | |
80 * @var \Drupal\Core\TypedData\TypedDataManagerInterface | |
81 */ | |
82 protected $typedDataManager; | |
83 | |
84 /** | |
85 * The language manager. | |
86 * | |
87 * @var \Drupal\Core\Language\LanguageManagerInterface | |
88 */ | |
89 protected $languageManager; | |
90 | |
91 /** | |
92 * The key-value factory. | |
93 * | |
94 * @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface | |
95 */ | |
96 protected $keyValueFactory; | |
97 | |
98 /** | |
99 * The module handler. | |
100 * | |
101 * @var \Drupal\Core\Extension\ModuleHandlerInterface | |
102 */ | |
103 protected $moduleHandler; | |
104 | |
105 /** | |
106 * The entity type manager. | |
107 * | |
108 * @var \Drupal\Core\Entity\EntityTypeManagerInterface | |
109 */ | |
110 protected $entityTypeManager; | |
111 | |
112 /** | |
113 * The entity type bundle info. | |
114 * | |
115 * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface | |
116 */ | |
117 protected $entityTypeBundleInfo; | |
118 | |
119 /** | |
120 * The entity display repository. | |
121 * | |
122 * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface | |
123 */ | |
124 protected $entityDisplayRepository; | |
125 | |
126 /** | |
127 * Constructs a new EntityFieldManager. | |
128 * | |
129 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager | |
130 * The entity type manager. | |
131 * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info | |
132 * The entity type bundle info. | |
133 * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository | |
134 * The entity display repository. | |
135 * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager | |
136 * The typed data manager. | |
137 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager | |
138 * The language manager. | |
139 * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory | |
140 * The key-value factory. | |
141 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
142 * The module handler. | |
143 * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend | |
144 * The cache backend. | |
145 */ | |
146 public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityDisplayRepositoryInterface $entity_display_repository, TypedDataManagerInterface $typed_data_manager, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend) { | |
147 $this->entityTypeManager = $entity_type_manager; | |
148 $this->entityTypeBundleInfo = $entity_type_bundle_info; | |
149 $this->entityDisplayRepository = $entity_display_repository; | |
150 | |
151 $this->typedDataManager = $typed_data_manager; | |
152 $this->languageManager = $language_manager; | |
153 $this->keyValueFactory = $key_value_factory; | |
154 $this->moduleHandler = $module_handler; | |
155 $this->cacheBackend = $cache_backend; | |
156 } | |
157 | |
158 /** | |
159 * {@inheritdoc} | |
160 */ | |
161 public function getBaseFieldDefinitions($entity_type_id) { | |
162 // Check the static cache. | |
163 if (!isset($this->baseFieldDefinitions[$entity_type_id])) { | |
164 // Not prepared, try to load from cache. | |
165 $cid = 'entity_base_field_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->getId(); | |
166 if ($cache = $this->cacheGet($cid)) { | |
167 $this->baseFieldDefinitions[$entity_type_id] = $cache->data; | |
168 } | |
169 else { | |
170 // Rebuild the definitions and put it into the cache. | |
171 $this->baseFieldDefinitions[$entity_type_id] = $this->buildBaseFieldDefinitions($entity_type_id); | |
172 $this->cacheSet($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, ['entity_types', 'entity_field_info']); | |
173 } | |
174 } | |
175 return $this->baseFieldDefinitions[$entity_type_id]; | |
176 } | |
177 | |
178 /** | |
179 * Builds base field definitions for an entity type. | |
180 * | |
181 * @param string $entity_type_id | |
182 * The entity type ID. Only entity types that implement | |
183 * \Drupal\Core\Entity\FieldableEntityInterface are supported. | |
184 * | |
185 * @return \Drupal\Core\Field\FieldDefinitionInterface[] | |
186 * An array of field definitions, keyed by field name. | |
187 * | |
188 * @throws \LogicException | |
189 * Thrown if a config entity type is given or if one of the entity keys is | |
190 * flagged as translatable. | |
191 */ | |
192 protected function buildBaseFieldDefinitions($entity_type_id) { | |
193 $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); | |
194 $class = $entity_type->getClass(); | |
195 $keys = array_filter($entity_type->getKeys()); | |
196 | |
197 // Fail with an exception for non-fieldable entity types. | |
198 if (!$entity_type->entityClassImplements(FieldableEntityInterface::class)) { | |
199 throw new \LogicException("Getting the base fields is not supported for entity type {$entity_type->getLabel()}."); | |
200 } | |
201 | |
202 // Retrieve base field definitions. | |
203 /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $base_field_definitions */ | |
204 $base_field_definitions = $class::baseFieldDefinitions($entity_type); | |
205 | |
206 // Make sure translatable entity types are correctly defined. | |
207 if ($entity_type->isTranslatable()) { | |
208 // The langcode field should always be translatable if the entity type is. | |
209 if (isset($keys['langcode']) && isset($base_field_definitions[$keys['langcode']])) { | |
210 $base_field_definitions[$keys['langcode']]->setTranslatable(TRUE); | |
211 } | |
212 // A default_langcode field should always be defined. | |
213 if (!isset($base_field_definitions[$keys['default_langcode']])) { | |
214 $base_field_definitions[$keys['default_langcode']] = BaseFieldDefinition::create('boolean') | |
215 ->setLabel($this->t('Default translation')) | |
216 ->setDescription($this->t('A flag indicating whether this is the default translation.')) | |
217 ->setTranslatable(TRUE) | |
218 ->setRevisionable(TRUE) | |
219 ->setDefaultValue(TRUE); | |
220 } | |
221 } | |
222 | |
223 // Make sure that revisionable entity types are correctly defined. | |
224 if ($entity_type->isRevisionable() && $entity_type->isTranslatable()) { | |
225 // The 'revision_translation_affected' field should always be defined. | |
226 // This field has been added unconditionally in Drupal 8.4.0 and it is | |
227 // overriding any pre-existing definition on purpose so that any | |
228 // differences are immediately available in the status report. | |
229 $base_field_definitions[$keys['revision_translation_affected']] = BaseFieldDefinition::create('boolean') | |
230 ->setLabel($this->t('Revision translation affected')) | |
231 ->setDescription($this->t('Indicates if the last edit of a translation belongs to current revision.')) | |
232 ->setReadOnly(TRUE) | |
233 ->setRevisionable(TRUE) | |
234 ->setTranslatable(TRUE); | |
235 } | |
236 | |
237 // Assign base field definitions the entity type provider. | |
238 $provider = $entity_type->getProvider(); | |
239 foreach ($base_field_definitions as $definition) { | |
240 // @todo Remove this check once FieldDefinitionInterface exposes a proper | |
241 // provider setter. See https://www.drupal.org/node/2225961. | |
242 if ($definition instanceof BaseFieldDefinition) { | |
243 $definition->setProvider($provider); | |
244 } | |
245 } | |
246 | |
247 // Retrieve base field definitions from modules. | |
248 foreach ($this->moduleHandler->getImplementations('entity_base_field_info') as $module) { | |
249 $module_definitions = $this->moduleHandler->invoke($module, 'entity_base_field_info', [$entity_type]); | |
250 if (!empty($module_definitions)) { | |
251 // Ensure the provider key actually matches the name of the provider | |
252 // defining the field. | |
253 foreach ($module_definitions as $field_name => $definition) { | |
254 // @todo Remove this check once FieldDefinitionInterface exposes a | |
255 // proper provider setter. See https://www.drupal.org/node/2225961. | |
256 if ($definition instanceof BaseFieldDefinition && $definition->getProvider() == NULL) { | |
257 $definition->setProvider($module); | |
258 } | |
259 $base_field_definitions[$field_name] = $definition; | |
260 } | |
261 } | |
262 } | |
263 | |
264 // Automatically set the field name, target entity type and bundle | |
265 // for non-configurable fields. | |
266 foreach ($base_field_definitions as $field_name => $base_field_definition) { | |
267 if ($base_field_definition instanceof BaseFieldDefinition) { | |
268 $base_field_definition->setName($field_name); | |
269 $base_field_definition->setTargetEntityTypeId($entity_type_id); | |
270 $base_field_definition->setTargetBundle(NULL); | |
271 } | |
272 } | |
273 | |
274 // Invoke alter hook. | |
275 $this->moduleHandler->alter('entity_base_field_info', $base_field_definitions, $entity_type); | |
276 | |
277 // Ensure defined entity keys are there and have proper revisionable and | |
278 // translatable values. | |
279 foreach (array_intersect_key($keys, array_flip(['id', 'revision', 'uuid', 'bundle'])) as $key => $field_name) { | |
280 if (!isset($base_field_definitions[$field_name])) { | |
281 throw new \LogicException("The $field_name field definition does not exist and it is used as $key entity key."); | |
282 } | |
283 if ($base_field_definitions[$field_name]->isRevisionable()) { | |
284 throw new \LogicException("The {$base_field_definitions[$field_name]->getLabel()} field cannot be revisionable as it is used as $key entity key."); | |
285 } | |
286 if ($base_field_definitions[$field_name]->isTranslatable()) { | |
287 throw new \LogicException("The {$base_field_definitions[$field_name]->getLabel()} field cannot be translatable as it is used as $key entity key."); | |
288 } | |
289 } | |
290 | |
291 // Make sure translatable entity types define the "langcode" field properly. | |
292 if ($entity_type->isTranslatable() && (!isset($keys['langcode']) || !isset($base_field_definitions[$keys['langcode']]) || !$base_field_definitions[$keys['langcode']]->isTranslatable())) { | |
293 throw new \LogicException("The {$entity_type->getLabel()} entity type cannot be translatable as it does not define a translatable \"langcode\" field."); | |
294 } | |
295 | |
296 return $base_field_definitions; | |
297 } | |
298 | |
299 /** | |
300 * {@inheritdoc} | |
301 */ | |
302 public function getFieldDefinitions($entity_type_id, $bundle) { | |
303 if (!isset($this->fieldDefinitions[$entity_type_id][$bundle])) { | |
304 $base_field_definitions = $this->getBaseFieldDefinitions($entity_type_id); | |
305 // Not prepared, try to load from cache. | |
306 $cid = 'entity_bundle_field_definitions:' . $entity_type_id . ':' . $bundle . ':' . $this->languageManager->getCurrentLanguage()->getId(); | |
307 if ($cache = $this->cacheGet($cid)) { | |
308 $bundle_field_definitions = $cache->data; | |
309 } | |
310 else { | |
311 // Rebuild the definitions and put it into the cache. | |
312 $bundle_field_definitions = $this->buildBundleFieldDefinitions($entity_type_id, $bundle, $base_field_definitions); | |
313 $this->cacheSet($cid, $bundle_field_definitions, Cache::PERMANENT, ['entity_types', 'entity_field_info']); | |
314 } | |
315 // Field definitions consist of the bundle specific overrides and the | |
316 // base fields, merge them together. Use array_replace() to replace base | |
317 // fields with by bundle overrides and keep them in order, append | |
318 // additional by bundle fields. | |
319 $this->fieldDefinitions[$entity_type_id][$bundle] = array_replace($base_field_definitions, $bundle_field_definitions); | |
320 } | |
321 return $this->fieldDefinitions[$entity_type_id][$bundle]; | |
322 } | |
323 | |
324 /** | |
325 * Builds field definitions for a specific bundle within an entity type. | |
326 * | |
327 * @param string $entity_type_id | |
328 * The entity type ID. Only entity types that implement | |
329 * \Drupal\Core\Entity\FieldableEntityInterface are supported. | |
330 * @param string $bundle | |
331 * The bundle. | |
332 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions | |
333 * The list of base field definitions. | |
334 * | |
335 * @return \Drupal\Core\Field\FieldDefinitionInterface[] | |
336 * An array of bundle field definitions, keyed by field name. Does | |
337 * not include base fields. | |
338 */ | |
339 protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $base_field_definitions) { | |
340 $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); | |
341 $class = $entity_type->getClass(); | |
342 | |
343 // Allow the entity class to provide bundle fields and bundle-specific | |
344 // overrides of base fields. | |
345 $bundle_field_definitions = $class::bundleFieldDefinitions($entity_type, $bundle, $base_field_definitions); | |
346 | |
347 // Load base field overrides from configuration. These take precedence over | |
348 // base field overrides returned above. | |
349 $base_field_override_ids = array_map(function ($field_name) use ($entity_type_id, $bundle) { | |
350 return $entity_type_id . '.' . $bundle . '.' . $field_name; | |
351 }, array_keys($base_field_definitions)); | |
352 $base_field_overrides = $this->entityTypeManager->getStorage('base_field_override')->loadMultiple($base_field_override_ids); | |
353 foreach ($base_field_overrides as $base_field_override) { | |
354 /** @var \Drupal\Core\Field\Entity\BaseFieldOverride $base_field_override */ | |
355 $field_name = $base_field_override->getName(); | |
356 $bundle_field_definitions[$field_name] = $base_field_override; | |
357 } | |
358 | |
359 $provider = $entity_type->getProvider(); | |
360 foreach ($bundle_field_definitions as $definition) { | |
361 // @todo Remove this check once FieldDefinitionInterface exposes a proper | |
362 // provider setter. See https://www.drupal.org/node/2225961. | |
363 if ($definition instanceof BaseFieldDefinition) { | |
364 $definition->setProvider($provider); | |
365 } | |
366 } | |
367 | |
368 // Retrieve base field definitions from modules. | |
369 foreach ($this->moduleHandler->getImplementations('entity_bundle_field_info') as $module) { | |
370 $module_definitions = $this->moduleHandler->invoke($module, 'entity_bundle_field_info', [$entity_type, $bundle, $base_field_definitions]); | |
371 if (!empty($module_definitions)) { | |
372 // Ensure the provider key actually matches the name of the provider | |
373 // defining the field. | |
374 foreach ($module_definitions as $field_name => $definition) { | |
375 // @todo Remove this check once FieldDefinitionInterface exposes a | |
376 // proper provider setter. See https://www.drupal.org/node/2225961. | |
377 if ($definition instanceof BaseFieldDefinition) { | |
378 $definition->setProvider($module); | |
379 } | |
380 $bundle_field_definitions[$field_name] = $definition; | |
381 } | |
382 } | |
383 } | |
384 | |
385 // Automatically set the field name, target entity type and bundle | |
386 // for non-configurable fields. | |
387 foreach ($bundle_field_definitions as $field_name => $field_definition) { | |
388 if ($field_definition instanceof BaseFieldDefinition) { | |
389 $field_definition->setName($field_name); | |
390 $field_definition->setTargetEntityTypeId($entity_type_id); | |
391 $field_definition->setTargetBundle($bundle); | |
392 } | |
393 } | |
394 | |
395 // Invoke 'per bundle' alter hook. | |
396 $this->moduleHandler->alter('entity_bundle_field_info', $bundle_field_definitions, $entity_type, $bundle); | |
397 | |
398 return $bundle_field_definitions; | |
399 } | |
400 | |
401 /** | |
402 * {@inheritdoc} | |
403 */ | |
404 public function getFieldStorageDefinitions($entity_type_id) { | |
405 if (!isset($this->fieldStorageDefinitions[$entity_type_id])) { | |
406 $this->fieldStorageDefinitions[$entity_type_id] = []; | |
407 // Add all non-computed base fields. | |
408 foreach ($this->getBaseFieldDefinitions($entity_type_id) as $field_name => $definition) { | |
409 if (!$definition->isComputed()) { | |
410 $this->fieldStorageDefinitions[$entity_type_id][$field_name] = $definition; | |
411 } | |
412 } | |
413 // Not prepared, try to load from cache. | |
414 $cid = 'entity_field_storage_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->getId(); | |
415 if ($cache = $this->cacheGet($cid)) { | |
416 $field_storage_definitions = $cache->data; | |
417 } | |
418 else { | |
419 // Rebuild the definitions and put it into the cache. | |
420 $field_storage_definitions = $this->buildFieldStorageDefinitions($entity_type_id); | |
421 $this->cacheSet($cid, $field_storage_definitions, Cache::PERMANENT, ['entity_types', 'entity_field_info']); | |
422 } | |
423 $this->fieldStorageDefinitions[$entity_type_id] += $field_storage_definitions; | |
424 } | |
425 return $this->fieldStorageDefinitions[$entity_type_id]; | |
426 } | |
427 | |
428 /** | |
429 * {@inheritdoc} | |
430 */ | |
431 public function setFieldMap(array $field_map) { | |
432 $this->fieldMap = $field_map; | |
433 return $this; | |
434 } | |
435 | |
436 /** | |
437 * {@inheritdoc} | |
438 */ | |
439 public function getFieldMap() { | |
440 if (!$this->fieldMap) { | |
441 // Not prepared, try to load from cache. | |
442 $cid = 'entity_field_map'; | |
443 if ($cache = $this->cacheGet($cid)) { | |
444 $this->fieldMap = $cache->data; | |
445 } | |
446 else { | |
447 // The field map is built in two steps. First, add all base fields, by | |
448 // looping over all fieldable entity types. They always exist for all | |
449 // bundles, and we do not expect to have so many different entity | |
450 // types for this to become a bottleneck. | |
451 foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { | |
452 if ($entity_type->entityClassImplements(FieldableEntityInterface::class)) { | |
453 $bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($entity_type_id)); | |
454 foreach ($this->getBaseFieldDefinitions($entity_type_id) as $field_name => $base_field_definition) { | |
455 $this->fieldMap[$entity_type_id][$field_name] = [ | |
456 'type' => $base_field_definition->getType(), | |
457 'bundles' => array_combine($bundles, $bundles), | |
458 ]; | |
459 } | |
460 } | |
461 } | |
462 | |
463 // In the second step, the per-bundle fields are added, based on the | |
464 // persistent bundle field map stored in a key value collection. This | |
465 // data is managed in the EntityManager::onFieldDefinitionCreate() | |
466 // and EntityManager::onFieldDefinitionDelete() methods. Rebuilding this | |
467 // information in the same way as base fields would not scale, as the | |
468 // time to query would grow exponentially with more fields and bundles. | |
469 // A cache would be deleted during cache clears, which is the only time | |
470 // it is needed, so a key value collection is used. | |
471 $bundle_field_maps = $this->keyValueFactory->get('entity.definitions.bundle_field_map')->getAll(); | |
472 foreach ($bundle_field_maps as $entity_type_id => $bundle_field_map) { | |
473 foreach ($bundle_field_map as $field_name => $map_entry) { | |
474 if (!isset($this->fieldMap[$entity_type_id][$field_name])) { | |
475 $this->fieldMap[$entity_type_id][$field_name] = $map_entry; | |
476 } | |
477 else { | |
478 $this->fieldMap[$entity_type_id][$field_name]['bundles'] += $map_entry['bundles']; | |
479 } | |
480 } | |
481 } | |
482 | |
483 $this->cacheSet($cid, $this->fieldMap, Cache::PERMANENT, ['entity_types']); | |
484 } | |
485 } | |
486 return $this->fieldMap; | |
487 } | |
488 | |
489 /** | |
490 * {@inheritdoc} | |
491 */ | |
492 public function getFieldMapByFieldType($field_type) { | |
493 if (!isset($this->fieldMapByFieldType[$field_type])) { | |
494 $filtered_map = []; | |
495 $map = $this->getFieldMap(); | |
496 foreach ($map as $entity_type => $fields) { | |
497 foreach ($fields as $field_name => $field_info) { | |
498 if ($field_info['type'] == $field_type) { | |
499 $filtered_map[$entity_type][$field_name] = $field_info; | |
500 } | |
501 } | |
502 } | |
503 $this->fieldMapByFieldType[$field_type] = $filtered_map; | |
504 } | |
505 return $this->fieldMapByFieldType[$field_type]; | |
506 } | |
507 | |
508 /** | |
509 * Builds field storage definitions for an entity type. | |
510 * | |
511 * @param string $entity_type_id | |
512 * The entity type ID. Only entity types that implement | |
513 * \Drupal\Core\Entity\FieldableEntityInterface are supported | |
514 * | |
515 * @return \Drupal\Core\Field\FieldStorageDefinitionInterface[] | |
516 * An array of field storage definitions, keyed by field name. | |
517 */ | |
518 protected function buildFieldStorageDefinitions($entity_type_id) { | |
519 $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); | |
520 $field_definitions = []; | |
521 | |
522 // Retrieve base field definitions from modules. | |
523 foreach ($this->moduleHandler->getImplementations('entity_field_storage_info') as $module) { | |
524 $module_definitions = $this->moduleHandler->invoke($module, 'entity_field_storage_info', [$entity_type]); | |
525 if (!empty($module_definitions)) { | |
526 // Ensure the provider key actually matches the name of the provider | |
527 // defining the field. | |
528 foreach ($module_definitions as $field_name => $definition) { | |
529 // @todo Remove this check once FieldDefinitionInterface exposes a | |
530 // proper provider setter. See https://www.drupal.org/node/2225961. | |
531 if ($definition instanceof BaseFieldDefinition) { | |
532 $definition->setProvider($module); | |
533 } | |
534 $field_definitions[$field_name] = $definition; | |
535 } | |
536 } | |
537 } | |
538 | |
539 // Invoke alter hook. | |
540 $this->moduleHandler->alter('entity_field_storage_info', $field_definitions, $entity_type); | |
541 | |
542 return $field_definitions; | |
543 } | |
544 | |
545 /** | |
546 * {@inheritdoc} | |
547 */ | |
548 public function clearCachedFieldDefinitions() { | |
549 $this->baseFieldDefinitions = []; | |
550 $this->fieldDefinitions = []; | |
551 $this->fieldStorageDefinitions = []; | |
552 $this->fieldMap = []; | |
553 $this->fieldMapByFieldType = []; | |
554 $this->entityDisplayRepository->clearDisplayModeInfo(); | |
555 $this->extraFields = []; | |
556 Cache::invalidateTags(['entity_field_info']); | |
557 // The typed data manager statically caches prototype objects with injected | |
558 // definitions, clear those as well. | |
559 $this->typedDataManager->clearCachedDefinitions(); | |
560 } | |
561 | |
562 /** | |
563 * {@inheritdoc} | |
564 */ | |
565 public function useCaches($use_caches = FALSE) { | |
566 $this->useCaches = $use_caches; | |
567 if (!$use_caches) { | |
568 $this->fieldDefinitions = []; | |
569 $this->baseFieldDefinitions = []; | |
570 $this->fieldStorageDefinitions = []; | |
571 } | |
572 } | |
573 | |
574 /** | |
575 * {@inheritdoc} | |
576 */ | |
577 public function getExtraFields($entity_type_id, $bundle) { | |
578 // Read from the "static" cache. | |
579 if (isset($this->extraFields[$entity_type_id][$bundle])) { | |
580 return $this->extraFields[$entity_type_id][$bundle]; | |
581 } | |
582 | |
583 // Read from the persistent cache. Since hook_entity_extra_field_info() and | |
584 // hook_entity_extra_field_info_alter() might contain t() calls, we cache | |
585 // per language. | |
586 $cache_id = 'entity_bundle_extra_fields:' . $entity_type_id . ':' . $bundle . ':' . $this->languageManager->getCurrentLanguage()->getId(); | |
587 $cached = $this->cacheGet($cache_id); | |
588 if ($cached) { | |
589 $this->extraFields[$entity_type_id][$bundle] = $cached->data; | |
590 return $this->extraFields[$entity_type_id][$bundle]; | |
591 } | |
592 | |
593 $extra = $this->moduleHandler->invokeAll('entity_extra_field_info'); | |
594 $this->moduleHandler->alter('entity_extra_field_info', $extra); | |
595 $info = isset($extra[$entity_type_id][$bundle]) ? $extra[$entity_type_id][$bundle] : []; | |
596 $info += [ | |
597 'form' => [], | |
598 'display' => [], | |
599 ]; | |
600 | |
601 // Store in the 'static' and persistent caches. | |
602 $this->extraFields[$entity_type_id][$bundle] = $info; | |
603 $this->cacheSet($cache_id, $info, Cache::PERMANENT, [ | |
604 'entity_field_info', | |
605 ]); | |
606 | |
607 return $this->extraFields[$entity_type_id][$bundle]; | |
608 } | |
609 | |
610 } |