Commit 2099b18e authored by Dries's avatar Dries

Issue #1934448 by chx, dawehner: Clean up a little Views date handling/arguments.

parent 497bec2d
......@@ -22,14 +22,6 @@
*/
class CreatedDay extends Date {
/**
* Overrides Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
function get_formula() {
$this->formula = $this->extractSQL('DAY');
return parent::get_formula();
}
/**
* Provide a link to the next level of the view
*/
......
......@@ -22,14 +22,6 @@
*/
class CreatedFullDate extends Date {
/**
* Overrides Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
function get_formula() {
$this->formula = $this->getSQLFormat($this->definition['arg_format']);
return parent::get_formula();
}
/**
* Provide a link to the next level of the view
*/
......
......@@ -22,14 +22,6 @@
*/
class CreatedMonth extends Date {
/**
* Overrides Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
function get_formula() {
$this->formula = $this->extractSQL('MONTH');
return parent::get_formula();
}
/**
* Provide a link to the next level of the view
*/
......
......@@ -15,20 +15,12 @@
*
* @Plugin(
* id = "node_created_week",
* arg_format = "w",
* arg_format = "W",
* module = "node"
* )
*/
class CreatedWeek extends Date {
/**
* Overrides Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
function get_formula() {
$this->formula = $this->extractSQL('WEEK');
return parent::get_formula();
}
/**
* Provide a link to the next level of the view
*/
......
......@@ -21,12 +21,4 @@
*/
class CreatedYear extends Date {
/**
* Overrides Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
function get_formula() {
$this->formula = $this->extractSQL('YEAR');
return parent::get_formula();
}
}
......@@ -22,14 +22,6 @@
*/
class CreatedYearMonth extends Date {
/**
* Overrides Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
function get_formula() {
$this->formula = $this->getSQLFormat($this->definition['arg_format']);
return parent::get_formula();
}
/**
* Provide a link to the next level of the view
*/
......
......@@ -620,74 +620,8 @@ public function broken() { }
* @return string
* An appropriate SQL string for the DB type and field type.
*/
public function getSQLFormat($format) {
$db_type = Database::getConnection()->databaseType();
$field = $this->getSQLDateField();
switch ($db_type) {
case 'mysql':
$replace = array(
'Y' => '%Y',
'y' => '%y',
'M' => '%b',
'm' => '%m',
'n' => '%c',
'F' => '%M',
'D' => '%a',
'd' => '%d',
'l' => '%W',
'j' => '%e',
'W' => '%v',
'H' => '%H',
'h' => '%h',
'i' => '%i',
's' => '%s',
'A' => '%p',
);
$format = strtr($format, $replace);
return "DATE_FORMAT($field, '$format')";
case 'pgsql':
$replace = array(
'Y' => 'YYYY',
'y' => 'YY',
'M' => 'Mon',
'm' => 'MM',
'n' => 'MM', // no format for Numeric representation of a month, without leading zeros
'F' => 'Month',
'D' => 'Dy',
'd' => 'DD',
'l' => 'Day',
'j' => 'DD', // no format for Day of the month without leading zeros
'W' => 'WW',
'H' => 'HH24',
'h' => 'HH12',
'i' => 'MI',
's' => 'SS',
'A' => 'AM',
);
$format = strtr($format, $replace);
return "TO_CHAR($field, '$format')";
case 'sqlite':
$replace = array(
'Y' => '%Y', // 4 digit year number
'y' => '%Y', // no format for 2 digit year number
'M' => '%m', // no format for 3 letter month name
'm' => '%m', // month number with leading zeros
'n' => '%m', // no format for month number without leading zeros
'F' => '%m', // no format for full month name
'D' => '%d', // no format for 3 letter day name
'd' => '%d', // day of month number with leading zeros
'l' => '%d', // no format for full day name
'j' => '%d', // no format for day of month number without leading zeros
'W' => '%W', // ISO week number
'H' => '%H', // 24 hour hour with leading zeros
'h' => '%H', // no format for 12 hour hour with leading zeros
'i' => '%M', // minutes with leading zeros
's' => '%S', // seconds with leading zeros
'A' => '', // no format for AM/PM
);
$format = strtr($format, $replace);
return "strftime('$format', $field, 'unixepoch')";
}
public function getDateFormat($format) {
return $this->query->getDateFormat($this->getDateField(), $format);
}
/**
......@@ -696,61 +630,8 @@ public function getSQLFormat($format) {
* @return string
* An appropriate SQL string for the db type and field type.
*/
public function getSQLDateField() {
$field = "$this->tableAlias.$this->realField";
$db_type = Database::getConnection()->databaseType();
$offset = $this->getTimezone();
if (isset($offset) && !is_numeric($offset)) {
$dtz = new \DateTimeZone($offset);
$dt = new \DateTime('now', $dtz);
$offset_seconds = $dtz->getOffset($dt);
}
switch ($db_type) {
case 'mysql':
$field = "DATE_ADD('19700101', INTERVAL $field SECOND)";
if (!empty($offset)) {
$field = "($field + INTERVAL $offset_seconds SECOND)";
}
return $field;
case 'pgsql':
$field = "TO_TIMESTAMP($field)";
if (!empty($offset)) {
$field = "($field + INTERVAL '$offset_seconds SECONDS')";
}
return $field;
case 'sqlite':
if (!empty($offset)) {
$field = "($field + '$offset_seconds')";
}
return $field;
}
}
/**
* Figure out what timezone we're in; needed for some date manipulations.
*/
public static function getTimezone() {
$timezone = drupal_get_user_timezone();
// set up the database timezone
$db_type = Database::getConnection()->databaseType();
if (in_array($db_type, array('mysql', 'pgsql'))) {
$offset = '+00:00';
static $already_set = FALSE;
if (!$already_set) {
if ($db_type == 'pgsql') {
db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
}
elseif ($db_type == 'mysql') {
db_query("SET @@session.time_zone = '$offset'");
}
$already_set = TRUE;
}
}
return $timezone;
public function getDateField() {
return $this->query->getDateField("$this->tableAlias.$this->realField");
}
/**
......
......@@ -14,27 +14,25 @@
*
* Adds an option to set a default argument based on the current date.
*
* @param $arg_format
* The format string to use on the current time when
* creating a default date argument.
*
* 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.
* - arg_format: The format string to use on the current time when dealing with
* date values.
*
* @see Drupal\views\ManyTonOneHelper
*
* @ingroup views_argument_handlers
*
* @Plugin(
* id = "date"
* id = "date",
* arg_format = "Y-m-d"
* )
*/
class Date extends Formula {
var $option_name = 'default_argument_date';
var $arg_format = 'Y-m-d';
/**
* Add an option to set the default value to the current date.
......@@ -84,62 +82,11 @@ function get_sort_name() {
}
/**
* Creates cross-database SQL date extraction.
*
* @param string $extract_type
* The type of value to extract from the date, like 'MONTH'.
*
* @return string
* An appropriate SQL string for the DB type and field type.
* Overrides \Drupal\views\Plugin\views\argument\Formula::get_formula().
*/
public function extractSQL($extract_type) {
$db_type = Database::getConnection()->databaseType();
$field = $this->getSQLDateField();
// Note there is no space after FROM to avoid db_rewrite problems
// see http://drupal.org/node/79904.
switch ($extract_type) {
case 'DATE':
return $field;
case 'YEAR':
return "EXTRACT(YEAR FROM($field))";
case 'MONTH':
return "EXTRACT(MONTH FROM($field))";
case 'DAY':
return "EXTRACT(DAY FROM($field))";
case 'HOUR':
return "EXTRACT(HOUR FROM($field))";
case 'MINUTE':
return "EXTRACT(MINUTE FROM($field))";
case 'SECOND':
return "EXTRACT(SECOND FROM($field))";
// ISO week number for date
case 'WEEK':
switch ($db_type) {
case 'mysql':
// WEEK using arg 3 in mysql should return the same value as postgres
// EXTRACT.
return "WEEK($field, 3)";
case 'pgsql':
return "EXTRACT(WEEK FROM($field))";
}
case 'DOW':
switch ($db_type) {
case 'mysql':
// mysql returns 1 for Sunday through 7 for Saturday php date
// functions and postgres use 0 for Sunday and 6 for Saturday.
return "INTEGER(DAYOFWEEK($field) - 1)";
case 'pgsql':
return "EXTRACT(DOW FROM($field))";
}
case 'DOY':
switch ($db_type) {
case 'mysql':
return "DAYOFYEAR($field)";
case 'pgsql':
return "EXTRACT(DOY FROM($field))";
}
}
function get_formula() {
$this->formula = $this->getDateFormat($this->definition['arg_format']);
return parent::get_formula();
}
}
......@@ -169,4 +169,43 @@ function set_group_operator($type = 'AND') {
*/
function load_entities(&$results) {}
/**
* Returns a Unix timestamp to database native timestamp expression.
*
* @param string $field
* The query field that will be used in the expression.
*
* @return string
* An expression representing a timestamp with time zone.
*/
public function getDateField($field) {
return $field;
}
/**
* Set the database to the current user timezone,
*
* @return string
* The current timezone as returned by drupal_get_user_timezone().
*/
public function setupTimezone() {
return drupal_get_user_timezone();
}
/**
* Creates cross-database date formatting.
*
* @param string $field
* 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'.
*
* @return string
* A string representing the field formatted as a date in the format
* specified by $format.
*/
public function getDateFormat($field, $format) {
return $field;
}
}
......@@ -1739,4 +1739,149 @@ function aggregation_method_distinct($group_type, $field) {
return strtoupper($group_type) . '(DISTINCT ' . $field . ')';
}
/**
* Overrides \Drupal\views\Plugin\views\query\QueryPluginBase::getDateField().
*/
public function getDateField($field) {
$db_type = Database::getConnection()->databaseType();
$offset = $this->setupTimezone();
if (isset($offset) && !is_numeric($offset)) {
$dtz = new \DateTimeZone($offset);
$dt = new \DateTime('now', $dtz);
$offset_seconds = $dtz->getOffset($dt);
}
switch ($db_type) {
case 'mysql':
$field = "DATE_ADD('19700101', INTERVAL $field SECOND)";
if (!empty($offset)) {
$field = "($field + INTERVAL $offset_seconds SECOND)";
}
break;
case 'pgsql':
$field = "TO_TIMESTAMP($field)";
if (!empty($offset)) {
$field = "($field + INTERVAL '$offset_seconds SECONDS')";
}
break;
case 'sqlite':
if (!empty($offset)) {
$field = "($field + '$offset_seconds')";
}
break;
}
return $field;
}
/**
* Overrides \Drupal\views\Plugin\views\query\QueryPluginBase::setupTimezone().
*/
public function setupTimezone() {
$timezone = drupal_get_user_timezone();
// set up the database timezone
$db_type = Database::getConnection()->databaseType();
if (in_array($db_type, array('mysql', 'pgsql'))) {
$offset = '+00:00';
static $already_set = FALSE;
if (!$already_set) {
if ($db_type == 'pgsql') {
Database::getConnection()->query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
}
elseif ($db_type == 'mysql') {
Database::getConnection()->query("SET @@session.time_zone = '$offset'");
}
$already_set = TRUE;
}
}
return $timezone;
}
/**
* Overrides \Drupal\views\Plugin\views\query\QueryPluginBase::getDateFormat().
*/
public function getDateFormat($field, $format) {
$db_type = Database::getConnection()->databaseType();
switch ($db_type) {
case 'mysql':
$replace = array(
'Y' => '%Y',
'y' => '%y',
'M' => '%b',
'm' => '%m',
'n' => '%c',
'F' => '%M',
'D' => '%a',
'd' => '%d',
'l' => '%W',
'j' => '%e',
'W' => '%v',
'H' => '%H',
'h' => '%h',
'i' => '%i',
's' => '%s',
'A' => '%p',
);
$format = strtr($format, $replace);
return "DATE_FORMAT($field, '$format')";
case 'pgsql':
$replace = array(
'Y' => 'YYYY',
'y' => 'YY',
'M' => 'Mon',
'm' => 'MM',
// No format for Numeric representation of a month, without leading
// zeros.
'n' => 'MM',
'F' => 'Month',
'D' => 'Dy',
'd' => 'DD',
'l' => 'Day',
// No format for Day of the month without leading zeros.
'j' => 'DD',
'W' => 'WW',
'H' => 'HH24',
'h' => 'HH12',
'i' => 'MI',
's' => 'SS',
'A' => 'AM',
);
$format = strtr($format, $replace);
return "TO_CHAR($field, '$format')";
case 'sqlite':
$replace = array(
'Y' => '%Y',
// No format for 2 digit year number.
'y' => '%Y',
// No format for 3 letter month name.
'M' => '%m',
'm' => '%m',
// No format for month number without leading zeros.
'n' => '%m',
// No format for full month name.
'F' => '%m',
// No format for 3 letter day name.
'D' => '%d',
'd' => '%d',
// No format for full day name.
'l' => '%d',
// no format for day of month number without leading zeros.
'j' => '%d',
'W' => '%W',
'H' => '%H',
// No format for 12 hour hour with leading zeros.
'h' => '%H',
'i' => '%M',
's' => '%S',
// No format for AM/PM.
'A' => '',
);
$format = strtr($format, $replace);
return "strftime('$format', $field, 'unixepoch')";
}
}
}
......@@ -59,19 +59,19 @@ public function query() {
$this->query->add_orderby($this->tableAlias, $this->realField, $this->options['order']);
return;
case 'minute':
$formula = $this->getSQLFormat('YmdHi');
$formula = $this->getDateFormat('YmdHi');
break;
case 'hour':
$formula = $this->getSQLFormat('YmdH');
$formula = $this->getDateFormat('YmdH');
break;
case 'day':
$formula = $this->getSQLFormat('Ymd');
$formula = $this->getDateFormat('Ymd');
break;
case 'month':
$formula = $this->getSQLFormat('Ym');
$formula = $this->getDateFormat('Ym');
break;
case 'year':
$formula = $this->getSQLFormat('Y');
$formula = $this->getDateFormat('Y');
break;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment