search_api-8.x-1.15/src/Plugin/views/argument/SearchApiDate.php
src/Plugin/views/argument/SearchApiDate.php
<?php namespace Drupal\search_api\Plugin\views\argument; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Datetime\DateFormatterInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Defines a contextual filter for conditions on date fields. * * @ingroup views_argument_handlers * * @ViewsArgument("search_api_date") */ class SearchApiDate extends SearchApiStandard { /** * The date formatter. * * @var \Drupal\Core\Datetime\DateFormatterInterface|null */ protected $dateFormatter; /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { /** @var static $plugin */ $plugin = parent::create($container, $configuration, $plugin_id, $plugin_definition); $plugin->setDateFormatter($container->get('date.formatter')); return $plugin; } /** * Retrieves the date formatter. * * @return \Drupal\Core\Datetime\DateFormatterInterface * The date formatter. */ public function getDateFormatter() { return $this->dateFormatter ?: \Drupal::service('date.formatter'); } /** * Sets the date formatter. * * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter * The new date formatter. * * @return $this */ public function setDateFormatter(DateFormatterInterface $date_formatter) { $this->dateFormatter = $date_formatter; return $this; } /** * {@inheritdoc} */ public function query($group_by = FALSE) { $this->fillValue(); if ($this->value === FALSE) { $this->abort(); return; } $outer_conjunction = strtoupper($this->operator); if (empty($this->options['not'])) { $condition_operator = '='; $inner_conjunction = 'OR'; } else { $condition_operator = '<>'; $inner_conjunction = 'AND'; } if (!empty($this->value)) { $outer_conditions = $this->query->createConditionGroup($outer_conjunction); // @todo Refactor to use only a single nested filter, and only if // necessary. $value_conditions will currently only ever contain a // single child – a condition or a nested filter with two conditions. foreach ($this->value as $value) { $value_conditions = $this->query->createConditionGroup($inner_conjunction); $values = explode(';', $value); $values = array_map([$this, 'getTimestamp'], $values); if (in_array(FALSE, $values, TRUE)) { $this->abort(); return; } $is_range = (count($values) > 1); $inner_conditions = ($is_range ? $this->query->createConditionGroup('AND') : $value_conditions); $range_op = (empty($this->options['not']) ? '>=' : '<'); $inner_conditions->addCondition($this->realField, $values[0], $is_range ? $range_op : $condition_operator); if ($is_range) { $range_op = (empty($this->options['not']) ? '<=' : '>'); $inner_conditions->addCondition($this->realField, $values[1], $range_op); $value_conditions->addConditionGroup($inner_conditions); } $outer_conditions->addConditionGroup($value_conditions); } $this->query->addConditionGroup($outer_conditions); } } /** * {@inheritdoc} */ public function title() { if (!empty($this->argument)) { $this->fillValue(); $dates = []; foreach ($this->value as $date) { $date_parts = explode(';', $date); $ts = $this->getTimestamp($date_parts[0]); $date_string = $this->getDateFormatter()->format($ts, 'short'); if (count($date_parts) > 1) { $ts = $this->getTimestamp($date_parts[1]); $date_string .= ' – ' . $this->getDateFormatter()->format($ts, 'short'); } if ($date_string) { $dates[] = $date_string; } } return $dates ? implode(', ', $dates) : $this->argument; } return $this->argument; } /** * Converts a value to a timestamp, if it isn't one already. * * @param string|int $value * The value to convert. Either a timestamp, or a date/time string as * recognized by strtotime(). * * @return int|false * The parsed timestamp, or FALSE if an illegal string was passed. */ protected function getTimestamp($value) { if (is_numeric($value)) { return (int) $value; } return strtotime($value); } /** * {@inheritdoc} */ protected function unpackArgumentValue($force_int = FALSE) { // Set up the defaults. if (!isset($this->value)) { $this->value = []; } if (!isset($this->operator)) { $this->operator = 'or'; } if (empty($this->argument)) { return; } if (preg_match('/^([-\d;:\s]+\+)*[-\d;:\s]+$/', $this->argument)) { // The '+' character in a query string may be parsed as ' '. $this->value = explode('+', $this->argument); } elseif (preg_match('/^([-\d;:\s]+,)*[-\d;:\s]+$/', $this->argument)) { $this->operator = 'and'; $this->value = explode(',', $this->argument); } // Keep an "error" value if invalid strings were given. if (!empty($this->argument) && (empty($this->value) || !is_array($this->value))) { $this->value = FALSE; } } /** * Aborts the associated query due to an illegal argument. * * @see \Drupal\search_api\Plugin\views\query\SearchApiQuery::abort() */ protected function abort() { $variables['@field'] = $this->definition['group'] . ': ' . $this->definition['title']; $this->query->abort(new FormattableMarkup('Illegal argument passed to @field contextual filter.', $variables)); } }