Projet

Général

Profil

Paste
Télécharger (35,6 ko) Statistiques
| Branche: | Révision:

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
}