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 @@ ...@@ -22,14 +22,6 @@
*/ */
class CreatedDay extends Date { 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 * Provide a link to the next level of the view
*/ */
......
...@@ -22,14 +22,6 @@ ...@@ -22,14 +22,6 @@
*/ */
class CreatedFullDate extends Date { 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 * Provide a link to the next level of the view
*/ */
......
...@@ -22,14 +22,6 @@ ...@@ -22,14 +22,6 @@
*/ */
class CreatedMonth extends Date { 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 * Provide a link to the next level of the view
*/ */
......
...@@ -15,20 +15,12 @@ ...@@ -15,20 +15,12 @@
* *
* @Plugin( * @Plugin(
* id = "node_created_week", * id = "node_created_week",
* arg_format = "w", * arg_format = "W",
* module = "node" * module = "node"
* ) * )
*/ */
class CreatedWeek extends Date { 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 * Provide a link to the next level of the view
*/ */
......
...@@ -21,12 +21,4 @@ ...@@ -21,12 +21,4 @@
*/ */
class CreatedYear extends Date { 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 @@ ...@@ -22,14 +22,6 @@
*/ */
class CreatedYearMonth extends Date { 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 * Provide a link to the next level of the view
*/ */
......
...@@ -620,74 +620,8 @@ public function broken() { } ...@@ -620,74 +620,8 @@ public function broken() { }
* @return string * @return string
* An appropriate SQL string for the DB type and field type. * An appropriate SQL string for the DB type and field type.
*/ */
public function getSQLFormat($format) { public function getDateFormat($format) {
$db_type = Database::getConnection()->databaseType(); return $this->query->getDateFormat($this->getDateField(), $format);
$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')";
}
} }
/** /**
...@@ -696,61 +630,8 @@ public function getSQLFormat($format) { ...@@ -696,61 +630,8 @@ public function getSQLFormat($format) {
* @return string * @return string
* An appropriate SQL string for the db type and field type. * An appropriate SQL string for the db type and field type.
*/ */
public function getSQLDateField() { public function getDateField() {
$field = "$this->tableAlias.$this->realField"; return $this->query->getDateField("$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;
} }
/** /**
......
...@@ -14,27 +14,25 @@ ...@@ -14,27 +14,25 @@
* *
* Adds an option to set a default argument based on the current date. * 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: * Definitions terms:
* - many to one: If true, the "many to one" helper will be used. * - 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. * - invalid input: A string to give to the user for obviously invalid input.
* This is deprecated in favor of argument validators. * 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 * @see Drupal\views\ManyTonOneHelper
* *
* @ingroup views_argument_handlers * @ingroup views_argument_handlers
* *
* @Plugin( * @Plugin(
* id = "date" * id = "date",
* arg_format = "Y-m-d"
* ) * )
*/ */
class Date extends Formula { class Date extends Formula {
var $option_name = 'default_argument_date'; var $option_name = 'default_argument_date';
var $arg_format = 'Y-m-d';
/** /**
* Add an option to set the default value to the current date. * Add an option to set the default value to the current date.
...@@ -84,62 +82,11 @@ function get_sort_name() { ...@@ -84,62 +82,11 @@ function get_sort_name() {
} }
/** /**
* Creates cross-database SQL date extraction. * Overrides \Drupal\views\Plugin\views\argument\Formula::get_formula().
*
* @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.
*/ */
public function extractSQL($extract_type) { function get_formula() {
$db_type = Database::getConnection()->databaseType(); $this->formula = $this->getDateFormat($this->definition['arg_format']);
$field = $this->getSQLDateField(); return parent::get_formula();
// 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))";
}
}
} }
} }
...@@ -169,4 +169,43 @@ function set_group_operator($type = 'AND') { ...@@ -169,4 +169,43 @@ function set_group_operator($type = 'AND') {
*/ */
function load_entities(&$results) {} 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) { ...@@ -1739,4 +1739,149 @@ function aggregation_method_distinct($group_type, $field) {
return strtoupper($group_type) . '(DISTINCT ' . $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() { ...@@ -59,19 +59,19 @@ public function query() {
$this->query->add_orderby($this->tableAlias, $this->realField, $this->options['order']); $this->query->add_orderby($this->tableAlias, $this->realField, $this->options['order']);
return; return;
case 'minute': case 'minute':
$formula = $this->getSQLFormat('YmdHi'); $formula = $this->getDateFormat('YmdHi');
break; break;
case 'hour': case 'hour':
$formula = $this->getSQLFormat('YmdH'); $formula = $this->getDateFormat('YmdH');
break; break;
case 'day': case 'day':
$formula = $this->getSQLFormat('Ymd');