root / drupal7 / sites / all / modules / views / plugins / views_wizard / views_ui_base_views_wizard.class.php @ 5d12d676
1 |
<?php
|
---|---|
2 |
|
3 |
/**
|
4 |
* @file
|
5 |
* Provides the interface and base class for Views Wizard plugins.
|
6 |
*/
|
7 |
|
8 |
/**
|
9 |
* Defines a common interface for Views Wizard plugins.
|
10 |
*/
|
11 |
interface ViewsWizardInterface { |
12 |
|
13 |
/**
|
14 |
* Constructor.
|
15 |
*/
|
16 |
function __construct($plugin); |
17 |
|
18 |
/**
|
19 |
* For AJAX callbacks to build other elements in the "show" form.
|
20 |
*/
|
21 |
function build_form($form, &$form_state); |
22 |
|
23 |
/**
|
24 |
* Validate form and values.
|
25 |
*
|
26 |
* @return an array of form errors.
|
27 |
*/
|
28 |
function validate($form, &$form_state); |
29 |
|
30 |
/**
|
31 |
* Create a new View from form values.
|
32 |
*
|
33 |
* @return a view object.
|
34 |
*
|
35 |
* @throws ViewsWizardException in the event of a problem.
|
36 |
*/
|
37 |
function create_view($form, &$form_state); |
38 |
|
39 |
} |
40 |
|
41 |
/**
|
42 |
* A custom exception class for our errors.
|
43 |
*/
|
44 |
class ViewsWizardException extends Exception { |
45 |
} |
46 |
|
47 |
/**
|
48 |
* A very generic Views Wizard class - can be constructed for any base table.
|
49 |
*/
|
50 |
class ViewsUiBaseViewsWizard implements ViewsWizardInterface { |
51 |
|
52 |
protected $base_table; |
53 |
protected $entity_type; |
54 |
protected $entity_info = array(); |
55 |
protected $validated_views = array(); |
56 |
protected $plugin = array(); |
57 |
protected $filter_defaults = array( |
58 |
'id' => NULL, |
59 |
'expose' => array('operator' => FALSE), |
60 |
'group' => 1, |
61 |
); |
62 |
|
63 |
function __construct($plugin) { |
64 |
$this->base_table = $plugin['base_table']; |
65 |
$default = $this->filter_defaults; |
66 |
|
67 |
if (isset($plugin['filters'])) { |
68 |
foreach ($plugin['filters'] as $name => $info) { |
69 |
$default['id'] = $name; |
70 |
$plugin['filters'][$name] = $info + $default; |
71 |
} |
72 |
} |
73 |
|
74 |
$this->plugin = $plugin; |
75 |
|
76 |
$entities = entity_get_info();
|
77 |
foreach ($entities as $entity_type => $entity_info) { |
78 |
if (isset($entity_info['base table']) && $this->base_table == $entity_info['base table']) { |
79 |
$this->entity_info = $entity_info; |
80 |
$this->entity_type = $entity_type; |
81 |
} |
82 |
} |
83 |
} |
84 |
|
85 |
function build_form($form, &$form_state) { |
86 |
$style_options = views_fetch_plugin_names('style', 'normal', array($this->base_table)); |
87 |
$feed_row_options = views_fetch_plugin_names('row', 'feed', array($this->base_table)); |
88 |
$path_prefix = url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='); |
89 |
|
90 |
// Add filters and sorts which apply to the view as a whole.
|
91 |
$this->build_filters($form, $form_state); |
92 |
$this->build_sorts($form, $form_state); |
93 |
|
94 |
$form['displays']['page'] = array( |
95 |
'#type' => 'fieldset', |
96 |
'#attributes' => array('class' => array('views-attachment', 'fieldset-no-legend')), |
97 |
'#tree' => TRUE, |
98 |
); |
99 |
$form['displays']['page']['create'] = array( |
100 |
'#title' => t('Create a page'), |
101 |
'#type' => 'checkbox', |
102 |
'#attributes' => array('class' => array('strong')), |
103 |
'#default_value' => TRUE, |
104 |
'#id' => 'edit-page-create', |
105 |
); |
106 |
|
107 |
// All options for the page display are included in this container so they
|
108 |
// can be hidden en masse when the "Create a page" checkbox is unchecked.
|
109 |
$form['displays']['page']['options'] = array( |
110 |
'#type' => 'container', |
111 |
'#attributes' => array('class' => array('options-set')), |
112 |
'#dependency' => array( |
113 |
'edit-page-create' => array(1), |
114 |
), |
115 |
'#pre_render' => array('ctools_dependent_pre_render'), |
116 |
'#prefix' => '<div><div id="edit-page-wrapper">', |
117 |
'#suffix' => '</div></div>', |
118 |
'#parents' => array('page'), |
119 |
); |
120 |
|
121 |
$form['displays']['page']['options']['title'] = array( |
122 |
'#title' => t('Page title'), |
123 |
'#type' => 'textfield', |
124 |
); |
125 |
$form['displays']['page']['options']['path'] = array( |
126 |
'#title' => t('Path'), |
127 |
'#type' => 'textfield', |
128 |
'#field_prefix' => $path_prefix, |
129 |
); |
130 |
$form['displays']['page']['options']['style'] = array( |
131 |
'#type' => 'fieldset', |
132 |
'#attributes' => array('class' => array('container-inline', 'fieldset-no-legend')), |
133 |
); |
134 |
|
135 |
// Create the dropdown for choosing the display format.
|
136 |
$form['displays']['page']['options']['style']['style_plugin'] = array( |
137 |
'#title' => t('Display format'), |
138 |
'#help_topic' => 'style', |
139 |
'#type' => 'select', |
140 |
'#options' => $style_options, |
141 |
); |
142 |
$style_form = &$form['displays']['page']['options']['style']; |
143 |
$style_form['style_plugin']['#default_value'] = views_ui_get_selected($form_state, array('page', 'style', 'style_plugin'), 'default', $style_form['style_plugin']); |
144 |
// Changing this dropdown updates $form['displays']['page']['options'] via
|
145 |
// AJAX.
|
146 |
views_ui_add_ajax_trigger($style_form, 'style_plugin', array('displays', 'page', 'options')); |
147 |
|
148 |
$this->build_form_style($form, $form_state, 'page'); |
149 |
$form['displays']['page']['options']['items_per_page'] = array( |
150 |
'#title' => t('Items to display'), |
151 |
'#type' => 'textfield', |
152 |
'#default_value' => '10', |
153 |
'#size' => 5, |
154 |
'#element_validate' => array('views_element_validate_integer'), |
155 |
); |
156 |
$form['displays']['page']['options']['pager'] = array( |
157 |
'#title' => t('Use a pager'), |
158 |
'#type' => 'checkbox', |
159 |
'#default_value' => TRUE, |
160 |
); |
161 |
$form['displays']['page']['options']['link'] = array( |
162 |
'#title' => t('Create a menu link'), |
163 |
'#type' => 'checkbox', |
164 |
'#id' => 'edit-page-link', |
165 |
); |
166 |
$form['displays']['page']['options']['link_properties'] = array( |
167 |
'#type' => 'container', |
168 |
'#dependency' => array( |
169 |
'edit-page-link' => array(1), |
170 |
), |
171 |
'#pre_render' => array('ctools_dependent_pre_render'), |
172 |
'#prefix' => '<div id="edit-page-link-properties-wrapper">', |
173 |
'#suffix' => '</div>', |
174 |
); |
175 |
if (module_exists('menu')) { |
176 |
$menu_options = menu_get_menus();
|
177 |
} |
178 |
else {
|
179 |
// These are not yet translated.
|
180 |
$menu_options = menu_list_system_menus();
|
181 |
foreach ($menu_options as $name => $title) { |
182 |
$menu_options[$name] = t($title); |
183 |
} |
184 |
} |
185 |
$form['displays']['page']['options']['link_properties']['menu_name'] = array( |
186 |
'#title' => t('Menu'), |
187 |
'#type' => 'select', |
188 |
'#options' => $menu_options, |
189 |
); |
190 |
$form['displays']['page']['options']['link_properties']['title'] = array( |
191 |
'#title' => t('Link text'), |
192 |
'#type' => 'textfield', |
193 |
); |
194 |
// Only offer a feed if we have at least one available feed row style.
|
195 |
if ($feed_row_options) { |
196 |
$form['displays']['page']['options']['feed'] = array( |
197 |
'#title' => t('Include an RSS feed'), |
198 |
'#type' => 'checkbox', |
199 |
'#id' => 'edit-page-feed', |
200 |
); |
201 |
$form['displays']['page']['options']['feed_properties'] = array( |
202 |
'#type' => 'container', |
203 |
'#dependency' => array( |
204 |
'edit-page-feed' => array(1), |
205 |
), |
206 |
'#pre_render' => array('ctools_dependent_pre_render'), |
207 |
'#prefix' => '<div id="edit-page-feed-properties-wrapper">', |
208 |
'#suffix' => '</div>', |
209 |
); |
210 |
$form['displays']['page']['options']['feed_properties']['path'] = array( |
211 |
'#title' => t('Feed path'), |
212 |
'#type' => 'textfield', |
213 |
'#field_prefix' => $path_prefix, |
214 |
); |
215 |
// This will almost never be visible.
|
216 |
$form['displays']['page']['options']['feed_properties']['row_plugin'] = array( |
217 |
'#title' => t('Feed row style'), |
218 |
'#type' => 'select', |
219 |
'#options' => $feed_row_options, |
220 |
'#default_value' => key($feed_row_options), |
221 |
'#access' => (count($feed_row_options) > 1), |
222 |
'#dependency' => array( |
223 |
'edit-page-feed' => array(1), |
224 |
), |
225 |
'#pre_render' => array('ctools_dependent_pre_render'), |
226 |
'#prefix' => '<div id="edit-page-feed-properties-row-plugin-wrapper">', |
227 |
'#suffix' => '</div>', |
228 |
); |
229 |
} |
230 |
|
231 |
$form['displays']['block'] = array( |
232 |
'#type' => 'fieldset', |
233 |
'#attributes' => array('class' => array('views-attachment', 'fieldset-no-legend')), |
234 |
'#tree' => TRUE, |
235 |
); |
236 |
$form['displays']['block']['create'] = array( |
237 |
'#title' => t('Create a block'), |
238 |
'#type' => 'checkbox', |
239 |
'#attributes' => array('class' => array('strong')), |
240 |
'#id' => 'edit-block-create', |
241 |
); |
242 |
|
243 |
// All options for the block display are included in this container so they
|
244 |
// can be hidden en masse when the "Create a block" checkbox is unchecked.
|
245 |
$form['displays']['block']['options'] = array( |
246 |
'#type' => 'container', |
247 |
'#attributes' => array('class' => array('options-set')), |
248 |
'#dependency' => array( |
249 |
'edit-block-create' => array(1), |
250 |
), |
251 |
'#pre_render' => array('ctools_dependent_pre_render'), |
252 |
'#prefix' => '<div id="edit-block-wrapper">', |
253 |
'#suffix' => '</div>', |
254 |
'#parents' => array('block'), |
255 |
); |
256 |
|
257 |
$form['displays']['block']['options']['title'] = array( |
258 |
'#title' => t('Block title'), |
259 |
'#type' => 'textfield', |
260 |
); |
261 |
$form['displays']['block']['options']['style'] = array( |
262 |
'#type' => 'fieldset', |
263 |
'#attributes' => array('class' => array('container-inline', 'fieldset-no-legend')), |
264 |
); |
265 |
|
266 |
// Create the dropdown for choosing the display format.
|
267 |
$form['displays']['block']['options']['style']['style_plugin'] = array( |
268 |
'#title' => t('Display format'), |
269 |
'#help_topic' => 'style', |
270 |
'#type' => 'select', |
271 |
'#options' => $style_options, |
272 |
); |
273 |
$style_form = &$form['displays']['block']['options']['style']; |
274 |
$style_form['style_plugin']['#default_value'] = views_ui_get_selected($form_state, array('block', 'style', 'style_plugin'), 'default', $style_form['style_plugin']); |
275 |
// Changing this dropdown updates $form['displays']['block']['options'] via
|
276 |
// AJAX.
|
277 |
views_ui_add_ajax_trigger($style_form, 'style_plugin', array('displays', 'block', 'options')); |
278 |
|
279 |
$this->build_form_style($form, $form_state, 'block'); |
280 |
$form['displays']['block']['options']['items_per_page'] = array( |
281 |
'#title' => t('Items per page'), |
282 |
'#type' => 'textfield', |
283 |
'#default_value' => '5', |
284 |
'#size' => 5, |
285 |
'#element_validate' => array('views_element_validate_integer'), |
286 |
); |
287 |
$form['displays']['block']['options']['pager'] = array( |
288 |
'#title' => t('Use a pager'), |
289 |
'#type' => 'checkbox', |
290 |
'#default_value' => FALSE, |
291 |
); |
292 |
|
293 |
return $form; |
294 |
} |
295 |
|
296 |
/**
|
297 |
* Build the part of the form that builds the display format options.
|
298 |
*/
|
299 |
protected function build_form_style(&$form, &$form_state, $type) { |
300 |
$style_form =& $form['displays'][$type]['options']['style']; |
301 |
$style = $style_form['style_plugin']['#default_value']; |
302 |
$style_plugin = views_get_plugin('style', $style); |
303 |
if (isset($style_plugin) && $style_plugin->uses_row_plugin()) { |
304 |
$options = $this->row_style_options($type); |
305 |
$style_form['row_plugin'] = array( |
306 |
'#type' => 'select', |
307 |
'#title' => t('of'), |
308 |
'#options' => $options, |
309 |
'#access' => count($options) > 1, |
310 |
); |
311 |
// For the block display, the default value should be "titles (linked)",
|
312 |
// if it's available (since that's the most common use case).
|
313 |
$block_with_linked_titles_available = ($type == 'block' && isset($options['titles_linked'])); |
314 |
$default_value = $block_with_linked_titles_available ? 'titles_linked' : key($options); |
315 |
$style_form['row_plugin']['#default_value'] = views_ui_get_selected($form_state, array($type, 'style', 'row_plugin'), $default_value, $style_form['row_plugin']); |
316 |
// Changing this dropdown updates the individual row options via AJAX.
|
317 |
views_ui_add_ajax_trigger($style_form, 'row_plugin', array('displays', $type, 'options', 'style', 'row_options')); |
318 |
|
319 |
// This is the region that can be updated by AJAX. The base class doesn't
|
320 |
// add anything here, but child classes can.
|
321 |
$style_form['row_options'] = array( |
322 |
'#theme_wrappers' => array('container'), |
323 |
); |
324 |
} |
325 |
elseif ($style_plugin->uses_fields()) { |
326 |
$style_form['row_plugin'] = array('#markup' => '<span>' . t('of fields') . '</span>'); |
327 |
} |
328 |
} |
329 |
|
330 |
/**
|
331 |
* Add possible row style options.
|
332 |
*
|
333 |
* Per default use fields with base field.
|
334 |
*/
|
335 |
protected function row_style_options($type) { |
336 |
$data = views_fetch_data($this->base_table); |
337 |
// Get all available row plugins by default.
|
338 |
$options = views_fetch_plugin_names('row', 'normal', array($this->base_table)); |
339 |
return $options; |
340 |
} |
341 |
|
342 |
/**
|
343 |
* Build the part of the form that allows the user to select the filters.
|
344 |
*
|
345 |
* By default, this adds "of type" and "tagged with" filters (when they are
|
346 |
* available).
|
347 |
*/
|
348 |
protected function build_filters(&$form, &$form_state) { |
349 |
// Find all the fields we are allowed to filter by.
|
350 |
$fields = views_fetch_fields($this->base_table, 'filter'); |
351 |
|
352 |
$entity_info = $this->entity_info; |
353 |
// If the current base table support bundles and has more than one (like
|
354 |
// user).
|
355 |
if (isset($entity_info['bundle keys']) && isset($entity_info['bundles'])) { |
356 |
// Get all bundles and their human readable names.
|
357 |
$options = array('all' => t('All')); |
358 |
foreach ($entity_info['bundles'] as $type => $bundle) { |
359 |
$options[$type] = $bundle['label']; |
360 |
} |
361 |
$form['displays']['show']['type'] = array( |
362 |
'#type' => 'select', |
363 |
'#title' => t('of type'), |
364 |
'#options' => $options, |
365 |
); |
366 |
$selected_bundle = views_ui_get_selected($form_state, array('show', 'type'), 'all', $form['displays']['show']['type']); |
367 |
$form['displays']['show']['type']['#default_value'] = $selected_bundle; |
368 |
// Changing this dropdown updates the entire content of $form['displays']
|
369 |
// via AJAX, since each bundle might have entirely different fields
|
370 |
// attached to it, etc.
|
371 |
views_ui_add_ajax_trigger($form['displays']['show'], 'type', array('displays')); |
372 |
} |
373 |
|
374 |
// Check if we are allowed to filter by taxonomy, and if so, add the
|
375 |
// "tagged with" filter to the view.
|
376 |
//
|
377 |
// We construct this filter using taxonomy_index.tid (which limits the
|
378 |
// filtering to a specific vocabulary) rather than taxonomy_term_data.name
|
379 |
// (which matches terms in any vocabulary). This is because it is a more
|
380 |
// commonly-used filter that works better with the autocomplete UI, and
|
381 |
// also to avoid confusion with other vocabularies on the site that may
|
382 |
// have terms with the same name but are not used for free tagging.
|
383 |
//
|
384 |
// The downside is that if there *is* more than one vocabulary on the site
|
385 |
// that is used for free tagging, the wizard will only be able to make the
|
386 |
// "tagged with" filter apply to one of them (see below for the method it
|
387 |
// uses to choose).
|
388 |
if (isset($fields['taxonomy_index.tid'])) { |
389 |
// Check if this view will be displaying fieldable entities.
|
390 |
if (!empty($entity_info['fieldable'])) { |
391 |
// Find all "tag-like" taxonomy fields associated with the view's
|
392 |
// entities. If a particular entity type (i.e., bundle) has been
|
393 |
// selected above, then we only search for taxonomy fields associated
|
394 |
// with that bundle. Otherwise, we use all bundles.
|
395 |
$bundles = array_keys($entity_info['bundles']); |
396 |
// Double check that this is a real bundle before using it (since above
|
397 |
// we added a dummy option 'all' to the bundle list on the form).
|
398 |
if (isset($selected_bundle) && in_array($selected_bundle, $bundles)) { |
399 |
$bundles = array($selected_bundle); |
400 |
} |
401 |
$tag_fields = array(); |
402 |
foreach ($bundles as $bundle) { |
403 |
foreach (field_info_instances($this->entity_type, $bundle) as $instance) { |
404 |
// We define "tag-like" taxonomy fields as ones that use the
|
405 |
// "Autocomplete term widget (tagging)" widget.
|
406 |
if ($instance['widget']['type'] == 'taxonomy_autocomplete') { |
407 |
$tag_fields[] = $instance['field_name']; |
408 |
} |
409 |
} |
410 |
} |
411 |
$tag_fields = array_unique($tag_fields); |
412 |
if (!empty($tag_fields)) { |
413 |
// If there is more than one "tag-like" taxonomy field available to
|
414 |
// the view, we can only make our filter apply to one of them (as
|
415 |
// described above). We choose 'field_tags' if it is available, since
|
416 |
// that is created by the Standard install profile in core and also
|
417 |
// commonly used by contrib modules; thus, it is most likely to be
|
418 |
// associated with the "main" free-tagging vocabulary on the site.
|
419 |
if (in_array('field_tags', $tag_fields)) { |
420 |
$tag_field_name = 'field_tags'; |
421 |
} |
422 |
else {
|
423 |
$tag_field_name = reset($tag_fields); |
424 |
} |
425 |
// Add the autocomplete textfield to the wizard.
|
426 |
$form['displays']['show']['tagged_with'] = array( |
427 |
'#type' => 'textfield', |
428 |
'#title' => t('tagged with'), |
429 |
'#autocomplete_path' => 'taxonomy/autocomplete/' . $tag_field_name, |
430 |
'#size' => 30, |
431 |
'#maxlength' => 1024, |
432 |
'#field_name' => $tag_field_name, |
433 |
'#element_validate' => array('views_ui_taxonomy_autocomplete_validate'), |
434 |
); |
435 |
} |
436 |
} |
437 |
} |
438 |
} |
439 |
|
440 |
/**
|
441 |
* Build the part of the form that allows the user to select the sort order.
|
442 |
*
|
443 |
* By default, this adds a "sorted by [date]" filter (when it is available).
|
444 |
*/
|
445 |
protected function build_sorts(&$form, &$form_state) { |
446 |
$sorts = array( |
447 |
'none' => t('Unsorted'), |
448 |
); |
449 |
// Check if we are allowed to sort by creation date.
|
450 |
if (!empty($this->plugin['created_column'])) { |
451 |
$sorts += array( |
452 |
$this->plugin['created_column'] . ':DESC' => t('Newest first'), |
453 |
$this->plugin['created_column'] . ':ASC' => t('Oldest first'), |
454 |
); |
455 |
} |
456 |
if (isset($this->plugin['available_sorts'])) { |
457 |
$sorts += $this->plugin['available_sorts']; |
458 |
} |
459 |
|
460 |
// If there is no sorts option available continue.
|
461 |
if (!empty($sorts)) { |
462 |
$form['displays']['show']['sort'] = array( |
463 |
'#type' => 'select', |
464 |
'#title' => t('sorted by'), |
465 |
'#options' => $sorts, |
466 |
'#default_value' => isset($this->plugin['created_column']) ? $this->plugin['created_column'] . ':DESC' : 'none', |
467 |
); |
468 |
} |
469 |
} |
470 |
|
471 |
protected function instantiate_view($form, &$form_state) { |
472 |
// Build the basic view properties.
|
473 |
$view = views_new_view();
|
474 |
$view->name = $form_state['values']['name']; |
475 |
$view->human_name = $form_state['values']['human_name']; |
476 |
$view->description = $form_state['values']['description']; |
477 |
$view->tag = 'default'; |
478 |
$view->core = VERSION; |
479 |
$view->base_table = $this->base_table; |
480 |
|
481 |
// Build all display options for this view.
|
482 |
$display_options = $this->build_display_options($form, $form_state); |
483 |
|
484 |
// Allow the fully built options to be altered. This happens before adding
|
485 |
// the options to the view, so that once they are eventually added we will
|
486 |
// be able to get all the overrides correct.
|
487 |
$this->alter_display_options($display_options, $form, $form_state); |
488 |
|
489 |
$this->add_displays($view, $display_options, $form, $form_state); |
490 |
|
491 |
return $view; |
492 |
} |
493 |
|
494 |
/**
|
495 |
* Build an array of display options for the view.
|
496 |
*
|
497 |
* @return
|
498 |
* An array whose keys are the names of each display and whose values are
|
499 |
* arrays of options for that display.
|
500 |
*/
|
501 |
protected function build_display_options($form, $form_state) { |
502 |
// Display: Master.
|
503 |
$display_options['default'] = $this->default_display_options($form, $form_state); |
504 |
$display_options['default'] += array( |
505 |
'filters' => array(), |
506 |
'sorts' => array(), |
507 |
); |
508 |
$display_options['default']['filters'] += $this->default_display_filters($form, $form_state); |
509 |
$display_options['default']['sorts'] += $this->default_display_sorts($form, $form_state); |
510 |
|
511 |
// Display: Page.
|
512 |
if (!empty($form_state['values']['page']['create'])) { |
513 |
$display_options['page'] = $this->page_display_options($form, $form_state); |
514 |
|
515 |
// Display: Feed (attached to the page).
|
516 |
if (!empty($form_state['values']['page']['feed'])) { |
517 |
$display_options['feed'] = $this->page_feed_display_options($form, $form_state); |
518 |
} |
519 |
} |
520 |
|
521 |
// Display: Block.
|
522 |
if (!empty($form_state['values']['block']['create'])) { |
523 |
$display_options['block'] = $this->block_display_options($form, $form_state); |
524 |
} |
525 |
|
526 |
return $display_options; |
527 |
} |
528 |
|
529 |
/**
|
530 |
* Alter the full array of display options before they are added to the view.
|
531 |
*/
|
532 |
protected function alter_display_options(&$display_options, $form, $form_state) { |
533 |
// If any of the displays use jump menus, we want to add fields to the view
|
534 |
// that store the path that will be used in the jump menu. The fields to
|
535 |
// use for this are defined by the plugin.
|
536 |
if (isset($this->plugin['path_field'])) { |
537 |
$path_field = $this->plugin['path_field']; |
538 |
$path_fields_added = FALSE; |
539 |
foreach ($display_options as $display_type => $options) { |
540 |
if (!empty($options['style_plugin']) && $options['style_plugin'] == 'jump_menu') { |
541 |
// Regardless of how many displays have jump menus, we only need to
|
542 |
// add a single set of path fields to the view.
|
543 |
if (!$path_fields_added) { |
544 |
// The plugin might provide supplemental fields that it needs to
|
545 |
// generate the path (for example, node revisions need the node ID
|
546 |
// as well as the revision ID). We need to add these first so they
|
547 |
// are available as replacement patterns in the main path field.
|
548 |
$path_fields = !empty($this->plugin['path_fields_supplemental']) ? $this->plugin['path_fields_supplemental'] : array(); |
549 |
$path_fields[] = &$path_field; |
550 |
|
551 |
// Generate a unique ID for each field so we don't overwrite
|
552 |
// existing ones.
|
553 |
foreach ($path_fields as &$field) { |
554 |
$field['id'] = view::generate_item_id($field['id'], $display_options['default']['fields']); |
555 |
$display_options['default']['fields'][$field['id']] = $field; |
556 |
} |
557 |
|
558 |
$path_fields_added = TRUE; |
559 |
} |
560 |
|
561 |
// Configure the style plugin to use the path field to generate the
|
562 |
// jump menu path.
|
563 |
$display_options[$display_type]['style_options']['path'] = $path_field['id']; |
564 |
} |
565 |
} |
566 |
} |
567 |
|
568 |
// If any of the displays use the table style, take sure that the fields
|
569 |
// always have a labels by unsetting the override.
|
570 |
foreach ($display_options as &$options) { |
571 |
if ($options['style_plugin'] == 'table') { |
572 |
foreach ($display_options['default']['fields'] as &$field) { |
573 |
unset($field['label']); |
574 |
} |
575 |
} |
576 |
} |
577 |
} |
578 |
|
579 |
/**
|
580 |
* Add the array of display options to the view, with appropriate overrides.
|
581 |
*/
|
582 |
protected function add_displays($view, $display_options, $form, $form_state) { |
583 |
// Display: Master.
|
584 |
$default_display = $view->new_display('default', 'Master', 'default'); |
585 |
foreach ($display_options['default'] as $option => $value) { |
586 |
$default_display->set_option($option, $value); |
587 |
} |
588 |
|
589 |
// Display: Page.
|
590 |
if (isset($display_options['page'])) { |
591 |
$display = $view->new_display('page', 'Page', 'page'); |
592 |
// The page display is usually the main one (from the user's point of
|
593 |
// view). Its options should therefore become the overall view defaults,
|
594 |
// so that new displays which are added later automatically inherit them.
|
595 |
$this->set_default_options($display_options['page'], $display, $default_display); |
596 |
|
597 |
// Display: Feed (attached to the page).
|
598 |
if (isset($display_options['feed'])) { |
599 |
$display = $view->new_display('feed', 'Feed', 'feed'); |
600 |
$this->set_override_options($display_options['feed'], $display, $default_display); |
601 |
} |
602 |
} |
603 |
|
604 |
// Display: Block.
|
605 |
if (isset($display_options['block'])) { |
606 |
$display = $view->new_display('block', 'Block', 'block'); |
607 |
// When there is no page, the block display options should become the
|
608 |
// overall view defaults.
|
609 |
if (!isset($display_options['page'])) { |
610 |
$this->set_default_options($display_options['block'], $display, $default_display); |
611 |
} |
612 |
else {
|
613 |
$this->set_override_options($display_options['block'], $display, $default_display); |
614 |
} |
615 |
} |
616 |
} |
617 |
|
618 |
/**
|
619 |
* Most subclasses will need to override this method to provide some fields
|
620 |
* or a different row plugin.
|
621 |
*/
|
622 |
protected function default_display_options($form, $form_state) { |
623 |
$display_options = array(); |
624 |
$display_options['access']['type'] = 'none'; |
625 |
$display_options['cache']['type'] = 'none'; |
626 |
$display_options['query']['type'] = 'views_query'; |
627 |
$display_options['exposed_form']['type'] = 'basic'; |
628 |
$display_options['pager']['type'] = 'full'; |
629 |
$display_options['style_plugin'] = 'default'; |
630 |
$display_options['row_plugin'] = 'fields'; |
631 |
|
632 |
// Add a least one field so the view validates and the user has already a
|
633 |
// preview. Therefore the basefield could provide 'defaults][field]' in
|
634 |
// it's base settings. If there is nothing like this choose the first field
|
635 |
// with a field handler.
|
636 |
$data = views_fetch_data($this->base_table); |
637 |
if (isset($data['table']['base']['defaults']['field'])) { |
638 |
$field = $data['table']['base']['defaults']['field']; |
639 |
} |
640 |
else {
|
641 |
foreach ($data as $field => $field_data) { |
642 |
if (isset($field_data['field']['handler'])) { |
643 |
break;
|
644 |
} |
645 |
} |
646 |
} |
647 |
$display_options['fields'][$field] = array( |
648 |
'table' => $this->base_table, |
649 |
'field' => $field, |
650 |
'id' => $field, |
651 |
); |
652 |
|
653 |
return $display_options; |
654 |
} |
655 |
|
656 |
protected function default_display_filters($form, $form_state) { |
657 |
$filters = array(); |
658 |
|
659 |
// Add any filters provided by the plugin.
|
660 |
if (isset($this->plugin['filters'])) { |
661 |
foreach ($this->plugin['filters'] as $name => $info) { |
662 |
$filters[$name] = $info; |
663 |
} |
664 |
} |
665 |
|
666 |
// Add any filters specified by the user when filling out the wizard.
|
667 |
$filters = array_merge($filters, $this->default_display_filters_user($form, $form_state)); |
668 |
|
669 |
return $filters; |
670 |
} |
671 |
|
672 |
protected function default_display_filters_user($form, $form_state) { |
673 |
$filters = array(); |
674 |
|
675 |
if (!empty($form_state['values']['show']['type']) && $form_state['values']['show']['type'] != 'all') { |
676 |
$bundle_key = $this->entity_info['bundle keys']['bundle']; |
677 |
// Figure out the table where $bundle_key lives. It may not be the same as
|
678 |
// the base table for the view; the taxonomy vocabulary machine_name, for
|
679 |
// example, is stored in taxonomy_vocabulary, not taxonomy_term_data.
|
680 |
$fields = views_fetch_fields($this->base_table, 'filter'); |
681 |
if (isset($fields[$this->base_table . '.' . $bundle_key])) { |
682 |
$table = $this->base_table; |
683 |
} |
684 |
else {
|
685 |
foreach ($fields as $field_name => $value) { |
686 |
if ($pos = strpos($field_name, '.' . $bundle_key)) { |
687 |
$table = substr($field_name, 0, $pos); |
688 |
break;
|
689 |
} |
690 |
} |
691 |
} |
692 |
$table_data = views_fetch_data($table); |
693 |
// Check whether the bundle key filter handler is or an child of it
|
694 |
// views_handler_filter_in_operator. If it's not just use a single value
|
695 |
// instead of an array.
|
696 |
$handler = $table_data[$bundle_key]['filter']['handler']; |
697 |
if ($handler == 'views_handler_filter_in_operator' || is_subclass_of($handler, 'views_handler_filter_in_operator')) { |
698 |
$value = drupal_map_assoc(array($form_state['values']['show']['type'])); |
699 |
} |
700 |
else {
|
701 |
$value = $form_state['values']['show']['type']; |
702 |
} |
703 |
|
704 |
$filters[$bundle_key] = array( |
705 |
'id' => $bundle_key, |
706 |
'table' => $table, |
707 |
'field' => $bundle_key, |
708 |
'value' => $value, |
709 |
); |
710 |
} |
711 |
|
712 |
// @todo Figure out why this isn't part of node_views_wizard.
|
713 |
if (!empty($form_state['values']['show']['tagged_with']['tids'])) { |
714 |
$filters['tid'] = array( |
715 |
'id' => 'tid', |
716 |
'table' => 'taxonomy_index', |
717 |
'field' => 'tid', |
718 |
'value' => $form_state['values']['show']['tagged_with']['tids'], |
719 |
'vocabulary' => $form_state['values']['show']['tagged_with']['vocabulary'], |
720 |
); |
721 |
// If the user entered more than one valid term in the autocomplete
|
722 |
// field, they probably intended both of them to be applied.
|
723 |
if (count($form_state['values']['show']['tagged_with']['tids']) > 1) { |
724 |
$filters['tid']['operator'] = 'and'; |
725 |
// Sort the terms so the filter will be displayed as it normally would
|
726 |
// on the edit screen.
|
727 |
sort($filters['tid']['value']); |
728 |
} |
729 |
} |
730 |
|
731 |
return $filters; |
732 |
} |
733 |
|
734 |
protected function default_display_sorts($form, $form_state) { |
735 |
$sorts = array(); |
736 |
|
737 |
// Add any sorts provided by the plugin.
|
738 |
if (isset($this->plugin['sorts'])) { |
739 |
foreach ($this->plugin['sorts'] as $name => $info) { |
740 |
$sorts[$name] = $info; |
741 |
} |
742 |
} |
743 |
|
744 |
// Add any sorts specified by the user when filling out the wizard.
|
745 |
$sorts = array_merge($sorts, $this->default_display_sorts_user($form, $form_state)); |
746 |
|
747 |
return $sorts; |
748 |
} |
749 |
|
750 |
protected function default_display_sorts_user($form, $form_state) { |
751 |
$sorts = array(); |
752 |
|
753 |
// Don't add a sort if there is no form value or the user selected none as
|
754 |
// sort.
|
755 |
if (!empty($form_state['values']['show']['sort']) && $form_state['values']['show']['sort'] != 'none') { |
756 |
list($column, $sort) = explode(':', $form_state['values']['show']['sort']); |
757 |
// Column either be a column-name or the table-columnn-ame.
|
758 |
$column = explode('-', $column); |
759 |
if (count($column) > 1) { |
760 |
$table = $column[0]; |
761 |
$column = $column[1]; |
762 |
} |
763 |
else {
|
764 |
$table = $this->base_table; |
765 |
$column = $column[0]; |
766 |
} |
767 |
|
768 |
$sorts[$column] = array( |
769 |
'id' => $column, |
770 |
'table' => $table, |
771 |
'field' => $column, |
772 |
'order' => $sort, |
773 |
); |
774 |
} |
775 |
|
776 |
return $sorts; |
777 |
} |
778 |
|
779 |
protected function page_display_options($form, $form_state) { |
780 |
$display_options = array(); |
781 |
$page = $form_state['values']['page']; |
782 |
$display_options['title'] = $page['title']; |
783 |
$display_options['path'] = $page['path']; |
784 |
$display_options['style_plugin'] = $page['style']['style_plugin']; |
785 |
// Not every style plugin supports row style plugins.
|
786 |
$display_options['row_plugin'] = isset($page['style']['row_plugin']) ? $page['style']['row_plugin'] : 'fields'; |
787 |
if (empty($page['items_per_page'])) { |
788 |
$display_options['pager']['type'] = 'none'; |
789 |
} |
790 |
elseif ($page['pager']) { |
791 |
$display_options['pager']['type'] = 'full'; |
792 |
} |
793 |
else {
|
794 |
$display_options['pager']['type'] = 'some'; |
795 |
} |
796 |
$display_options['pager']['options']['items_per_page'] = $page['items_per_page']; |
797 |
if (!empty($page['link'])) { |
798 |
$display_options['menu']['type'] = 'normal'; |
799 |
$display_options['menu']['title'] = $page['link_properties']['title']; |
800 |
$display_options['menu']['name'] = $page['link_properties']['menu_name']; |
801 |
} |
802 |
return $display_options; |
803 |
} |
804 |
|
805 |
protected function block_display_options($form, $form_state) { |
806 |
$display_options = array(); |
807 |
$block = $form_state['values']['block']; |
808 |
$display_options['title'] = $block['title']; |
809 |
$display_options['style_plugin'] = $block['style']['style_plugin']; |
810 |
$display_options['row_plugin'] = isset($block['style']['row_plugin']) ? $block['style']['row_plugin'] : 'fields'; |
811 |
$display_options['pager']['type'] = $block['pager'] ? 'full' : (empty($block['items_per_page']) ? 'none' : 'some'); |
812 |
$display_options['pager']['options']['items_per_page'] = $block['items_per_page']; |
813 |
return $display_options; |
814 |
} |
815 |
|
816 |
protected function page_feed_display_options($form, $form_state) { |
817 |
$display_options = array(); |
818 |
$display_options['pager']['type'] = 'some'; |
819 |
$display_options['style_plugin'] = 'rss'; |
820 |
$display_options['row_plugin'] = $form_state['values']['page']['feed_properties']['row_plugin']; |
821 |
$display_options['path'] = $form_state['values']['page']['feed_properties']['path']; |
822 |
$display_options['title'] = $form_state['values']['page']['title']; |
823 |
$display_options['displays'] = array( |
824 |
'default' => 'default', |
825 |
'page' => 'page', |
826 |
); |
827 |
return $display_options; |
828 |
} |
829 |
|
830 |
/**
|
831 |
* Sets options for a display and makes them the default options if possible.
|
832 |
*
|
833 |
* This function can be used to set options for a display when it is desired
|
834 |
* that the options also become the defaults for the view whenever possible.
|
835 |
* This should be done for the "primary" display created in the view wizard,
|
836 |
* so that new displays which the user adds later will be similar to this
|
837 |
* one.
|
838 |
*
|
839 |
* @param array $options
|
840 |
* An array whose keys are the name of each option and whose values are the
|
841 |
* desired values to set.
|
842 |
* @param object $display
|
843 |
* The display which the options will be applied to. The default display
|
844 |
* will actually be assigned the options (and this display will inherit
|
845 |
* them) when possible.
|
846 |
* @param object$default_display
|
847 |
* The default display, which will store the options when possible.
|
848 |
*/
|
849 |
protected function set_default_options($options, $display, $default_display) { |
850 |
foreach ($options as $option => $value) { |
851 |
// If the default display supports this option, set the value there.
|
852 |
// Otherwise, set it on the provided display.
|
853 |
$default_value = $default_display->get_option($option); |
854 |
if (isset($default_value)) { |
855 |
$default_display->set_option($option, $value); |
856 |
} |
857 |
else {
|
858 |
$display->set_option($option, $value); |
859 |
} |
860 |
} |
861 |
} |
862 |
|
863 |
/**
|
864 |
* Sets options for a display, inheriting from the defaults when possible.
|
865 |
*
|
866 |
* This function can be used to set options for a display when it is desired
|
867 |
* that the options inherit from the default display whenever possible. This
|
868 |
* avoids setting too many options as overrides, which will be harder for the
|
869 |
* user to modify later. For example, if $this->set_default_options() was
|
870 |
* previously called on a page display and then this function is called on a
|
871 |
* block display, and if the user entered the same title for both displays in
|
872 |
* the views wizard, then the view will wind up with the title stored as the
|
873 |
* default (with the page and block both inheriting from it).
|
874 |
*
|
875 |
* @param array $options
|
876 |
* An array whose keys are the name of each option and whose values are the
|
877 |
* desired values.
|
878 |
* @param object $display
|
879 |
* The display which the options will apply to. It will get the options by
|
880 |
* inheritance from the default display when possible.
|
881 |
* @param object $default_display
|
882 |
* The default display, from which the options will be inherited when
|
883 |
* possible.
|
884 |
*/
|
885 |
protected function set_override_options($options, $display, $default_display) { |
886 |
foreach ($options as $option => $value) { |
887 |
// Only override the default value if it is different from the value that
|
888 |
// was provided.
|
889 |
$default_value = $default_display->get_option($option); |
890 |
if (!isset($default_value)) { |
891 |
$display->set_option($option, $value); |
892 |
} |
893 |
elseif ($default_value !== $value) { |
894 |
$display->override_option($option, $value); |
895 |
} |
896 |
} |
897 |
} |
898 |
|
899 |
protected function retrieve_validated_view($form, $form_state, $unset = TRUE) { |
900 |
$key = hash('sha256', serialize($form_state['values'])); |
901 |
$view = (isset($this->validated_views[$key]) ? $this->validated_views[$key] : NULL); |
902 |
if ($unset) { |
903 |
unset($this->validated_views[$key]); |
904 |
} |
905 |
return $view; |
906 |
} |
907 |
|
908 |
protected function set_validated_view($form, $form_state, $view) { |
909 |
$key = hash('sha256', serialize($form_state['values'])); |
910 |
$this->validated_views[$key] = $view; |
911 |
} |
912 |
|
913 |
/**
|
914 |
* Instantiates a view and validates values.
|
915 |
*/
|
916 |
function validate($form, &$form_state) { |
917 |
$view = $this->instantiate_view($form, $form_state); |
918 |
$errors = $view->validate(); |
919 |
if (!is_array($errors) || empty($errors)) { |
920 |
$this->set_validated_view($form, $form_state, $view); |
921 |
return array(); |
922 |
} |
923 |
return $errors; |
924 |
} |
925 |
|
926 |
/**
|
927 |
* Create a View from values that have been already submitted to validate().
|
928 |
*
|
929 |
* @throws ViewsWizardException if the values have not been validated.
|
930 |
*/
|
931 |
function create_view($form, &$form_state) { |
932 |
$view = $this->retrieve_validated_view($form, $form_state); |
933 |
if (empty($view)) { |
934 |
throw new ViewsWizardException(t('Attempted to create_view with values that have not been validated')); |
935 |
} |
936 |
return $view; |
937 |
} |
938 |
|
939 |
} |