Issue #1838242 by jhedstrom, pivica, tim.plunkett, GaëlG, dawehner, Lendude: Provide Views integration for datetime field
parent
7d532f7b0e
commit
26b7df5c43
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides views data for the datetime module.
|
||||
*/
|
||||
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_field_views_data().
|
||||
*/
|
||||
function datetime_field_views_data(FieldStorageConfigInterface $field_storage) {
|
||||
// @todo This code only covers configurable fields, handle base table fields
|
||||
// in https://www.drupal.org/node/2489476.
|
||||
$data = views_field_default_views_data($field_storage);
|
||||
foreach ($data as $table_name => $table_data) {
|
||||
// Set the 'datetime' filter type.
|
||||
$data[$table_name][$field_storage->getName() . '_value']['filter']['id'] = 'datetime';
|
||||
|
||||
// Set the 'datetime' argument type.
|
||||
$data[$table_name][$field_storage->getName() . '_value']['argument']['id'] = 'datetime';
|
||||
|
||||
// Create year, month, and day arguments.
|
||||
$group = $data[$table_name][$field_storage->getName() . '_value']['group'];
|
||||
$arguments = array(
|
||||
// Argument type => help text.
|
||||
'year' => t('Date in the form of YYYY.'),
|
||||
'month' => t('Date in the form of MM.'),
|
||||
'day' => t('Date in the form of DD.'),
|
||||
);
|
||||
foreach ($arguments as $argument_type => $help_text) {
|
||||
$data[$table_name][$field_storage->getName() . '_value_' . $argument_type] = array(
|
||||
'title' => $field_storage->getLabel() . ' (' . $argument_type . ')',
|
||||
'help' => $help_text,
|
||||
'argument' => array(
|
||||
'field' => $field_storage->getName() . '_value',
|
||||
'id' => 'datetime_' . $argument_type,
|
||||
),
|
||||
'group' => $group,
|
||||
);
|
||||
}
|
||||
|
||||
// Set the 'datetime' sort handler.
|
||||
$data[$table_name][$field_storage->getName() . '_value']['sort']['id'] = 'datetime';
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Plugin\views\Argument\Date.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Plugin\views\Argument;
|
||||
|
||||
use Drupal\views\Plugin\views\argument\Date as NumericDate;
|
||||
|
||||
/**
|
||||
* Abstract argument handler for dates.
|
||||
*
|
||||
* Adds an option to set a default argument based on the current date.
|
||||
*
|
||||
* Definitions terms:
|
||||
* - many to one: If true, the "many to one" helper will be used.
|
||||
* - invalid input: A string to give to the user for obviously invalid input.
|
||||
* This is deprecated in favor of argument validators.
|
||||
*
|
||||
* @see \Drupal\views\ManyTonOneHelper
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("datetime")
|
||||
*/
|
||||
class Date extends NumericDate {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDateField() {
|
||||
// Return the real field, since it is already in string format.
|
||||
return "$this->tableAlias.$this->realField";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDateFormat($format) {
|
||||
// Pass in the string-field option.
|
||||
return $this->query->getDateFormat($this->getDateField(), $format, TRUE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Plugin\views\argument\DayDate.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Plugin\views\argument;
|
||||
|
||||
/**
|
||||
* Argument handler for a day.
|
||||
*
|
||||
* @ViewsArgument("datetime_day")
|
||||
*/
|
||||
class DayDate extends Date {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $argFormat = 'd';
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Plugin\views\argument\MonthDate.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Plugin\views\argument;
|
||||
|
||||
/**
|
||||
* Argument handler for a month.
|
||||
*
|
||||
* @ViewsArgument("datetime_month")
|
||||
*/
|
||||
class MonthDate extends Date {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $argFormat = 'm';
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Plugin\views\argument\YearDate.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Plugin\views\argument;
|
||||
|
||||
/**
|
||||
* Argument handler for a year.
|
||||
*
|
||||
* @ViewsArgument("datetime_year")
|
||||
*/
|
||||
class YearDate extends Date {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $argFormat = 'Y';
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Plugin\views\filter\String.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Plugin\views\filter;
|
||||
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\views\Plugin\views\filter\Date as NumericDate;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Date/time views filter.
|
||||
*
|
||||
* Even thought dates are stored as strings, the numeric filter is extended
|
||||
* because it provides more sensible operators.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("datetime")
|
||||
*/
|
||||
class Date extends NumericDate implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* Constructs a new Date handler.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatter $date_formatter) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->dateFormatter = $date_formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('date.formatter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date format for SQL conversion.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @see \Drupal\views\Plugin\views\query\Sql::getDateFormat()
|
||||
*/
|
||||
protected static $dateFormat = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* Override parent method, which deals with dates as integers.
|
||||
*/
|
||||
protected function opBetween($field) {
|
||||
$origin = ($this->value['type'] == 'offset') ? REQUEST_TIME : 0;
|
||||
$a = intval(strtotime($this->value['min'], $origin));
|
||||
$b = intval(strtotime($this->value['max'], $origin));
|
||||
|
||||
// Convert to ISO format and format for query.
|
||||
$a = $this->query->getDateFormat("'" . $this->dateFormatter->format($a, 'custom', 'c') . "'", static::$dateFormat, TRUE);
|
||||
$b = $this->query->getDateFormat("'" . $this->dateFormatter->format($b, 'custom', 'c') . "'", static::$dateFormat, TRUE);
|
||||
|
||||
// This is safe because we are manually scrubbing the values.
|
||||
$operator = strtoupper($this->operator);
|
||||
$field = $this->query->getDateFormat($field, static::$dateFormat, TRUE);
|
||||
$this->query->addWhereExpression($this->options['group'], "$field $operator $a AND $b");
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parent method, which deals with dates as integers.
|
||||
*/
|
||||
protected function opSimple($field) {
|
||||
$origin = (!empty($this->value['type']) && $this->value['type'] == 'offset') ? REQUEST_TIME : 0;
|
||||
$value = intval(strtotime($this->value['value'], $origin));
|
||||
|
||||
// Convert to ISO.
|
||||
$value = $this->query->getDateFormat("'" . $this->dateFormatter->format($value, 'custom', 'c') . "'", static::$dateFormat, TRUE);
|
||||
|
||||
// This is safe because we are manually scrubbing the value.
|
||||
$field = $this->query->getDateFormat($field, static::$dateFormat, TRUE);
|
||||
$this->query->addWhereExpression($this->options['group'], "$field $this->operator $value");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Plugin\views\sort\Date.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Plugin\views\sort;
|
||||
|
||||
use Drupal\views\Plugin\views\sort\Date as NumericDate;
|
||||
|
||||
/**
|
||||
* Basic sort handler for datetime fields.
|
||||
*
|
||||
* This handler enables granularity, which is the ability to make dates
|
||||
* equivalent based upon nearness.
|
||||
*
|
||||
* @ViewsSort("datetime")
|
||||
*/
|
||||
class Date extends NumericDate {
|
||||
|
||||
/**
|
||||
* Override to account for dates stored as strings.
|
||||
*/
|
||||
public function getDateField() {
|
||||
// Return the real field, since it is already in string format.
|
||||
return "$this->tableAlias.$this->realField";
|
||||
}
|
||||
|
||||
/**
|
||||
* Override query to provide 'second' granularity.
|
||||
*/
|
||||
public function query() {
|
||||
$this->ensureMyTable();
|
||||
switch ($this->options['granularity']) {
|
||||
case 'second':
|
||||
$formula = $this->getDateFormat('YmdHis');
|
||||
$this->query->addOrderBy(NULL, $formula, $this->options['order'], $this->tableAlias . '_' . $this->field . '_' . $this->options['granularity']);
|
||||
return;
|
||||
}
|
||||
|
||||
// All other granularities are handled by the numeric sort handler.
|
||||
parent::query();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Tests\Views\ArgumentDateTimeTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Tests\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the Drupal\datetime\Plugin\views\filter\Date handler.
|
||||
*
|
||||
* @group datetime
|
||||
*/
|
||||
class ArgumentDateTimeTest extends DateTimeHandlerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = array('test_argument_datetime');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Add some basic test nodes.
|
||||
$dates = array(
|
||||
'2000-10-10',
|
||||
'2001-10-10',
|
||||
'2002-01-01',
|
||||
);
|
||||
foreach ($dates as $date) {
|
||||
$this->nodes[] = $this->drupalCreateNode(array(
|
||||
'field_date' => array(
|
||||
'value' => $date,
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test year argument.
|
||||
*
|
||||
* @see \Drupal\datetime\Plugin\views\argument\YearDate
|
||||
*/
|
||||
public function testDatetimeArgumentYear() {
|
||||
$view = Views::getView('test_argument_datetime');
|
||||
|
||||
// The 'default' display has the 'year' argument.
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view, array('2000'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[0]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view, array('2002'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[2]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test month argument.
|
||||
*
|
||||
* @see \Drupal\datetime\Plugin\views\argument\MonthDate
|
||||
*/
|
||||
public function testDatetimeArgumentMonth() {
|
||||
$view = Views::getView('test_argument_datetime');
|
||||
// The 'embed_1' display has the 'month' argument.
|
||||
$view->setDisplay('embed_1');
|
||||
|
||||
$this->executeView($view, array('10'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[0]->id());
|
||||
$expected[] = array('nid' => $this->nodes[1]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
$view->setDisplay('embed_1');
|
||||
$this->executeView($view, array('01'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[2]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test day argument.
|
||||
*
|
||||
* @see \Drupal\datetime\Plugin\views\argument\DayDate
|
||||
*/
|
||||
public function testDatetimeArgumentDay() {
|
||||
$view = Views::getView('test_argument_datetime');
|
||||
|
||||
// The 'embed_2' display has the 'day' argument.
|
||||
$view->setDisplay('embed_2');
|
||||
$this->executeView($view, array('10'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[0]->id());
|
||||
$expected[] = array('nid' => $this->nodes[1]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
$view->setDisplay('embed_2');
|
||||
$this->executeView($view, array('01'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[2]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test year, month, and day arguments combined.
|
||||
*/
|
||||
public function testDatetimeArgumentAll() {
|
||||
$view = Views::getView('test_argument_datetime');
|
||||
// The 'embed_3' display has year, month, and day arguments.
|
||||
$view->setDisplay('embed_3');
|
||||
|
||||
$this->executeView($view, array('2000', '10', '10'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[0]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
$view->setDisplay('embed_3');
|
||||
$this->executeView($view, array('2002', '01', '01'));
|
||||
$expected = array();
|
||||
$expected[] = array('nid' => $this->nodes[2]->id());
|
||||
$this->assertIdenticalResultset($view, $expected, $this->map);
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Tests\Views\DateTimeHandlerTestBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Tests\Views;
|
||||
|
||||
use Drupal\views\Tests\Handler\HandlerTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Base class for testing datetime handlers.
|
||||
*/
|
||||
abstract class DateTimeHandlerTestBase extends HandlerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('datetime_test', 'node', 'datetime');
|
||||
|
||||
/**
|
||||
* Name of the field.
|
||||
*
|
||||
* Note, this is used in the default test view.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $field_name = 'field_date';
|
||||
|
||||
/**
|
||||
* Nodes to test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $nodes = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Add a date field to page nodes.
|
||||
$node_type = entity_create('node_type', array(
|
||||
'type' => 'page',
|
||||
'name' => 'page'
|
||||
));
|
||||
$node_type->save();
|
||||
$fieldStorage = entity_create('field_storage_config', array(
|
||||
'field_name' => static::$field_name,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'datetime',
|
||||
'settings' => array('datetime_type' => 'datetime'),
|
||||
));
|
||||
$fieldStorage->save();
|
||||
$field = entity_create('field_config', array(
|
||||
'field_storage' => $fieldStorage,
|
||||
'bundle' => 'page',
|
||||
'required' => TRUE,
|
||||
));
|
||||
$field->save();
|
||||
|
||||
// Views needs to be aware of the new field.
|
||||
$this->container->get('views.views_data')->clear();
|
||||
|
||||
// Set column map.
|
||||
$this->map = array(
|
||||
'nid' => 'nid',
|
||||
);
|
||||
|
||||
// Load test views.
|
||||
ViewTestData::createTestViews(get_class($this), array('datetime_test'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Tests\Views\FilterDateTimeTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Tests\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the Drupal\datetime\Plugin\views\filter\Date handler.
|
||||
*
|
||||
* @group datetime
|
||||
*/
|
||||
class FilterDateTimeTest extends DateTimeHandlerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = array('test_filter_datetime');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Add some basic test nodes.
|
||||
$dates = array(
|
||||
'2000-10-10',
|
||||
'2001-10-10',
|
||||
'2002-10-10',
|
||||
\Drupal::service('date.formatter')->format(REQUEST_TIME + 86400, 'custom', 'Y-m-d'),
|
||||
);
|
||||
foreach ($dates as $date) {
|
||||
$this->nodes[] = $this->drupalCreateNode(array(
|
||||
'field_date' => array(
|
||||
'value' => $date,
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test filter operations.
|
||||
*/
|
||||
public function testDatetimeFilter() {
|
||||
$this->_testOffset();
|
||||
$this->_testBetween();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test offset operations.
|
||||
*/
|
||||
protected function _testOffset() {
|
||||
$view = Views::getView('test_filter_datetime');
|
||||
$field = static::$field_name . '_value';
|
||||
|
||||
// Test simple operations.
|
||||
$view->initHandlers();
|
||||
|
||||
$view->filter[$field]->operator = '>';
|
||||
$view->filter[$field]->value['type'] = 'offset';
|
||||
$view->filter[$field]->value['value'] = '+1 hour';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test offset for between operator.
|
||||
$view->initHandlers();
|
||||
$view->filter[$field]->operator = 'between';
|
||||
$view->filter[$field]->value['type'] = 'offset';
|
||||
$view->filter[$field]->value['max'] = '+2 days';
|
||||
$view->filter[$field]->value['min'] = '+1 hour';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test between operations.
|
||||
*/
|
||||
protected function _testBetween() {
|
||||
$view = Views::getView('test_filter_datetime');
|
||||
$field = static::$field_name . '_value';
|
||||
|
||||
// Test between with min and max.
|
||||
$view->initHandlers();
|
||||
$view->filter[$field]->operator = 'between';
|
||||
$view->filter[$field]->value['min'] = '2001-01-01';
|
||||
$view->filter[$field]->value['max'] = '2002-01-01';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[1]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test between with just max.
|
||||
$view->initHandlers();
|
||||
$view->filter[$field]->operator = 'between';
|
||||
$view->filter[$field]->value['max'] = '2002-01-01';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[0]->id()),
|
||||
array('nid' => $this->nodes[1]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test not between with min and max.
|
||||
$view->initHandlers();
|
||||
$view->filter[$field]->operator = 'not between';
|
||||
$view->filter[$field]->value['min'] = '2001-01-01';
|
||||
$view->filter[$field]->value['max'] = '2002-01-01';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[0]->id()),
|
||||
array('nid' => $this->nodes[2]->id()),
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Test not between with just max.
|
||||
$view->initHandlers();
|
||||
$view->filter[$field]->operator = 'not between';
|
||||
$view->filter[$field]->value['max'] = '2001-01-01';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[1]->id()),
|
||||
array('nid' => $this->nodes[2]->id()),
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\datetime\Tests\Views\SortDateTimeTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\datetime\Tests\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests for core Drupal\datetime\Plugin\views\sort\Date handler.
|
||||
*
|
||||
* @group datetime
|
||||
*/
|
||||
class SortDateTimeTest extends DateTimeHandlerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = array('test_sort_datetime');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Add some basic test nodes.
|
||||
$dates = array(
|
||||
'2014-10-10T00:03:00',
|
||||
'2000-10-10T00:01:00',
|
||||
'2000-10-10T00:02:00',
|
||||
'2000-10-10T00:03:00',
|
||||
);
|
||||
foreach ($dates as $date) {
|
||||
$this->nodes[] = $this->drupalCreateNode(array(
|
||||
'field_date' => array(
|
||||
'value' => $date,
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the datetime sort handler.
|
||||
*/
|
||||
public function testDateTimeSort() {
|
||||
$field = static::$field_name . '_value';
|
||||
$view = Views::getView('test_sort_datetime');
|
||||
|
||||
// Sort order is DESC.
|
||||
$view->initHandlers();
|
||||
$view->sort[$field]->options['granularity'] = 'minute';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[0]->id()),
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
array('nid' => $this->nodes[2]->id()),
|
||||
array('nid' => $this->nodes[1]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Check ASC.
|
||||
$view->initHandlers();
|
||||
$field = static::$field_name . '_value';
|
||||
$view->sort[$field]->options['order'] = 'ASC';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[1]->id()),
|
||||
array('nid' => $this->nodes[2]->id()),
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
array('nid' => $this->nodes[0]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
|
||||
// Change granularity to 'year', and the secondary node ID order should
|
||||
// define the order of nodes with the same year.
|
||||
$view->initHandlers();
|
||||
$view->sort[$field]->options['granularity'] = 'year';
|
||||
$view->sort[$field]->options['order'] = 'DESC';
|
||||
$view->setDisplay('default');
|
||||
$this->executeView($view);
|
||||
$expected_result = array(
|
||||
array('nid' => $this->nodes[0]->id()),
|
||||
array('nid' => $this->nodes[1]->id()),
|
||||
array('nid' => $this->nodes[2]->id()),
|
||||
array('nid' => $this->nodes[3]->id()),
|
||||
);
|
||||
$this->assertIdenticalResultset($view, $expected_result, $this->map);
|
||||
$view->destroy();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
name: 'Datetime test'
|
||||
type: module
|
||||
description: 'Provides default views for tests.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- views
|
|
@ -0,0 +1,99 @@
|
|||
langcode: und
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: test_argument_datetime
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
defaults:
|
||||
fields: false
|
||||
pager: false
|
||||
sorts: false
|
||||
arguments:
|
||||
field_date_value_year:
|
||||
field: field_date_value_year
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
plugin_id: datetime_year
|
||||
fields:
|
||||
id:
|
||||
field: nid
|
||||
id: nid
|
||||
relationship: none
|
||||
table: node
|
||||
plugin_id: numeric
|
||||
pager:
|
||||
options:
|
||||
offset: 0
|
||||
type: none
|
||||
sorts:
|
||||
id:
|
||||
field: nid
|
||||
id: nid
|
||||
order: ASC
|
||||
relationship: none
|
||||
table: node
|
||||
plugin_id: numeric
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
||||
embed_1:
|
||||
display_options:
|
||||
defaults:
|
||||
arguments: false
|
||||
arguments:
|
||||
field_date_value_month:
|
||||
field: field_date_value_month
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
plugin_id: datetime_month
|
||||
display_plugin: embed
|
||||
id: embed_1
|
||||
display_title: ''
|
||||
position: null
|
||||
embed_2:
|
||||
display_options:
|
||||
defaults:
|
||||
arguments: false
|
||||
arguments:
|
||||
field_date_value_day:
|
||||
field: field_date_value_day
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
plugin_id: datetime_day
|
||||
display_plugin: embed
|
||||
id: embed_2
|
||||
display_title: ''
|
||||
position: null
|
||||
embed_3:
|
||||
display_options:
|
||||
defaults:
|
||||
arguments: false
|
||||
arguments:
|
||||
field_date_value_year:
|
||||
field: field_date_value_year
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
plugin_id: datetime_year
|
||||
field_date_value_month:
|
||||
field: field_date_value_month
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
plugin_id: datetime_month
|
||||
field_date_value_day:
|
||||
field: field_date_value_day
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
plugin_id: datetime_day
|
||||
display_plugin: embed
|
||||
id: embed_2
|
||||
display_title: ''
|
||||
position: null
|
|
@ -0,0 +1,56 @@
|
|||
langcode: und
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: test_filter_datetime
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: none
|
||||
exposed_form:
|
||||
type: basic
|
||||
fields:
|
||||
nid:
|
||||
field: nid
|
||||
id: nid
|
||||
table: node
|
||||
plugin_id: node
|
||||
filters:
|
||||
field_date_value:
|
||||
id: field_date_value
|
||||
table: node__field_date
|
||||
field: field_date_value
|
||||
plugin_id: datetime
|
||||
sorts:
|
||||
id:
|
||||
field: nid
|
||||
id: nid
|
||||
order: ASC
|
||||
relationship: none
|
||||
table: node
|
||||
plugin_id: numeric
|
||||
pager:
|
||||
type: full
|
||||
query:
|
||||
options:
|
||||
query_comment: ''
|
||||
type: views_query
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,57 @@
|
|||
langcode: und
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: test_sort_datetime
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: none
|
||||
exposed_form:
|
||||
type: basic
|
||||
fields:
|
||||
nid:
|
||||
field: nid
|
||||
id: nid
|
||||
table: node
|
||||
plugin_id: node
|
||||
sorts:
|
||||
field_date_value:
|
||||
field: field_date_value
|
||||
id: field_date_value
|
||||
relationship: none
|
||||
table: node__field_date
|
||||
order: DESC
|
||||
plugin_id: datetime
|
||||
id:
|
||||
field: nid
|
||||
id: nid
|
||||
order: ASC
|
||||
relationship: none
|
||||
table: node
|
||||
plugin_id: numeric
|
||||
pager:
|
||||
type: full
|
||||
query:
|
||||
options:
|
||||
query_comment: ''
|
||||
type: views_query
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -237,12 +237,15 @@ abstract class QueryPluginBase extends PluginBase implements CacheablePluginInte
|
|||
* An appropriate query expression pointing to the date field.
|
||||
* @param string $format
|
||||
* A format string for the result, like 'Y-m-d H:i:s'.
|
||||
* @param boolean $string_date
|
||||
* For certain databases, date format functions vary depending on string or
|
||||
* numeric storage.
|
||||
*
|
||||
* @return string
|
||||
* A string representing the field formatted as a date in the format
|
||||
* specified by $format.
|
||||
*/
|
||||
public function getDateFormat($field, $format) {
|
||||
public function getDateFormat($field, $format, $string_date = FALSE) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
|
|
@ -1748,9 +1748,9 @@ class Sql extends QueryPluginBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\views\Plugin\views\query\QueryPluginBase::getDateFormat().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDateFormat($field, $format) {
|
||||
public function getDateFormat($field, $format, $string_date = FALSE) {
|
||||
$db_type = Database::getConnection()->databaseType();
|
||||
switch ($db_type) {
|
||||
case 'mysql':
|
||||
|
@ -1797,7 +1797,13 @@ class Sql extends QueryPluginBase {
|
|||
'A' => 'AM',
|
||||
);
|
||||
$format = strtr($format, $replace);
|
||||
return "TO_CHAR($field, '$format')";
|
||||
if (!$string_date) {
|
||||
return "TO_CHAR($field, '$format')";
|
||||
}
|
||||
// In order to allow for partials (eg, only the year), transform to a
|
||||
// date, back to a string again.
|
||||
// @todo this is very messy, and EXTRACT should probably be used.
|
||||
return "TO_CHAR(TO_TIMESTAMP($field, 'YYYY-MM-DD HH24:MI:SS'), '$format')";
|
||||
case 'sqlite':
|
||||
$replace = array(
|
||||
'Y' => '%Y',
|
||||
|
|
Loading…
Reference in New Issue