diff --git a/core/modules/datetime/datetime.views.inc b/core/modules/datetime/datetime.views.inc index 1512dcce49..455c9cf58b 100644 --- a/core/modules/datetime/datetime.views.inc +++ b/core/modules/datetime/datetime.views.inc @@ -27,6 +27,9 @@ function datetime_field_views_data(FieldStorageConfigInterface $field_storage) { * Field view data or views_field_default_views_data($field_storage) if empty. * @param string $column_name * The schema column name with the datetime value. + * @param string[] $plugin_ids + * An associative array of plugin IDs keyed by handler type. Defaults to + * "datetime" for all handler types. * * @return array * The array of field views data with the datetime plugin. @@ -34,16 +37,22 @@ function datetime_field_views_data(FieldStorageConfigInterface $field_storage) { * @see datetime_field_views_data() * @see datetime_range_field_views_data() */ -function datetime_type_field_views_data_helper(FieldStorageConfigInterface $field_storage, array $data, $column_name) { +function datetime_type_field_views_data_helper(FieldStorageConfigInterface $field_storage, array $data, $column_name, $plugin_ids = []) { + $plugin_ids += [ + 'filter' => 'datetime', + 'argument' => 'datetime', + 'sort' => 'datetime', + ]; + // @todo This code only covers configurable fields, handle base table fields // in https://www.drupal.org/node/2489476. $data = empty($data) ? views_field_default_views_data($field_storage) : $data; foreach ($data as $table_name => $table_data) { // Set the 'datetime' filter type. - $data[$table_name][$field_storage->getName() . '_' . $column_name]['filter']['id'] = 'datetime'; + $data[$table_name][$field_storage->getName() . '_' . $column_name]['filter']['id'] = $plugin_ids['filter']; // Set the 'datetime' argument type. - $data[$table_name][$field_storage->getName() . '_' . $column_name]['argument']['id'] = 'datetime'; + $data[$table_name][$field_storage->getName() . '_' . $column_name]['argument']['id'] = $plugin_ids['argument']; // Create year, month, and day arguments. $group = $data[$table_name][$field_storage->getName() . '_' . $column_name]['group']; @@ -67,7 +76,7 @@ function datetime_type_field_views_data_helper(FieldStorageConfigInterface $fiel 'help' => $help_text, 'argument' => [ 'field' => $field_storage->getName() . '_' . $column_name, - 'id' => 'datetime_' . $argument_type, + 'id' => $plugin_ids['argument'] . '_' . $argument_type, 'entity_type' => $field_storage->getTargetEntityTypeId(), 'field_name' => $field_storage->getName(), ], @@ -76,7 +85,7 @@ function datetime_type_field_views_data_helper(FieldStorageConfigInterface $fiel } // Set the 'datetime' sort handler. - $data[$table_name][$field_storage->getName() . '_' . $column_name]['sort']['id'] = 'datetime'; + $data[$table_name][$field_storage->getName() . '_' . $column_name]['sort']['id'] = $plugin_ids['sort']; } return $data; diff --git a/core/modules/datetime/src/Plugin/views/argument/Date.php b/core/modules/datetime/src/Plugin/views/argument/Date.php index 4b8caa57c6..a1ffa723b0 100644 --- a/core/modules/datetime/src/Plugin/views/argument/Date.php +++ b/core/modules/datetime/src/Plugin/views/argument/Date.php @@ -2,6 +2,7 @@ namespace Drupal\datetime\Plugin\views\argument; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; use Drupal\views\FieldAPIHandlerTrait; @@ -48,6 +49,63 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition } } + + /** + * {@inheritdoc} + */ + protected function defineOptions() { + $options = parent::defineOptions(); + $options['operator'] = ['default' => '=']; + $options['formula'] = [ + 'contains' => [ + 'operator' => ['default' => '='], + ], + ]; + return $options; + } + + /** + * {@inheritdoc} + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + parent::buildOptionsForm($form, $form_state); + + $form['formula'] = [ + '#type' => 'details', + '#title' => $this->t('Formula'), + ]; + $form['formula']['operator'] = [ + '#type' => 'select', + '#title' => $this->t('Operator'), + '#options' => [ + '<' => $this->t('Is less than'), + '<=' => $this->t('Is less than or equal to'), + '=' => $this->t('Is equal to'), + '>=' => $this->t('Is greater than or equal to'), + '>' => $this->t('Is greater than'), + ], + '#default_value' => $this->options['formula']['operator'], + '#required' => TRUE, + ]; + } + + /** + * {@inheritdoc} + * + * This identical to the original query method except for the configurable + * operator. + */ + public function query($group_by = FALSE) { + $this->ensureMyTable(); + // Now that our table is secure, get our formula. + $placeholder = $this->placeholder(); + $formula = $this->getFormula() . " {$this->options['formula']['operator']} " . $placeholder; + $placeholders = [ + $placeholder => $this->argument, + ]; + $this->query->addWhere(0, $formula, $placeholders, 'formula'); + } + /** * {@inheritdoc} */ diff --git a/core/modules/datetime/tests/src/Kernel/Views/ArgumentDateTimeTest.php b/core/modules/datetime/tests/src/Kernel/Views/ArgumentDateTimeTest.php index 8261b27793..4361641992 100644 --- a/core/modules/datetime/tests/src/Kernel/Views/ArgumentDateTimeTest.php +++ b/core/modules/datetime/tests/src/Kernel/Views/ArgumentDateTimeTest.php @@ -48,7 +48,7 @@ protected function setUp($import_test_views = TRUE) { /** * Test year argument. * - * @see \Drupal\datetime\Plugin\views\argument\YearDate + * @see \Drupal\datetime\Plugin\views\argument\YearDateRange */ public function testDatetimeArgumentYear() { $view = Views::getView('test_argument_datetime'); @@ -91,7 +91,7 @@ public function testDatetimeArgumentYear() { /** * Test month argument. * - * @see \Drupal\datetime\Plugin\views\argument\MonthDate + * @see \Drupal\datetime\Plugin\views\argument\MonthDateRange */ public function testDatetimeArgumentMonth() { $view = Views::getView('test_argument_datetime'); diff --git a/core/modules/datetime_range/datetime_range.views.inc b/core/modules/datetime_range/datetime_range.views.inc index 6892ab244e..9abc9b6a5a 100644 --- a/core/modules/datetime_range/datetime_range.views.inc +++ b/core/modules/datetime_range/datetime_range.views.inc @@ -17,8 +17,11 @@ function datetime_range_field_views_data(FieldStorageConfigInterface $field_stor \Drupal::moduleHandler()->loadInclude('datetime', 'inc', 'datetime.views'); // Get datetime field data for value and end_value. - $data = datetime_type_field_views_data_helper($field_storage, [], 'value'); - $data = datetime_type_field_views_data_helper($field_storage, $data, 'end_value'); + $plugin_ids = [ + 'argument' => 'datetime_range', + ]; + $data = datetime_type_field_views_data_helper($field_storage, [], 'value', $plugin_ids); + $data = datetime_type_field_views_data_helper($field_storage, $data, 'end_value', $plugin_ids); return $data; } diff --git a/core/modules/datetime_range/src/Plugin/views/argument/DateRange.php b/core/modules/datetime_range/src/Plugin/views/argument/DateRange.php new file mode 100644 index 0000000000..a4b70fec49 --- /dev/null +++ b/core/modules/datetime_range/src/Plugin/views/argument/DateRange.php @@ -0,0 +1,118 @@ +startDateField = str_replace('_end_value', '_value', $this->realField); + $this->endDateField = str_replace('_value', '_end_value', $this->startDateField); + } + + /** + * {@inheritdoc} + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + parent::buildOptionsForm($form, $form_state); + + $form['formula']['operator']['#options'] += [ + 'range_intersects' => $this->t('Intersects range'), + ]; + } + + /** + * {@inheritdoc} + */ + public function query($group_by = FALSE) { + if (strpos($this->options['formula']['operator'], 'range_') !== 0) { + parent::query($group_by); + return; + } + + $this->ensureMyTable(); + + $placeholder = $this->placeholder(); + $start_date_placeholder = $this->getStartDateQueryElement($placeholder); + $end_date_placeholder = $this->getEndDateQueryElement($start_date_placeholder); + + $formula = $this->getFormula(); + $start_date_formula = $this->getStartDateQueryElement($formula); + $end_date_formula = $this->getEndDateQueryElement($start_date_formula); + + $condition = ''; + switch ($this->options['formula']['operator']) { + case 'range_intersects': + $condition = "($end_date_formula >= $start_date_placeholder AND $start_date_formula <= $end_date_placeholder)"; + break; + } + + $placeholders = [ + $start_date_placeholder => $this->argument, + $end_date_placeholder => $this->argument, + ]; + + /** @var \Drupal\views\Plugin\views\query\Sql $query */ + $query = $this->query; + $query->addWhere(0, $condition, $placeholders, 'formula'); + } + + /** + * Converts a query element into the corresponding start date element. + * + * @param string $query_element + * A portion of a SQL query prepared statement. + * + * @return string + * The corresponding start date element. + */ + protected function getStartDateQueryElement($query_element) { + return str_replace($this->endDateField, $this->startDateField, $query_element); + } + + /** + * Converts a query element into the corresponding end date element. + * + * @param string $query_element + * A portion of a SQL query prepared statement. + * + * @return string + * The corresponding end date element. + */ + protected function getEndDateQueryElement($query_element) { + return str_replace($this->startDateField, $this->endDateField, $query_element); + } + +} diff --git a/core/modules/datetime_range/src/Plugin/views/argument/DayDateRange.php b/core/modules/datetime_range/src/Plugin/views/argument/DayDateRange.php new file mode 100644 index 0000000000..f5d7bfeb8e --- /dev/null +++ b/core/modules/datetime_range/src/Plugin/views/argument/DayDateRange.php @@ -0,0 +1,17 @@ +