commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / admin_views / plugins / views_plugin_display_system.inc
1 <?php
2
3 /**
4 * @file
5 * System display plugin.
6 */
7
8 /**
9 * Plugin to handle replacement of existing system paths.
10 *
11 * The System display is mostly identical to Views' native Page display. The
12 * only differences are:
13 * - No menu link options.
14 * - No tab/local task options.
15 * These options make no sense, because the System display is supposed to
16 * replace the main page output of an existing system path only. This plugin
17 * code should therefore always be kept in sync with the Page display plugin
18 * code (excluding the support code for the removed functionality).
19 *
20 * @see views_plugin_display_page
21 *
22 * To achieve a correct replacement of an existing system path,
23 * execute_hook_menu() performs some advanced processing on menu router
24 * definitions to account for possible child router items that would normally
25 * inherit properties of the original system path.
26 *
27 * @see views_plugin_display_system::execute_hook_menu()
28 *
29 * @ingroup views_display_plugins
30 */
31 class views_plugin_display_system extends views_plugin_display {
32
33 /**
34 * The system display requires a path.
35 */
36 function has_path() {
37 return TRUE;
38 }
39
40 /**
41 * The system display uses breadcrumbs.
42 */
43 function uses_breadcrumb() {
44 return TRUE;
45 }
46
47 /**
48 * Overrides views_plugin_display::option_definition().
49 */
50 function option_definition() {
51 $options = parent::option_definition();
52
53 $options['path'] = array(
54 'default' => '',
55 );
56
57 // Override the access plugin to always enforce views_plugin_access_menu.
58 // The UI widget for configuring access is additionally hidden.
59 // @see options_summary()
60 $options['defaults']['default']['access'] = FALSE;
61 $options['access'] = array(
62 'default' => array(
63 'type' => 'menu',
64 ),
65 );
66
67 return $options;
68 }
69
70 /**
71 * Overrides views_plugin_display::options_summary().
72 */
73 function options_summary(&$categories, &$options) {
74 parent::options_summary($categories, $options);
75
76 $categories['system'] = array(
77 'title' => t('System path settings'),
78 );
79
80 // Disable the access plugin configuration in the UI.
81 // @see option_definition()
82 $categories['access']['build']['#access'] = FALSE;
83
84 $path = strip_tags('/' . $this->get_option('path'));
85 if (empty($path)) {
86 $path = t('None');
87 }
88
89 $options['path'] = array(
90 'category' => 'system',
91 'title' => t('Path'),
92 'value' => views_ui_truncate($path, 24),
93 );
94 }
95
96 /**
97 * Overrides views_plugin_display::options_form().
98 */
99 function options_form(&$form, &$form_state) {
100 parent::options_form($form, $form_state);
101
102 switch ($form_state['section']) {
103 case 'path':
104 $form['#title'] .= t('An existing menu path this view replaces');
105 $form['path'] = array(
106 '#type' => 'textfield',
107 '#description' => t('This view replaces this path on your site. You may use "%" in your URL to represent values that will be used for contextual filters. For example: "node/%/feed".'),
108 '#default_value' => $this->get_option('path'),
109 '#field_prefix' => '<span dir="ltr">' . url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
110 '#field_suffix' => '</span>&lrm;',
111 '#attributes' => array('dir' => 'ltr'),
112 );
113 break;
114 }
115 }
116
117 /**
118 * Overrides views_plugin_display::options_validate().
119 */
120 function options_validate(&$form, &$form_state) {
121 parent::options_validate($form, $form_state);
122
123 switch ($form_state['section']) {
124 case 'path':
125 if (strpos($form_state['values']['path'], '$arg') !== FALSE) {
126 form_error($form['path'], t('"$arg" is no longer supported. Use % instead.'));
127 }
128
129 if (strpos($form_state['values']['path'], '%') === 0) {
130 form_error($form['path'], t('"%" may not be used for the first segment of a path.'));
131 }
132 // Automatically remove '/' from path.
133 $form_state['values']['path'] = trim($form_state['values']['path'], '/');
134 break;
135 }
136 }
137
138 /**
139 * Overrides views_plugin_display::options_submit().
140 */
141 function options_submit(&$form, &$form_state) {
142 parent::options_submit($form, $form_state);
143
144 switch ($form_state['section']) {
145 case 'path':
146 $this->set_option('path', $form_state['values']['path']);
147 break;
148 }
149 }
150
151 /**
152 * Add this display's path information to Drupal's menu system.
153 *
154 * @param array $callbacks
155 * All existing menu router items defined by modules. Taken by reference, in
156 * order to adjust any possibly existing child router items of the replaced
157 * system path. (This method only returns new router items normally.)
158 */
159 function execute_hook_menu(&$callbacks) {
160 $items = array();
161
162 // Replace % with the link to our standard views argument loader
163 // views_arg_load().
164 $bits = explode('/', $this->get_option('path'));
165 $page_arguments = array($this->view->name, $this->display->id);
166 $this->view->init_handlers();
167 $view_arguments = $this->view->argument;
168
169 // Replace % with %views_arg for menu autoloading and add to the
170 // page arguments so the argument actually comes through.
171 foreach ($bits as $pos => $bit) {
172 if ($bit == '%') {
173 $argument = array_shift($view_arguments);
174 if (!empty($argument->options['specify_validation']) && $argument->options['validate']['type'] != 'none') {
175 $bits[$pos] = '%views_arg';
176 }
177 $page_arguments[] = $pos;
178 }
179 }
180
181 $path = implode('/', $bits);
182 if (!$path) {
183 return $items;
184 }
185
186 // Only existing system paths can be replaced.
187 if (!isset($callbacks[$path])) {
188 // However, if the specified path contains dynamic argument placeholders,
189 // then we need to search more carefully.
190 $views_path = $this->get_option('path');
191 if (strpos($views_path, '%') !== FALSE) {
192 $views_path = preg_quote($views_path, '@');
193 $views_path = strtr($views_path, array('%' => '%[^/]*'));
194 $result = preg_grep('@^' . $views_path . '$@', array_keys($callbacks));
195 if ($result) {
196 $parent_path = reset($result);
197 $parent = &$callbacks[$parent_path];
198 }
199 else {
200 return $items;
201 }
202 }
203 // No dynamic placeholders found, so nothing can be replaced.
204 else {
205 return $items;
206 }
207 }
208 else {
209 $parent = &$callbacks[$path];
210 }
211
212 // Work out whether we need to get the access callback and arguments from
213 // the parent item.
214 $default_map = array(
215 'access callback' => 'user_access',
216 'access arguments' => array(),
217 );
218
219 foreach ($default_map as $menu_key => &$default) {
220 // Override the default if we can. Otherwise this will use the defaults
221 // above.
222 if (!empty($callbacks[$path][$menu_key])) {
223 $default = $callbacks[$path][$menu_key];
224 }
225 elseif (!empty($parent[$menu_key])) {
226 $default = $parent[$menu_key];
227 }
228 }
229
230 $items[$path] = array(
231 // default views page entry
232 'page callback' => 'views_page',
233 'page arguments' => $page_arguments,
234 // Take over the access definition from the original router item.
235 // @see option_definition()
236 // @see views_plugin_access_menu
237 'access callback' => $default_map['access callback'],
238 'access arguments' => $default_map['access arguments'],
239 // Identify URL embedded arguments and correlate them to a handler
240 'load arguments' => array($this->view->name, $this->display->id, '%index'),
241 );
242
243 // List of router item default property values, which are inherited to
244 // children. These default values are only applied if the original parent
245 // item does not define them (see below).
246 // @see _menu_router_build()
247 $defaults = array(
248 'access callback' => 'user_access',
249 'menu_name' => NULL,
250 'file' => NULL,
251 'file path' => NULL,
252 'delivery callback' => NULL,
253 'theme callback' => NULL,
254 'theme arguments' => array(),
255 );
256
257 // Grep all router items below the target path.
258 $num_parent_parts = count(explode('/', $path));
259 $children = preg_grep('@^' . preg_quote($path, '@') . '/@', array_keys($callbacks));
260
261 // Ensure correct inheritance of properties on the original parent path
262 // (being replaced) to child items.
263 foreach ($children as $child_path) {
264 // Only apply property inheritance to direct children of the parent path.
265 $num_child_parts = count(explode('/', $child_path));
266 if ($num_parent_parts == $num_child_parts - 1) {
267 // Check if the child router item is a views page. If so, there are
268 // default properties we do not want this item to inherit.
269 if (isset($callbacks[$child_path]['page callback']) && ($callbacks[$child_path]['page callback'] === 'views_page')) {
270 continue;
271 }
272 $child = &$callbacks[$child_path];
273 // Get these first, as we want to know if they existed before parent and
274 // default values are merged.
275 $file = isset($child['file']);
276 $access_callback = isset($child['access callback']);
277 // Copy all properties from the original parent that will be replaced
278 // with new values.
279 // This typically resets 'access arguments', etc.
280 $child += array_intersect_key($parent, $items[$path]);
281 // Copy all properties from the original parent, for which the router
282 // system would inherit parent values or fill in default values.
283 // This typically adds back 'file' and other properties defined on the
284 // parent but not on $items[$path]. (The two operations could be
285 // combined with $items[$path] + $defaults, but are separated for
286 // documentation purposes and clarity.)
287 $child += array_intersect_key($parent, $defaults);
288 // Unset the child 'file' property if its implementing module doesn't
289 // match it's parent and it didn't have a 'file' preoperty specified
290 // before. Otherwise, for example, example_module could inherit a 'file'
291 // property of 'node.admin.inc', so the actual include path would be
292 // something like .../modules/example_module/node.admin.inc.
293 if (!$file && isset($child['module'], $parent['module']) && ($child['module'] != $parent['module'])) {
294 unset($child['file']);
295 }
296 // The access callback should only be inherited for default local tasks.
297 // Ensure it hasn't been mistakenly set.
298 if (!$access_callback && (!isset($child['type']) || $child['type'] != MENU_DEFAULT_LOCAL_TASK)) {
299 unset($child['access callback']);
300 }
301 // Last catch-22, insert new default properties and their default values
302 // for the child, which may not be defined on the original parent.
303 // This typically inserts 'access callback', which can be omitted in
304 // router item definitions and only gets a default of user_access() in
305 // the final _menu_router_build(). Without this, the new access callback
306 // views_access() in $items[$path] would be inherited to all children.
307 $child += $defaults;
308 }
309 }
310
311 // If the original parent path already existed, copy over its remaining
312 // properties.
313 $items[$path] += $parent;
314
315 return $items;
316 }
317
318 /**
319 * Overrides views_plugin_display::execute().
320 *
321 * Build and render the page view.
322 *
323 * Since we replace an existing page, we need to invoke views_set_page_view().
324 * Also set the page title, because original page callbacks might do this.
325 */
326 function execute() {
327 // Let the world know that this is the page view we're using.
328 views_set_page_view($this->view);
329
330 // Prior to this being called, the $view should already be set to this
331 // display, and arguments should be set on the view.
332 $this->view->build();
333 if (!empty($this->view->build_info['fail'])) {
334 return drupal_not_found();
335 }
336
337 if (!empty($this->view->build_info['denied'])) {
338 return drupal_access_denied();
339 }
340
341 drupal_add_css(drupal_get_path('module', 'admin_views') . '/admin_views.css');
342
343 return $this->view->render();
344 }
345
346 /**
347 * Overrides views_plugin_display::get_argument_text().
348 */
349 function get_argument_text() {
350 return array(
351 'filter value not present' => t('When the filter value is <em>NOT</em> in the URL'),
352 'filter value present' => t('When the filter value <em>IS</em> in the URL or a default is provided'),
353 'description' => t('The contextual filter values is provided by the URL.'),
354 );
355 }
356
357 }