This commit is contained in:
Ingo Schommer 2017-04-03 12:00:59 +12:00
parent 326aa37ea4
commit 3b94d14e42
11 changed files with 169 additions and 484 deletions

View File

@ -4,7 +4,11 @@ summary: How to format and use the DateField class.
# DateField # DateField
This `FormField` subclass lets you display an editable date, in a single text input field. This `FormField` subclass lets you display an editable date, in a single text input field.
It also provides a calendar date picker. It implements the [HTML5 input date type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date)
(with `type=date`). In supported browsers, this will cause a localised date picker to appear for users.
HTML5 date fields present and save ISO 8601 date formats (`y-MM-dd`),
since the browser takes care of converting to/from a localised presentation.
Browsers without support receive an `<input type=text>` based polyfill.
The following example will add a simple DateField to your Page, allowing you to enter a date manually. The following example will add a simple DateField to your Page, allowing you to enter a date manually.
@ -34,10 +38,13 @@ The following example will add a simple DateField to your Page, allowing you to
## Custom Date Format ## Custom Date Format
A custom date format for a [api:DateField] can be provided through `setDateFormat`. A custom date format for a [api:DateField] can be provided through `setDateFormat`.
This is only necessary if you want to opt-out of the built-in browser localisation via `type=date`.
:::php :::php
// will display a date in the following format: 31-06-2012 // will display a date in the following format: 31/06/2012
DateField::create('MyDate')->setDateFormat('dd-MM-yyyy'); DateField::create('MyDate')
->setHTML5(false)
->setDateFormat('dd/MM/yyyy');
<div class="info" markdown="1"> <div class="info" markdown="1">
The formats are based on [ICU format](http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details). The formats are based on [ICU format](http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details).
@ -54,34 +61,6 @@ Sets the minimum and maximum allowed date values using the `min` and `max` confi
->setMinDate('-7 days') ->setMinDate('-7 days')
->setMaxDate('2012-12-31') ->setMaxDate('2012-12-31')
## Separate Day / Month / Year Fields
To display separate input fields for day, month and year separately you can use the `SeparatedDateField` subclass`.
HTML5 placeholders 'day', 'month' and 'year' are enabled by default.
:::php
SeparatedDateField::create('MyDate');
<div class="alert" markdown="1">
Any custom date format settings will be ignored.
</div>
## Date Picker and HTML5 support
The field can be used as a [HTML5 input date type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date)
(with `type=date`) by calling `setHTML5(true)`.
:::php
DateField::create('MyDate')
->setHTML5(true);
In browsers [supporting HTML5 date inputs](caniuse.com/#feat=input-datetime),
this will cause a localised date picker to appear for users.
In this mode, the field will be forced to present and save ISO 8601 date formats (`y-MM-dd`),
since the browser takes care of converting to/from a localised presentation.
Browsers without support receive an `<input type=text>` based polyfill.
## Formatting Hints ## Formatting Hints
It's often not immediate apparent which format a field accepts, and showing the technical format (e.g. `HH:mm:ss`) is It's often not immediate apparent which format a field accepts, and showing the technical format (e.g. `HH:mm:ss`) is

View File

@ -405,6 +405,7 @@ in `DateField` and `TimeField` now ([discussion](https://github.com/silverstripe
where the browser localises the output based on the browser/system preferences. where the browser localises the output based on the browser/system preferences.
In this context it no longer makes sense to give users control over their own In this context it no longer makes sense to give users control over their own
date and time formats in their CMS profile. date and time formats in their CMS profile.
Consequently, we've also removed `MemberDatetimeOptionsetField`.
`Member->getDateFormat()` and `Member->getTimeFormat()` still exist, and default to `Member->getDateFormat()` and `Member->getTimeFormat()` still exist, and default to
the [IntlDateFormatter defaults](http://php.net/manual/en/class.intldateformatter.php) for the selected locale. the [IntlDateFormatter defaults](http://php.net/manual/en/class.intldateformatter.php) for the selected locale.
@ -1514,13 +1515,11 @@ New `DateField` methods replace `getConfig()` / `setConfig()`:
The `DateField` has changed behavior: The `DateField` has changed behavior:
* `DateField` no longer provides a jQuery UI date picker, * `DateField` no longer provides a jQuery UI date picker (`showcalendar` option),
and uses [HTML5 date pickers](https://www.wufoo.com/html5/types/4-date.html) instead. and uses [HTML5 date pickers](https://www.wufoo.com/html5/types/4-date.html) by default instead.
Use `setUseHTML()` to activate this mode (instead of `setConfig('showcalendar', true)`).
* `DateField` provides an optional polyfill for * `DateField` provides an optional polyfill for
[browsers without HTML5 date picker support](http://caniuse.com/#feat=input-datetime) [browsers without HTML5 date picker support](http://caniuse.com/#feat=input-datetime)
* The `dmyfields` option is now superceded with an `SeparatedDateField` class. * The `dmyfields` option has been replced with native HTML5 behaviour (as one single `<input type=date>`).
* `getPlaceholders()` / `setPlaceholders()` moved to a new `SeparatedDateField` class
* `getClientLocale` / `setClientLocale` have been removed (handled by `DateField->locale` and browser settings) * `getClientLocale` / `setClientLocale` have been removed (handled by `DateField->locale` and browser settings)
New `TimeField` methods replace `getConfig()` / `setConfig()` New `TimeField` methods replace `getConfig()` / `setConfig()`
@ -1570,6 +1569,8 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
* `get_source_file_comments()` * `get_source_file_comments()`
* `getOption` * `getOption`
* `setOption` * `setOption`
* Removed `MemberDatetimeOptionsetField` (no replacement)
* Removed `DateField_View_JQuery` (replaced with native HTML5 support in `DateField`)
### <a name="overview-i18n"></a>i18n API ### <a name="overview-i18n"></a>i18n API

View File

@ -5,6 +5,7 @@ namespace SilverStripe\Forms;
use IntlDateFormatter; use IntlDateFormatter;
use SilverStripe\i18n\i18n; use SilverStripe\i18n\i18n;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\ORM\FieldType\DBDate;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
/** /**
@ -119,7 +120,7 @@ class DateField extends TextField
* *
* @var bool * @var bool
*/ */
protected $html5 = false; protected $html5 = true;
/** /**
* @return bool * @return bool
@ -159,12 +160,8 @@ class DateField extends TextField
} }
/** /**
* Get length of the date format to use. One of: * Get length of the date format to use.
* * Only applicable with {@link setHTML5(false)}.
* - IntlDateFormatter::SHORT
* - IntlDateFormatter::MEDIUM
* - IntlDateFormatter::LONG
* - IntlDateFormatter::FULL
* *
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants * @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
* *
@ -187,6 +184,11 @@ class DateField extends TextField
*/ */
public function getDateFormat() public function getDateFormat()
{ {
if ($this->getHTML5()) {
// Browsers expect ISO 8601 dates, localisation is handled on the client
$this->setDateFormat(DBDate::ISO_DATE);
}
if ($this->dateFormat) { if ($this->dateFormat) {
return $this->dateFormat; return $this->dateFormat;
} }
@ -197,6 +199,7 @@ class DateField extends TextField
/** /**
* Set date format in CLDR standard format. * Set date format in CLDR standard format.
* Only applicable with {@link setHTML5(false)}.
* *
* @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table * @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table
* @param string $format * @param string $format
@ -216,24 +219,33 @@ class DateField extends TextField
*/ */
protected function getFormatter() protected function getFormatter()
{ {
if ($this->getHTML5() && $this->dateFormat && $this->dateFormat !== DBDate::ISO_DATE) {
throw new \LogicException(
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setDateFormat()'
);
}
if ($this->getHTML5() && $this->dateLength) {
throw new \LogicException(
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setDateLength()'
);
}
if ($this->getHTML5() && $this->locale) {
throw new \LogicException(
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setLocale()'
);
}
$formatter = IntlDateFormatter::create( $formatter = IntlDateFormatter::create(
$this->getLocale(), $this->getLocale(),
$this->getDateLength(), $this->getDateLength(),
IntlDateFormatter::NONE IntlDateFormatter::NONE
); );
$isoFormat = 'y-MM-dd';
if ($this->dateFormat && $this->getHTML5() && $this->dateFormat !== $isoFormat) {
throw new \LogicException(sprintf(
'Can\'t use a custom dateFormat value with $html5=true (needs to be %s)',
$isoFormat
));
}
if ($this->getHTML5()) { if ($this->getHTML5()) {
// Browsers expect ISO 8601 dates, localisation is handled on the client // Browsers expect ISO 8601 dates, localisation is handled on the client
$formatter->setPattern($isoFormat); $formatter->setPattern(DBDate::ISO_DATE);
} elseif ($this->dateFormat) { } elseif ($this->dateFormat) {
// Don't invoke getDateFormat() directly to avoid infinite loop // Don't invoke getDateFormat() directly to avoid infinite loop
$ok = $formatter->setPattern($this->dateFormat); $ok = $formatter->setPattern($this->dateFormat);
@ -259,20 +271,10 @@ class DateField extends TextField
); );
$formatter->setLenient(false); $formatter->setLenient(false);
// CLDR ISO 8601 date. // CLDR ISO 8601 date.
$formatter->setPattern('y-MM-dd'); $formatter->setPattern(DBDate::ISO_DATE);
return $formatter; return $formatter;
} }
public function FieldHolder($properties = array())
{
if ($this->getHTML5()) {
// Browsers expect ISO 8601 dates, localisation is handled on the client
$this->setDateFormat('y-MM-dd');
}
return parent::FieldHolder($properties);
}
public function getAttributes() public function getAttributes()
{ {
$attributes = parent::getAttributes(); $attributes = parent::getAttributes();
@ -421,7 +423,9 @@ class DateField extends TextField
} }
/** /**
* Caution: Will not update the 'dateformat' config value. * Determines the presented/processed format based on locale defaults,
* instead of explicitly setting {@link setDateFormat()}.
* Only applicable with {@link setHTML5(false)}.
* *
* @param string $locale * @param string $locale
* @return $this * @return $this

View File

@ -1,206 +0,0 @@
<?php
namespace SilverStripe\Forms;
use SilverStripe\i18n\i18n;
/**
* Date field with separate inputs for d/m/y
*/
class SeparatedDateField extends DateField
{
/**
* @var string
*/
protected $separator = '/';
/**
* Set whether to show placeholders
*
* @var bool
*/
protected $placeholders = true;
public function Field($properties = array())
{
// Three separate fields for day, month and year
$valArr = $this->iso8601ToArray($this->dataValue());
$fieldDay = NumericField::create($this->name . '[day]', false, $valArr ? $valArr['day'] : null)
->addExtraClass('day')
->setHTML5(true)
->setMaxLength(2);
$fieldMonth = NumericField::create($this->name . '[month]', false, $valArr ? $valArr['month'] : null)
->addExtraClass('month')
->setHTML5(true)
->setMaxLength(2);
$fieldYear = NumericField::create($this->name . '[year]', false, $valArr ? $valArr['year'] : null)
->addExtraClass('year')
->setHTML5(true)
->setMaxLength(4);
// Set placeholders
if ($this->getPlaceholders()) {
$fieldDay->setAttribute('placeholder', _t(__CLASS__ . '.DAY', 'Day'));
$fieldMonth->setAttribute('placeholder', _t(__CLASS__ . '.MONTH', 'Month'));
$fieldYear->setAttribute('placeholder', _t(__CLASS__ . '.YEAR', 'Year'));
}
$format = $this->getDateFormat();
$validFormat = (
stripos($format, 'd') !== false
&& stripos($format, 'm') !== false
&& stripos($format, 'y') !== false
);
if (!$validFormat) {
throw new \InvalidArgumentException(
'Invalid date format for field ordering: ' . $format
. '. Requires "d", "m", and "y" values to determine order'
);
}
$fields = array();
$fields[stripos($format, 'd')] = $fieldDay->Field();
$fields[stripos($format, 'm')] = $fieldMonth->Field();
$fields[stripos($format, 'y')] = $fieldYear->Field();
ksort($fields);
// Join all fields
$sep = '&nbsp;<span class="separator">' . $this->getSeparator() . '</span>&nbsp;';
return implode($sep, $fields);
}
/**
* @param $string
* @return self
*/
public function setSeparator($separator)
{
$this->separator = $separator;
return $this;
}
/**
* @return string
*/
public function getSeparator()
{
return $this->separator;
}
/**
* If placeholders are shown
*
* @return bool
*/
public function getPlaceholders()
{
return $this->placeholders;
}
/**
* Set if placeholders are shown
*
* @param bool $placeholders
* @return $this
*/
public function setPlaceholders($placeholders)
{
$this->placeholders = $placeholders;
return $this;
}
/**
* Convert array to timestamp
*
* @param array $value
* @return string
*/
public function arrayToISO8601($value)
{
if ($this->isEmptyArray($value)) {
return null;
}
// ensure all keys are specified
if (!isset($value['month']) || !isset($value['day']) || !isset($value['year'])) {
return null;
}
// Ensure valid range
if (!checkdate($value['month'], $value['day'], $value['year'])) {
return null;
}
// Note: Set formatter to strict for array input
$formatter = $this->getISO8601Formatter();
$timestamp = mktime(0, 0, 0, $value['month'], $value['day'], $value['year']);
if ($timestamp === false) {
return null;
}
return $formatter->format($timestamp);
}
/**
* Convert iso 8601 date to array (day / month / year)
*
* @param string $date
* @return array|null Array form, or null if not valid
*/
public function iso8601ToArray($date)
{
if (!$date) {
return null;
}
$formatter = $this->getISO8601Formatter();
$timestamp = $formatter->parse($date);
if ($timestamp === false) {
return null;
}
// Format time manually into an array
return [
'day' => date('j', $timestamp),
'month' => date('n', $timestamp),
'year' => date('Y', $timestamp),
];
}
/**
* Assign value posted from form submission
*
* @param mixed $value
* @param mixed $data
* @return $this
*/
public function setSubmittedValue($value, $data = null)
{
// Filter out empty arrays
if ($this->isEmptyArray($value)) {
$value = null;
}
$this->rawValue = $value;
// Null case
if (!$value || !is_array($value)) {
$this->value = null;
return $this;
}
// Parse
$this->value = $this->arrayToISO8601($value);
return $this;
}
/**
* Check if this array is empty
*
* @param $value
* @return bool
*/
public function isEmptyArray($value)
{
return is_array($value) && !array_filter($value);
}
}

View File

@ -6,6 +6,7 @@ use IntlDateFormatter;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\i18n\i18n; use SilverStripe\i18n\i18n;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBTime;
/** /**
* Form field to display editable time values in an <input type="text"> field. * Form field to display editable time values in an <input type="text"> field.
@ -58,11 +59,11 @@ class TimeField extends TextField
protected $timezone = null; protected $timezone = null;
/** /**
* Use HTML5-based input fields (and force ISO 8601 date formats). * Use HTML5-based input fields (and force ISO 8601 time formats).
* *
* @var bool * @var bool
*/ */
protected $html5 = false; protected $html5 = true;
/** /**
* @return bool * @return bool
@ -92,6 +93,11 @@ class TimeField extends TextField
*/ */
public function getTimeFormat() public function getTimeFormat()
{ {
if ($this->getHTML5()) {
// Browsers expect ISO 8601 times, localisation is handled on the client
$this->setTimeFormat(DBTime::ISO_TIME);
}
if ($this->timeFormat) { if ($this->timeFormat) {
return $this->timeFormat; return $this->timeFormat;
} }
@ -102,6 +108,7 @@ class TimeField extends TextField
/** /**
* Set time format in CLDR standard format. * Set time format in CLDR standard format.
* Only applicable with {@link setHTML5(false)}.
* *
* @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table * @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table
* @param string $format * @param string $format
@ -133,12 +140,8 @@ class TimeField extends TextField
} }
/** /**
* Get length of the time format to use. One of: * Get length of the time format to use.
* * Only applicable with {@link setHTML5(false)}.
* - IntlDateFormatter::SHORT E.g. '6:31 PM'
* - IntlDateFormatter::MEDIUM E.g. '6:30:48 PM'
* - IntlDateFormatter::LONG E.g. '6:32:09 PM NZDT'
* - IntlDateFormatter::FULL E.g. '6:32:24 PM New Zealand Daylight Time'
* *
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants * @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
* *
@ -158,6 +161,24 @@ class TimeField extends TextField
*/ */
protected function getFormatter() protected function getFormatter()
{ {
if ($this->getHTML5() && $this->timeFormat && $this->timeFormat !== DBTime::ISO_TIME) {
throw new \LogicException(
'Please opt-out of HTML5 processing of ISO 8601 times via setHTML5(false) if using setTimeFormat()'
);
}
if ($this->getHTML5() && $this->timeLength) {
throw new \LogicException(
'Please opt-out of HTML5 processing of ISO 8601 times via setHTML5(false) if using setTimeLength()'
);
}
if ($this->getHTML5() && $this->locale) {
throw new \LogicException(
'Please opt-out of HTML5 processing of ISO 8601 times via setHTML5(false) if using setLocale()'
);
}
$formatter = IntlDateFormatter::create( $formatter = IntlDateFormatter::create(
$this->getLocale(), $this->getLocale(),
IntlDateFormatter::NONE, IntlDateFormatter::NONE,
@ -165,18 +186,9 @@ class TimeField extends TextField
$this->getTimezone() $this->getTimezone()
); );
$isoFormat = 'HH:mm:ss';
if ($this->timeFormat && $this->getHTML5() && $this->timeFormat !== $isoFormat) {
throw new \LogicException(sprintf(
'Can\'t use a custom timeFormat value with $html5=true (needs to be %s)',
$isoFormat
));
}
if ($this->getHTML5()) { if ($this->getHTML5()) {
// Browsers expect ISO 8601 times, localisation is handled on the client // Browsers expect ISO 8601 times, localisation is handled on the client
$formatter->setPattern($isoFormat); $formatter->setPattern(DBTime::ISO_TIME);
// Don't invoke getTimeFormat() directly to avoid infinite loop // Don't invoke getTimeFormat() directly to avoid infinite loop
} elseif ($this->timeFormat) { } elseif ($this->timeFormat) {
$ok = $formatter->setPattern($this->timeFormat); $ok = $formatter->setPattern($this->timeFormat);
@ -201,9 +213,10 @@ class TimeField extends TextField
date_default_timezone_get() // Default to server timezone date_default_timezone_get() // Default to server timezone
); );
$formatter->setLenient(false); $formatter->setLenient(false);
// ISO 8601 time
// Note we omit timezone from this format, and we assume server TZ always. // Note we omit timezone from this format, and we assume server TZ always.
$formatter->setPattern('HH:mm:ss'); $formatter->setPattern(DBTime::ISO_TIME);
return $formatter; return $formatter;
} }
@ -325,6 +338,10 @@ class TimeField extends TextField
} }
/** /**
* Determines the presented/processed format based on locale defaults,
* instead of explicitly setting {@link setTimeFormat()}.
* Only applicable with {@link setHTML5(false)}.
*
* @param string $locale * @param string $locale
* @return $this * @return $this
*/ */
@ -363,7 +380,7 @@ class TimeField extends TextField
// Try to parse time without seconds, since that's a valid HTML5 submission format // Try to parse time without seconds, since that's a valid HTML5 submission format
// See https://html.spec.whatwg.org/multipage/infrastructure.html#times // See https://html.spec.whatwg.org/multipage/infrastructure.html#times
if ($timestamp === false && $this->setHTML5(true)) { if ($timestamp === false && $this->getHTML5()) {
$fromFormatter->setPattern('HH:mm'); $fromFormatter->setPattern('HH:mm');
$timestamp = $fromFormatter->parse($time); $timestamp = $fromFormatter->parse($time);
} }

View File

@ -141,10 +141,7 @@ class DBTime extends DBField
public function scaffoldFormField($title = null, $params = null) public function scaffoldFormField($title = null, $params = null)
{ {
$field = TimeField::create($this->name, $title); return TimeField::create($this->name, $title);
$field->setHTML5(true);
return $field;
} }
/** /**

View File

@ -1318,8 +1318,15 @@ class Member extends DataObject implements TemplateGlobalProvider
*/ */
public function getDateFormat() public function getDateFormat()
{ {
$format = $this->getDefaultDateFormat(); $formatter = new IntlDateFormatter(
$this->getLocale(),
IntlDateFormatter::MEDIUM,
IntlDateFormatter::NONE
);
$format = $formatter->getPattern();
$this->extend('updateDateFormat', $format); $this->extend('updateDateFormat', $format);
return $format; return $format;
} }
@ -1343,7 +1350,13 @@ class Member extends DataObject implements TemplateGlobalProvider
*/ */
public function getTimeFormat() public function getTimeFormat()
{ {
$format = $this->getDefaultTimeFormat(); $formatter = new IntlDateFormatter(
$this->getLocale(),
IntlDateFormatter::NONE,
IntlDateFormatter::MEDIUM
);
$format = $formatter->getPattern();
$this->extend('updateTimeFormat', $format); $this->extend('updateTimeFormat', $format);
return $format; return $format;
@ -1588,33 +1601,6 @@ class Member extends DataObject implements TemplateGlobalProvider
return parent::getCMSFields(); return parent::getCMSFields();
} }
/**
* @return string
*/
public function getDefaultDateFormat()
{
$formatter = new IntlDateFormatter(
$this->getLocale(),
IntlDateFormatter::MEDIUM,
IntlDateFormatter::NONE
);
return $formatter->getPattern();
}
/**
* @return string
*/
public function getDefaultTimeFormat()
{
$formatter = new IntlDateFormatter(
$this->getLocale(),
IntlDateFormatter::NONE,
IntlDateFormatter::MEDIUM
);
$defaultTimeFormat = $formatter->getPattern();
return $defaultTimeFormat;
}
/** /**
* @param bool $includerelations Indicate if the labels returned include relation fields * @param bool $includerelations Indicate if the labels returned include relation fields
* @return array * @return array

View File

@ -2,9 +2,9 @@
namespace SilverStripe\Forms\Tests; namespace SilverStripe\Forms\Tests;
use IntlDateFormatter;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\DateField; use SilverStripe\Forms\DateField;
use SilverStripe\Forms\SeparatedDateField;
use SilverStripe\Forms\RequiredFields; use SilverStripe\Forms\RequiredFields;
use SilverStripe\i18n\i18n; use SilverStripe\i18n\i18n;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
@ -105,21 +105,11 @@ class DateFieldTest extends SapphireTest
public function testSetValueWithDateString() public function testSetValueWithDateString()
{ {
$f = new DateField('Date', 'Date'); $f = new DateField('Date', 'Date');
$f->setHTML5(false);
$f->setSubmittedValue('29/03/2003'); $f->setSubmittedValue('29/03/2003');
$this->assertEquals($f->dataValue(), '2003-03-29'); $this->assertEquals($f->dataValue(), '2003-03-29');
} }
public function testSetValueWithDateArray()
{
$f = new SeparatedDateField('Date', 'Date');
$f->setSubmittedValue([
'day' => 29,
'month' => 03,
'year' => 2003
]);
$this->assertEquals($f->dataValue(), '2003-03-29');
}
public function testConstructorWithIsoDate() public function testConstructorWithIsoDate()
{ {
// used by Form->loadDataFrom() // used by Form->loadDataFrom()
@ -145,84 +135,11 @@ class DateFieldTest extends SapphireTest
$this->assertFalse($f->validate(new RequiredFields())); $this->assertFalse($f->validate(new RequiredFields()));
} }
public function testEmptyValueValidation()
{
$validator = new RequiredFields();
$field = new SeparatedDateField('Date');
$this->assertTrue($field->validate($validator));
$field->setSubmittedValue([
'day' => '',
'month' => '',
'year' => '',
]);
$this->assertTrue($field->validate($validator));
}
public function testValidateArray()
{
$f = new SeparatedDateField('Date', 'Date');
$f->setSubmittedValue([
'day' => 29,
'month' => 03,
'year' => 2003
]);
$this->assertTrue($f->validate(new RequiredFields()));
$f->setValue(null);
$this->assertTrue($f->validate(new RequiredFields()), 'NULL values are validating TRUE');
$f->setSubmittedValue(array());
$this->assertTrue($f->validate(new RequiredFields()), 'Empty array values are validating TRUE');
$f->setSubmittedValue([
'day' => null,
'month' => null,
'year' => null
]);
$this->assertTrue($f->validate(new RequiredFields()), 'Empty array values with keys are validating TRUE');
$f->setSubmittedValue([
'day' => 9999,
'month' => 9999,
'year' => 9999
]);
$this->assertFalse($f->validate(new RequiredFields()));
}
public function testValidateEmptyArrayValuesSetsNullForValueObject()
{
$f = new SeparatedDateField('Date', 'Date');
$f->setSubmittedValue([
'day' => '',
'month' => '',
'year' => ''
]);
$this->assertNull($f->dataValue());
$f->setSubmittedValue([
'day' => null,
'month' => null,
'year' => null
]);
$this->assertNull($f->dataValue());
}
public function testValidateArrayValue()
{
$f = new SeparatedDateField('Date', 'Date');
$f->setSubmittedValue(['day' => 29, 'month' => 03, 'year' => 2003]);
$this->assertTrue($f->validate(new RequiredFields()));
$f->setSubmittedValue(['month' => 03, 'year' => 2003]);
$this->assertFalse($f->validate(new RequiredFields()));
$f->setSubmittedValue(array('day' => 99, 'month' => 99, 'year' => 2003));
$this->assertFalse($f->validate(new RequiredFields()));
}
public function testFormatEnNz() public function testFormatEnNz()
{ {
/* We get YYYY-MM-DD format as the data value for DD/MM/YYYY input value */ /* We get YYYY-MM-DD format as the data value for DD/MM/YYYY input value */
$f = new DateField('Date', 'Date'); $f = new DateField('Date', 'Date');
$f->setHTML5(false);
$f->setSubmittedValue('29/03/2003'); $f->setSubmittedValue('29/03/2003');
$this->assertEquals($f->dataValue(), '2003-03-29'); $this->assertEquals($f->dataValue(), '2003-03-29');
} }
@ -232,6 +149,7 @@ class DateFieldTest extends SapphireTest
// should get en_NZ by default through setUp() // should get en_NZ by default through setUp()
i18n::set_locale('de_DE'); i18n::set_locale('de_DE');
$f = new DateField('Date', 'Date', '29/03/2003'); $f = new DateField('Date', 'Date', '29/03/2003');
$f->setHTML5(false);
$f->setValue('29.06.2006'); $f->setValue('29.06.2006');
$this->assertEquals($f->dataValue(), '2006-06-29'); $this->assertEquals($f->dataValue(), '2006-06-29');
} }
@ -242,6 +160,7 @@ class DateFieldTest extends SapphireTest
public function testMDYFormat() public function testMDYFormat()
{ {
$dateField = new DateField('Date', 'Date'); $dateField = new DateField('Date', 'Date');
$dateField->setHTML5(false);
$dateField->setDateFormat('d/M/y'); $dateField->setDateFormat('d/M/y');
$dateField->setSubmittedValue('31/03/2003'); $dateField->setSubmittedValue('31/03/2003');
$this->assertEquals( $this->assertEquals(
@ -251,6 +170,7 @@ class DateFieldTest extends SapphireTest
); );
$dateField2 = new DateField('Date', 'Date'); $dateField2 = new DateField('Date', 'Date');
$dateField2->setHTML5(false);
$dateField2->setDateFormat('d/M/y'); $dateField2->setDateFormat('d/M/y');
$dateField2->setSubmittedValue('04/3/03'); $dateField2->setSubmittedValue('04/3/03');
$this->assertEquals( $this->assertEquals(
@ -262,13 +182,37 @@ class DateFieldTest extends SapphireTest
/** /**
* @expectedException \LogicException * @expectedException \LogicException
* @expectedExceptionMessageRegExp /Please opt-out .* if using setDateFormat/
*/ */
public function testHtml5WithCustomFormatThrowsException() public function testHtml5WithCustomFormatThrowsException()
{ {
$dateField = new DateField('Date', 'Date'); $dateField = new DateField('Date', 'Date');
$dateField->setValue('2010-03-31'); $dateField->setValue('2010-03-31');
$dateField->setHTML5(true);
$dateField->setDateFormat('d/M/y'); $dateField->setDateFormat('d/M/y');
$dateField->Value(); $dateField->Value();
} }
/**
* @expectedException \LogicException
* @expectedExceptionMessageRegExp /Please opt-out .* if using setDateLength/
*/
public function testHtml5WithCustomDateLengthThrowsException()
{
$dateField = new DateField('Date', 'Date');
$dateField->setValue('2010-03-31');
$dateField->setDateLength(IntlDateFormatter::MEDIUM);
$dateField->Value();
}
/**
* @expectedException \LogicException
* @expectedExceptionMessageRegExp /Please opt-out .* if using setLocale/
*/
public function testHtml5WithCustomLocaleThrowsException()
{
$dateField = new DateField('Date', 'Date');
$dateField->setValue('2010-03-31');
$dateField->setLocale('de_DE');
$dateField->Value();
}
} }

View File

@ -7,7 +7,6 @@ use SilverStripe\Control\Controller;
use SilverStripe\Forms\DatetimeField; use SilverStripe\Forms\DatetimeField;
use SilverStripe\Forms\RequiredFields; use SilverStripe\Forms\RequiredFields;
use SilverStripe\Forms\DateField; use SilverStripe\Forms\DateField;
use SilverStripe\Forms\SeparatedDateField;
use SilverStripe\Forms\Tests\DatetimeFieldTest\Model; use SilverStripe\Forms\Tests\DatetimeFieldTest\Model;
use SilverStripe\Forms\TimeField; use SilverStripe\Forms\TimeField;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
@ -105,17 +104,6 @@ class DatetimeFieldTest extends SapphireTest
$this->assertEquals($datetimeField->dataValue(), '2003-03-29 23:00:00'); $this->assertEquals($datetimeField->dataValue(), '2003-03-29 23:00:00');
} }
public function testSetValueWithDmyArray()
{
$f = new DatetimeField('Datetime', 'Datetime');
$f->setDateField(new SeparatedDateField('Datetime[date]'));
$f->setSubmittedValue([
'date' => ['day' => 29, 'month' => 03, 'year' => 2003],
'time' => '11:00:00 pm'
]);
$this->assertEquals($f->dataValue(), '2003-03-29 23:00:00');
}
public function testValidate() public function testValidate()
{ {
$f = new DatetimeField('Datetime', 'Datetime', '2003-03-29 23:59:38'); $f = new DatetimeField('Datetime', 'Datetime', '2003-03-29 23:59:38');

View File

@ -1,53 +0,0 @@
<?php
namespace SilverStripe\Forms\Tests;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\DateField;
use SilverStripe\Forms\SeparatedDateField;
use SilverStripe\Forms\RequiredFields;
use SilverStripe\i18n\i18n;
use SilverStripe\ORM\FieldType\DBDatetime;
class SeparatedDateFieldTest extends SapphireTest
{
protected function setUp()
{
parent::setUp();
i18n::set_locale('en_NZ');
DBDatetime::set_mock_now('2011-02-01 8:34:00');
}
public function testFieldOrderingBasedOnLocale()
{
$dateField = new SeparatedDateField('Date');
$dateField->setLocale('en_NZ');
$this->assertRegExp('/.*[day].*[month].*[year]/', $dateField->Field());
}
public function testFieldOrderingBasedOnDateFormat()
{
$dateField = new SeparatedDateField('Date');
$dateField->setDateFormat('y/MM/dd');
$this->assertRegExp('/.*[year].*[month].*[day]/', $dateField->Field());
}
public function testCustomSeparator()
{
$dateField = new SeparatedDateField('Date');
$dateField->setDateFormat('dd/MM/y');
$dateField->setSeparator('###');
$this->assertRegExp('/.*[day].*###.*[month].*###.*[day]/', $dateField->Field());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Invalid date format
*/
public function testInvalidDateFormat()
{
$dateField = new SeparatedDateField('Date');
$dateField->setDateFormat('y/MM');
$dateField->Field();
}
}

View File

@ -2,6 +2,7 @@
namespace SilverStripe\Forms\Tests; namespace SilverStripe\Forms\Tests;
use IntlDateFormatter;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\TimeField; use SilverStripe\Forms\TimeField;
@ -55,7 +56,8 @@ class TimeFieldTest extends SapphireTest
{ {
// should get en_NZ by default through setUp() // should get en_NZ by default through setUp()
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setLocale('de_DE'); $f->setHTML5(false);
$f->setLocale('fr_FR');
// TODO Find a hour format thats actually different // TODO Find a hour format thats actually different
$f->setValue('23:59'); $f->setValue('23:59');
$this->assertEquals($f->dataValue(), '23:59:00'); $this->assertEquals($f->dataValue(), '23:59:00');
@ -96,8 +98,7 @@ class TimeFieldTest extends SapphireTest
public function testOverrideWithNull() public function testOverrideWithNull()
{ {
$field = new TimeField('Time', 'Time'); $field = new TimeField('Time', 'Time');
$field->setValue('11:00:00');
$field->setValue('11:00pm');
$field->setValue(''); $field->setValue('');
$this->assertEquals($field->dataValue(), ''); $this->assertEquals($field->dataValue(), '');
} }
@ -105,31 +106,35 @@ class TimeFieldTest extends SapphireTest
/** /**
* Test that AM/PM is preserved correctly in various situations * Test that AM/PM is preserved correctly in various situations
*/ */
public function testPreserveAMPM() public function testSetTimeFormat()
{ {
// Test with timeformat that includes hour // Test with timeformat that includes hour
// Check pm // Check pm
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setHTML5(false);
$f->setTimeFormat('h:mm:ss a'); $f->setTimeFormat('h:mm:ss a');
$f->setValue('3:59 pm'); $f->setValue('3:59 pm');
$this->assertEquals($f->dataValue(), '15:59:00'); $this->assertEquals($f->dataValue(), '15:59:00');
// Check am // Check am
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setHTML5(false);
$f->setTimeFormat('h:mm:ss a'); $f->setTimeFormat('h:mm:ss a');
$f->setValue('3:59 am'); $f->setValue('3:59 am');
$this->assertEquals($f->dataValue(), '03:59:00'); $this->assertEquals($f->dataValue(), '03:59:00');
// Check with ISO date/time // Check with ISO date/time
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setHTML5(false);
$f->setTimeFormat('h:mm:ss a'); $f->setTimeFormat('h:mm:ss a');
$f->setValue('15:59:00'); $f->setValue('15:59:00');
$this->assertEquals($f->dataValue(), '15:59:00'); $this->assertEquals($f->dataValue(), '15:59:00');
// ISO am // ISO am
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setHTML5(false);
$f->setTimeFormat('h:mm:ss a'); $f->setTimeFormat('h:mm:ss a');
$f->setValue('03:59:00'); $f->setValue('03:59:00');
$this->assertEquals($f->dataValue(), '03:59:00'); $this->assertEquals($f->dataValue(), '03:59:00');
@ -138,20 +143,43 @@ class TimeFieldTest extends SapphireTest
public function testLenientSubmissionParseWithoutSecondsOnHtml5() public function testLenientSubmissionParseWithoutSecondsOnHtml5()
{ {
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setHTML5(true);
$f->setSubmittedValue('23:59'); $f->setSubmittedValue('23:59');
$this->assertEquals($f->Value(), '23:59:00'); $this->assertEquals($f->Value(), '23:59:00');
} }
/** /**
* @expectedException \LogicException * @expectedException \LogicException
* @expectedExceptionMessageRegExp /Please opt-out .* if using setTimeFormat/
*/ */
public function testHtml5WithCustomFormatThrowsException() public function testHtml5WithCustomFormatThrowsException()
{ {
$f = new TimeField('Time', 'Time'); $f = new TimeField('Time', 'Time');
$f->setValue('15:59:00'); $f->setValue('15:59:00');
$f->setHTML5(true);
$f->setTimeFormat('mm:HH'); $f->setTimeFormat('mm:HH');
$f->Value(); $f->Value();
} }
/**
* @expectedException \LogicException
* @expectedExceptionMessageRegExp /Please opt-out .* if using setTimeLength/
*/
public function testHtml5WithCustomDateLengthThrowsException()
{
$f = new TimeField('Time', 'Time');
$f->setValue('15:59:00');
$f->setTimeLength(IntlDateFormatter::MEDIUM);
$f->Value();
}
/**
* @expectedException \LogicException
* @expectedExceptionMessageRegExp /Please opt-out .* if using setLocale/
*/
public function testHtml5WithCustomLocaleThrowsException()
{
$f = new TimeField('Time', 'Time');
$f->setValue('15:59:00');
$f->setLocale('de_DE');
$f->Value();
}
} }