Skip to content
Snippets Groups Projects
Commit 5b3ff0d5 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2000384 by yuradoc, Damien Tournoud, alexpott: Fixed php-intl module...

Issue #2000384 by yuradoc, Damien Tournoud, alexpott: Fixed php-intl module causes problems with Date and Time fields when editing Basic Page.
parent 53e17bb8
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
......@@ -205,20 +205,57 @@ public static function createFromFormat($format, $time, $timezone = NULL, $setti
// invalid it doesn't return an exception.
$datetimeplus = new static('', $timezone, $settings);
$date = \DateTime::createFromFormat($format, $time, $datetimeplus->getTimezone());
$format_string_type = isset($settings['format_string_type']) ? $settings['format_string_type'] : static::PHP;
if ($datetimeplus->canUseIntl() && $format_string_type == static::INTL) {
// Construct the $locale variable needed by the IntlDateFormatter.
$locale = $datetimeplus->langcode . '_' . $datetimeplus->country;
// If we have information about a calendar, add it.
if (!empty($datetimeplus->calendar) && $datetimeplus->calendar != static::CALENDAR) {
$locale .= '@calendar=' . $datetimeplus->calendar;
}
// If we're working with a non-gregorian calendar, indicate that.
$calendar_type = \IntlDateFormatter::GREGORIAN;
if ($datetimeplus->calendar != static::CALENDAR) {
$calendar_type = \IntlDateFormatter::TRADITIONAL;
}
$date_type = !empty($settings['date_type']) ? $settings['date_type'] : \IntlDateFormatter::FULL;
$time_type = !empty($settings['time_type']) ? $settings['time_type'] : \IntlDateFormatter::FULL;
$timezone = !empty($settings['timezone']) ? $settings['timezone'] : $datetimeplus->getTimezone()->getName();
$formatter = new \IntlDateFormatter($locale, $date_type, $time_type, $timezone, $calendar_type, $format);
$timestamp = $formatter->parse($time);
if ($timestamp) {
$date = $datetimeplus->createFromTimestamp($timestamp, $timezone, $settings);
}
else {
$date = NULL;
}
}
else {
$date = \DateTime::createFromFormat($format, $time, $datetimeplus->getTimezone());
}
if (!$date instanceOf \DateTime) {
throw new \Exception('The date cannot be created from a format.');
}
else {
// Functions that parse date is forgiving, it might create a date that
// is not exactly a match for the provided value, so test for that by
// re-creating the date/time formatted string and comparing it to the input. For
// instance, an input value of '11' using a format of Y (4 digits) gets
// created as '0011' instead of '2011'.
if ($date instanceOf DateTimePlus) {
$test_time = $date->format($format, $settings);
}
elseif ($date instanceOf \DateTime) {
$test_time = $date->format($format);
}
$datetimeplus->setTimestamp($date->getTimestamp());
$datetimeplus->setTimezone($date->getTimezone());
// The createFromFormat function is forgiving, it might create a date that
// is not exactly a match for the provided value, so test for that. For
// instance, an input value of '11' using a format of Y (4 digits) gets
// created as '0011' instead of '2011'. Use the parent::format() because
// we do not want to use the IntlDateFormatter here.
if ($settings['validate_format'] && $date->format($format) != $time) {
if ($settings['validate_format'] && $test_time != $time) {
throw new \Exception('The created date does not match the input value.');
}
}
......
......@@ -119,17 +119,15 @@ protected function prepareTimezone($timezone) {
*/
public function format($format, $settings = array()) {
$format_string_type = isset($settings['format_string_type']) ? $settings['format_string_type'] : static::PHP;
$settings['format_string_type'] = isset($settings['format_string_type']) ? $settings['format_string_type'] : static::PHP;
$settings['calendar'] = !empty($settings['calendar']) ? $settings['calendar'] : $this->calendar;
$settings['langcode'] = !empty($settings['langcode']) ? $settings['langcode'] : $this->langcode;
$settings['country'] = !empty($settings['country']) ? $settings['country'] : $this->country;
// Format the date and catch errors.
try {
// If we have what we need to use the IntlDateFormatter, do so.
if ($this->canUseIntl($settings['calendar'], $settings['langcode'], $settings['country']) && $format_string_type == parent::INTL) {
if ($this->canUseIntl($settings['calendar'], $settings['langcode'], $settings['country']) && $settings['format_string_type'] == parent::INTL) {
$value = parent::format($format, $settings);
}
......
......@@ -50,6 +50,7 @@ function datetime_element_info() {
'#theme' => 'datetime_form',
'#theme_wrappers' => array('datetime_wrapper'),
'#date_date_format' => $date_format,
'#date_format_string_type' => $format_type,
'#date_date_element' => 'date',
'#date_date_callbacks' => array(),
'#date_time_format' => $time_format,
......@@ -383,7 +384,7 @@ function template_preprocess_datetime_wrapper(&$variables) {
* The form element whose value has been processed.
*/
function datetime_datetime_form_process($element, &$form_state) {
$format_settings = array('format_string_type' => $element['#date_format_string_type']);
// The value callback has populated the #value array.
$date = !empty($element['#value']['object']) ? $element['#value']['object'] : NULL;
......@@ -403,7 +404,7 @@ function datetime_datetime_form_process($element, &$form_state) {
if ($element['#date_date_element'] != 'none') {
$date_format = $element['#date_date_element'] != 'none' ? datetime_html5_format('date', $element) : '';
$date_value = !empty($date) ? $date->format($date_format) : $element['#value']['date'];
$date_value = !empty($date) ? $date->format($date_format, $format_settings) : $element['#value']['date'];
// Creating format examples on every individual date item is messy, and
// placeholders are invalid for HTML5 date and datetime, so an example
......@@ -422,8 +423,8 @@ function datetime_datetime_form_process($element, &$form_state) {
$html5_max->setDate($range[1], 12, 31)->setTime(23, 59, 59);
$extra_attributes += array(
'min' => $html5_min->format($date_format),
'max' => $html5_max->format($date_format),
'min' => $html5_min->format($date_format, $format_settings),
'max' => $html5_max->format($date_format, $format_settings),
);
}
......@@ -450,7 +451,7 @@ function datetime_datetime_form_process($element, &$form_state) {
if ($element['#date_time_element'] != 'none') {
$time_format = $element['#date_time_element'] != 'none' ? datetime_html5_format('time', $element) : '';
$time_value = !empty($date) ? $date->format($time_format) : $element['#value']['time'];
$time_value = !empty($date) ? $date->format($time_format, $format_settings) : $element['#value']['time'];
// Adds the HTML5 attributes.
$extra_attributes = array(
......@@ -508,7 +509,10 @@ function form_type_datetime_value($element, $input = FALSE) {
}
try {
$date = DrupalDateTime::createFromFormat(trim($date_format . ' ' . $time_format), trim($date_input . ' ' . $time_input), $timezone);
$date_time_format = trim($date_format . ' ' . $time_format);
$date_time_input = trim($date_input . ' ' . $time_input);
$date_time_settings = array('format_string_type' => $element['#date_format_string_type']);
$date = DrupalDateTime::createFromFormat($date_time_format, $date_time_input, $timezone, $date_time_settings);
}
catch (\Exception $e) {
$date = NULL;
......@@ -523,8 +527,8 @@ function form_type_datetime_value($element, $input = FALSE) {
$date = $element['#default_value'];
if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
$input = array(
'date' => $date->format($element['#date_date_format']),
'time' => $date->format($element['#date_time_format']),
'date' => $date->format($element['#date_date_format'], array('format_string_type' => $element['#date_format_string_type'])),
'time' => $date->format($element['#date_time_format'], array('format_string_type' => $element['#date_format_string_type'])),
'object' => $date,
);
}
......@@ -643,11 +647,12 @@ function datetime_html5_format($part, $element) {
*
*/
function datetime_format_example($format) {
$format_type = datetime_default_format_type();
$date = &drupal_static(__FUNCTION__);
if (empty($date)) {
$date = new DrupalDateTime();
}
return $date->format($format);
return $date->format($format, array('format_string_type' => $format_type));
}
/**
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Datetime\DrupalDateTimeIntlTest.
*/
namespace Drupal\system\Tests\Datetime;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\simpletest\DrupalUnitTestBase;
/**
* Tests use of PHP's internationalization extension to format dates.
*/
class DrupalDateTimeIntlTest extends DrupalUnitTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
public static function getInfo() {
return array(
'name' => 'DrupalDateTimeIntl',
'description' => 'Test DrupalDateTime Intl functionality.',
'group' => 'Datetime',
);
}
public function setUp() {
parent::setUp();
// Install default config for system.
$this->installConfig(array('system'));
}
/**
* Ensures that PHP's Intl extension is installed.
*
* @return array
* Array of errors containing a list of unmet requirements.
*/
function checkRequirements() {
if (!class_exists('IntlDateFormatter')) {
return array(
'PHP\'s Intl extension needs to be installed and enabled.',
);
}
return parent::checkRequirements();
}
/**
* Tests that PHP and Intl default formats are equivalent.
*/
function testDrupalDateTimeIntl() {
$input_value = '2013-09-27 17:40:41';
$timezone = drupal_get_user_timezone();
$format = 'yyyy-MM-dd HH:mm:ss';
$format_settings = array(
'country' => 'UA',
'langcode' => 'ru',
'format_string_type' => DrupalDateTime::INTL
);
$date = DrupalDateTime::createFromFormat($format, $input_value, $timezone, $format_settings);
$output_value = $date->format($format, $format_settings);
$this->assertIdentical($input_value, $output_value);
}
}
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