5 * Post update functions for Views.
8 use Drupal\Core\Config\Entity\ConfigEntityUpdater;
9 use Drupal\Core\StringTranslation\TranslatableMarkup;
10 use Drupal\views\Entity\View;
11 use Drupal\views\Plugin\views\filter\NumericFilter;
12 use Drupal\views\Plugin\views\filter\StringFilter;
13 use Drupal\views\Views;
16 * Update the cacheability metadata for all views.
18 function views_post_update_update_cacheability_metadata() {
20 $views = \Drupal::entityManager()->getStorage('view')->loadMultiple();
22 /* @var \Drupal\views\Entity\View[] $views */
23 foreach ($views as $view) {
24 $displays = $view->get('display');
25 foreach (array_keys($displays) as $display_id) {
26 $display =& $view->getDisplay($display_id);
27 // Unset the cache_metadata key, so all cacheability metadata for the
28 // display is recalculated.
29 unset($display['cache_metadata']);
37 * Update some views fields that were previously duplicated.
39 function views_post_update_cleanup_duplicate_views_data() {
40 $config_factory = \Drupal::configFactory();
45 $revision_tables = [];
46 $entities_by_table = [];
47 $duplicate_fields = [];
48 $handler_types = Views::getHandlerTypes();
50 /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
51 $entity_type_manager = \Drupal::service('entity_type.manager');
52 // This will allow us to create an index of all entity types of the site.
53 foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) {
54 // Store the entity keyed by base table. If it has a data table, use that as
56 if ($data_table = $entity_type->getDataTable()) {
57 $entities_by_table[$data_table] = $entity_type;
59 if ($base_table = $entity_type->getBaseTable()) {
60 $entities_by_table[$base_table] = $entity_type;
63 // The following code basically contains the same kind of logic as
64 // \Drupal\Core\Entity\Sql\SqlContentEntityStorage::initTableLayout() to
65 // prefetch all tables (base, data, revision, and revision data).
66 $base_tables[$entity_type_id] = $entity_type->getBaseTable() ?: $entity_type->id();
67 $revisionable = $entity_type->isRevisionable();
71 $revision_table = $entity_type->getRevisionTable() ?: $entity_type->id() . '_revision';
73 $revision_tables[$entity_type_id] = $revision_table;
75 $translatable = $entity_type->isTranslatable();
77 // For example the data table just exists, when the entity type is
80 $data_table = $entity_type->getDataTable() ?: $entity_type->id() . '_field_data';
82 $data_tables[$entity_type_id] = $data_table;
84 $duplicate_fields[$entity_type_id] = array_intersect_key($entity_type->getKeys(), array_flip(['id', 'revision', 'bundle']));
87 foreach ($config_factory->listAll('views.view.') as $view_config_name) {
89 $view = $config_factory->getEditable($view_config_name);
91 $displays = $view->get('display');
92 if (isset($entities_by_table[$view->get('base_table')])) {
93 $entity_type = $entities_by_table[$view->get('base_table')];
94 $entity_type_id = $entity_type->id();
95 $data_table = $data_tables[$entity_type_id];
96 $base_table = $base_tables[$entity_type_id];
97 $revision_table = $revision_tables[$entity_type_id];
100 foreach ($displays as $display_name => &$display) {
101 foreach ($handler_types as $handler_type) {
102 if (!empty($display['display_options'][$handler_type['plural']])) {
103 foreach ($display['display_options'][$handler_type['plural']] as $field_name => &$field) {
104 $table = $field['table'];
105 if (($table === $base_table || $table === $revision_table) && in_array($field_name, $duplicate_fields[$entity_type_id])) {
106 $field['table'] = $data_table;
117 $view->set('display', $displays);
119 $ids[] = $view->get('id');
123 $message = new TranslatableMarkup('Updated tables for field handlers for views: @ids', ['@ids' => implode(', ', array_unique($ids))]);
130 * Include field formatter dependencies in a view when the formatter is used.
132 function views_post_update_field_formatter_dependencies() {
133 $views = View::loadMultiple();
134 array_walk($views, function (View $view) {
140 * Fix views with dependencies on taxonomy terms that don't exist.
142 function views_post_update_taxonomy_index_tid() {
143 $views = View::loadMultiple();
144 array_walk($views, function (View $view) {
145 $old_dependencies = $view->getDependencies();
146 $new_dependencies = $view->calculateDependencies()->getDependencies();
147 if ($old_dependencies !== $new_dependencies) {
154 * Fix views with serializer dependencies.
156 function views_post_update_serializer_dependencies() {
157 $views = View::loadMultiple();
158 array_walk($views, function (View $view) {
159 $old_dependencies = $view->getDependencies();
160 $new_dependencies = $view->calculateDependencies()->getDependencies();
161 if ($old_dependencies !== $new_dependencies) {
168 * Set all boolean filter values to strings.
170 function views_post_update_boolean_filter_values() {
171 $config_factory = \Drupal::configFactory();
172 foreach ($config_factory->listAll('views.view.') as $view_config_name) {
173 $view = $config_factory->getEditable($view_config_name);
175 foreach ($view->get('display') as $display_name => $display) {
176 if (isset($display['display_options']['filters'])) {
177 foreach ($display['display_options']['filters'] as $filter_name => $filter) {
178 if (isset($filter['plugin_id']) && $filter['plugin_id'] === 'boolean') {
180 // Update all boolean and integer values to strings.
181 if ($filter['value'] === TRUE || $filter['value'] === 1) {
184 elseif ($filter['value'] === FALSE || $filter['value'] === 0) {
187 if ($new_value !== FALSE) {
188 $view->set("display.$display_name.display_options.filters.$filter_name.value", $new_value);
202 * Rebuild caches to ensure schema changes are read in.
204 function views_post_update_grouped_filters() {
205 // Empty update to cause a cache rebuild so that the schema changes are read.
209 * Fix table names for revision metadata fields.
211 * @see https://www.drupal.org/node/2831499
213 function views_post_update_revision_metadata_fields() {
214 // The table names are fixed automatically in
215 // \Drupal\views\Entity\View::preSave(), so we just need to re-save all views.
216 $views = View::loadMultiple();
217 array_walk($views, function (View $view) {
223 * Add additional settings to the entity link field and convert node_path usage
226 function views_post_update_entity_link_url() {
228 $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
230 /* @var \Drupal\views\Entity\View[] $views */
231 foreach ($views as $view) {
232 $displays = $view->get('display');
234 foreach ($displays as $display_name => &$display) {
235 if (isset($display['display_options']['fields'])) {
236 foreach ($display['display_options']['fields'] as $field_name => &$field) {
237 if (isset($field['plugin_id']) && $field['plugin_id'] === 'entity_link') {
238 // Add any missing settings for entity_link.
239 if (!isset($field['output_url_as_text'])) {
240 $field['output_url_as_text'] = FALSE;
243 if (!isset($field['absolute'])) {
244 $field['absolute'] = FALSE;
248 elseif (isset($field['plugin_id']) && $field['plugin_id'] === 'node_path') {
249 // Convert the use of node_path to entity_link.
250 $field['plugin_id'] = 'entity_link';
251 $field['field'] = 'view_node';
252 $field['output_url_as_text'] = TRUE;
259 $view->set('display', $displays);
266 * Update dependencies for moved bulk field plugin.
268 function views_post_update_bulk_field_moved() {
269 $views = View::loadMultiple();
270 array_walk($views, function (View $view) {
271 $old_dependencies = $view->getDependencies();
272 $new_dependencies = $view->calculateDependencies()->getDependencies();
273 if ($old_dependencies !== $new_dependencies) {
280 * Add placeholder settings to string or numeric filters.
282 function views_post_update_filter_placeholder_text() {
284 $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
285 /** @var \Drupal\views\Plugin\ViewsHandlerManager $filter_manager */
286 $filter_manager = \Drupal::service('plugin.manager.views.filter');
288 /* @var \Drupal\views\Entity\View[] $views */
289 foreach ($views as $view) {
290 $displays = $view->get('display');
292 foreach ($displays as $display_name => &$display) {
293 if (isset($display['display_options']['filters'])) {
294 foreach ($display['display_options']['filters'] as $filter_name => &$filter) {
295 // Any of the children of the modified classes will also be inheriting
297 $filter_instance = $filter_manager->getHandler($filter);
298 if ($filter_instance instanceof StringFilter) {
299 if (!isset($filter['expose']['placeholder'])) {
300 $filter['expose']['placeholder'] = '';
304 elseif ($filter_instance instanceof NumericFilter) {
305 if (!isset($filter['expose']['placeholder'])) {
306 $filter['expose']['placeholder'] = '';
309 if (!isset($filter['expose']['min_placeholder'])) {
310 $filter['expose']['min_placeholder'] = '';
313 if (!isset($filter['expose']['max_placeholder'])) {
314 $filter['expose']['max_placeholder'] = '';
322 $view->set('display', $displays);
329 * Include views data table provider in views dependencies.
331 function views_post_update_views_data_table_dependencies(&$sandbox = NULL) {
332 $storage = \Drupal::entityTypeManager()->getStorage('view');
333 if (!isset($sandbox['views'])) {
334 $sandbox['views'] = $storage->getQuery()->accessCheck(FALSE)->execute();
335 $sandbox['count'] = count($sandbox['views']);
338 // Process 10 views at a time.
339 $views = $storage->loadMultiple(array_splice($sandbox['views'], 0, 10));
340 foreach ($views as $view) {
341 $original_dependencies = $view->getDependencies();
342 // Only re-save if dependencies have changed.
343 if ($view->calculateDependencies()->getDependencies() !== $original_dependencies) {
344 // We can trust the data because we've already recalculated the
351 $sandbox['#finished'] = empty($sandbox['views']) ? 1 : ($sandbox['count'] - count($sandbox['views'])) / $sandbox['count'];
355 * Fix cache max age for table displays.
357 function views_post_update_table_display_cache_max_age(&$sandbox = NULL) {
358 \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) {
359 /** @var \Drupal\views\ViewEntityInterface $view */
360 $displays = $view->get('display');
361 foreach ($displays as $display_name => &$display) {
362 if (isset($display['display_options']['style']['type']) && $display['display_options']['style']['type'] === 'table') {