Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.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\Entity; | |
4 | |
5 use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; | |
6 use Drupal\Core\Entity\Schema\EntityStorageSchemaInterface; | |
7 use Drupal\Core\Field\BaseFieldDefinition; | |
8 use Drupal\Core\Field\FieldStorageDefinitionInterface; | |
9 use Drupal\Core\StringTranslation\StringTranslationTrait; | |
10 | |
11 /** | |
12 * Manages entity definition updates. | |
13 */ | |
14 class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInterface { | |
15 use StringTranslationTrait; | |
16 | |
17 /** | |
18 * The entity manager service. | |
19 * | |
20 * @var \Drupal\Core\Entity\EntityManagerInterface | |
21 */ | |
22 protected $entityManager; | |
23 | |
24 /** | |
25 * Constructs a new EntityDefinitionUpdateManager. | |
26 * | |
27 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager | |
28 * The entity manager. | |
29 */ | |
30 public function __construct(EntityManagerInterface $entity_manager) { | |
31 $this->entityManager = $entity_manager; | |
32 } | |
33 | |
34 /** | |
35 * {@inheritdoc} | |
36 */ | |
37 public function needsUpdates() { | |
38 return (bool) $this->getChangeList(); | |
39 } | |
40 | |
41 /** | |
42 * {@inheritdoc} | |
43 */ | |
44 public function getChangeSummary() { | |
45 $summary = []; | |
46 | |
47 foreach ($this->getChangeList() as $entity_type_id => $change_list) { | |
48 // Process entity type definition changes. | |
49 if (!empty($change_list['entity_type'])) { | |
50 $entity_type = $this->entityManager->getDefinition($entity_type_id); | |
51 | |
52 switch ($change_list['entity_type']) { | |
53 case static::DEFINITION_CREATED: | |
54 $summary[$entity_type_id][] = $this->t('The %entity_type entity type needs to be installed.', ['%entity_type' => $entity_type->getLabel()]); | |
55 break; | |
56 | |
57 case static::DEFINITION_UPDATED: | |
58 $summary[$entity_type_id][] = $this->t('The %entity_type entity type needs to be updated.', ['%entity_type' => $entity_type->getLabel()]); | |
59 break; | |
60 } | |
61 } | |
62 | |
63 // Process field storage definition changes. | |
64 if (!empty($change_list['field_storage_definitions'])) { | |
65 $storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); | |
66 $original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
67 | |
68 foreach ($change_list['field_storage_definitions'] as $field_name => $change) { | |
69 switch ($change) { | |
70 case static::DEFINITION_CREATED: | |
71 $summary[$entity_type_id][] = $this->t('The %field_name field needs to be installed.', ['%field_name' => $storage_definitions[$field_name]->getLabel()]); | |
72 break; | |
73 | |
74 case static::DEFINITION_UPDATED: | |
75 $summary[$entity_type_id][] = $this->t('The %field_name field needs to be updated.', ['%field_name' => $storage_definitions[$field_name]->getLabel()]); | |
76 break; | |
77 | |
78 case static::DEFINITION_DELETED: | |
79 $summary[$entity_type_id][] = $this->t('The %field_name field needs to be uninstalled.', ['%field_name' => $original_storage_definitions[$field_name]->getLabel()]); | |
80 break; | |
81 } | |
82 } | |
83 } | |
84 } | |
85 | |
86 return $summary; | |
87 } | |
88 | |
89 /** | |
90 * {@inheritdoc} | |
91 */ | |
92 public function applyUpdates() { | |
93 $complete_change_list = $this->getChangeList(); | |
94 if ($complete_change_list) { | |
95 // self::getChangeList() only disables the cache and does not invalidate. | |
96 // In case there are changes, explicitly invalidate caches. | |
97 $this->entityManager->clearCachedDefinitions(); | |
98 } | |
99 foreach ($complete_change_list as $entity_type_id => $change_list) { | |
100 // Process entity type definition changes before storage definitions ones | |
101 // this is necessary when you change an entity type from non-revisionable | |
102 // to revisionable and at the same time add revisionable fields to the | |
103 // entity type. | |
104 if (!empty($change_list['entity_type'])) { | |
105 $this->doEntityUpdate($change_list['entity_type'], $entity_type_id); | |
106 } | |
107 | |
108 // Process field storage definition changes. | |
109 if (!empty($change_list['field_storage_definitions'])) { | |
110 $storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); | |
111 $original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
112 | |
113 foreach ($change_list['field_storage_definitions'] as $field_name => $change) { | |
114 $storage_definition = isset($storage_definitions[$field_name]) ? $storage_definitions[$field_name] : NULL; | |
115 $original_storage_definition = isset($original_storage_definitions[$field_name]) ? $original_storage_definitions[$field_name] : NULL; | |
116 $this->doFieldUpdate($change, $storage_definition, $original_storage_definition); | |
117 } | |
118 } | |
119 } | |
120 } | |
121 | |
122 /** | |
123 * {@inheritdoc} | |
124 */ | |
125 public function getEntityType($entity_type_id) { | |
126 $entity_type = $this->entityManager->getLastInstalledDefinition($entity_type_id); | |
127 return $entity_type ? clone $entity_type : NULL; | |
128 } | |
129 | |
130 /** | |
131 * {@inheritdoc} | |
132 */ | |
133 public function installEntityType(EntityTypeInterface $entity_type) { | |
134 $this->entityManager->clearCachedDefinitions(); | |
135 $this->entityManager->onEntityTypeCreate($entity_type); | |
136 } | |
137 | |
138 /** | |
139 * {@inheritdoc} | |
140 */ | |
141 public function updateEntityType(EntityTypeInterface $entity_type) { | |
142 $original = $this->getEntityType($entity_type->id()); | |
143 $this->entityManager->clearCachedDefinitions(); | |
144 $this->entityManager->onEntityTypeUpdate($entity_type, $original); | |
145 } | |
146 | |
147 /** | |
148 * {@inheritdoc} | |
149 */ | |
150 public function uninstallEntityType(EntityTypeInterface $entity_type) { | |
151 $this->entityManager->clearCachedDefinitions(); | |
152 $this->entityManager->onEntityTypeDelete($entity_type); | |
153 } | |
154 | |
155 /** | |
156 * {@inheritdoc} | |
157 */ | |
158 public function installFieldStorageDefinition($name, $entity_type_id, $provider, FieldStorageDefinitionInterface $storage_definition) { | |
159 // @todo Pass a mutable field definition interface when we have one. See | |
160 // https://www.drupal.org/node/2346329. | |
161 if ($storage_definition instanceof BaseFieldDefinition) { | |
162 $storage_definition | |
163 ->setName($name) | |
164 ->setTargetEntityTypeId($entity_type_id) | |
165 ->setProvider($provider) | |
166 ->setTargetBundle(NULL); | |
167 } | |
168 $this->entityManager->clearCachedDefinitions(); | |
169 $this->entityManager->onFieldStorageDefinitionCreate($storage_definition); | |
170 } | |
171 | |
172 /** | |
173 * {@inheritdoc} | |
174 */ | |
175 public function getFieldStorageDefinition($name, $entity_type_id) { | |
176 $storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
177 return isset($storage_definitions[$name]) ? clone $storage_definitions[$name] : NULL; | |
178 } | |
179 | |
180 /** | |
181 * {@inheritdoc} | |
182 */ | |
183 public function updateFieldStorageDefinition(FieldStorageDefinitionInterface $storage_definition) { | |
184 $original = $this->getFieldStorageDefinition($storage_definition->getName(), $storage_definition->getTargetEntityTypeId()); | |
185 $this->entityManager->clearCachedDefinitions(); | |
186 $this->entityManager->onFieldStorageDefinitionUpdate($storage_definition, $original); | |
187 } | |
188 | |
189 /** | |
190 * {@inheritdoc} | |
191 */ | |
192 public function uninstallFieldStorageDefinition(FieldStorageDefinitionInterface $storage_definition) { | |
193 $this->entityManager->clearCachedDefinitions(); | |
194 $this->entityManager->onFieldStorageDefinitionDelete($storage_definition); | |
195 } | |
196 | |
197 /** | |
198 * Performs an entity type definition update. | |
199 * | |
200 * @param string $op | |
201 * The operation to perform, either static::DEFINITION_CREATED or | |
202 * static::DEFINITION_UPDATED. | |
203 * @param string $entity_type_id | |
204 * The entity type ID. | |
205 */ | |
206 protected function doEntityUpdate($op, $entity_type_id) { | |
207 $entity_type = $this->entityManager->getDefinition($entity_type_id); | |
208 switch ($op) { | |
209 case static::DEFINITION_CREATED: | |
210 $this->entityManager->onEntityTypeCreate($entity_type); | |
211 break; | |
212 | |
213 case static::DEFINITION_UPDATED: | |
214 $original = $this->entityManager->getLastInstalledDefinition($entity_type_id); | |
215 $this->entityManager->onEntityTypeUpdate($entity_type, $original); | |
216 break; | |
217 } | |
218 } | |
219 | |
220 /** | |
221 * Performs a field storage definition update. | |
222 * | |
223 * @param string $op | |
224 * The operation to perform, possible values are static::DEFINITION_CREATED, | |
225 * static::DEFINITION_UPDATED or static::DEFINITION_DELETED. | |
226 * @param array|null $storage_definition | |
227 * The new field storage definition. | |
228 * @param array|null $original_storage_definition | |
229 * The original field storage definition. | |
230 */ | |
231 protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL) { | |
232 switch ($op) { | |
233 case static::DEFINITION_CREATED: | |
234 $this->entityManager->onFieldStorageDefinitionCreate($storage_definition); | |
235 break; | |
236 | |
237 case static::DEFINITION_UPDATED: | |
238 $this->entityManager->onFieldStorageDefinitionUpdate($storage_definition, $original_storage_definition); | |
239 break; | |
240 | |
241 case static::DEFINITION_DELETED: | |
242 $this->entityManager->onFieldStorageDefinitionDelete($original_storage_definition); | |
243 break; | |
244 } | |
245 } | |
246 | |
247 /** | |
248 * Gets a list of changes to entity type and field storage definitions. | |
249 * | |
250 * @return array | |
251 * An associative array keyed by entity type id of change descriptors. Every | |
252 * entry is an associative array with the following optional keys: | |
253 * - entity_type: a scalar having only the DEFINITION_UPDATED value. | |
254 * - field_storage_definitions: an associative array keyed by field name of | |
255 * scalars having one value among: | |
256 * - DEFINITION_CREATED | |
257 * - DEFINITION_UPDATED | |
258 * - DEFINITION_DELETED | |
259 */ | |
260 protected function getChangeList() { | |
261 $this->entityManager->useCaches(FALSE); | |
262 $change_list = []; | |
263 | |
264 foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { | |
265 $original = $this->entityManager->getLastInstalledDefinition($entity_type_id); | |
266 | |
267 // @todo Support non-storage-schema-changing definition updates too: | |
268 // https://www.drupal.org/node/2336895. | |
269 if (!$original) { | |
270 $change_list[$entity_type_id]['entity_type'] = static::DEFINITION_CREATED; | |
271 } | |
272 else { | |
273 if ($this->requiresEntityStorageSchemaChanges($entity_type, $original)) { | |
274 $change_list[$entity_type_id]['entity_type'] = static::DEFINITION_UPDATED; | |
275 } | |
276 | |
277 if ($this->entityManager->getStorage($entity_type_id) instanceof DynamicallyFieldableEntityStorageInterface) { | |
278 $field_changes = []; | |
279 $storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); | |
280 $original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
281 | |
282 // Detect created field storage definitions. | |
283 foreach (array_diff_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) { | |
284 $field_changes[$field_name] = static::DEFINITION_CREATED; | |
285 } | |
286 | |
287 // Detect deleted field storage definitions. | |
288 foreach (array_diff_key($original_storage_definitions, $storage_definitions) as $field_name => $original_storage_definition) { | |
289 $field_changes[$field_name] = static::DEFINITION_DELETED; | |
290 } | |
291 | |
292 // Detect updated field storage definitions. | |
293 foreach (array_intersect_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) { | |
294 // @todo Support non-storage-schema-changing definition updates too: | |
295 // https://www.drupal.org/node/2336895. So long as we're checking | |
296 // based on schema change requirements rather than definition | |
297 // equality, skip the check if the entity type itself needs to be | |
298 // updated, since that can affect the schema of all fields, so we | |
299 // want to process that update first without reporting false | |
300 // positives here. | |
301 if (!isset($change_list[$entity_type_id]['entity_type']) && $this->requiresFieldStorageSchemaChanges($storage_definition, $original_storage_definitions[$field_name])) { | |
302 $field_changes[$field_name] = static::DEFINITION_UPDATED; | |
303 } | |
304 } | |
305 | |
306 if ($field_changes) { | |
307 $change_list[$entity_type_id]['field_storage_definitions'] = $field_changes; | |
308 } | |
309 } | |
310 } | |
311 } | |
312 | |
313 // @todo Support deleting entity definitions when we support base field | |
314 // purging. See https://www.drupal.org/node/2282119. | |
315 | |
316 $this->entityManager->useCaches(TRUE); | |
317 | |
318 return array_filter($change_list); | |
319 } | |
320 | |
321 /** | |
322 * Checks if the changes to the entity type requires storage schema changes. | |
323 * | |
324 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type | |
325 * The updated entity type definition. | |
326 * @param \Drupal\Core\Entity\EntityTypeInterface $original | |
327 * The original entity type definition. | |
328 * | |
329 * @return bool | |
330 * TRUE if storage schema changes are required, FALSE otherwise. | |
331 */ | |
332 protected function requiresEntityStorageSchemaChanges(EntityTypeInterface $entity_type, EntityTypeInterface $original) { | |
333 $storage = $this->entityManager->getStorage($entity_type->id()); | |
334 return ($storage instanceof EntityStorageSchemaInterface) && $storage->requiresEntityStorageSchemaChanges($entity_type, $original); | |
335 } | |
336 | |
337 /** | |
338 * Checks if the changes to the storage definition requires schema changes. | |
339 * | |
340 * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition | |
341 * The updated field storage definition. | |
342 * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $original | |
343 * The original field storage definition. | |
344 * | |
345 * @return bool | |
346 * TRUE if storage schema changes are required, FALSE otherwise. | |
347 */ | |
348 protected function requiresFieldStorageSchemaChanges(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { | |
349 $storage = $this->entityManager->getStorage($storage_definition->getTargetEntityTypeId()); | |
350 return ($storage instanceof DynamicallyFieldableEntityStorageSchemaInterface) && $storage->requiresFieldStorageSchemaChanges($storage_definition, $original); | |
351 } | |
352 | |
353 } |