2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
2016-08-19 00:51:35 +02:00
|
|
|
|
|
|
|
namespace SilverStripe\Forms;
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
use IntlDateFormatter;
|
|
|
|
use InvalidArgumentException;
|
2016-08-19 00:51:35 +02:00
|
|
|
use SilverStripe\i18n\i18n;
|
2017-01-26 05:20:08 +01:00
|
|
|
use SilverStripe\ORM\FieldType\DBDatetime;
|
2017-04-03 02:00:59 +02:00
|
|
|
use SilverStripe\ORM\FieldType\DBTime;
|
FEATURE New DatetimeField class (form field wrapper composed of DateField andTimeField)
FEATURE New DateField and TimeField form classes with more consistent API and easier localization
API CHANGE Date/time parsing in DateField, TimeField and DatetimeField defaults to i18n::get_locale() ('en_US') instead of using en_NZ/en_GB specific parsing. Use i18n::set_locale('en_NZ') in mysite/_config.php to revert to old behaviour.
API CHANGE constructor parameter in TimeField needs to be in ISO date notation (not PHP's date())
API CHANGE TimeField, DateField and related subclasses use Zend_Date for date parsing, meaning they're stricer than the previously used strtotime()
API CHANGE Removed DMYCalendarDateField and CalendarDateField, use DateField with setConfig('showcalendar')
API CHANGE Removed CompositeDateField, DMYDateField, use DateField with setConfig('dmyfields')
API CHANGE Removed DropdownTimeField, use TimeField with setConfig('showdropdown')
API CHANGE Removed PopupDateTimeField, use DatetimeField
API CHANGE Changed 'date', 'month' and 'year' HTML field names to lowercase in DMYDateField
API CHANGE Removed support for ambiguous date formats in DateField, e.g. '06/03/03'. Use DateField->setConfig('dateformat', '<format>') to revert to this behaviour.
API CHANGE Removed flag from DateField, CalendarDateField etc., use DateField->setConfig('min') and DateField->setConfig('max')
ENHANCEMENT Using Zend_Date for DateField and TimeField, with more robust date handling, starting localization support. Set globally via i18n::set_locale(), or for a field instance through setLocale(). Note: Javascript validation is not localized yet. (from r99360)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102859 467b73ca-7a2a-4603-9d3b-597d59a354a9
2010-04-14 06:38:40 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
2014-08-15 08:53:05 +02:00
|
|
|
* Form field to display editable time values in an <input type="text"> field.
|
|
|
|
*
|
FEATURE New DatetimeField class (form field wrapper composed of DateField andTimeField)
FEATURE New DateField and TimeField form classes with more consistent API and easier localization
API CHANGE Date/time parsing in DateField, TimeField and DatetimeField defaults to i18n::get_locale() ('en_US') instead of using en_NZ/en_GB specific parsing. Use i18n::set_locale('en_NZ') in mysite/_config.php to revert to old behaviour.
API CHANGE constructor parameter in TimeField needs to be in ISO date notation (not PHP's date())
API CHANGE TimeField, DateField and related subclasses use Zend_Date for date parsing, meaning they're stricer than the previously used strtotime()
API CHANGE Removed DMYCalendarDateField and CalendarDateField, use DateField with setConfig('showcalendar')
API CHANGE Removed CompositeDateField, DMYDateField, use DateField with setConfig('dmyfields')
API CHANGE Removed DropdownTimeField, use TimeField with setConfig('showdropdown')
API CHANGE Removed PopupDateTimeField, use DatetimeField
API CHANGE Changed 'date', 'month' and 'year' HTML field names to lowercase in DMYDateField
API CHANGE Removed support for ambiguous date formats in DateField, e.g. '06/03/03'. Use DateField->setConfig('dateformat', '<format>') to revert to this behaviour.
API CHANGE Removed flag from DateField, CalendarDateField etc., use DateField->setConfig('min') and DateField->setConfig('max')
ENHANCEMENT Using Zend_Date for DateField and TimeField, with more robust date handling, starting localization support. Set globally via i18n::set_locale(), or for a field instance through setLocale(). Note: Javascript validation is not localized yet. (from r99360)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102859 467b73ca-7a2a-4603-9d3b-597d59a354a9
2010-04-14 06:38:40 +02:00
|
|
|
* # Localization
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
FEATURE New DatetimeField class (form field wrapper composed of DateField andTimeField)
FEATURE New DateField and TimeField form classes with more consistent API and easier localization
API CHANGE Date/time parsing in DateField, TimeField and DatetimeField defaults to i18n::get_locale() ('en_US') instead of using en_NZ/en_GB specific parsing. Use i18n::set_locale('en_NZ') in mysite/_config.php to revert to old behaviour.
API CHANGE constructor parameter in TimeField needs to be in ISO date notation (not PHP's date())
API CHANGE TimeField, DateField and related subclasses use Zend_Date for date parsing, meaning they're stricer than the previously used strtotime()
API CHANGE Removed DMYCalendarDateField and CalendarDateField, use DateField with setConfig('showcalendar')
API CHANGE Removed CompositeDateField, DMYDateField, use DateField with setConfig('dmyfields')
API CHANGE Removed DropdownTimeField, use TimeField with setConfig('showdropdown')
API CHANGE Removed PopupDateTimeField, use DatetimeField
API CHANGE Changed 'date', 'month' and 'year' HTML field names to lowercase in DMYDateField
API CHANGE Removed support for ambiguous date formats in DateField, e.g. '06/03/03'. Use DateField->setConfig('dateformat', '<format>') to revert to this behaviour.
API CHANGE Removed flag from DateField, CalendarDateField etc., use DateField->setConfig('min') and DateField->setConfig('max')
ENHANCEMENT Using Zend_Date for DateField and TimeField, with more robust date handling, starting localization support. Set globally via i18n::set_locale(), or for a field instance through setLocale(). Note: Javascript validation is not localized yet. (from r99360)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102859 467b73ca-7a2a-4603-9d3b-597d59a354a9
2010-04-14 06:38:40 +02:00
|
|
|
* See {@link DateField}
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
FEATURE New DatetimeField class (form field wrapper composed of DateField andTimeField)
FEATURE New DateField and TimeField form classes with more consistent API and easier localization
API CHANGE Date/time parsing in DateField, TimeField and DatetimeField defaults to i18n::get_locale() ('en_US') instead of using en_NZ/en_GB specific parsing. Use i18n::set_locale('en_NZ') in mysite/_config.php to revert to old behaviour.
API CHANGE constructor parameter in TimeField needs to be in ISO date notation (not PHP's date())
API CHANGE TimeField, DateField and related subclasses use Zend_Date for date parsing, meaning they're stricer than the previously used strtotime()
API CHANGE Removed DMYCalendarDateField and CalendarDateField, use DateField with setConfig('showcalendar')
API CHANGE Removed CompositeDateField, DMYDateField, use DateField with setConfig('dmyfields')
API CHANGE Removed DropdownTimeField, use TimeField with setConfig('showdropdown')
API CHANGE Removed PopupDateTimeField, use DatetimeField
API CHANGE Changed 'date', 'month' and 'year' HTML field names to lowercase in DMYDateField
API CHANGE Removed support for ambiguous date formats in DateField, e.g. '06/03/03'. Use DateField->setConfig('dateformat', '<format>') to revert to this behaviour.
API CHANGE Removed flag from DateField, CalendarDateField etc., use DateField->setConfig('min') and DateField->setConfig('max')
ENHANCEMENT Using Zend_Date for DateField and TimeField, with more robust date handling, starting localization support. Set globally via i18n::set_locale(), or for a field instance through setLocale(). Note: Javascript validation is not localized yet. (from r99360)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102859 467b73ca-7a2a-4603-9d3b-597d59a354a9
2010-04-14 06:38:40 +02:00
|
|
|
* @todo Timezone support
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2016-11-29 00:31:16 +01:00
|
|
|
class TimeField extends TextField
|
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
protected $schemaDataType = FormField::SCHEMA_DATA_TYPE_TIME;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Override locale. If empty will default to current locale
|
|
|
|
*
|
|
|
|
* @var string
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
protected $locale = null;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-05-08 07:21:51 +02:00
|
|
|
protected $inputType = 'time';
|
|
|
|
|
2016-11-29 00:31:16 +01:00
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Override time format. If empty will default to that used by the current locale.
|
|
|
|
*
|
|
|
|
* @var string
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
protected $timeFormat = null;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Length of this date (full, short, etc).
|
|
|
|
*
|
|
|
|
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
|
|
|
|
* @var int
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
protected $timeLength = null;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Unparsed value, used exclusively for comparing with internal value
|
|
|
|
* to detect invalid values.
|
|
|
|
*
|
|
|
|
* @var mixed
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
protected $rawValue = null;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
/**
|
|
|
|
* Set custom timezone
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $timezone = null;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-03-30 23:37:21 +02:00
|
|
|
/**
|
2017-04-03 02:00:59 +02:00
|
|
|
* Use HTML5-based input fields (and force ISO 8601 time formats).
|
2017-03-30 23:37:21 +02:00
|
|
|
*
|
|
|
|
* @var bool
|
|
|
|
*/
|
2017-04-03 02:00:59 +02:00
|
|
|
protected $html5 = true;
|
2017-03-30 23:37:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function getHTML5()
|
|
|
|
{
|
|
|
|
return $this->html5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param boolean $bool
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function setHTML5($bool)
|
|
|
|
{
|
|
|
|
$this->html5 = $bool;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
/**
|
|
|
|
* Get time format in CLDR standard format
|
|
|
|
*
|
|
|
|
* This can be set explicitly. If not, this will be generated from the current locale
|
|
|
|
* with the current time length.
|
|
|
|
*
|
2021-10-15 00:28:16 +02:00
|
|
|
* @see https://unicode-org.github.io/icu/userguide/format_parse/datetime/#date-field-symbol-table
|
2017-01-26 05:20:08 +01:00
|
|
|
*/
|
|
|
|
public function getTimeFormat()
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-04-03 02:00:59 +02:00
|
|
|
if ($this->getHTML5()) {
|
|
|
|
// Browsers expect ISO 8601 times, localisation is handled on the client
|
|
|
|
$this->setTimeFormat(DBTime::ISO_TIME);
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
if ($this->timeFormat) {
|
|
|
|
return $this->timeFormat;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Get from locale
|
2017-04-27 01:53:43 +02:00
|
|
|
return $this->getFrontendFormatter()->getPattern();
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
/**
|
|
|
|
* Set time format in CLDR standard format.
|
2017-04-03 02:00:59 +02:00
|
|
|
* Only applicable with {@link setHTML5(false)}.
|
2017-01-26 05:20:08 +01:00
|
|
|
*
|
2021-10-15 00:28:16 +02:00
|
|
|
* @see https://unicode-org.github.io/icu/userguide/format_parse/datetime/#date-field-symbol-table
|
2017-01-26 05:20:08 +01:00
|
|
|
* @param string $format
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function setTimeFormat($format)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
$this->timeFormat = $format;
|
|
|
|
return $this;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
/**
|
|
|
|
* Get length of the time format to use. One of:
|
|
|
|
*
|
|
|
|
* - 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
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getTimeLength()
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
if ($this->timeLength) {
|
|
|
|
return $this->timeLength;
|
|
|
|
}
|
|
|
|
return IntlDateFormatter::MEDIUM;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-04-03 02:00:59 +02:00
|
|
|
* Get length of the time format to use.
|
|
|
|
* Only applicable with {@link setHTML5(false)}.
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
2017-01-26 05:20:08 +01:00
|
|
|
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
2017-01-26 05:20:08 +01:00
|
|
|
* @param int $length
|
|
|
|
* @return $this
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
public function setTimeLength($length)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
$this->timeLength = $length;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get time formatter with the standard locale / date format
|
|
|
|
*
|
|
|
|
* @return IntlDateFormatter
|
|
|
|
*/
|
2017-04-27 01:53:43 +02:00
|
|
|
protected function getFrontendFormatter()
|
2017-01-26 05:20:08 +01:00
|
|
|
{
|
2017-04-03 02:00:59 +02:00
|
|
|
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()'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
$formatter = IntlDateFormatter::create(
|
|
|
|
$this->getLocale(),
|
|
|
|
IntlDateFormatter::NONE,
|
|
|
|
$this->getTimeLength(),
|
|
|
|
$this->getTimezone()
|
|
|
|
);
|
|
|
|
|
2017-03-30 23:37:21 +02:00
|
|
|
if ($this->getHTML5()) {
|
|
|
|
// Browsers expect ISO 8601 times, localisation is handled on the client
|
2017-04-03 02:00:59 +02:00
|
|
|
$formatter->setPattern(DBTime::ISO_TIME);
|
2017-03-30 23:37:21 +02:00
|
|
|
// Don't invoke getTimeFormat() directly to avoid infinite loop
|
|
|
|
} elseif ($this->timeFormat) {
|
2017-01-26 05:20:08 +01:00
|
|
|
$ok = $formatter->setPattern($this->timeFormat);
|
|
|
|
if (!$ok) {
|
|
|
|
throw new InvalidArgumentException("Invalid time format {$this->timeFormat}");
|
|
|
|
}
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
2017-01-26 05:20:08 +01:00
|
|
|
return $formatter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a time formatter for the ISO 8601 format
|
|
|
|
*
|
|
|
|
* @return IntlDateFormatter
|
|
|
|
*/
|
2017-04-27 01:53:43 +02:00
|
|
|
protected function getInternalFormatter()
|
2017-01-26 05:20:08 +01:00
|
|
|
{
|
|
|
|
$formatter = IntlDateFormatter::create(
|
2017-02-22 04:14:53 +01:00
|
|
|
i18n::config()->uninherited('default_locale'),
|
2017-01-26 05:20:08 +01:00
|
|
|
IntlDateFormatter::NONE,
|
|
|
|
IntlDateFormatter::MEDIUM,
|
|
|
|
date_default_timezone_get() // Default to server timezone
|
|
|
|
);
|
|
|
|
$formatter->setLenient(false);
|
2017-04-03 02:00:59 +02:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Note we omit timezone from this format, and we assume server TZ always.
|
2017-04-03 02:00:59 +02:00
|
|
|
$formatter->setPattern(DBTime::ISO_TIME);
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
return $formatter;
|
|
|
|
}
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-03-30 23:37:21 +02:00
|
|
|
public function getAttributes()
|
2017-01-26 05:20:08 +01:00
|
|
|
{
|
|
|
|
$attributes = parent::getAttributes();
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-05-08 07:21:51 +02:00
|
|
|
if (!$this->getHTML5()) {
|
|
|
|
$attributes['type'] = 'text';
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
2017-03-30 23:37:21 +02:00
|
|
|
return $attributes;
|
2017-01-26 05:20:08 +01:00
|
|
|
}
|
|
|
|
|
2017-04-12 12:39:23 +02:00
|
|
|
public function getSchemaDataDefaults()
|
|
|
|
{
|
|
|
|
$defaults = parent::getSchemaDataDefaults();
|
|
|
|
return array_merge($defaults, [
|
2017-04-27 01:47:04 +02:00
|
|
|
'lang' => i18n::convert_rfc1766($this->getLocale()),
|
|
|
|
'data' => array_merge($defaults['data'], [
|
|
|
|
'html5' => $this->getHTML5(),
|
|
|
|
])
|
2017-04-12 12:39:23 +02:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
public function Type()
|
|
|
|
{
|
|
|
|
return 'time text';
|
|
|
|
}
|
2016-11-29 00:31:16 +01:00
|
|
|
|
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Assign value posted from form submission
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
2017-01-26 05:20:08 +01:00
|
|
|
* @param mixed $value
|
|
|
|
* @param mixed $data
|
2016-11-29 00:31:16 +01:00
|
|
|
* @return $this
|
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
public function setSubmittedValue($value, $data = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
// Save raw value for later validation
|
|
|
|
$this->rawValue = $value;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Parse from submitted value
|
2017-04-27 01:53:43 +02:00
|
|
|
$this->value = $this->frontendToInternal($value);
|
2017-01-26 05:20:08 +01:00
|
|
|
return $this;
|
|
|
|
}
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
/**
|
|
|
|
* Set time assigned from database value
|
|
|
|
*
|
|
|
|
* @param mixed $value
|
|
|
|
* @param mixed $data
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function setValue($value, $data = null)
|
|
|
|
{
|
|
|
|
// Save raw value for later validation
|
|
|
|
$this->rawValue = $value;
|
|
|
|
|
|
|
|
// Null case
|
|
|
|
if (!$value) {
|
2016-11-29 00:31:16 +01:00
|
|
|
$this->value = null;
|
2017-01-26 05:20:08 +01:00
|
|
|
return $this;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Re-run through formatter to tidy up (e.g. remove date component)
|
2017-04-27 01:53:43 +02:00
|
|
|
$this->value = $this->tidyInternal($value);
|
2016-11-29 00:31:16 +01:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
public function Value()
|
|
|
|
{
|
2017-04-27 01:53:43 +02:00
|
|
|
$localised = $this->internalToFrontend($this->value);
|
2017-01-26 05:20:08 +01:00
|
|
|
if ($localised) {
|
|
|
|
return $localised;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show midnight in localised format
|
|
|
|
return $this->getMidnight();
|
|
|
|
}
|
|
|
|
|
2016-11-29 00:31:16 +01:00
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Show midnight in current format (adjusts for timezone)
|
|
|
|
*
|
|
|
|
* @return string
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
public function getMidnight()
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-04-27 01:53:43 +02:00
|
|
|
$formatter = $this->getFrontendFormatter();
|
2017-01-26 05:20:08 +01:00
|
|
|
$timestamp = $this->withTimezone($this->getTimezone(), function () {
|
|
|
|
return strtotime('midnight');
|
|
|
|
});
|
|
|
|
return $formatter->format($timestamp);
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validate this field
|
|
|
|
*
|
|
|
|
* @param Validator $validator
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function validate($validator)
|
|
|
|
{
|
|
|
|
// Don't validate empty fields
|
2017-01-26 05:20:08 +01:00
|
|
|
if (empty($this->rawValue)) {
|
2016-11-29 00:31:16 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// We submitted a value, but it couldn't be parsed
|
|
|
|
if (empty($this->value)) {
|
2016-11-29 00:31:16 +01:00
|
|
|
$validator->validationError(
|
|
|
|
$this->name,
|
|
|
|
_t(
|
2017-04-20 03:15:24 +02:00
|
|
|
'SilverStripe\\Forms\\TimeField.VALIDATEFORMAT',
|
2016-11-29 00:31:16 +01:00
|
|
|
"Please enter a valid time format ({format})",
|
2017-01-26 05:20:08 +01:00
|
|
|
['format' => $this->getTimeFormat()]
|
|
|
|
)
|
2016-11-29 00:31:16 +01:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getLocale()
|
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
return $this->locale ?: i18n::get_locale();
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-04-03 02:00:59 +02:00
|
|
|
* Determines the presented/processed format based on locale defaults,
|
|
|
|
* instead of explicitly setting {@link setTimeFormat()}.
|
|
|
|
* Only applicable with {@link setHTML5(false)}.
|
|
|
|
*
|
2016-11-29 00:31:16 +01:00
|
|
|
* @param string $locale
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function setLocale($locale)
|
|
|
|
{
|
|
|
|
$this->locale = $locale;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Creates a new readonly field specified below
|
|
|
|
*
|
|
|
|
* @return TimeField_Readonly
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
public function performReadonlyTransformation()
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
/** @var TimeField_Readonly $result */
|
|
|
|
$result = $this->castedCopy(TimeField_Readonly::class);
|
2020-02-24 14:59:00 +01:00
|
|
|
$result
|
|
|
|
->setValue(false)
|
|
|
|
->setHTML5($this->html5)
|
|
|
|
->setTimeFormat($this->timeFormat)
|
|
|
|
->setTimezone($this->getTimezone())
|
|
|
|
->setLocale($this->locale)
|
|
|
|
->setTimeLength($this->timeLength)
|
|
|
|
->setValue($this->value);
|
2017-01-26 05:20:08 +01:00
|
|
|
return $result;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-04-27 01:53:43 +02:00
|
|
|
* Convert frontend time to the internal representation (ISO 8601).
|
|
|
|
* The frontend time is also in ISO 8601 when $html5=true.
|
2017-01-26 05:20:08 +01:00
|
|
|
*
|
|
|
|
* @param string $time
|
|
|
|
* @return string The formatted time, or null if not a valid time
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-04-27 01:53:43 +02:00
|
|
|
protected function frontendToInternal($time)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
if (!$time) {
|
|
|
|
return null;
|
|
|
|
}
|
2017-04-27 01:53:43 +02:00
|
|
|
$fromFormatter = $this->getFrontendFormatter();
|
|
|
|
$toFormatter = $this->getInternalFormatter();
|
2017-01-26 05:20:08 +01:00
|
|
|
$timestamp = $fromFormatter->parse($time);
|
2017-03-30 23:37:21 +02:00
|
|
|
|
|
|
|
// Try to parse time without seconds, since that's a valid HTML5 submission format
|
|
|
|
// See https://html.spec.whatwg.org/multipage/infrastructure.html#times
|
2017-04-03 02:00:59 +02:00
|
|
|
if ($timestamp === false && $this->getHTML5()) {
|
2017-04-26 03:49:29 +02:00
|
|
|
$fromFormatter->setPattern(str_replace(':ss', '', DBTime::ISO_TIME));
|
2017-03-30 23:37:21 +02:00
|
|
|
$timestamp = $fromFormatter->parse($time);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If timestamp still can't be detected, we've got an invalid time
|
2017-01-26 05:20:08 +01:00
|
|
|
if ($timestamp === false) {
|
|
|
|
return null;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
2017-03-30 23:37:21 +02:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
return $toFormatter->format($timestamp);
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-04-27 01:53:43 +02:00
|
|
|
* Convert the internal time representation (ISO 8601) to a format used by the frontend,
|
|
|
|
* as defined by {@link $timeFormat}. With $html5=true, the frontend time will also be
|
|
|
|
* in ISO 8601.
|
2017-01-26 05:20:08 +01:00
|
|
|
*
|
|
|
|
* @param string $time
|
|
|
|
* @return string
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2017-04-27 01:53:43 +02:00
|
|
|
protected function internalToFrontend($time)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-04-27 01:53:43 +02:00
|
|
|
$time = $this->tidyInternal($time);
|
2017-01-26 05:20:08 +01:00
|
|
|
if (!$time) {
|
|
|
|
return null;
|
|
|
|
}
|
2017-04-27 01:53:43 +02:00
|
|
|
$fromFormatter = $this->getInternalFormatter();
|
|
|
|
$toFormatter = $this->getFrontendFormatter();
|
2017-01-26 05:20:08 +01:00
|
|
|
$timestamp = $fromFormatter->parse($time);
|
|
|
|
if ($timestamp === false) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $toFormatter->format($timestamp);
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2017-04-27 01:53:43 +02:00
|
|
|
* Tidy up the internal time representation (ISO 8601),
|
|
|
|
* and fall back to strtotime() if there's parsing errors.
|
2017-01-26 05:20:08 +01:00
|
|
|
*
|
2017-04-27 01:53:43 +02:00
|
|
|
* @param string $time Time in ISO 8601 or approximate form
|
|
|
|
* @return string ISO 8601 time, or null if not valid
|
2017-01-26 05:20:08 +01:00
|
|
|
*/
|
2017-04-27 01:53:43 +02:00
|
|
|
protected function tidyInternal($time)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
if (!$time) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// Re-run through formatter to tidy up (e.g. remove date component)
|
2017-04-27 01:53:43 +02:00
|
|
|
$formatter = $this->getInternalFormatter();
|
2017-01-26 05:20:08 +01:00
|
|
|
$timestamp = $formatter->parse($time);
|
|
|
|
if ($timestamp === false) {
|
|
|
|
// Fallback to strtotime
|
|
|
|
$timestamp = strtotime($time, DBDatetime::now()->getTimestamp());
|
|
|
|
if ($timestamp === false) {
|
|
|
|
return null;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
}
|
2017-01-26 05:20:08 +01:00
|
|
|
return $formatter->format($timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getTimezone()
|
|
|
|
{
|
|
|
|
return $this->timezone;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $timezone
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function setTimezone($timezone)
|
|
|
|
{
|
|
|
|
if ($this->value && $timezone !== $this->timezone) {
|
|
|
|
throw new \BadMethodCallException("Can't change timezone after setting a value");
|
|
|
|
}
|
|
|
|
$this->timezone = $timezone;
|
|
|
|
return $this;
|
|
|
|
}
|
2016-11-29 00:31:16 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Run a callback within a specific timezone
|
|
|
|
*
|
|
|
|
* @param string $timezone
|
|
|
|
* @param callable $callback
|
|
|
|
*/
|
|
|
|
protected function withTimezone($timezone, $callback)
|
|
|
|
{
|
|
|
|
$currentTimezone = date_default_timezone_get();
|
|
|
|
try {
|
|
|
|
if ($timezone) {
|
|
|
|
date_default_timezone_set($timezone);
|
|
|
|
}
|
|
|
|
return $callback();
|
|
|
|
} finally {
|
|
|
|
// Restore timezone
|
|
|
|
if ($timezone) {
|
|
|
|
date_default_timezone_set($currentTimezone);
|
|
|
|
}
|
|
|
|
}
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|