class ContextualRangeFilterAssignmentForm in Views Contextual Range Filter 8
Convert selected contextual filters to contextual range filters.
From a UI perspective it would make sense to simply have a tick-box on the the Views UI contextual filter config panel. The problem is that at that point the plugin class has already been selected and instantiated. This is why we make the user define the contextual filter first, then have them select on this page which contextual filters need to be converted to range filters.
Hierarchy
- class \Drupal\Core\Form\FormBase implements ContainerInjectionInterface, FormInterface uses DependencySerializationTrait, LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\Core\Form\ConfigFormBase uses ConfigFormBaseTrait
- class \Drupal\contextual_range_filter\Form\ContextualRangeFilterAssignmentForm
- class \Drupal\Core\Form\ConfigFormBase uses ConfigFormBaseTrait
Expanded class hierarchy of ContextualRangeFilterAssignmentForm
1 string reference to 'ContextualRangeFilterAssignmentForm'
File
- src/
Form/ ContextualRangeFilterAssignmentForm.php, line 19
Namespace
Drupal\contextual_range_filter\FormView source
class ContextualRangeFilterAssignmentForm extends ConfigFormBase {
/**
* Return the form id.
*/
public function getFormId() {
return 'contextual_range_filter_settings';
}
/**
* Return the configuration route.
*/
protected function getEditableConfigNames() {
return [
'contextual_range_filter.settings',
];
}
/**
* Build the form.
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$range_fields = [
'date_field_names' => [],
'numeric_field_names' => [],
'string_field_names' => [],
];
$class_path = 'Drupal\\views\\Plugin\\views\\argument';
$argument_info = Views::pluginManager('argument')
->getDefinitions();
foreach (Views::getAllViews() as $view) {
$view_name = $view
->get('label');
if (views_view_is_disabled($view)) {
$view_name .= ' (' . $this
->t('disabled') . ')';
}
foreach ($view
->get('display') as $display) {
if (!empty($display['display_options']['arguments'])) {
foreach ($display['display_options']['arguments'] as $contextual_filter) {
$plugin_id = $contextual_filter['plugin_id'];
$class = $argument_info[$plugin_id]['class'];
// Does this contextual filter class extend one of the base
// contextual filter classes?
// Note: lists have a class of Numeric or String, so nothing special
// needs or can be done for lists...
$is_date_handler = is_a($class, "{$class_path}\\Date", TRUE);
$is_string_handler = is_a($class, "{$class_path}\\StringArgument", TRUE);
// Anything that is not a date or string will be shown as numeric.
$is_numeric_handler = !$is_date_handler && !$is_string_handler;
if ($is_date_handler || $is_numeric_handler || $is_string_handler) {
// For every View $display we get a number of fields.
// Should we allow selection per display AND per field?
// Currently we find, but don't add, the "duplicates".
// @todo: Find something more human-readible than this.
$title = "{$plugin_id}: " . $contextual_filter['id'];
// @todo Taxonomy term depth has Views machine name
// "taxonomy_term_data:tid", not "node:term_node_tid_depth".
$machine_name = $contextual_filter['table'] . ':' . $contextual_filter['field'];
if ($is_date_handler) {
$title_used = isset($range_fields['date_field_names'][$machine_name][$title]);
if (!$title_used || !in_array($view_name, $range_fields['date_field_names'][$machine_name][$title])) {
$range_fields['date_field_names'][$machine_name][$title][] = $view_name;
}
}
elseif ($is_numeric_handler) {
$title_used = isset($range_fields['numeric_field_names'][$machine_name][$title]);
if (!$title_used || !in_array($view_name, $range_fields['numeric_field_names'][$machine_name][$title])) {
$range_fields['numeric_field_names'][$machine_name][$title][] = $view_name;
}
}
elseif ($is_string_handler) {
$title_used = isset($range_fields['string_field_names'][$machine_name][$title]);
if (!$title_used || !in_array($view_name, $range_fields['string_field_names'][$machine_name][$title])) {
$range_fields['string_field_names'][$machine_name][$title][] = $view_name;
}
}
}
}
}
}
}
$form['field_names'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Select contextual filters to be converted to contextual range filters'),
];
$config = $this->configFactory
->get('contextual_range_filter.settings');
$labels = [
$this
->t('date'),
$this
->t('numeric'),
$this
->t('string'),
];
$label = reset($labels);
foreach ($range_fields as $type => $data) {
$options = [];
foreach ($data as $machine_name => $view_names) {
$title = key($view_names);
$views_list = implode(', ', $view_names[$title]);
$replace = [
'%field' => $title,
'@views' => $views_list,
];
$options[$machine_name] = $this
->t('%field in view @views', $replace);
$form['#view_names'][$machine_name] = $view_names;
}
$form['field_names'][$type] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Select which of the below contextual <em>@label</em> filters should be converted to <em>@label range</em> filters:', [
'@label' => $label,
]),
'#default_value' => $config
->get($type) ?: [],
'#options' => $options,
];
$label = next($labels);
}
$form['actions']['note'] = [
'#markup' => '<p><em>' . $this
->t('Caches will be cleared as part of this operation. This may take a while.') . '</em></p>',
'#weight' => 1,
];
return parent::buildForm($form, $form_state);
}
/**
* Submit the form.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$config = $this->configFactory
->getEditable('contextual_range_filter.settings');
foreach ([
'numeric',
'string',
'date',
] as $type) {
$field_names = $type . '_field_names';
// Clear out the unticked boxes.
$filters = array_filter($form_state
->getValue($field_names));
$saved_filters = $config
->get($field_names) ?: [];
$added_filters = array_diff($filters, $saved_filters);
$removed_filters = array_diff($saved_filters, $filters);
$changed_filters = array_merge($added_filters, $removed_filters);
if (empty($changed_filters)) {
continue;
}
$config
->set($field_names, $filters);
// Find corresponding Views, (un)set the (range) filter and save them.
// $form['#view_names'][node__field_price:field_price_value] is an array.
$changed_view_names = [];
foreach ($changed_filters as $filter_name) {
if (!empty($form['#view_names'][$filter_name])) {
foreach ($form['#view_names'][$filter_name] as $view_names) {
foreach ($view_names as $view_name) {
if (!in_array($view_name, $changed_view_names)) {
$changed_view_names[] = $view_name;
}
}
}
}
}
// We cycle through all the views. If the view is flagged as needing to be
// edited, we check if any of the changed filters is present in that view.
// If we find one, we (re)set the plugin id accordingly.
$range_type = $type . '_range';
foreach (Views::getAllViews() as $view) {
$view_name = $view
->get('label');
if (in_array($view_name, $changed_view_names)) {
$display =& $view
->getDisplay('default');
foreach ($changed_filters as $filter_name) {
$field_name = substr($filter_name, strpos($filter_name, ":") + 1);
if (isset($display['display_options']['arguments'][$field_name]['plugin_id'])) {
$plugin_id = in_array($filter_name, $added_filters) ? $range_type : $type;
$display['display_options']['arguments'][$field_name]['plugin_id'] = $plugin_id;
}
$this
->messenger()
->addStatus($this
->t('Updated contextual filter(s) on view %view_name.', [
'%view_name' => $view_name,
]));
$view
->save();
}
}
}
}
$config
->save();
// We now need to invoke contextual_range_filter_views_data_alter() for the
// changes to take effect. We do this by clearing the caches.
drupal_flush_all_caches();
parent::submitForm($form, $form_state);
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ConfigFormBase:: |
public static | function |
Instantiates a new instance of this class. Overrides FormBase:: |
13 |
ConfigFormBase:: |
public | function | Constructs a \Drupal\system\ConfigFormBase object. | 11 |
ConfigFormBaseTrait:: |
protected | function | Retrieves a configuration object. | |
ContextualRangeFilterAssignmentForm:: |
public | function |
Build the form. Overrides ConfigFormBase:: |
|
ContextualRangeFilterAssignmentForm:: |
protected | function |
Return the configuration route. Overrides ConfigFormBaseTrait:: |
|
ContextualRangeFilterAssignmentForm:: |
public | function |
Return the form id. Overrides FormInterface:: |
|
ContextualRangeFilterAssignmentForm:: |
public | function |
Submit the form. Overrides ConfigFormBase:: |
|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
FormBase:: |
protected | property | The config factory. | 1 |
FormBase:: |
protected | property | The request stack. | 1 |
FormBase:: |
protected | property | The route match. | |
FormBase:: |
protected | function | Gets the config factory for this form. | 1 |
FormBase:: |
private | function | Returns the service container. | |
FormBase:: |
protected | function | Gets the current user. | |
FormBase:: |
protected | function | Gets the request object. | |
FormBase:: |
protected | function | Gets the route match. | |
FormBase:: |
protected | function | Gets the logger for a specific channel. | |
FormBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
FormBase:: |
public | function | Resets the configuration factory. | |
FormBase:: |
public | function | Sets the config factory for this form. | |
FormBase:: |
public | function | Sets the request stack object to use. | |
FormBase:: |
public | function |
Form validation handler. Overrides FormInterface:: |
62 |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. |