Mercurial > hg > isophonics-drupal-site
comparison core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\views\EventSubscriber; | |
4 | |
5 use Drupal\Core\Entity\EntityManagerInterface; | |
6 use Drupal\Core\Entity\EntityTypeEventSubscriberTrait; | |
7 use Drupal\Core\Entity\EntityTypeInterface; | |
8 use Drupal\Core\Entity\EntityTypeListenerInterface; | |
9 use Drupal\Core\Entity\Sql\SqlContentEntityStorage; | |
10 use Drupal\views\Views; | |
11 use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |
12 | |
13 /** | |
14 * Reacts to changes on entity types to update all views entities. | |
15 */ | |
16 class ViewsEntitySchemaSubscriber implements EntityTypeListenerInterface, EventSubscriberInterface { | |
17 | |
18 use EntityTypeEventSubscriberTrait; | |
19 | |
20 /** | |
21 * Indicates that a base table got renamed. | |
22 */ | |
23 const BASE_TABLE_RENAME = 0; | |
24 | |
25 /** | |
26 * Indicates that a data table got renamed. | |
27 */ | |
28 const DATA_TABLE_RENAME = 1; | |
29 | |
30 /** | |
31 * Indicates that a data table got added. | |
32 */ | |
33 const DATA_TABLE_ADDITION = 2; | |
34 | |
35 /** | |
36 * Indicates that a data table got removed. | |
37 */ | |
38 const DATA_TABLE_REMOVAL = 3; | |
39 | |
40 /** | |
41 * Indicates that a revision table got renamed. | |
42 */ | |
43 const REVISION_TABLE_RENAME = 4; | |
44 | |
45 /** | |
46 * Indicates that a revision table got added. | |
47 */ | |
48 const REVISION_TABLE_ADDITION = 5; | |
49 | |
50 /** | |
51 * Indicates that a revision table got removed. | |
52 */ | |
53 const REVISION_TABLE_REMOVAL = 6; | |
54 | |
55 /** | |
56 * Indicates that a revision data table got renamed. | |
57 */ | |
58 const REVISION_DATA_TABLE_RENAME = 7; | |
59 | |
60 /** | |
61 * Indicates that a revision data table got added. | |
62 */ | |
63 const REVISION_DATA_TABLE_ADDITION = 8; | |
64 | |
65 /** | |
66 * Indicates that a revision data table got removed. | |
67 */ | |
68 const REVISION_DATA_TABLE_REMOVAL = 9; | |
69 | |
70 /** | |
71 * The entity manager. | |
72 * | |
73 * @var \Drupal\Core\Entity\EntityManagerInterface | |
74 */ | |
75 protected $entityManager; | |
76 | |
77 /** | |
78 * Constructs a ViewsEntitySchemaSubscriber. | |
79 * | |
80 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager | |
81 * The entity manager. | |
82 */ | |
83 public function __construct(EntityManagerInterface $entity_manager) { | |
84 $this->entityManager = $entity_manager; | |
85 } | |
86 | |
87 /** | |
88 * {@inheritdoc} | |
89 */ | |
90 public static function getSubscribedEvents() { | |
91 return static::getEntityTypeEvents(); | |
92 } | |
93 | |
94 /** | |
95 * {@inheritdoc} | |
96 */ | |
97 public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original) { | |
98 $changes = []; | |
99 | |
100 // We implement a specific logic for table updates, which is bound to the | |
101 // default sql content entity storage. | |
102 if (!$this->entityManager->getStorage($entity_type->id()) instanceof SqlContentEntityStorage) { | |
103 return; | |
104 } | |
105 | |
106 if ($entity_type->getBaseTable() != $original->getBaseTable()) { | |
107 $changes[] = static::BASE_TABLE_RENAME; | |
108 } | |
109 | |
110 $revision_add = $entity_type->isRevisionable() && !$original->isRevisionable(); | |
111 $revision_remove = !$entity_type->isRevisionable() && $original->isRevisionable(); | |
112 $translation_add = $entity_type->isTranslatable() && !$original->isTranslatable(); | |
113 $translation_remove = !$entity_type->isTranslatable() && $original->isTranslatable(); | |
114 | |
115 if ($revision_add) { | |
116 $changes[] = static::REVISION_TABLE_ADDITION; | |
117 } | |
118 elseif ($revision_remove) { | |
119 $changes[] = static::REVISION_TABLE_REMOVAL; | |
120 } | |
121 elseif ($entity_type->isRevisionable() && $entity_type->getRevisionTable() != $original->getRevisionTable()) { | |
122 $changes[] = static::REVISION_TABLE_RENAME; | |
123 } | |
124 | |
125 if ($translation_add) { | |
126 $changes[] = static::DATA_TABLE_ADDITION; | |
127 } | |
128 elseif ($translation_remove) { | |
129 $changes[] = static::DATA_TABLE_REMOVAL; | |
130 } | |
131 elseif ($entity_type->isTranslatable() && $entity_type->getDataTable() != $original->getDataTable()) { | |
132 $changes[] = static::DATA_TABLE_RENAME; | |
133 } | |
134 | |
135 if ($entity_type->isRevisionable() && $entity_type->isTranslatable()) { | |
136 if ($revision_add || $translation_add) { | |
137 $changes[] = static::REVISION_DATA_TABLE_ADDITION; | |
138 } | |
139 elseif ($entity_type->getRevisionDataTable() != $original->getRevisionDataTable()) { | |
140 $changes[] = static::REVISION_DATA_TABLE_RENAME; | |
141 } | |
142 } | |
143 elseif ($original->isRevisionable() && $original->isTranslatable() && ($revision_remove || $translation_remove)) { | |
144 $changes[] = static::REVISION_DATA_TABLE_REMOVAL; | |
145 } | |
146 | |
147 // Stop here if no changes are needed. | |
148 if (empty($changes)) { | |
149 return; | |
150 } | |
151 | |
152 /** @var \Drupal\views\Entity\View[] $all_views */ | |
153 $all_views = $this->entityManager->getStorage('view')->loadMultiple(NULL); | |
154 | |
155 foreach ($changes as $change) { | |
156 switch ($change) { | |
157 case static::BASE_TABLE_RENAME: | |
158 $this->baseTableRename($all_views, $entity_type->id(), $original->getBaseTable(), $entity_type->getBaseTable()); | |
159 break; | |
160 case static::DATA_TABLE_RENAME: | |
161 $this->dataTableRename($all_views, $entity_type->id(), $original->getDataTable(), $entity_type->getDataTable()); | |
162 break; | |
163 case static::DATA_TABLE_ADDITION: | |
164 $this->dataTableAddition($all_views, $entity_type, $entity_type->getDataTable(), $entity_type->getBaseTable()); | |
165 break; | |
166 case static::DATA_TABLE_REMOVAL: | |
167 $this->dataTableRemoval($all_views, $entity_type->id(), $original->getDataTable(), $entity_type->getBaseTable()); | |
168 break; | |
169 case static::REVISION_TABLE_RENAME: | |
170 $this->baseTableRename($all_views, $entity_type->id(), $original->getRevisionTable(), $entity_type->getRevisionTable()); | |
171 break; | |
172 case static::REVISION_TABLE_ADDITION: | |
173 // If we add revision support we don't have to do anything. | |
174 break; | |
175 case static::REVISION_TABLE_REMOVAL: | |
176 $this->revisionRemoval($all_views, $original); | |
177 break; | |
178 case static::REVISION_DATA_TABLE_RENAME: | |
179 $this->dataTableRename($all_views, $entity_type->id(), $original->getRevisionDataTable(), $entity_type->getRevisionDataTable()); | |
180 break; | |
181 case static::REVISION_DATA_TABLE_ADDITION: | |
182 $this->dataTableAddition($all_views, $entity_type, $entity_type->getRevisionDataTable(), $entity_type->getRevisionTable()); | |
183 break; | |
184 case static::REVISION_DATA_TABLE_REMOVAL: | |
185 $this->dataTableRemoval($all_views, $entity_type->id(), $original->getRevisionDataTable(), $entity_type->getRevisionTable()); | |
186 break; | |
187 } | |
188 } | |
189 | |
190 foreach ($all_views as $view) { | |
191 // All changes done to the views here can be trusted and this might be | |
192 // called during updates, when it is not safe to rely on configuration | |
193 // containing valid schema. Trust the data and disable schema validation | |
194 // and casting. | |
195 $view->trustData()->save(); | |
196 } | |
197 } | |
198 | |
199 /** | |
200 * {@inheritdoc} | |
201 */ | |
202 public function onEntityTypeDelete(EntityTypeInterface $entity_type) { | |
203 $tables = [ | |
204 $entity_type->getBaseTable(), | |
205 $entity_type->getDataTable(), | |
206 $entity_type->getRevisionTable(), | |
207 $entity_type->getRevisionDataTable(), | |
208 ]; | |
209 | |
210 $all_views = $this->entityManager->getStorage('view')->loadMultiple(NULL); | |
211 /** @var \Drupal\views\Entity\View $view */ | |
212 foreach ($all_views as $id => $view) { | |
213 | |
214 // First check just the base table. | |
215 if (in_array($view->get('base_table'), $tables)) { | |
216 $view->disable(); | |
217 $view->save(); | |
218 } | |
219 } | |
220 } | |
221 | |
222 /** | |
223 * Applies a callable onto all handlers of all passed in views. | |
224 * | |
225 * @param \Drupal\views\Entity\View[] $all_views | |
226 * All views entities. | |
227 * @param callable $process | |
228 * A callable which retrieves a handler config array. | |
229 */ | |
230 protected function processHandlers(array $all_views, callable $process) { | |
231 foreach ($all_views as $view) { | |
232 foreach (array_keys($view->get('display')) as $display_id) { | |
233 $display = &$view->getDisplay($display_id); | |
234 foreach (Views::getHandlerTypes() as $handler_type) { | |
235 $handler_type = $handler_type['plural']; | |
236 if (!isset($display['display_options'][$handler_type])) { | |
237 continue; | |
238 } | |
239 foreach ($display['display_options'][$handler_type] as $id => &$handler_config) { | |
240 $process($handler_config); | |
241 if ($handler_config === NULL) { | |
242 unset($display['display_options'][$handler_type][$id]); | |
243 } | |
244 } | |
245 } | |
246 } | |
247 } | |
248 } | |
249 | |
250 /** | |
251 * Updates views if a base table is renamed. | |
252 * | |
253 * @param \Drupal\views\Entity\View[] $all_views | |
254 * All views. | |
255 * @param string $entity_type_id | |
256 * The entity type ID. | |
257 * @param string $old_base_table | |
258 * The old base table name. | |
259 * @param string $new_base_table | |
260 * The new base table name. | |
261 */ | |
262 protected function baseTableRename($all_views, $entity_type_id, $old_base_table, $new_base_table) { | |
263 foreach ($all_views as $view) { | |
264 if ($view->get('base_table') == $old_base_table) { | |
265 $view->set('base_table', $new_base_table); | |
266 } | |
267 } | |
268 | |
269 $this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $old_base_table, $new_base_table) { | |
270 if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id && $handler_config['table'] == $old_base_table) { | |
271 $handler_config['table'] = $new_base_table; | |
272 } | |
273 }); | |
274 } | |
275 | |
276 /** | |
277 * Updates views if a data table is renamed. | |
278 * | |
279 * @param \Drupal\views\Entity\View[] $all_views | |
280 * All views. | |
281 * @param string $entity_type_id | |
282 * The entity type ID. | |
283 * @param string $old_data_table | |
284 * The old data table name. | |
285 * @param string $new_data_table | |
286 * The new data table name. | |
287 */ | |
288 protected function dataTableRename($all_views, $entity_type_id, $old_data_table, $new_data_table) { | |
289 foreach ($all_views as $view) { | |
290 if ($view->get('base_table') == $old_data_table) { | |
291 $view->set('base_table', $new_data_table); | |
292 } | |
293 } | |
294 | |
295 $this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $old_data_table, $new_data_table) { | |
296 if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id && $handler_config['table'] == $old_data_table) { | |
297 $handler_config['table'] = $new_data_table; | |
298 } | |
299 }); | |
300 } | |
301 | |
302 /** | |
303 * Updates views if a data table is added. | |
304 * | |
305 * @param \Drupal\views\Entity\View[] $all_views | |
306 * All views. | |
307 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type | |
308 * The entity type. | |
309 * @param string $new_data_table | |
310 * The new data table. | |
311 * @param string $base_table | |
312 * The base table. | |
313 */ | |
314 protected function dataTableAddition($all_views, EntityTypeInterface $entity_type, $new_data_table, $base_table) { | |
315 /** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $storage */ | |
316 $entity_type_id = $entity_type->id(); | |
317 $storage = $this->entityManager->getStorage($entity_type_id); | |
318 $storage->setEntityType($entity_type); | |
319 $table_mapping = $storage->getTableMapping(); | |
320 $data_table_fields = $table_mapping->getFieldNames($new_data_table); | |
321 $base_table_fields = $table_mapping->getFieldNames($base_table); | |
322 | |
323 $data_table = $new_data_table; | |
324 | |
325 $this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $base_table, $data_table, $base_table_fields, $data_table_fields) { | |
326 if (isset($handler_config['entity_type']) && isset($handler_config['entity_field']) && $handler_config['entity_type'] == $entity_type_id) { | |
327 // Move all fields which just exists on the data table. | |
328 if ($handler_config['table'] == $base_table && in_array($handler_config['entity_field'], $data_table_fields) && !in_array($handler_config['entity_field'], $base_table_fields)) { | |
329 $handler_config['table'] = $data_table; | |
330 } | |
331 } | |
332 }); | |
333 } | |
334 | |
335 /** | |
336 * Updates views if a data table is removed. | |
337 * | |
338 * @param \Drupal\views\Entity\View[] $all_views | |
339 * All views. | |
340 * @param string $entity_type_id | |
341 * The entity type ID. | |
342 * @param string $old_data_table | |
343 * The name of the previous existing data table. | |
344 * @param string $base_table | |
345 * The name of the base table. | |
346 */ | |
347 protected function dataTableRemoval($all_views, $entity_type_id, $old_data_table, $base_table) { | |
348 // We move back the data table back to the base table. | |
349 $this->processHandlers($all_views, function (array &$handler_config) use ($entity_type_id, $old_data_table, $base_table) { | |
350 if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id) { | |
351 if ($handler_config['table'] == $old_data_table) { | |
352 $handler_config['table'] = $base_table; | |
353 } | |
354 } | |
355 }); | |
356 } | |
357 | |
358 /** | |
359 * Updates views if revision support is removed | |
360 * | |
361 * @param \Drupal\views\Entity\View[] $all_views | |
362 * All views. | |
363 * @param \Drupal\Core\Entity\EntityTypeInterface $original | |
364 * The origin entity type. | |
365 */ | |
366 protected function revisionRemoval($all_views, EntityTypeInterface $original) { | |
367 $revision_base_table = $original->getRevisionTable(); | |
368 $revision_data_table = $original->getRevisionDataTable(); | |
369 | |
370 foreach ($all_views as $view) { | |
371 if (in_array($view->get('base_table'), [$revision_base_table, $revision_data_table])) { | |
372 // Let's disable the views as we no longer support revisions. | |
373 $view->setStatus(FALSE); | |
374 } | |
375 | |
376 // For any kind of field, let's rely on the broken handler functionality. | |
377 } | |
378 } | |
379 | |
380 } |