1<?php 2 3namespace Drupal\Core\Field; 4 5use Drupal\Core\Cache\CacheBackendInterface; 6use Drupal\Core\Entity\EntityFieldManagerInterface; 7use Drupal\Core\Entity\EntityTypeManagerInterface; 8use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; 9 10/** 11 * Reacts to field definition CRUD on behalf of the Entity system. 12 */ 13class FieldDefinitionListener implements FieldDefinitionListenerInterface { 14 15 /** 16 * The entity type manager. 17 * 18 * @var \Drupal\Core\Entity\EntityTypeManagerInterface 19 */ 20 protected $entityTypeManager; 21 22 /** 23 * The key-value factory. 24 * 25 * @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface 26 */ 27 protected $keyValueFactory; 28 29 /** 30 * Cache backend instance. 31 * 32 * @var \Drupal\Core\Cache\CacheBackendInterface 33 */ 34 protected $cacheBackend; 35 36 /** 37 * The entity field manager. 38 * 39 * @var \Drupal\Core\Entity\EntityFieldManagerInterface 40 */ 41 protected $entityFieldManager; 42 43 /** 44 * Constructs a new FieldDefinitionListener. 45 * 46 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager 47 * The entity type manager. 48 * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager 49 * The entity field manager. 50 * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory 51 * The key-value factory. 52 * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend 53 * The cache backend. 54 */ 55 public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, KeyValueFactoryInterface $key_value_factory, CacheBackendInterface $cache_backend) { 56 $this->entityTypeManager = $entity_type_manager; 57 $this->entityFieldManager = $entity_field_manager; 58 $this->keyValueFactory = $key_value_factory; 59 $this->cacheBackend = $cache_backend; 60 } 61 62 /** 63 * {@inheritdoc} 64 */ 65 public function onFieldDefinitionCreate(FieldDefinitionInterface $field_definition) { 66 $entity_type_id = $field_definition->getTargetEntityTypeId(); 67 $bundle = $field_definition->getTargetBundle(); 68 $field_name = $field_definition->getName(); 69 70 // Notify the storage about the new field. 71 $this->entityTypeManager->getStorage($entity_type_id)->onFieldDefinitionCreate($field_definition); 72 73 // Update the bundle field map key value collection, add the new field. 74 $bundle_field_map = $this->keyValueFactory->get('entity.definitions.bundle_field_map')->get($entity_type_id); 75 if (!isset($bundle_field_map[$field_name])) { 76 // This field did not exist yet, initialize it with the type and empty 77 // bundle list. 78 $bundle_field_map[$field_name] = [ 79 'type' => $field_definition->getType(), 80 'bundles' => [], 81 ]; 82 } 83 $bundle_field_map[$field_name]['bundles'][$bundle] = $bundle; 84 $this->keyValueFactory->get('entity.definitions.bundle_field_map')->set($entity_type_id, $bundle_field_map); 85 86 // Delete the cache entry. 87 $this->cacheBackend->delete('entity_field_map'); 88 89 // If the field map is initialized, update it as well, so that calls to it 90 // do not have to rebuild it again. 91 if ($field_map = $this->entityFieldManager->getFieldMap()) { 92 if (!isset($field_map[$entity_type_id][$field_name])) { 93 // This field did not exist yet, initialize it with the type and empty 94 // bundle list. 95 $field_map[$entity_type_id][$field_name] = [ 96 'type' => $field_definition->getType(), 97 'bundles' => [], 98 ]; 99 } 100 $field_map[$entity_type_id][$field_name]['bundles'][$bundle] = $bundle; 101 $this->entityFieldManager->setFieldMap($field_map); 102 } 103 } 104 105 /** 106 * {@inheritdoc} 107 */ 108 public function onFieldDefinitionUpdate(FieldDefinitionInterface $field_definition, FieldDefinitionInterface $original) { 109 // Notify the storage about the updated field. 110 $this->entityTypeManager->getStorage($field_definition->getTargetEntityTypeId())->onFieldDefinitionUpdate($field_definition, $original); 111 } 112 113 /** 114 * {@inheritdoc} 115 */ 116 public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definition) { 117 $entity_type_id = $field_definition->getTargetEntityTypeId(); 118 $bundle = $field_definition->getTargetBundle(); 119 $field_name = $field_definition->getName(); 120 121 // Notify the storage about the field deletion. 122 $this->entityTypeManager->getStorage($entity_type_id)->onFieldDefinitionDelete($field_definition); 123 124 // Unset the bundle from the bundle field map key value collection. 125 $bundle_field_map = $this->keyValueFactory->get('entity.definitions.bundle_field_map')->get($entity_type_id); 126 unset($bundle_field_map[$field_name]['bundles'][$bundle]); 127 if (empty($bundle_field_map[$field_name]['bundles'])) { 128 // If there are no bundles left, remove the field from the map. 129 unset($bundle_field_map[$field_name]); 130 } 131 $this->keyValueFactory->get('entity.definitions.bundle_field_map')->set($entity_type_id, $bundle_field_map); 132 133 // Delete the cache entry. 134 $this->cacheBackend->delete('entity_field_map'); 135 136 // If the field map is initialized, update it as well, so that calls to it 137 // do not have to rebuild it again. 138 if ($field_map = $this->entityFieldManager->getFieldMap()) { 139 unset($field_map[$entity_type_id][$field_name]['bundles'][$bundle]); 140 if (empty($field_map[$entity_type_id][$field_name]['bundles'])) { 141 unset($field_map[$entity_type_id][$field_name]); 142 } 143 $this->entityFieldManager->setFieldMap($field_map); 144 } 145 } 146 147} 148