Skip to content
Snippets Groups Projects
Commit 68c0e1cd authored by twistor's avatar twistor Committed by Chris Leppanen
Browse files

Issue #722740 by twistor, mglaman, relaxnow, dooug, willieseabrook,...

Issue #722740 by twistor, mglaman, relaxnow, dooug, willieseabrook, David_Rothstein, jeffschuler, lapek, Matthew Davidson: Feeds Date mapper converts imported dates to GMT unless in UNIX timestamp format
parent fa7c51b5
No related branches found
No related tags found
No related merge requests found
...@@ -2,26 +2,41 @@ ...@@ -2,26 +2,41 @@
/** /**
* @file * @file
* On behalf implementation of Feeds mapping API for date * On behalf implementation of Feeds mapping API for date.module.
*/ */
/** /**
* Implements hook_feeds_processor_targets(). * Implements hook_feeds_processor_targets().
*
* @todo Only provides "end date" target if field allows it.
*/ */
function date_feeds_processor_targets($entity_type, $bundle_name) { function date_feeds_processor_targets($entity_type, $bundle_name) {
$targets = array(); $targets = array();
$field_types = array(
'date' => TRUE,
'datestamp' => TRUE,
'datetime' => TRUE,
);
foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) { foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
$info = field_info_field($name); $info = field_info_field($name);
if (in_array($info['type'], array('date', 'datestamp', 'datetime'))) {
$targets[$name . ':start'] = array( if (!isset($field_types[$info['type']])) {
'name' => t('@name: Start', array('@name' => $instance['label'])), continue;
'callback' => 'date_feeds_set_target', }
'description' => t('The start date for the @name field. Also use if mapping both start and end.', array('@name' => $instance['label'])),
'real_target' => $name, $targets[$name . ':start'] = array(
); 'name' => check_plain($instance['label']),
'callback' => 'date_feeds_set_target',
'description' => t('The start date for the @name field. Also use if mapping both start and end.', array('@name' => $instance['label'])),
'real_target' => $name,
'summary_callbacks' => array('date_feeds_summary_callback'),
'form_callbacks' => array('date_feeds_form_callback'),
);
if (!empty($info['settings']['todate'])) {
// Change the label for the start date.
$targets[$name . ':start']['name'] = t('@name: Start', array('@name' => $instance['label']));
$targets[$name . ':end'] = array( $targets[$name . ':end'] = array(
'name' => t('@name: End', array('@name' => $instance['label'])), 'name' => t('@name: End', array('@name' => $instance['label'])),
'callback' => 'date_feeds_set_target', 'callback' => 'date_feeds_set_target',
...@@ -38,25 +53,142 @@ function date_feeds_processor_targets($entity_type, $bundle_name) { ...@@ -38,25 +53,142 @@ function date_feeds_processor_targets($entity_type, $bundle_name) {
* Callback for setting date values. * Callback for setting date values.
*/ */
function date_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) { function date_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping) {
list($field_name, $sub_field) = explode(':', $target, 2); $language = $mapping['language'];
list($target, $sub_field) = explode(':', $target, 2);
$value_key = $sub_field === 'start' ? 'value' : 'value2';
$offset_key = $sub_field === 'start' ? 'offset' : 'offset2';
$field = isset($entity->$target) ? $entity->$target : array($language => array());
$info = field_info_field($target);
$format = date_type_format($info['type']);
$db_tz = new DateTimeZone(date_get_timezone_db($info['settings']['tz_handling']));
$default_tz = new DateTimeZone(_date_feeds_get_default_timezone($mapping));
$delta = 0; $delta = 0;
foreach ($values as $value) { foreach ($values as $value) {
$value = _date_feeds_get_date_object($value, $default_tz);
if (!($value instanceof FeedsDateTimeElement)) { if (!$value || !empty($value->errors)) {
$field[$language][$delta][$value_key] = '';
if (empty($value) || !is_numeric($value) && is_string($value) && !date_create($value)) { }
$value = new FeedsDateTimeElement(NULL, NULL); else {
} if (!isset($field[$language][$delta]['timezone'])) {
elseif ($sub_field == 'end') { $field[$language][$delta]['timezone'] = $value->getTimezone()->getName();
$value = new FeedsDateTimeElement(NULL, $value);
}
else {
$value = new FeedsDateTimeElement($value, NULL);
} }
$value->setTimezone($db_tz);
$field[$language][$delta][$value_key] = $value->format($format, TRUE);
$field[$language][$delta][$offset_key] = $value->getOffset();
} }
$value->buildDateField($entity, $field_name, $delta, $mapping['language']);
$delta++; $delta++;
} }
$entity->$target = $field;
}
/**
* Summary callback for date field targets.
*/
function date_feeds_summary_callback(array $mapping, $target, array $form, array $form_state) {
$mapping += array('timezone' => 'UTC');
$options = _date_feeds_timezone_options();
return t('Default timezone: %zone', array('%zone' => $options[$mapping['timezone']]));
}
/**
* Form callback for date field targets.
*/
function date_feeds_form_callback(array $mapping, $target, array $form, array $form_state) {
$mapping += array('timezone' => 'UTC');
return array(
'timezone' => array(
'#type' => 'select',
'#title' => t('Timezone handling'),
'#options' => _date_feeds_timezone_options(),
'#default_value' => $mapping['timezone'],
'#description' => t('This value will only be used if the timezone is mising.'),
),
);
}
/**
* Returns the timezone options.
*
* @return array
* A map of timezone options.
*/
function _date_feeds_timezone_options() {
return array(
'__SITE__' => t('Site default'),
) + system_time_zones();
}
/**
* Returns the timezone to be used as the default.
*
* @param array $mapping
* The mapping array.
*
* @return string
* The timezone to use as the default.
*/
function _date_feeds_get_default_timezone(array $mapping) {
$mapping += array('timezone' => 'UTC');
if ($mapping['timezone'] === '__SITE__') {
return variable_get('date_default_timezone', 'UTC');
}
return $mapping['timezone'];
}
/**
* Converts a date string or object into a DateObject.
*
* @param DateTime|string|int $value
* The date value or object.
* @param DateTimeZone $default_tz
* The default timezone.
*
* @return DateObject
* The converted DateObject.
*/
function _date_feeds_get_date_object($value, DateTimeZone $default_tz) {
if ($value instanceof DateObject) {
return $value;
}
// Convert DateTime and FeedsDateTime.
if ($value instanceof DateTime) {
if (!$value->getTimezone() || !preg_match('/[a-zA-Z]/', $value->getTimezone()->getName())) {
$value->setTimezone($default_tz);
}
return new DateObject($value->format(DATE_FORMAT_ISO), $value->getTimezone());
}
if (is_string($value) || is_object($value) && method_exists($value, '__toString')) {
$value = trim($value);
}
// Filter out meaningless values.
if (empty($value) || !is_string($value) && !is_int($value)) {
return FALSE;
}
// Support year values.
if ((string) $value === (string) (int) $value) {
if ($value >= variable_get('date_min_year', 100) && $value <= variable_get('date_max_year', 4000)) {
return new DateObject('January ' . $value, $default_tz);
}
}
return new DateObject($value, $default_tz);
} }
...@@ -513,6 +513,8 @@ class FeedsEnclosure extends FeedsElement { ...@@ -513,6 +513,8 @@ class FeedsEnclosure extends FeedsElement {
/** /**
* Defines a date element of a parsed result (including ranges, repeat). * Defines a date element of a parsed result (including ranges, repeat).
*
* @deprecated This is no longer in use and will not be maintained.
*/ */
class FeedsDateTimeElement extends FeedsElement { class FeedsDateTimeElement extends FeedsElement {
...@@ -673,6 +675,8 @@ class FeedsDateTimeElement extends FeedsElement { ...@@ -673,6 +675,8 @@ class FeedsDateTimeElement extends FeedsElement {
* class. * class.
* *
* @see FeedsDateTimeElement * @see FeedsDateTimeElement
*
* @deprecated Use DateObject instead.
*/ */
class FeedsDateTime extends DateTime { class FeedsDateTime extends DateTime {
public $granularity = array(); public $granularity = array();
...@@ -878,12 +882,16 @@ function feeds_to_unixtime($date, $default_value) { ...@@ -878,12 +882,16 @@ function feeds_to_unixtime($date, $default_value) {
if (is_numeric($date)) { if (is_numeric($date)) {
return $date; return $date;
} }
elseif (is_string($date) && !empty($date)) {
$date = new FeedsDateTimeElement($date); if ($date instanceof FeedsDateTimeElement) {
return $date->getValue(); return $date->getValue();
} }
elseif ($date instanceof FeedsDateTimeElement) {
return $date->getValue(); if (is_string($date) || is_object($date) && method_exists($date, '__toString')) {
if ($date_object = date_create(trim($date))) {
return $date_object->format('U');
}
} }
return $default_value; return $default_value;
} }
...@@ -37,11 +37,11 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -37,11 +37,11 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
$typename = $this->createContentType(array(), array( $typename = $this->createContentType(array(), array(
'date' => 'date', 'date' => 'date',
'datestamp' => 'datestamp', 'datestamp' => 'datestamp',
//'datetime' => 'datetime', // REMOVED because the field is broken ATM. 'datetime' => 'datetime',
)); ));
// Hack to get date fields to not round to every 15 minutes. // Hack to get date fields to not round to every 15 minutes.
foreach (array('date', 'datestamp') as $field) { foreach (array('date', 'datestamp', 'datetime') as $field) {
$field = 'field_' . $field; $field = 'field_' . $field;
$edit = array( $edit = array(
'widget_type' => 'date_select', 'widget_type' => 'date_select',
...@@ -84,6 +84,10 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -84,6 +84,10 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
'source' => 'timestamp', 'source' => 'timestamp',
'target' => 'field_datestamp:start', 'target' => 'field_datestamp:start',
), ),
4 => array(
'source' => 'timestamp',
'target' => 'field_datetime:start',
),
)); ));
$edit = array( $edit = array(
...@@ -108,6 +112,7 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -108,6 +112,7 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
$this->drupalGet("node/$i/edit"); $this->drupalGet("node/$i/edit");
$this->assertNodeFieldValue('date', $values[$i-1]); $this->assertNodeFieldValue('date', $values[$i-1]);
$this->assertNodeFieldValue('datestamp', $values[$i-1]); $this->assertNodeFieldValue('datestamp', $values[$i-1]);
$this->assertNodeFieldValue('datetime', $values[$i-1]);
} }
} }
...@@ -141,6 +146,7 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -141,6 +146,7 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
$edit = array( $edit = array(
'instance[widget][settings][increment]' => 1, 'instance[widget][settings][increment]' => 1,
'field[settings][enddate_get]' => 1, 'field[settings][enddate_get]' => 1,
'instance[settings][default_value]' => 'blank',
); );
$this->drupalPost('admin/structure/types/manage/' . $typename . '/fields/' . $field, $edit, 'Save settings'); $this->drupalPost('admin/structure/types/manage/' . $typename . '/fields/' . $field, $edit, 'Save settings');
$edit = array( $edit = array(
...@@ -210,11 +216,11 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -210,11 +216,11 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
); );
for ($i = 1; $i <= 2; $i++) { for ($i = 1; $i <= 2; $i++) {
$this->drupalGet("node/$i/edit"); $this->drupalGet("node/$i/edit");
$this->assertNodeFieldValue('date', $date_values[$i]['created']); $this->assertFieldByName('field_date[und][0][value][date]', $date_values[$i]['created']);
$this->assertFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']);
$this->assertNodeFieldValue('datestamp', $date_values[$i]['created']); $this->assertFieldByName('field_datestamp[und][0][value][date]', $date_values[$i]['created']);
$this->assertFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']);
$this->assertNodeFieldValue('datetime', $date_values[$i]['created']); $this->assertFieldByName('field_datetime[und][0][value][date]', $date_values[$i]['created']);
$this->assertFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']);
} }
...@@ -225,12 +231,12 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -225,12 +231,12 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
// Check if all values were cleared out for both nodes. // Check if all values were cleared out for both nodes.
for ($i = 1; $i <= 2; $i++) { for ($i = 1; $i <= 2; $i++) {
$this->drupalGet("node/$i/edit"); $this->drupalGet("node/$i/edit");
$this->assertNoNodeFieldValue('date', $date_values[$i]['created']); $this->assertFieldByName('field_date[und][0][value][date]', '');
$this->assertNoFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_date[und][0][value2][date]', '');
$this->assertNoNodeFieldValue('datestamp', $date_values[$i]['created']); $this->assertFieldByName('field_datestamp[und][0][value][date]', '');
$this->assertNoFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_datestamp[und][0][value2][date]', '');
$this->assertNoNodeFieldValue('datetime', $date_values[$i]['created']); $this->assertFieldByName('field_datetime[und][0][value][date]', '');
$this->assertNoFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_datetime[und][0][value2][date]', '');
$this->drupalGet("node/$i"); $this->drupalGet("node/$i");
$this->assertNoText('date_label'); $this->assertNoText('date_label');
$this->assertNoText('datestamp_label'); $this->assertNoText('datestamp_label');
...@@ -242,11 +248,11 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -242,11 +248,11 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
$this->assertText('Updated 2 nodes'); $this->assertText('Updated 2 nodes');
for ($i = 1; $i <= 2; $i++) { for ($i = 1; $i <= 2; $i++) {
$this->drupalGet("node/$i/edit"); $this->drupalGet("node/$i/edit");
$this->assertNodeFieldValue('date', $date_values[$i]['created']); $this->assertFieldByName('field_date[und][0][value][date]', $date_values[$i]['created']);
$this->assertFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']);
$this->assertNodeFieldValue('datestamp', $date_values[$i]['created']); $this->assertFieldByName('field_datestamp[und][0][value][date]', $date_values[$i]['created']);
$this->assertFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']);
$this->assertNodeFieldValue('datetime', $date_values[$i]['created']); $this->assertFieldByName('field_datetime[und][0][value][date]', $date_values[$i]['created']);
$this->assertFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']); $this->assertFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']);
} }
...@@ -256,12 +262,12 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase { ...@@ -256,12 +262,12 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
// Check if all values were cleared out for node 1. // Check if all values were cleared out for node 1.
$this->drupalGet('node/1/edit'); $this->drupalGet('node/1/edit');
$this->assertNoNodeFieldValue('date', $date_values[1]['created']); $this->assertFieldByName('field_date[und][0][value2][date]', '');
$this->assertNoFieldByName('field_date[und][0][value2][date]', $date_values[1]['end']); $this->assertFieldByName('field_date[und][0][value2][date]', '');
$this->assertNoNodeFieldValue('datestamp', $date_values[1]['created']); $this->assertFieldByName('field_datestamp[und][0][value2][date]', '');
$this->assertNoFieldByName('field_datestamp[und][0][value2][date]', $date_values[1]['end']); $this->assertFieldByName('field_datestamp[und][0][value2][date]', '');
$this->assertNoNodeFieldValue('datetime', $date_values[1]['created']); $this->assertFieldByName('field_datetime[und][0][value2][date]', '');
$this->assertNoFieldByName('field_datetime[und][0][value2][date]', $date_values[1]['end']); $this->assertFieldByName('field_datetime[und][0][value2][date]', '');
// Check if labels for fields that should be cleared out are not shown. // Check if labels for fields that should be cleared out are not shown.
$this->drupalGet('node/1'); $this->drupalGet('node/1');
$this->assertNoText('date_label'); $this->assertNoText('date_label');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment