Last active
October 20, 2025 06:50
-
-
Save junaidpv/5bf0d42f255b7fe6b521fe6ea96e1596 to your computer and use it in GitHub Desktop.
It is exactly same patch as https://www.drupal.org/files/issues/2024-09-20/2982968-core-views-improve-date-filter-57.patch but mofied date format to use Americal style.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/core/modules/datetime/src/Plugin/views/filter/Date.php b/core/modules/datetime/src/Plugin/views/filter/Date.php | |
| index d401917b626..6f0dc28ecac 100644 | |
| --- a/core/modules/datetime/src/Plugin/views/filter/Date.php | |
| +++ b/core/modules/datetime/src/Plugin/views/filter/Date.php | |
| @@ -160,11 +160,20 @@ protected function opBetween($field) { | |
| // value as UNIX timestamp 0. | |
| $min = (!empty($this->value['min'])) ? $this->value['min'] : '@0'; | |
| + if (!empty($this->value['max']) && !strpos($this->value['max'], ':')) { | |
| + // No time was specified, so make the date range inclusive. | |
| + $this->value['max'] .= ' +1 day'; | |
| + } | |
| + | |
| + // Although both 'min' and 'max' values are required, default empty 'max' | |
| + // value as PHP_INT_MAX. | |
| + $max = (!empty($this->value['max'])) ? $this->value['max'] : DateTimePlus::createFromTimestamp(PHP_INT_MAX)->format('Y-m-d'); | |
| + | |
| // Convert to ISO format and format for query. UTC timezone is used since | |
| // dates are stored in UTC. | |
| $a = new DateTimePlus($min, new \DateTimeZone($timezone)); | |
| $a = $this->query->getDateFormat($this->query->getDateField("'" . $this->dateFormatter->format($a->getTimestamp() + $origin_offset, 'custom', DateTimeItemInterface::DATETIME_STORAGE_FORMAT, DateTimeItemInterface::STORAGE_TIMEZONE) . "'", TRUE, $this->calculateOffset), $this->dateFormat, TRUE); | |
| - $b = new DateTimePlus($this->value['max'], new \DateTimeZone($timezone)); | |
| + $b = new DateTimePlus($max, new \DateTimeZone($timezone)); | |
| $b = $this->query->getDateFormat($this->query->getDateField("'" . $this->dateFormatter->format($b->getTimestamp() + $origin_offset, 'custom', DateTimeItemInterface::DATETIME_STORAGE_FORMAT, DateTimeItemInterface::STORAGE_TIMEZONE) . "'", TRUE, $this->calculateOffset), $this->dateFormat, TRUE); | |
| // This is safe because we are manually scrubbing the values. | |
| diff --git a/core/modules/views/src/Plugin/views/filter/Date.php b/core/modules/views/src/Plugin/views/filter/Date.php | |
| index 84d776c4b64..6382418bfaa 100644 | |
| --- a/core/modules/views/src/Plugin/views/filter/Date.php | |
| +++ b/core/modules/views/src/Plugin/views/filter/Date.php | |
| @@ -13,37 +13,52 @@ | |
| #[ViewsFilter("date")] | |
| class Date extends NumericFilter { | |
| - protected function defineOptions() { | |
| - $options = parent::defineOptions(); | |
| - | |
| - // Value is already set up properly, we're just adding our new field to it. | |
| - $options['value']['contains']['type']['default'] = 'date'; | |
| - | |
| - return $options; | |
| - } | |
| - | |
| /** | |
| - * Add a type selector to the value form. | |
| + * {@inheritdoc} | |
| */ | |
| protected function valueForm(&$form, FormStateInterface $form_state) { | |
| + parent::valueForm($form, $form_state); | |
| + | |
| if (!$form_state->get('exposed')) { | |
| - $form['value']['type'] = [ | |
| - '#type' => 'radios', | |
| - '#title' => $this->t('Value type'), | |
| - '#options' => [ | |
| - 'date' => $this->t('A date in any machine readable format. CCYY-MM-DD HH:MM:SS is preferred.'), | |
| - 'offset' => $this->t('An offset from the current time such as "@example1" or "@example2"', ['@example1' => '+1 day', '@example2' => '-2 hours -30 minutes']), | |
| - ], | |
| - '#default_value' => !empty($this->value['type']) ? $this->value['type'] : 'date', | |
| - ]; | |
| + // Use default values from options on the config form. | |
| + foreach (['min', 'max', 'value'] as $component) { | |
| + if (isset($this->options['value'][$component]) && isset($form['value'][$component])) { | |
| + $form['value'][$component]['#default_value'] = $this->options['value'][$component]; | |
| + | |
| + // Add description. | |
| + $form['value'][$component]['#description'] = $this->t('A date in any machine readable format (CCYY-MM-DD is preferred) or an offset from the current time such as "@example1" or "@example2".', [ | |
| + '@example1' => '+1 day', | |
| + '@example2' => '-2 years -10 days', | |
| + ]); | |
| + } | |
| + } | |
| + } | |
| + else { | |
| + // Convert relative date string representations to actual dates | |
| + // to solve potential datepicker problems. | |
| + foreach (['min', 'max', 'value'] as $component) { | |
| + if ( | |
| + isset($form['value'][$component]) && | |
| + !empty($form['value'][$component]['#default_value']) && | |
| + preg_match('/[a-zA-Z]+/', $form['value'][$component]['#default_value']) | |
| + ) { | |
| + $form['value'][$component]['#default_value'] = date('m/d/Y', strtotime($form['value'][$component]['#default_value'])); | |
| + } | |
| + } | |
| } | |
| - parent::valueForm($form, $form_state); | |
| } | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| public function validateOptionsForm(&$form, FormStateInterface $form_state) { | |
| parent::validateOptionsForm($form, $form_state); | |
| - if (!empty($this->options['exposed']) && $form_state->isValueEmpty(['options', 'expose', 'required'])) { | |
| + if (!empty($this->options['exposed']) && $form_state->isValueEmpty([ | |
| + 'options', | |
| + 'expose', | |
| + 'required', | |
| + ])) { | |
| // Who cares what the value is if it's exposed and non-required. | |
| return; | |
| } | |
| @@ -51,6 +66,9 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) { | |
| $this->validateValidTime($form['value'], $form_state, $form_state->getValue(['options', 'operator']), $form_state->getValue(['options', 'value'])); | |
| } | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| public function validateExposed(&$form, FormStateInterface $form_state) { | |
| if (empty($this->options['exposed'])) { | |
| return; | |
| @@ -105,39 +123,23 @@ protected function hasValidGroupedValue(array $group) { | |
| return FALSE; | |
| } | |
| - // Special case when validating grouped date filters because the | |
| - // $group['value'] array contains the type of filter (date or offset) and | |
| - // therefore the number of items the comparison has to be done against is | |
| - // one greater. | |
| $operators = $this->operators(); | |
| - $expected = $operators[$group['operator']]['values'] + 1; | |
| + $expected = $operators[$group['operator']]['values']; | |
| $actual = count(array_filter($group['value'], [static::class, 'arrayFilterZero'])); | |
| return $actual == $expected; | |
| } | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| public function acceptExposedInput($input) { | |
| if (empty($this->options['exposed'])) { | |
| return TRUE; | |
| } | |
| - // Store this because it will get overwritten. | |
| - $type = NULL; | |
| - if ($this->isAGroup()) { | |
| - if (is_array($this->group_info)) { | |
| - $type = $this->group_info['type']; | |
| - } | |
| - } | |
| - else { | |
| - $type = $this->value['type']; | |
| - } | |
| $rc = parent::acceptExposedInput($input); | |
| - // Restore what got overwritten by the parent. | |
| - if (!is_null($type)) { | |
| - $this->value['type'] = $type; | |
| - } | |
| - | |
| // Don't filter if value(s) are empty. | |
| $operators = $this->operators(); | |
| if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) { | |
| @@ -156,8 +158,8 @@ public function acceptExposedInput($input) { | |
| } | |
| elseif ($operators[$operator]['values'] == 2) { | |
| // When the operator is either between or not between the input contains | |
| - // two values. | |
| - if ($this->value['min'] == '' || $this->value['max'] == '') { | |
| + // at least one value. | |
| + if (empty($this->value['min']) && empty($this->value['max'])) { | |
| return FALSE; | |
| } | |
| } | |
| @@ -165,31 +167,57 @@ public function acceptExposedInput($input) { | |
| return $rc; | |
| } | |
| + /** | |
| + * Helper function to get converted values for the query. | |
| + * | |
| + * @return array | |
| + * Array of timestamps. | |
| + */ | |
| + protected function getConvertedValues() { | |
| + $values = []; | |
| + if (!empty($this->value['max']) && !strpos($this->value['max'], ':')) { | |
| + // No time was specified, so make the date range inclusive. | |
| + $this->value['max'] .= ' +1 day'; | |
| + } | |
| + foreach (['min', 'max', 'value'] as $component) { | |
| + if (!empty($this->value[$component])) { | |
| + $values[$component] = intval(strtotime($this->value[$component])); | |
| + } | |
| + } | |
| + return $values; | |
| + } | |
| + | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| protected function opBetween($field) { | |
| - $a = intval(strtotime($this->value['min'], 0)); | |
| - $b = intval(strtotime($this->value['max'], 0)); | |
| - | |
| - if ($this->value['type'] == 'offset') { | |
| - // Keep sign. | |
| - $a = '***CURRENT_TIME***' . sprintf('%+d', $a); | |
| - // Keep sign. | |
| - $b = '***CURRENT_TIME***' . sprintf('%+d', $b); | |
| - } | |
| - // This is safe because we are manually scrubbing the values. | |
| - // It is necessary to do it this way because $a and $b are formulas when using an offset. | |
| - $operator = strtoupper($this->operator); | |
| - $this->query->addWhereExpression($this->options['group'], "$field $operator $a AND $b"); | |
| + $values = $this->getConvertedValues(); | |
| + if (empty($values)) { | |
| + // do nothing | |
| + return; | |
| + } | |
| + // Support providing only one value for exposed filters. | |
| + if (empty($values['min'])) { | |
| + $operator = $this->operator === 'between' ? '<=' : '>'; | |
| + $this->query->addWhereExpression($this->options['group'], "$field $operator {$values['max']}"); | |
| + } | |
| + elseif (empty($values['max'])) { | |
| + $operator = $this->operator === 'between' ? '>=' : '<'; | |
| + $this->query->addWhereExpression($this->options['group'], "$field $operator {$values['min']}"); | |
| + } | |
| + // Both values given. | |
| + else { | |
| + $operator = strtoupper($this->operator); | |
| + $this->query->addWhereExpression($this->options['group'], "$field $operator {$values['min']} AND {$values['max']}"); | |
| + } | |
| } | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| protected function opSimple($field) { | |
| - $value = intval(strtotime($this->value['value'], 0)); | |
| - if (!empty($this->value['type']) && $this->value['type'] == 'offset') { | |
| - // Keep sign. | |
| - $value = '***CURRENT_TIME***' . sprintf('%+d', $value); | |
| - } | |
| - // This is safe because we are manually scrubbing the value. | |
| - // It is necessary to do it this way because $value is a formula when using an offset. | |
| - $this->query->addWhereExpression($this->options['group'], "$field $this->operator $value"); | |
| + $values = $this->getConvertedValues(); | |
| + $this->query->addWhereExpression($this->options['group'], "$field $this->operator {$values['value']}"); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment