Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / views_ui / views_ui.module
1 <?php
2
3 /**
4  * @file
5  * Provide structure for the administrative interface to Views.
6  */
7
8 use Drupal\Component\Utility\Unicode;
9 use Drupal\Core\Routing\RouteMatchInterface;
10 use Drupal\Core\Url;
11 use Drupal\views\ViewExecutable;
12 use Drupal\views\Analyzer;
13
14 /**
15  * Implements hook_help().
16  */
17 function views_ui_help($route_name, RouteMatchInterface $route_match) {
18   switch ($route_name) {
19     case 'help.page.views_ui':
20       $output = '';
21       $output .= '<h3>' . t('About') . '</h3>';
22       $output .= '<p>' . t('The Views UI module provides an interface for managing views for the <a href=":views">Views module</a>. For more information, see the <a href=":handbook">online documentation for the Views UI module</a>.', [':views' => \Drupal::url('help.page', ['name' => 'views']), ':handbook' => 'https://www.drupal.org/documentation/modules/views_ui']) . '</p>';
23       $output .= '<h3>' . t('Uses') . '</h3>';
24       $output .= '<dl>';
25       $output .= '<dt>' . t('Creating and managing views') . '</dt>';
26       $output .= '<dd>' . t('Views can be created from the <a href=":list">Views list page</a> by using the "Add view" action. Existing views can be managed from the <a href=":list">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".', [':list' => \Drupal::url('entity.view.collection', ['name' => 'views_ui'])]) . '</dd>';
27       $output .= '<dt>' . t('Enabling and disabling views') . '<dt>';
28       $output .= '<dd>' . t('Views can be enabled or disabled from the <a href=":list">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.', [':list' => \Drupal::url('entity.view.collection', ['name' => 'views_ui'])]) . '</dd>';
29       $output .= '<dt>' . t('Exporting and importing views') . '</dt>';
30       $output .= '<dd>' . t('Views can be exported and imported as configuration files by using the <a href=":config">Configuration Manager module</a>.', [':config' => (\Drupal::moduleHandler()->moduleExists('config')) ? \Drupal::url('help.page', ['name' => 'config']) : '#']) . '</dd>';
31       $output .= '</dl>';
32       return $output;
33   }
34 }
35
36 /**
37  * Implements hook_entity_type_build().
38  */
39 function views_ui_entity_type_build(array &$entity_types) {
40   /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
41   $entity_types['view']
42     ->setFormClass('edit', 'Drupal\views_ui\ViewEditForm')
43     ->setFormClass('add', 'Drupal\views_ui\ViewAddForm')
44     ->setFormClass('preview', 'Drupal\views_ui\ViewPreviewForm')
45     ->setFormClass('duplicate', 'Drupal\views_ui\ViewDuplicateForm')
46     ->setFormClass('delete', 'Drupal\Core\Entity\EntityDeleteForm')
47     ->setFormClass('break_lock', 'Drupal\views_ui\Form\BreakLockForm')
48     ->setListBuilderClass('Drupal\views_ui\ViewListBuilder')
49     ->setLinkTemplate('edit-form', '/admin/structure/views/view/{view}')
50     ->setLinkTemplate('edit-display-form', '/admin/structure/views/view/{view}/edit/{display_id}')
51     ->setLinkTemplate('preview-form', '/admin/structure/views/view/{view}/preview/{display_id}')
52     ->setLinkTemplate('duplicate-form', '/admin/structure/views/view/{view}/duplicate')
53     ->setLinkTemplate('delete-form', '/admin/structure/views/view/{view}/delete')
54     ->setLinkTemplate('enable', '/admin/structure/views/view/{view}/enable')
55     ->setLinkTemplate('disable', '/admin/structure/views/view/{view}/disable')
56     ->setLinkTemplate('break-lock-form', '/admin/structure/views/view/{view}/break-lock')
57     ->setLinkTemplate('collection', '/admin/structure/views');
58 }
59
60 /**
61  * Implements hook_theme().
62  */
63 function views_ui_theme() {
64   return [
65     // edit a view
66     'views_ui_display_tab_setting' => [
67       'variables' => ['description' => '', 'link' => '', 'settings_links' => [], 'overridden' => FALSE, 'defaulted' => FALSE, 'description_separator' => TRUE, 'class' => []],
68       'file' => 'views_ui.theme.inc',
69     ],
70     'views_ui_display_tab_bucket' => [
71       'render element' => 'element',
72       'file' => 'views_ui.theme.inc',
73     ],
74     'views_ui_rearrange_filter_form' => [
75       'render element' => 'form',
76       'file' => 'views_ui.theme.inc',
77     ],
78     'views_ui_expose_filter_form' => [
79       'render element' => 'form',
80       'file' => 'views_ui.theme.inc',
81     ],
82
83     // Legacy theme hook for displaying views info.
84     'views_ui_view_info' => [
85       'variables' => ['view' => NULL, 'displays' => NULL],
86       'file' => 'views_ui.theme.inc',
87     ],
88
89     // List views.
90     'views_ui_views_listing_table' => [
91       'variables' => [
92         'headers' => NULL,
93         'rows' => NULL,
94         'attributes' => [],
95       ],
96       'file' => 'views_ui.theme.inc',
97     ],
98     'views_ui_view_displays_list' => [
99       'variables' => ['displays' => []],
100     ],
101
102     // Group of filters.
103     'views_ui_build_group_filter_form' => [
104       'render element' => 'form',
105       'file' => 'views_ui.theme.inc',
106     ],
107
108     // On behalf of a plugin
109     'views_ui_style_plugin_table' => [
110       'render element' => 'form',
111       'file' => 'views_ui.theme.inc',
112     ],
113
114     // When previewing a view.
115     'views_ui_view_preview_section' => [
116       'variables' => ['view' => NULL, 'section' => NULL, 'content' => NULL, 'links' => ''],
117       'file' => 'views_ui.theme.inc',
118     ],
119
120     // Generic container wrapper, to use instead of theme_container when an id
121     // is not desired.
122     'views_ui_container' => [
123       'variables' => ['children' => NULL, 'attributes' => []],
124       'file' => 'views_ui.theme.inc',
125     ],
126   ];
127 }
128
129 /**
130  * Implements hook_preprocess_HOOK() for views templates.
131  */
132 function views_ui_preprocess_views_view(&$variables) {
133   $view = $variables['view'];
134
135   // Render title for the admin preview.
136   if (!empty($view->live_preview)) {
137     $variables['title'] = [
138       '#markup' => $view->getTitle()
139     ];
140   }
141
142   if (!empty($view->live_preview) && \Drupal::moduleHandler()->moduleExists('contextual')) {
143     $view->setShowAdminLinks(FALSE);
144     foreach (['title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before'] as $section) {
145       if (!empty($variables[$section])) {
146         $variables[$section] = [
147           '#theme' => 'views_ui_view_preview_section',
148           '#view' => $view,
149           '#section' => $section,
150           '#content' => $variables[$section],
151           '#theme_wrappers' => ['views_ui_container'],
152           '#attributes' => ['class' => ['contextual-region']],
153         ];
154       }
155     }
156   }
157 }
158
159 /**
160  * Returns contextual links for each handler of a certain section.
161  *
162  * @TODO
163  *   Bring in relationships
164  *   Refactor this function to use much stuff of views_ui_edit_form_get_bucket.
165  *
166  * @param $title
167  *   Add a bolded title of this section.
168  */
169 function views_ui_view_preview_section_handler_links(ViewExecutable $view, $type, $title = FALSE) {
170   $display = $view->display_handler->display;
171   $handlers = $view->display_handler->getHandlers($type);
172   $links = [];
173
174   $types = ViewExecutable::getHandlerTypes();
175   if ($title) {
176     $links[$type . '-title'] = [
177       'title' => $types[$type]['title'],
178     ];
179   }
180
181   foreach ($handlers as $id => $handler) {
182     $field_name = $handler->adminLabel(TRUE);
183     $links[$type . '-edit-' . $id] = [
184       'title' => t('Edit @section', ['@section' => $field_name]),
185       'url' => Url::fromRoute('views_ui.form_handler', ['js' => 'nojs', 'view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type, 'id' => $id]),
186       'attributes' => ['class' => ['views-ajax-link']],
187     ];
188   }
189   $links[$type . '-add'] = [
190     'title' => t('Add new'),
191     'url' => Url::fromRoute('views_ui.form_add_handler', ['js' => 'nojs', 'view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type]),
192     'attributes' => ['class' => ['views-ajax-link']],
193   ];
194
195   return $links;
196 }
197
198 /**
199  * Returns a link to editing a certain display setting.
200  */
201 function views_ui_view_preview_section_display_category_links(ViewExecutable $view, $type, $title) {
202   $display = $view->display_handler->display;
203   $links = [
204     $type . '-edit' => [
205       'title' => t('Edit @section', ['@section' => $title]),
206       'url' => Url::fromRoute('views_ui.form_display', ['js' => 'nojs', 'view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type]),
207       'attributes' => ['class' => ['views-ajax-link']],
208     ],
209   ];
210
211   return $links;
212 }
213
214 /**
215  * Returns all contextual links for the main content part of the view.
216  */
217 function views_ui_view_preview_section_rows_links(ViewExecutable $view) {
218   $links = [];
219   $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE));
220   $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE));
221   $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE));
222   $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'argument', TRUE));
223   $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'relationship', TRUE));
224
225   return $links;
226 }
227
228 /**
229  * Implements hook_views_plugins_display_alter().
230  */
231 function views_ui_views_plugins_display_alter(&$plugins) {
232   // Attach contextual links to each display plugin. The links will point to
233   // paths underneath "admin/structure/views/view/{$view->id()}" (i.e., paths
234   // for editing and performing other contextual actions on the view).
235   foreach ($plugins as &$display) {
236     $display['contextual links']['entity.view.edit_form'] = [
237       'route_name' => 'entity.view.edit_form',
238       'route_parameters_names' => ['view' => 'id'],
239     ];
240   }
241 }
242
243 /**
244  * Implements hook_contextual_links_view_alter().
245  */
246 function views_ui_contextual_links_view_alter(&$element, $items) {
247   // Remove contextual links from being rendered, when so desired, such as
248   // within a View preview.
249   if (views_ui_contextual_links_suppress()) {
250     $element['#links'] = [];
251   }
252   // Append the display ID to the Views UI edit links, so that clicking on the
253   // contextual link takes you directly to the correct display tab on the edit
254   // screen.
255   elseif (!empty($element['#links']['entityviewedit-form'])) {
256     $display_id = $items['entity.view.edit_form']['metadata']['display_id'];
257     $route_parameters = $element['#links']['entityviewedit-form']['url']->getRouteParameters() + ['display_id' => $display_id];
258     $element['#links']['entityviewedit-form']['url'] = Url::fromRoute('entity.view.edit_display_form', $route_parameters);
259   }
260 }
261
262 /**
263  * Sets a static variable for controlling whether contextual links are rendered.
264  *
265  * @see views_ui_contextual_links_view_alter()
266  */
267 function views_ui_contextual_links_suppress($set = NULL) {
268   $suppress = &drupal_static(__FUNCTION__);
269   if (isset($set)) {
270     $suppress = $set;
271   }
272   return $suppress;
273 }
274
275 /**
276  * Increments the views_ui_contextual_links_suppress() static variable.
277  *
278  * When this function is added to the #pre_render of an element, and
279  * 'views_ui_contextual_links_suppress_pop' is added to the #post_render of the
280  * same element, then all contextual links within the element and its
281  * descendants are suppressed from being rendered. This is used, for example,
282  * during a View preview, when it is not desired for nodes in the Views result
283  * to have contextual links.
284  *
285  * @see views_ui_contextual_links_suppress_pop()
286  */
287 function views_ui_contextual_links_suppress_push() {
288   views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) + 1);
289 }
290
291 /**
292  * Decrements the views_ui_contextual_links_suppress() static variable.
293  *
294  * @see views_ui_contextual_links_suppress_push()
295  */
296 function views_ui_contextual_links_suppress_pop() {
297   views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) - 1);
298 }
299
300 /**
301  * Implements hook_views_analyze().
302  *
303  * This is the basic views analysis that checks for very minimal problems.
304  * There are other analysis tools in core specific sections, such as
305  * node.views.inc as well.
306  */
307 function views_ui_views_analyze(ViewExecutable $view) {
308   $ret = [];
309   // Check for something other than the default display:
310   if (count($view->displayHandlers) < 2) {
311     $ret[] = Analyzer::formatMessage(t('This view has only a default display and therefore will not be placed anywhere on your site; perhaps you want to add a page or a block display.'), 'warning');
312   }
313   // You can give a page display the same path as an alias existing in the
314   // system, so the alias will not work anymore. Report this to the user,
315   // because he probably wanted something else.
316   foreach ($view->displayHandlers as $display) {
317     if (empty($display)) {
318       continue;
319     }
320     if ($display->hasPath() && $path = $display->getOption('path')) {
321       $normal_path = \Drupal::service('path.alias_manager')->getPathByAlias($path);
322       if ($path != $normal_path) {
323         $ret[] = Analyzer::formatMessage(t('You have configured display %display with a path which is an path alias as well. This might lead to unwanted effects so better use an internal path.', ['%display' => $display->display['display_title']]), 'warning');
324       }
325     }
326   }
327
328   return $ret;
329 }
330
331 /**
332  * Truncate strings to a set length and provide a '...' if they truncated.
333  *
334  * This is often used in the UI to ensure long strings fit.
335  */
336 function views_ui_truncate($string, $length) {
337   if (Unicode::strlen($string) > $length) {
338     $string = Unicode::substr($string, 0, $length);
339     $string .= '...';
340   }
341
342   return $string;
343 }