From 479b70db237a7180a80ddcd8aba9c5f66e45e91a Mon Sep 17 00:00:00 2001 From: Earl Miles Date: Fri, 28 Mar 2008 17:29:54 +0000 Subject: [PATCH] #239380: Database safe date handling by KarenS! This is a major improvement for PGSQL users! --- includes/admin.inc | 20 +++--- includes/handlers.inc | 15 ++-- includes/plugins.inc | 2 +- modules/node.views.inc | 15 ++-- views.module | 160 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 30 deletions(-) diff --git a/includes/admin.inc b/includes/admin.inc index 669ebbcd9..74e3fbe6c 100644 --- a/includes/admin.inc +++ b/includes/admin.inc @@ -1380,17 +1380,16 @@ function views_ui_rearrange_form(&$form_state) { $form[$id]['name'] = array( '#value' => $name, ); - $form[$id]['removed'] = array( - '#type' => 'checkbox', - '#id' => 'views-removed-' . $id, - '#attributes' => array('class' => 'views-remove-checkbox'), - '#default_value' => 0, - ); - } else { - $form[$id]['name'] = array('#value' => t('Broken field @id', $id)); + $form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id))); } + $form[$id]['removed'] = array( + '#type' => 'checkbox', + '#id' => 'views-removed-' . $id, + '#attributes' => array('class' => 'views-remove-checkbox'), + '#default_value' => 0, + ); } // Add javascript settings that will be added via $.extend for tabledragging @@ -1660,12 +1659,13 @@ function views_ui_config_item_form(&$form_state) { break; } $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); - $relationship_handler->init($view, $relationship); - // ignore invalid/broken relationships. if (empty($relationship_handler)) { continue; } + + $relationship_handler->init($view, $relationship); + $relationship_options[$relationship['id']] = $relationship_handler->label(); } diff --git a/includes/handlers.inc b/includes/handlers.inc index 32834932d..31dfa6755 100644 --- a/includes/handlers.inc +++ b/includes/handlers.inc @@ -936,29 +936,26 @@ class views_handler_sort_date extends views_handler_sort { * Called to add the sort to a query. */ function query() { - $timezone = views_get_timezone(); - $timezone = ($timezone) ? sprintf('%+d', $timezone) : ''; - $this->ensure_my_table(); switch($this->options['granularity']) { case 'second': default: - $this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']); + $this->query->add_orderby($this->table_alias, "$this->table_alias.$this->real_field", $this->options['order']); return; case 'minute': - $formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field), '%Y%m%%d%H%i')"; + $formula = views_date_sql_format('YmdHi', "$this->table_alias.$this->real_field"); break; case 'hour': - $formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field), '%Y%m%%d%H')"; + $formula = views_date_sql_format('YmdH', "$this->table_alias.$this->real_field"); break; case 'day': - $formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field $timezone), '%Y%m%%d')"; + $formula = views_date_sql_format('Ymd', "$this->table_alias.$this->real_field"); break; case 'month': - $formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field $timezone), '%Y%m')"; + $formula = views_date_sql_format('Ym', "$this->table_alias.$this->real_field"); break; case 'year': - $formula = "DATE_FORMAT(FROM_UNIXTIME($this->table_alias.$this->real_field $timezone), '%Y')"; + $formula = views_date_sql_format('Y', "$this->table_alias.$this->real_field"); break; } diff --git a/includes/plugins.inc b/includes/plugins.inc index 90f77ae9e..9a0ad04d7 100644 --- a/includes/plugins.inc +++ b/includes/plugins.inc @@ -164,7 +164,7 @@ class views_plugin_display extends views_object { if (!isset($this->has_exposed)) { foreach (array('field', 'filter') as $type) { foreach ($this->view->$type as $key => $info) { - if ($info['handler']->is_exposed()) { + if (!empty($info['handler']) && $info['handler']->is_exposed()) { // one is all we need; if we find it, return true. $this->has_exposed = TRUE; return TRUE; diff --git a/modules/node.views.inc b/modules/node.views.inc index 6c644c23d..c6a232d50 100644 --- a/modules/node.views.inc +++ b/modules/node.views.inc @@ -886,8 +886,7 @@ class views_handler_argument_node_created_fulldate extends views_handler_argumen * Constructor implementation */ function construct() { - $timezone = views_get_timezone(); - $this->formula = "DATE_FORMAT(FROM_UNIXTIME(***table***.$this->real_field+$timezone), '%Y%m%%d')"; + $this->formula = views_date_sql_format('Ymd', "***table***.$this->real_field"); $this->format = 'F j, Y'; } @@ -917,8 +916,7 @@ class views_handler_argument_node_created_year extends views_handler_argument_fo * Constructor implementation */ function construct() { - $timezone = views_get_timezone(); - $this->formula = "YEAR(FROM_UNIXTIME(***table***.$this->real_field+$timezone))"; + $this->formula = views_date_sql_extract('YEAR', "***table***.$this->real_field"); } } @@ -932,8 +930,7 @@ class views_handler_argument_node_created_year_month extends views_handler_argum * Constructor implementation */ function construct() { - $timezone = views_get_timezone(); - $this->formula = "DATE_FORMAT(FROM_UNIXTIME(***table***.$this->real_field+$timezone), '%Y%m')"; + $this->formula = views_date_sql_format('Ym', "***table***.$this->real_field"); $this->format = 'F, Y'; } @@ -963,8 +960,7 @@ class views_handler_argument_node_created_month extends views_handler_argument_f * Constructor implementation */ function construct() { - $timezone = views_get_timezone(); - $this->formula = "MONTH(FROM_UNIXTIME(***table***.$this->real_field+$timezone))"; + $this->formula = views_date_sql_extract('MONTH', "***table***.$this->real_field"); $this->format = 'F'; } @@ -994,8 +990,7 @@ class views_handler_argument_node_created_week extends views_handler_argument_fo * Constructor implementation */ function construct() { - $timezone = views_get_timezone(); - $this->formula = "WEEK(FROM_UNIXTIME(***table***.$this->real_field+$timezone), 3)"; + $this->formula = views_date_sql_extract('WEEK', "***table***.$this->real_field"); } /** diff --git a/views.module b/views.module index b479cab67..c0c5422bc 100644 --- a/views.module +++ b/views.module @@ -857,6 +857,166 @@ function views_get_timezone() { return $timezone; } +/** + * Helper function to create cross-database SQL dates. + * + * @param $field + * The real table and field name, like 'tablename.fieldname'. + * @param $field_type + * The type of date field, 'int' or 'datetime'. + * @param $set_offset + * The name of a field that holds the timezone offset or a fixed timezone + * offset value. If not provided, the normal Drupal timezone handling + * will be used, i.e. $set_offset = 0 will make no timezone adjustment. + * @return + * An appropriate SQL string for the db type and field type. + */ +function views_date_sql_field($field, $field_type = 'int', $set_offset = NULL) { + $db_type = $GLOBALS['db_type']; + $offset = $set_offset !== NULL ? $set_offset : views_get_timezone(); + switch ($db_type) { + case 'mysql': + case 'mysqli': + switch ($field_type) { + case 'int': + $field = "FROM_UNIXTIME($field)"; + break; + case 'datetime': + break; + } + if (!empty($offset)) { + $field = "($field + INTERVAL $offset SECOND)"; + } + return $field; + case 'pgsql': + switch ($field_type) { + case 'int': + $field = "$field::ABSTIME"; + break; + case 'datetime': + break; + } + if (!empty($offset)) { + $field = "($field + 'INTERVAL $offset SECONDS')"; + } + return $field; + } +} + +/** + * Helper function to create cross-database SQL date formatting. + * + * @param $format + * A format string for the result, like 'Y-m-d H:i:s'. + * @param $field + * The real table and field name, like 'tablename.fieldname'. + * @param $field_type + * The type of date field, 'int' or 'datetime'. + * @param $set_offset + * The name of a field that holds the timezone offset or a fixed timezone + * offset value. If not provided, the normal Drupal timezone handling + * will be used, i.e. $set_offset = 0 will make no timezone adjustment. + * @return + * An appropriate SQL string for the db type and field type. + */ +function views_date_sql_format($format, $field, $field_type = 'int', $set_offset = NULL) { + $db_type = $GLOBALS['db_type']; + $field = views_date_sql_field($field, $field_type, $set_offset); + switch ($db_type) { + case 'mysql': + case 'mysqli': + $replace = array( + 'Y' => '%Y', + 'm' => '%m', + 'd' => '%%d', + 'H' => '%H', + 'i' => '%i', + 's' => '%s', + ); + $format = str_replace($format, $replace); + return "DATE_FORMAT($field, $format)"; + case 'pgsql': + $replace = array( + 'Y' => 'YY', + 'm' => 'MM', + 'd' => 'DD', + 'H' => 'HH24', + 'i' => 'MI', + 's' => 'SS', + ); + $format = str_replace($format, $replace); + return "TO_CHAR($field, $format)"; + } +} + +/** + * Helper function to create cross-database SQL date extraction. + * + * @param $extract_type + * The type of value to extract from the date, like 'MONTH'. + * @param $field + * The real table and field name, like 'tablename.fieldname'. + * @param $field_type + * The type of date field, 'int' or 'datetime'. + * @param $set_offset + * The name of a field that holds the timezone offset or a fixed timezone + * offset value. If not provided, the normal Drupal timezone handling + * will be used, i.e. $set_offset = 0 will make no timezone adjustment. + * @return + * An appropriate SQL string for the db type and field type. + */ +function views_date_sql_extract($extract_type, $field, $field_type = 'int', $set_offset = NULL) { + $db_type = $GLOBALS['db_type']; + $field = views_date_sql_field($field, $field_type, $set_offset); + + // 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))"; + case('WEEK'): // ISO week number for date + switch ($db_type) { + case('mysql'): + case('mysqli'): + // 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'): + case('mysqli'): + // 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'): + case('mysqli'): + return "DAYOFYEAR($field)"; + case('pgsql'): + return "EXTRACT(DOY FROM($field))"; + } + } + +} + /** * Form builder for the exposed widgets form. * -- GitLab