/** * {@inheritdoc} */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { parent::buildOptionsForm($form, $form_state); // Get the sorts that apply to our base. $sorts = Views::viewsDataHelper()->fetchFields($this->definition['base'], 'sort'); $sort_options = array(); foreach ($sorts as $sort_id => $sort) { $sort_options[$sort_id] = "{$sort['group']}: {$sort['title']}"; } $base_table_data = Views::viewsData()->get($this->definition['base']); // Extends the relationship's basic options, allowing the user to pick a // sort and an order for it. $form['subquery_sort'] = array('#type' => 'select', '#title' => $this->t('Representative sort criteria'), '#default_value' => !empty($this->options['subquery_sort']) ? $this->options['subquery_sort'] : $this->definition['base'] . '.' . $base_table_data['table']['base']['field'], '#options' => $sort_options, '#description' => $this->t("The sort criteria is applied to the data brought in by the relationship to determine how a representative item is obtained for each row. For example, to show the most recent node for each user, pick 'Content: Updated date'.")); $form['subquery_order'] = array('#type' => 'radios', '#title' => $this->t('Representative sort order'), '#description' => $this->t("The ordering to use for the sort criteria selected above."), '#options' => array('ASC' => $this->t('Ascending'), 'DESC' => $this->t('Descending')), '#default_value' => $this->options['subquery_order']); $form['subquery_namespace'] = array('#type' => 'textfield', '#title' => $this->t('Subquery namespace'), '#description' => $this->t('Advanced. Enter a namespace for the subquery used by this relationship.'), '#default_value' => $this->options['subquery_namespace']); // WIP: This stuff doesn't work yet: namespacing issues. // A list of suitable views to pick one as the subview. $views = array('' => '- None -'); foreach (Views::getAllViews() as $view) { // Only get views that are suitable: // - base must the base that our relationship joins towards // - must have fields. if ($view->get('base_table') == $this->definition['base'] && !empty($view->getDisplay('default')['display_options']['fields'])) { // TODO: check the field is the correct sort? // or let users hang themselves at this stage and check later? $views[$view->id()] = $view->id(); } } $form['subquery_view'] = array('#type' => 'select', '#title' => $this->t('Representative view'), '#default_value' => $this->options['subquery_view'], '#options' => $views, '#description' => $this->t('Advanced. Use another view to generate the relationship subquery. This allows you to use filtering and more than one sort. If you pick a view here, the sort options above are ignored. Your view must have the ID of its base as its only field, and should have some kind of sorting.')); $form['subquery_regenerate'] = array('#type' => 'checkbox', '#title' => $this->t('Generate subquery each time view is run'), '#default_value' => $this->options['subquery_regenerate'], '#description' => $this->t('Will re-generate the subquery for this relationship every time the view is run, instead of only when these options are saved. Use for testing if you are making changes elsewhere. WARNING: seriously impairs performance.')); }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $view = $form_state->get('view'); $display_id = $form_state->get('display_id'); $type = $form_state->get('type'); $form = array('options' => array('#theme_wrappers' => array('container'), '#attributes' => array('class' => array('scroll'), 'data-drupal-views-scroll' => TRUE))); $executable = $view->getExecutable(); $executable->setDisplay($display_id); $display =& $executable->displayHandlers->get($display_id); $types = ViewExecutable::getHandlerTypes(); $ltitle = $types[$type]['ltitle']; $section = $types[$type]['plural']; if (!empty($types[$type]['type'])) { $type = $types[$type]['type']; } $form['#title'] = $this->t('Add @type', array('@type' => $ltitle)); $form['#section'] = $display_id . 'add-handler'; // Add the display override dropdown. views_ui_standard_display_dropdown($form, $form_state, $section); // Figure out all the base tables allowed based upon what the relationships provide. $base_tables = $executable->getBaseTables(); $options = Views::viewsDataHelper()->fetchFields(array_keys($base_tables), $type, $display->useGroupBy(), $form_state->get('type')); if (!empty($options)) { $form['override']['controls'] = array('#theme_wrappers' => array('container'), '#id' => 'views-filterable-options-controls', '#attributes' => array('class' => array('container-inline'))); $form['override']['controls']['options_search'] = array('#type' => 'textfield', '#title' => $this->t('Search')); $groups = array('all' => $this->t('- All -')); $form['override']['controls']['group'] = array('#type' => 'select', '#title' => $this->t('Type'), '#options' => array()); $form['options']['name'] = array('#prefix' => '<div class="views-radio-box form-checkboxes views-filterable-options">', '#suffix' => '</div>', '#tree' => TRUE, '#default_value' => 'all'); // Group options first to simplify the usage of #states. $grouped_options = array(); foreach ($options as $key => $option) { $group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group'])); $groups[$group] = $option['group']; $grouped_options[$group][$key] = $option; if (!empty($option['aliases']) && is_array($option['aliases'])) { foreach ($option['aliases'] as $id => $alias) { if (empty($alias['base']) || !empty($base_tables[$alias['base']])) { $copy = $option; $copy['group'] = $alias['group']; $copy['title'] = $alias['title']; if (isset($alias['help'])) { $copy['help'] = $alias['help']; } $group = preg_replace('/[^a-z0-9]/', '-', strtolower($copy['group'])); $groups[$group] = $copy['group']; $grouped_options[$group][$key . '$' . $id] = $copy; } } } } foreach ($grouped_options as $group => $group_options) { foreach ($group_options as $key => $option) { $form['options']['name'][$key] = array('#type' => 'checkbox', '#title' => $this->t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])), '#description' => $option['help'], '#return_value' => $key, '#prefix' => "<div class='filterable-option'>", '#suffix' => '</div>', '#states' => array('visible' => array(array(':input[name="override[controls][group]"]' => array('value' => 'all')), array(':input[name="override[controls][group]"]' => array('value' => $group))))); } } $form['override']['controls']['group']['#options'] = $groups; } else { $form['options']['markup'] = array('#markup' => '<div class="form-item">' . $this->t('There are no @types available to add.', array('@types' => $ltitle)) . '</div>'); } // Add a div to show the selected items $form['selected'] = array('#type' => 'item', '#markup' => '<span class="views-ui-view-title">' . $this->t('Selected:') . '</span> ' . '<div class="views-selected-options"></div>', '#theme_wrappers' => array('form_element', 'views_ui_container'), '#attributes' => array('class' => array('container-inline', 'views-add-form-selected'), 'data-drupal-views-offset' => 'bottom')); $view->getStandardButtons($form, $form_state, 'views_ui_add_handler_form', $this->t('Add and configure @types', array('@types' => $ltitle))); // Remove the default submit function. $form['actions']['submit']['#submit'] = array_filter($form['actions']['submit']['#submit'], function ($var) { return !(is_array($var) && isset($var[1]) && $var[1] == 'standardSubmit'); }); $form['actions']['submit']['#submit'][] = array($view, 'submitItemAdd'); return $form; }
/** * {@inheritdoc} */ public function buildForm(array $form, array &$form_state) { $view = $form_state['view']; $display_id = $form_state['display_id']; $type = $form_state['type']; $id = $form_state['id']; $form = array('options' => array('#tree' => TRUE, '#theme_wrappers' => array('container'), '#attributes' => array('class' => array('scroll'), 'data-drupal-views-scroll' => TRUE))); $executable = $view->getExecutable(); $save_ui_cache = FALSE; $executable->setDisplay($display_id); $item = $executable->getHandler($display_id, $type, $id); if ($item) { $handler = $executable->display_handler->getHandler($type, $id); if (empty($handler)) { $form['markup'] = array('#markup' => $this->t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field']))); } else { $types = ViewExecutable::getHandlerTypes(); // If this item can come from the default display, show a dropdown // that lets the user choose which display the changes should apply to. if ($executable->display_handler->defaultableSections($types[$type]['plural'])) { $form_state['section'] = $types[$type]['plural']; views_ui_standard_display_dropdown($form, $form_state, $form_state['section']); } // A whole bunch of code to figure out what relationships are valid for // this item. $relationships = $executable->display_handler->getOption('relationships'); $relationship_options = array(); foreach ($relationships as $relationship) { // relationships can't link back to self. But also, due to ordering, // relationships can only link to prior relationships. if ($type == 'relationship' && $id == $relationship['id']) { break; } $relationship_handler = Views::handlerManager('relationship')->getHandler($relationship); // ignore invalid/broken relationships. if (empty($relationship_handler)) { continue; } // If this relationship is valid for this type, add it to the list. $data = Views::viewsData()->get($relationship['table']); if (isset($data[$relationship['field']]['relationship']['base']) && ($base = $data[$relationship['field']]['relationship']['base'])) { $base_fields = Views::viewsDataHelper()->fetchFields($base, $form_state['type'], $executable->display_handler->useGroupBy()); if (isset($base_fields[$item['table'] . '.' . $item['field']])) { $relationship_handler->init($executable, $executable->display_handler, $relationship); $relationship_options[$relationship['id']] = $relationship_handler->adminLabel(); } } } if (!empty($relationship_options)) { // Make sure the existing relationship is even valid. If not, force // it to none. $base_fields = Views::viewsDataHelper()->fetchFields($view->get('base_table'), $form_state['type'], $executable->display_handler->useGroupBy()); if (isset($base_fields[$item['table'] . '.' . $item['field']])) { $relationship_options = array_merge(array('none' => $this->t('Do not use a relationship')), $relationship_options); } $rel = empty($item['relationship']) ? 'none' : $item['relationship']; if (empty($relationship_options[$rel])) { // Pick the first relationship. $rel = key($relationship_options); // We want this relationship option to get saved even if the user // skips submitting the form. $executable->setHandlerOption($display_id, $type, $id, 'relationship', $rel); $save_ui_cache = TRUE; } $form['options']['relationship'] = array('#type' => 'select', '#title' => $this->t('Relationship'), '#options' => $relationship_options, '#default_value' => $rel, '#weight' => -500); } else { $form['options']['relationship'] = array('#type' => 'value', '#value' => 'none'); } $form['#title'] = $this->t('Configure @type: @item', array('@type' => $types[$type]['lstitle'], '@item' => $handler->adminLabel())); if (!empty($handler->definition['help'])) { $form['options']['form_description'] = array('#markup' => $handler->definition['help'], '#theme_wrappers' => array('container'), '#attributes' => array('class' => array('form-item description')), '#weight' => -1000); } $form['#section'] = $display_id . '-' . $type . '-' . $id; // Get form from the handler. $handler->buildOptionsForm($form['options'], $form_state); $form_state['handler'] = $handler; } $name = NULL; if (isset($form_state['update_name'])) { $name = $form_state['update_name']; } $view->getStandardButtons($form, $form_state, 'views_ui_config_item_form', $name); // Add a 'remove' button. $form['actions']['remove'] = array('#type' => 'submit', '#value' => $this->t('Remove'), '#submit' => array(array($this, 'remove')), '#limit_validation_errors' => array(array('override')), '#ajax' => array('path' => current_path())); } if ($save_ui_cache) { $view->cacheSet(); } return $form; }
/** * Retrieves filter information based on user input for the default display. * * @param array $form * The full wizard form array. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the wizard form. * * @return array * An array of filter arrays keyed by ID. A sort array contains the options * accepted by a filter handler. */ protected function defaultDisplayFiltersUser(array $form, FormStateInterface $form_state) { $filters = array(); if (($type = $form_state->getValue(array('show', 'type'))) && $type != 'all') { $bundle_key = $this->entityType->getKey('bundle'); // Figure out the table where $bundle_key lives. It may not be the same as // the base table for the view; the taxonomy vocabulary machine_name, for // example, is stored in taxonomy_vocabulary, not taxonomy_term_data. module_load_include('inc', 'views_ui', 'admin'); $fields = Views::viewsDataHelper()->fetchFields($this->base_table, 'filter'); if (isset($fields[$this->base_table . '.' . $bundle_key])) { $table = $this->base_table; } else { foreach ($fields as $field_name => $value) { if ($pos = strpos($field_name, '.' . $bundle_key)) { $table = substr($field_name, 0, $pos); break; } } } $table_data = Views::viewsData()->get($table); // If the 'in' operator is being used, map the values to an array. $handler = $table_data[$bundle_key]['filter']['id']; $handler_definition = Views::pluginManager('filter')->getDefinition($handler); if ($handler == 'in_operator' || is_subclass_of($handler_definition['class'], 'Drupal\\views\\Plugin\\views\\filter\\InOperator')) { $value = array($type => $type); } else { $value = $type; } $filters[$bundle_key] = array('id' => $bundle_key, 'table' => $table, 'field' => $bundle_key, 'value' => $value); } return $filters; }