diff --git a/core/model/fieldtypes/Datetime.php b/core/model/fieldtypes/Datetime.php
index 13e070879..2f63bd8b1 100644
--- a/core/model/fieldtypes/Datetime.php
+++ b/core/model/fieldtypes/Datetime.php
@@ -58,7 +58,7 @@ class SS_Datetime extends Date {
}
public function scaffoldFormField($title = null, $params = null) {
- return new PopupDateTimeField($this->name, $title);
+ return new DatetimeField($this->name, $title);
}
/**
diff --git a/css/CalendarDateField.css b/css/DateField.css
similarity index 100%
rename from css/CalendarDateField.css
rename to css/DateField.css
diff --git a/css/PopupDateTimeField.css b/css/DatetimeField.css
similarity index 100%
rename from css/PopupDateTimeField.css
rename to css/DatetimeField.css
diff --git a/css/DropdownTimeField.css b/css/TimeField_dropdown.css
similarity index 100%
rename from css/DropdownTimeField.css
rename to css/TimeField_dropdown.css
diff --git a/forms/CalendarDateField.php b/forms/CalendarDateField.php
deleted file mode 100755
index b2cf702db..000000000
--- a/forms/CalendarDateField.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-HTML;
- }
-
- function Field() {
- Requirements::javascript(THIRDPARTY_DIR . '/prototype/prototype.js');
- Requirements::javascript(THIRDPARTY_DIR . '/behaviour/behaviour.js');
- Requirements::javascript(THIRDPARTY_DIR . "/calendar/calendar.js");
- Requirements::javascript(THIRDPARTY_DIR . "/calendar/lang/calendar-en.js");
- Requirements::javascript(THIRDPARTY_DIR . "/calendar/calendar-setup.js");
- Requirements::javascript(SAPPHIRE_DIR . "/javascript/CalendarDateField.js");
- Requirements::css(SAPPHIRE_DIR . "/css/CalendarDateField.css");
- Requirements::css(THIRDPARTY_DIR . "/calendar/calendar-win2k-1.css");
-
- $id = $this->id();
- $val = $this->attrValue();
-
- $futureClass = $this->futureOnly ? ' futureonly' : '';
-
- $innerHTML = self::HTMLField( $id, $this->name, $val );
-
- return <<
- $innerHTML
-
-HTML;
- }
-
- /**
- * Sets the field so that only future dates can be set on them
- */
- function futureDateOnly() {
- $this->futureOnly = true;
- }
-}
-
-?>
diff --git a/forms/CompositeDateField.php b/forms/CompositeDateField.php
deleted file mode 100755
index 12f95e116..000000000
--- a/forms/CompositeDateField.php
+++ /dev/null
@@ -1,179 +0,0 @@
-dateDropdown = new DropdownField($name."[date]", "",
- array('NotSet' => '('._t('CompositeDateField.DAY', 'Day').')',
- '01'=>'01', '02'=>'02', '03'=>'03', '04'=>'04', '05'=>'05',
- '06'=>'06', '07'=>'07', '08'=>'08', '09'=>'09', '10'=>'10',
- '11'=>'11', '12'=>'12', '13'=>'13', '14'=>'14', '15'=>'15',
- '16'=>'16', '17'=>'17', '18'=>'18', '19'=>'19', '20'=>'20',
- '21'=>'21', '22'=>'22', '23'=>'23', '24'=>'24', '25'=>'25',
- '26'=>'26', '27'=>'27', '28'=>'28', '29'=>'29', '30'=>'30',
- '31'=>'31'
- ),
- $date
- );
-
- $this->monthDropdown = new DropdownField($name."[month]", "",
- array( 'NotSet' => '('._t('CompositeDateField.MONTH', 'Month').')',
- '01'=>'01', '02'=>'02', '03'=>'03', '04'=>'04', '05'=>'05',
- '06'=>'06', '07'=>'07', '08'=>'08', '09'=>'09', '10'=>'10',
- '11'=>'11', '12'=>'12'
- ),
- $month
- );
-
- if($yearRange == null){
- $this->customiseYearDropDown($name, "1995-2012", $year);
- }else{
- $this->customiseYearDropDown($name, $yearRange, $year);
- }
- parent::__construct($name, $title);
- }
-
- function Field() {
- $this->dateDropdown->setTabIndex($this->getTabIndex());
- $this->monthDropdown->setTabIndex($this->getTabIndex()+1);
- $this->yearDropdown->setTabIndex($this->getTabIndex()+2);
- return $this->dateDropdown->Field() . $this->monthDropdown->Field() . $this->yearDropdown->Field();
- }
-
-
- function performReadonlyTransformation() {
- $field = new CompositeDateField_Disabled($this->name, $this->title, $this->value);
- $field->setForm($this->form);
- return $field;
- }
-
- function customiseYearDropDown($name, $yearRange, $year){
- list($from,$to) = explode('-', $yearRange);
- $source['NotSet'] = '(Year)';
- for($i = $to; $i >= $from; $i--){
- $source[$i]=$i;
- }
- $this->yearDropdown = new DropdownField($name."[year]", "", $source, $year);
- $this->yearDropdown->setValue($year);
- }
-
- function setForm($form) {
- $this->dateDropdown->setForm($form);
- $this->monthDropdown->setForm($form);
- $this->yearDropdown->setForm($form);
- parent::setForm($form);
- }
-
- function setValue($val) {
- if($val) {
- if(is_array($val)){
- if($val['date'] == 'NotSet' || $val['month'] == 'NotSet' || $val['year'] == 'NotSet'){
- $this->value = null; return;
- }
- $val = $val['year'] . '-' . $val['month'] . '-' . $val['date'];
- }
- $this->value = date('d/m/Y', strtotime($val));
- list($year, $month, $date) = explode("-", $val);
- $this->yearDropdown->setValue($year);
- $this->monthDropdown->setValue($month);
- $this->dateDropdown->setValue($date);
-
- } else {
- $this->value = null;
- }
- }
-
- function jsValidation() {
- if(Validator::get_javascript_validator_handler() == 'none') {
- return '';
- }
- $formID = $this->form->FormName();
- $error1 = _t('CompositeDateField.VALIDATIONJS1', 'Please ensure you have set the');
- $error2 = _t('CompositeDateField.VALIDATIONJS2', 'correctly.');
- $day = _t('CompositeDateField.DAYJS', 'day');
- $month = _t('CompositeDateField.MONTHJS', 'month');
- $year = _t('CompositeDateField.YEARJS', 'year');
- $jsFunc =<<name');";
- }
-
- function validate($validator) {
- // TODO Implement server-side validation
- if($this->value == null) {
- $validator->validationError($this->name,_t('Form.VALIDATIONALLDATEVALUES',"Please ensure you have set all date values"),"validation");
- return false;
- } else {
- return true;
- }
- }
-}
-
-/**
- * Allows dates to be represented in a form, by
- * showing in a user friendly format, eg, dd/mm/yyyy.
- * @package forms
- * @subpackage fields-datetime
- */
-class CompositeDateField_Disabled extends DateField {
-
- protected $disabled = true;
-
- function setValue($val) {
- if($val && $val != "0000-00-00") $this->value = date('d/m/Y', strtotime($val));
- else $this->value = _t('Form.DATENOTSET', "(No date set)");
- }
-
- function Field() {
- if($this->value) {
- $df = new Date($this->name);
- $df->setValue($this->dataValue());
- $val = Convert::raw2xml($this->value);
- } else {
- $val = '' . _t('Form.NOTSET', '(not set)') . '';
- }
-
- return "id() . "\">$val";
- }
-
- function Type() {
- return "date_disabled readonly";
- }
-}
-?>
\ No newline at end of file
diff --git a/forms/DMYCalendarDateField.php b/forms/DMYCalendarDateField.php
deleted file mode 100755
index ba5915c36..000000000
--- a/forms/DMYCalendarDateField.php
+++ /dev/null
@@ -1,102 +0,0 @@
-id();
- $val = $this->attrValue();
-
- $day = $month = $year = null;
-
- if( preg_match( '/^\d{2}\/\d{2}\/\d{4}$/', $val ) ) {
- $dateArray = explode( '/', $val );
- $val = $dateArray[2] . '-' . $dateArray[1] . '-' . $dateArray[0];
- }
-
- if($val) {
- $dateArray = explode( '-', $val );
- $day = $dateArray[2];
- $month = $dateArray[1];
- $year = $dateArray[0];
- }
-
- if(preg_match('/(.*)[(.+)]$/', $this->name, $fieldNameParts)) {
- $fieldNamePrefix = $fieldNameParts[1];
- $fieldName = $fieldNameParts[2];
- } else {
- $fieldNamePrefix = $this->name;
- $fieldName = $this->name;
- }
-
- return <<
-
- /
- /
-
-
-
-HTML;
- }
-
- function jsValidation() {
- if(Validator::get_javascript_validator_handler() == 'none') {
- return '';
- }
-
- $formID = $this->form->FormName();
- $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format (DD/MM/YYYY).');
- $error = 'Please enter a valid date format (DD/MM/YYYY) from dmy.';
- $jsFunc =<< 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/[1-2]([0-9]){3}\$/)) {
- validationError(_CURRENT_FORM.elements[fieldName+'[Day]'],"$error","validation",false);
- return false;
- }
- return true;
- }
- }
-});
-JS;
- Requirements :: customScript($jsFunc, 'func_validateDMYDate_'.$formID);
-
-// return "\$('$formID').validateDate('$this->name');";
- return <<name')
- \$('$formID').validateDMYDate('$this->name');
- }else{
- \$('$formID').validateDMYDate('$this->name');
- }
-}
-JS;
- }
-
-}
-?>
\ No newline at end of file
diff --git a/forms/DMYDateField.php b/forms/DMYDateField.php
deleted file mode 100644
index 834d7ae2f..000000000
--- a/forms/DMYDateField.php
+++ /dev/null
@@ -1,112 +0,0 @@
-value = $value['Year'] . '-' . $value['Month'] . '-' . $value['Day'];
- else if(is_array($value)&&(!$value['Day']||!$value['Month']||!$value['Year']))
- $this->value = null;
- else if(is_string($value))
- $this->value = $value;
- }
-
- function Field() {
- Requirements::javascript(SAPPHIRE_DIR . "/javascript/CalendarDateField.js");
-
- $field = DateField::Field();
-
- $id = $this->id();
- $val = $this->attrValue();
-
- if( preg_match( '/^\d{2}\/\d{2}\/\d{4}$/', $val ) ) {
- $dateArray = explode( '/', $val );
-
- $val = $dateArray[2] . '-' . $dateArray[1] . '-' . $dateArray[0];
- }
-
- $day = $month = $year = null;
- if($val) {
- $dateArray = explode( '-', $val );
-
- $day = $dateArray[2];
- $month = $dateArray[1];
- $year = $dateArray[0];
- }
-
- $fieldName = $this->name;
-
- return <<
- /
- /
-
-
-
-HTML;
- }
-
- function validate($validator)
- {
- if(!empty ($this->value) && !preg_match('/^([0-9][0-9]){1,2}\-[0-9]{1,2}\-[0-9]{1,2}$/', $this->value))
- {
- $validator->validationError(
- $this->name,
- _t('DMYDateField.VALIDDATEFORMAT', "Please enter a valid date format (DD-MM-YYYY)."),
- "validation",
- false
- );
- return false;
- }
- return true;
- }
-
- function jsValidation() {
- if(Validator::get_javascript_validator_handler() == 'none') {
- return '';
- }
- $formID = $this->form->FormName();
- $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format (DD/MM/YYYY).');
- $error = 'Please enter a valid date format (DD/MM/YYYY) from dmy.';
- $jsFunc =<< 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/([0-9][0-9]){1,2}\$/)) {
- validationError(_CURRENT_FORM.elements[fieldName+'[Day]'],"$error","validation",false);
- return false;
- }
- return true;
- }
- }
-});
-JS;
- Requirements :: customScript($jsFunc, 'func_validateDMYDate_'.$formID);
-
-// return "\$('$formID').validateDate('$this->name');";
- return <<name')
- \$('$formID').validateDMYDate('$this->name');
- }else{
- \$('$formID').validateDMYDate('$this->name');
- }
-}
-JS;
- }
-}
-?>
\ No newline at end of file
diff --git a/forms/DateField.php b/forms/DateField.php
index f67fb4122..50077d9d6 100755
--- a/forms/DateField.php
+++ b/forms/DateField.php
@@ -1,9 +1,41 @@
` field,
+ * or in three separate fields for day, month and year.
*
- * @todo Add localization support, see http://open.silverstripe.com/ticket/2931
+ * # Configuration
+ *
+ * - 'showcalendar' (boolean): Determines if a calendar picker is shown.
+ * By default, "DHTML Calendar" is used,see http://www.dynarch.com/projects/calendar.
+ * CAUTION: Only works in NZ date format, see calendar-setup.js
+ * - 'dmyfields' (boolean): Show three input fields for day, month and year separately.
+ * CAUTION: Might not be useable in combination with 'showcalendar', depending on the used javascript library
+ * - 'dateformat' (string): Date format compatible with Zend_Date.
+ * Usually set to default format for {@link locale}
+ * through {@link Zend_Locale_Format::getDateFormat()}.
+ * - 'datavalueformat' (string): Internal ISO format string used by {@link dataValue()} to save the
+ * date to a database.
+ * - 'min' (string): Minimum allowed date value (in ISO format, or strtotime() compatible).
+ * Example: '2010-03-31', or '-7 days'
+ * - 'max' (string): Maximum allowed date value (in ISO format, or strtotime() compatible).
+ * Example: '2010-03-31', or '1 year'
+ *
+ * # Localization
+ *
+ * The field will get its default locale from {@link i18n::get_locale()}, and set the `dateformat`
+ * configuration accordingly. Changing the locale through {@link setLocale()} will not update the
+ * `dateformat` configuration automatically.
+ *
+ * # Usage
+ *
+ * ## Example: German dates with separate fields for day, month, year
+ *
+ * $f = new DateField('MyDate');
+ * $f->setLocale('de_DE');
+ * $f->setConfig('dmyfields');
*
* @package forms
* @subpackage fields-datetime
@@ -11,73 +43,260 @@
class DateField extends TextField {
/**
- * Enable DD/MM/YYYY field format validation
- * in {@link DateField->validate()}. Set to
- * FALSE to disable this validation.
- *
- * @var boolean
+ * @var array
*/
- public static $validation_enabled = true;
+ protected $config = array(
+ 'showcalendar' => false,
+ 'dmyfields' => false,
+ 'dateformat' => null,
+ 'datavalueformat' => 'yyyy-MM-dd',
+ 'min' => null,
+ 'max' => null
+ );
+
+ /**
+ * @var String
+ */
+ protected $locale = null;
+ /**
+ * @var Zend_Date Just set if the date is valid.
+ * {@link $value} will always be set to aid validation,
+ * and might contain invalid values.
+ */
+ protected $valueObj = null;
+
+ function __construct($name, $title = null, $value = null, $form = null, $rightTitle = null) {
+ if(!$this->locale) {
+ $this->locale = i18n::get_locale();
+ }
+
+ if(!$this->getConfig('dateformat')) {
+ $this->setConfig('dateformat', Zend_Locale_Format::getDateFormat($this->locale));
+ }
+
+ parent::__construct($name, $title, $value, $form, $rightTitle);
+ }
+
+ function FieldHolder() {
+
+
+ return parent::FieldHolder();
+ }
+
+ function Field() {
+ // Three separate fields for day, month and year
+ if($this->getConfig('dmyfields')) {
+ // values
+ $valArr = ($this->valueObj) ? $this->valueObj->toArray() : null;
+
+ // fields
+ $fieldDay = new NumericField($this->name . '[day]', false, ($valArr) ? $valArr['day'] : null);
+ $fieldDay->addExtraClass('day');
+ $fieldDay->setMaxLength(2);
+ $fieldMonth = new NumericField($this->name . '[month]', false, ($valArr) ? $valArr['month'] : null);
+ $fieldMonth->addExtraClass('month');
+ $fieldMonth->setMaxLength(2);
+ $fieldYear = new NumericField($this->name . '[year]', false, ($valArr) ? $valArr['year'] : null);
+ $fieldYear->addExtraClass('year');
+ $fieldYear->setMaxLength(4);
+
+ // TODO Locale specific ordering of fields
+ $sep = ' / ';
+ $html = $fieldDay->Field() .
+ $sep .
+ $fieldMonth->Field() .
+ $sep .
+ $fieldYear->Field();
+ }
+ // Default text input field
+ else {
+ $html = parent::Field();
+ }
+
+ $html = $this->FieldDriver($html);
+
+ // wrap in additional div for legacy reasons and to apply behaviour correctly
+ if($this->getConfig('showcalendar')) $html = sprintf('%s
', $html);
+
+ return $html;
+ }
+
+ /**
+ * Caution: API might change. This will evolve into a pluggable
+ * API for 'form field drivers' which can add their own
+ * markup and requirements.
+ *
+ * @param String $html
+ * @return $html
+ */
+ protected function FieldDriver($html) {
+ // Optionally add a "DHTML" calendar icon. Mainly legacy, a date picker
+ // should be unobtrusively added by javascript (e.g. jQuery UI).
+ // CAUTION: Only works in NZ date format, see calendar-setup.js
+ if($this->getConfig('showcalendar')) {
+ Requirements::javascript(THIRDPARTY_DIR . '/prototype/prototype.js');
+ Requirements::javascript(THIRDPARTY_DIR . '/behaviour/behaviour.js');
+ Requirements::javascript(THIRDPARTY_DIR . "/calendar/calendar.js");
+ Requirements::javascript(THIRDPARTY_DIR . "/calendar/lang/calendar-en.js");
+ Requirements::javascript(THIRDPARTY_DIR . "/calendar/calendar-setup.js");
+ Requirements::css(SAPPHIRE_DIR . "/css/DateField.css");
+ Requirements::css(THIRDPARTY_DIR . "/calendar/calendar-win2k-1.css");
+
+ $html .= sprintf('', $this->id());
+ $html .= sprintf('', $this->id());
+ }
+
+ return $html;
+ }
+
+ /**
+ * Sets the internal value to ISO date format.
+ *
+ * @param String|Array $val
+ */
function setValue($val) {
- if(is_string($val) && preg_match('/^([\d]{2,4})-([\d]{1,2})-([\d]{1,2})/', $val)) {
- $this->value = preg_replace('/^([\d]{2,4})-([\d]{1,2})-([\d]{1,2})/','\\3/\\2/\\1', $val);
+ if(empty($val)) {
+ $this->value = null;
+ $this->valueObj = null;
} else {
- $this->value = $val;
+ if($this->getConfig('dmyfields')) {
+ // Setting in correct locale
+ if(is_array($val) && $this->validateArrayValue($val)) {
+ // set() gets confused with custom date formats when using array notation
+ $this->valueObj = new Zend_Date($val, null, $this->locale);
+ $this->value = $this->valueObj->toArray();
+ }
+ // load ISO date from database (usually through Form->loadDataForm())
+ else if(!empty($val) && Zend_Date::isDate($val, $this->getConfig('datavalueformat'))) {
+ $this->valueObj = new Zend_Date($val, $this->getConfig('datavalueformat'));
+ $this->value = $this->valueObj->toArray();
+ }
+ else {
+ $this->value = $val;
+ $this->valueObj = null;
+ }
+ } else {
+ // Setting in corect locale.
+ // Caution: Its important to have this check *before* the ISO date fallback,
+ // as some dates are falsely detected as ISO by isDate(), e.g. '03/04/03'
+ // (en_NZ for 3rd of April, definetly not yyyy-MM-dd)
+ if(!empty($val) && Zend_Date::isDate($val, $this->getConfig('dateformat'), $this->locale)) {
+ $this->valueObj = new Zend_Date($val, $this->getConfig('dateformat'), $this->locale);
+ $this->value = $this->valueObj->get($this->getConfig('dateformat'));
+ }
+ // load ISO date from database (usually through Form->loadDataForm())
+ else if(!empty($val) && Zend_Date::isDate($val, $this->getConfig('datavalueformat'))) {
+ $this->valueObj = new Zend_Date($val, $this->getConfig('datavalueformat'));
+ $this->value = $this->valueObj->get($this->getConfig('dateformat'));
+ }
+ else {
+ $this->value = $val;
+ $this->valueObj = null;
+ }
+ }
}
}
+ /**
+ * @return String ISO 8601 date, suitable for insertion into database
+ */
function dataValue() {
- if(is_array($this->value)) {
- if(isset($this->value['Year']) && isset($this->value['Month']) && isset($this->value['Day'])) {
- return $this->value['Year'] . '-' . $this->value['Month'] . '-' . $this->value['Day'];
- } else {
- user_error("Bad DateField value " . var_export($this->value,true), E_USER_WARNING);
- }
- } elseif(preg_match('/^([\d]{1,2})\/([\d]{1,2})\/([\d]{2,4})/', $this->value, $parts)) {
- return "$parts[3]-$parts[2]-$parts[1]";
- } elseif(!empty($this->value)) {
- return date('Y-m-d', strtotime($this->value));
+ if($this->valueObj) {
+ return $this->valueObj->toString($this->getConfig('datavalueformat'));
} else {
return null;
}
}
function performReadonlyTransformation() {
- $field = new DateField_Disabled($this->name, $this->title, $this->value);
+ $field = new DateField_Disabled($this->name, $this->title, $this->valueObj);
$field->setForm($this->form);
$field->readonly = true;
+
return $field;
}
function jsValidation() {
$formID = $this->form->FormName();
-
- if(Validator::get_javascript_validator_handler() == 'none') {
- return true;
- }
-
- $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format (DD/MM/YYYY).');
- $jsFunc =<<showSeparateFields) {
+ $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format (DD/MM/YYYY).');
+ $error = 'Please enter a valid date format (DD/MM/YYYY) from dmy.';
+ $jsFunc =<< 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/[0-90-9]{2,4}\$/)) {
- validationError(el,"$error","validation",false);
+ validateDMYDate: function(fieldName) {
+ var day_value = \$F(_CURRENT_FORM.elements[fieldName+'[day]']);
+ var month_value = \$F(_CURRENT_FORM.elements[fieldName+'[month]']);
+ var year_value = \$F(_CURRENT_FORM.elements[fieldName+'[year]']);
+
+ // TODO NZ specific
+ var value = day_value + '/' + month_value + '/' + year_value;
+ if(value && value.length > 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/([0-9][0-9]){1,2}\$/)) {
+ validationError(_CURRENT_FORM.elements[fieldName+'[day]'],"$error","validation",false);
+
return false;
}
+
return true;
}
}
});
JS;
- Requirements :: customScript($jsFunc, 'func_validateDate_'.$formID);
-
-// return "\$('$formID').validateDate('$this->name');";
- return <<name')
+ \$('$formID').validateDMYDate('$this->name');
+ }else{
+ \$('$formID').validateDMYDate('$this->name');
+ }
+ }
+JS;
+ } else {
+ $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format (DD/MM/YYYY).');
+ $jsFunc =<< 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/([0-9][0-9]){1,2}\$/)) {
+ validationError(_CURRENT_FORM.elements[fieldName+'[day]'],"$error","validation",false);
+ return false;
+ }
+ } else {
+ // single field validation
+ if(value && value.length > 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/[0-90-9]{2,4}\$/)) {
+ validationError(el,"$error","validation",false);
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+});
+JS;
+ Requirements :: customScript($jsFunc, 'func_validateDate_'.$formID);
+
+ return <<name')
@@ -87,17 +306,45 @@ if(\$('$formID')){
}
}
JS;
+ }
}
+ /**
+ * Validate an array with expected keys 'day', 'month' and 'year.
+ * Used because Zend_Date::isDate() doesn't provide this.
+ *
+ * @param Array $val
+ * @return boolean
+ */
+ function validateArrayValue($val) {
+ if(!is_array($val)) return false;
+
+ return (
+ array_key_exists('year', $val)
+ && Zend_Date::isDate($val['year'], 'yyyy', $this->locale)
+ && array_key_exists('month', $val)
+ && Zend_Date::isDate($val['month'], 'MM', $this->locale)
+ && array_key_exists('day', $val)
+ && Zend_Date::isDate($val['day'], 'dd', $this->locale)
+ );
+ }
+
+ /**
+ * @return Boolean
+ */
function validate($validator) {
- $validationHandler = Validator::get_javascript_validator_handler();
+ $valid = true;
- if(!self::$validation_enabled || $validationHandler == 'none') {
- return true;
+ // Don't validate empty fields
+ if(empty($this->value)) return true;
+
+ // date format
+ if($this->getConfig('dmyfields')) {
+ $valid = ($this->validateArrayValue($this->value));
+ } else {
+ $valid = (Zend_Date::isDate($this->value, $this->getConfig('dateformat'), $this->locale));
}
-
- if(!empty ($this->value) && is_string($this->value) && !preg_match('/^[0-9]{1,2}\/[0-9]{1,2}\/[0-90-9]{2,4}$/', $this->value))
- {
+ if(!$valid) {
$validator->validationError(
$this->name,
_t('DateField.VALIDDATEFORMAT', "Please enter a valid date format (DD/MM/YYYY)."),
@@ -106,8 +353,98 @@ JS;
);
return false;
}
+
+ // min/max - Assumes that the date value was valid in the first place
+ if($min = $this->getConfig('min')) {
+ // ISO or strtotime()
+ if(Zend_Date::isDate($min, $this->getConfig('datavalueformat'))) {
+ $minDate = new Zend_Date($min, $this->getConfig('datavalueformat'));
+ } else {
+ $minDate = new Zend_Date(strftime('%F', strtotime($min)), $this->getConfig('datavalueformat'));
+ }
+ if(!$this->valueObj->isLater($minDate) && !$this->valueObj->equals($minDate)) {
+ $validator->validationError(
+ $this->name,
+ sprintf(
+ _t('DateField.VALIDDATEMINDATE', "Your date has to be newer or matching the minimum allowed date (%s)"),
+ $minDate->toString($this->getConfig('dateformat'))
+ ),
+ "validation",
+ false
+ );
+ return false;
+ }
+ }
+ if($max = $this->getConfig('max')) {
+ // ISO or strtotime()
+ if(Zend_Date::isDate($min, $this->getConfig('datavalueformat'))) {
+ $maxDate = new Zend_Date($max, $this->getConfig('datavalueformat'));
+ } else {
+ $maxDate = new Zend_Date(strftime('%F', strtotime($max)), $this->getConfig('datavalueformat'));
+ }
+ if(!$this->valueObj->isEarlier($maxDate) && !$this->valueObj->equals($maxDate)) {
+ $validator->validationError(
+ $this->name,
+ sprintf(
+ _t('DateField.VALIDDATEMAXDATE', "Your date has to be older or matching the maximum allowed date (%s)"),
+ $maxDate->toString($this->getConfig('dateformat'))
+ ),
+ "validation",
+ false
+ );
+ return false;
+ }
+ }
+
return true;
}
+
+ /**
+ * @return string
+ */
+ function getLocale() {
+ return $this->locale;
+ }
+
+ /**
+ * Caution: Will not update the 'dateformat' config value.
+ *
+ * @param String $locale
+ */
+ function setLocale($locale) {
+ $this->locale = $locale;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $val
+ */
+ function setConfig($name, $val) {
+ switch($name) {
+ case 'min':
+ $format = $this->getConfig('datavalueformat');
+ if($val && !Zend_Date::isDate($val, $format) && !strtotime($val)) {
+ throw new InvalidArgumentException('Date "%s" is not a valid minimum date format (%s) or strtotime() argument', $val, $format);
+ }
+ break;
+ case 'max':
+ $format = $this->getConfig('datavalueformat');
+ if($val && !Zend_Date::isDate($val, $format) && !strtotime($val)) {
+ throw new InvalidArgumentException('Date "%s" is not a valid maximum date format (%s) or strtotime() argument', $val, $format);
+ }
+ break;
+ }
+
+ $this->config[$name] = $val;
+ }
+
+ /**
+ * @param String $name
+ * @return mixed
+ */
+ function getConfig($name) {
+ return $this->config[$name];
+ }
}
/**
@@ -119,31 +456,21 @@ JS;
class DateField_Disabled extends DateField {
protected $disabled = true;
-
- function setValue($val) {
- if(is_string($val) && preg_match('/^([\d]{2,4})-([\d]{1,2})-([\d]{1,2})/', $val)) {
- $this->value = preg_replace('/^([\d]{2,4})-([\d]{1,2})-([\d]{1,2})/','\\3/\\2/\\1', $val);
- } else {
- $this->value = $val;
- }
- }
-
+
function Field() {
- if($this->value) {
- $df = new Date($this->name);
- $df->setValue($this->dataValue());
-
- if(date('Y-m-d', time()) == $this->dataValue()) {
- $val = Convert::raw2xml($this->value . ' ('._t('DateField.TODAY','today').')');
+ if($this->valueObj) {
+ if($this->valueObj->isToday()) {
+ $val = Convert::raw2xml($this->valueObj->toString($this->getConfig('dateformat')) . ' ('._t('DateField.TODAY','today').')');
} else {
- $val = Convert::raw2xml($this->value . ', ' . $df->Ago());
+ $df = new Date($this->name);
+ $df->setValue($this->dataValue());
+ $val = Convert::raw2xml($this->valueObj->toString($this->getConfig('dateformat')) . ', ' . $df->Ago());
}
} else {
$val = '('._t('DateField.NOTSET', 'not set').')';
}
- return "id() . "\">$val
- value}\" name=\"$this->name\" />";
+ return "id() . "\">$val";
}
function Type() {
@@ -153,13 +480,10 @@ class DateField_Disabled extends DateField {
function jsValidation() {
return null;
}
-
- function php() {
- return true;
- }
function validate($validator) {
return true;
}
}
+
?>
\ No newline at end of file
diff --git a/forms/DatetimeField.php b/forms/DatetimeField.php
new file mode 100644
index 000000000..e1dad8438
--- /dev/null
+++ b/forms/DatetimeField.php
@@ -0,0 +1,202 @@
+ 'YYYY-MM-dd HH:mm:ss'
+ );
+
+ function __construct($name, $title = null, $value = ""){
+ $this->dateField = new DateField($name . '[date]', false);
+ $this->timeField = new TimeField($name . '[time]', false);
+
+ parent::__construct($name, $title, $value);
+ }
+
+ function setForm($form) {
+ parent::setForm($form);
+
+ $this->dateField->setForm($form);
+ $this->timeField->setForm($form);
+ }
+
+ function Field() {
+ return $this->dateField->Field() . $this->timeField->Field();
+ }
+
+ /**
+ * Sets the internal value to ISO date format.
+ *
+ * @param string|array $val String expects an ISO date format. Array notation with 'date' and 'time'
+ * keys can contain localized strings. If the 'dmyfields' option is used for {@link DateField},
+ * the 'date' value may contain array notation was well (see {@link DateField->setValue()}).
+ */
+ function setValue($val) {
+ if(empty($val)) {
+ $this->dateField->setValue(null);
+ $this->timeField->setValue(null);
+ } else {
+ // String setting is only possible from the database, so we don't allow anything but ISO format
+ if(is_string($val) && Zend_Date::isDate($val, $this->getConfig('datavalueformat'), $this->locale)) {
+ // split up in date and time string values.
+ $valueObj = new Zend_Date($val, $this->getConfig('datavalueformat'), $this->locale);
+ // set date either as array, or as string
+ if($this->dateField->getConfig('dmyfields')) {
+ $this->dateField->setValue($valueObj->toArray());
+ } else {
+ $this->dateField->setValue($valueObj->get($this->dateField->getConfig('dateformat')));
+ }
+ // set time
+ $this->timeField->setValue($valueObj->get($this->timeField->getConfig('timeformat')));
+ }
+ // Setting from form submission
+ elseif(is_array($val) && array_key_exists('date', $val) && array_key_exists('time', $val)) {
+ $this->dateField->setValue($val['date']);
+ $this->timeField->setValue($val['time']);
+ } else {
+ $this->dateField->setValue($val);
+ $this->timeField->setValue($val);
+ }
+ }
+ }
+
+ function dataValue() {
+ $valDate = $this->dateField->dataValue();
+ $valTime = $this->timeField->dataValue();
+
+ if($valDate && $valTime) {
+ return $valDate . ' ' . $valTime;
+ } else {
+ // TODO
+ return null;
+ }
+ }
+
+ /**
+ * @return DateField
+ */
+ function getDateField() {
+ return $this->dateField;
+ }
+
+ /**
+ * @return TimeField
+ */
+ function getTimeField() {
+ return $this->timeField;
+ }
+
+ function setLocale($locale) {
+ $this->dateField->setLocale($locale);
+ $this->timeField->setLocale($locale);
+ }
+
+ function getLocale() {
+ return $this->dateField->getLocale();
+ }
+
+ /**
+ * Note: Use {@link getDateField()} and {@link getTimeField()}
+ * to set field-specific config options.
+ *
+ * @param string $name
+ * @param mixed $val
+ */
+ function setConfig($name, $val) {
+ $this->config[$name] = $val;
+ }
+
+ /**
+ * Note: Use {@link getDateField()} and {@link getTimeField()}
+ * to get field-specific config options.
+ *
+ * @param String $name
+ * @return mixed
+ */
+ function getConfig($name) {
+ return $this->config[$name];
+ }
+
+ function validate($validator) {
+ $dateValid = $this->dateField->validate($validator);
+ $timeValid = $this->timeField->validate($validator);
+
+ return ($dateValid && $timeValid);
+ }
+
+ function jsValidation() {
+ return $this->dateField->jsValidation() . $this->timeField->jsValidation();
+ }
+
+ function performReadonlyTransformation() {
+ $field = new DatetimeField_Readonly($this->name, $this->title, $this->dataValue());
+ $field->setForm($this->form);
+
+ return $field;
+ }
+}
+
+/**
+ * The readonly class for our {@link DatetimeField}.
+ *
+ * @package forms
+ * @subpackage fields-datetime
+ */
+class DatetimeField_Readonly extends DatetimeField {
+
+ protected $readonly = true;
+
+ function Field() {
+ $valDate = $this->dateField->dataValue();
+ $valTime = $this->timeField->dataValue();
+ if($valDate && $valTime) {
+ $format = $this->dateField->getConfig('dateformat') . ' ' . $this->timeField->getConfig('timeformat');
+ $valueObj = new Zend_Date(
+ $valDate . ' ' . $valTime,
+ $this->getConfig('datavalueformat'),
+ $this->dateField->getLocale()
+ );
+ $val = $valueObj->toString($format);
+ } else {
+ // TODO Localization
+ $val = '(not set)';
+ }
+
+ return "id() . "\">$val";
+ }
+
+ function jsValidation() {
+ return null;
+ }
+
+ function validate($validator) {
+ return true;
+ }
+}
+?>
\ No newline at end of file
diff --git a/forms/DropdownTimeField.php b/forms/DropdownTimeField.php
deleted file mode 100644
index cf88e6234..000000000
--- a/forms/DropdownTimeField.php
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-HTML;
- }
-
- function Field() {
-
- self::Requirements();
-
- $field = parent::Field();
-
- $id = $this->id();
- $val = $this->attrValue();
-
- $innerHTML = self::HTMLField( $id, $this->name, $val );
-
- return <<
- $innerHTML
-
-HTML;
- }
-}
\ No newline at end of file
diff --git a/forms/FormField.php b/forms/FormField.php
index 7647b2c32..08ce37b82 100755
--- a/forms/FormField.php
+++ b/forms/FormField.php
@@ -75,7 +75,7 @@ class FormField extends RequestHandler {
$this->name = $name;
$this->title = ($title === null) ? $name : $title;
- if(isset($value)) $this->value = $value;
+ if($value) $this->setValue($value);
if($form) $this->setForm($form);
parent::__construct();
diff --git a/forms/PopupDateTimeField.php b/forms/PopupDateTimeField.php
deleted file mode 100644
index d4c606edd..000000000
--- a/forms/PopupDateTimeField.php
+++ /dev/null
@@ -1,100 +0,0 @@
-id();
-
- $val = $this->attrValue();
-
- $date = $this->attrValueDate();
- $time = $this->attrValueTime();
-
- $futureClass = $this->futureOnly ? ' futureonly' : '';
-
- $innerHTMLDate = parent::HTMLField( $id . '_Date', $this->name . '[Date]', $date );
- $innerHTMLTime = DropdownTimeField::HTMLField( $id . '_Time', $this->name . '[Time]', $time );
-
- return <<
-
- - $innerHTMLDate
- - $innerHTMLTime
-
-
-HTML;
- }
-
- function attrValueDate() {
- if( $this->value )
- return date( 'd/m/Y', strtotime( $this->value ) );
- else
- return '';
- }
-
- function attrValueTime() {
- if( $this->value )
- return date( 'h:i a', strtotime( $this->value ) );
- else
- return '';
- }
-
- function setValue( $val ) {
- if( is_array( $val ) ) {
-
- // 1) Date
-
- if( $val[ 'Date' ] && preg_match( '/^([\d]{1,2})\/([\d]{1,2})\/([\d]{2,4})/', $val[ 'Date' ], $parts ) )
- $date = "$parts[3]-$parts[2]-$parts[1]";
- else
- $date = null;
-
- // 2) Time
-
- $time = $val[ 'Time' ] ? date( 'H:i:s', strtotime( $val[ 'Time' ] ) ) : null;
-
- if( $date == null )
- $this->value = $time;
- else if( $time == null )
- $this->value = $date;
- else
- $this->value = $date . ' ' . $time;
- }
- else
- $this->value = $val;
- }
-
- function dataValue() {
- return $this->value;
- }
-}
-
-?>
\ No newline at end of file
diff --git a/forms/TextField.php b/forms/TextField.php
index 7850d65a0..62eb48067 100755
--- a/forms/TextField.php
+++ b/forms/TextField.php
@@ -5,6 +5,10 @@
* @subpackage fields-basic
*/
class TextField extends FormField {
+
+ /**
+ * @var Int
+ */
protected $maxLength;
/**
@@ -12,9 +16,24 @@ class TextField extends FormField {
*/
function __construct($name, $title = null, $value = "", $maxLength = null, $form = null){
$this->maxLength = $maxLength;
+
parent::__construct($name, $title, $value, $form);
}
+ /**
+ * @param Int $length
+ */
+ function setMaxLength($length) {
+ $this->maxLength = $length;
+ }
+
+ /**
+ * @return Int
+ */
+ function getMaxLength() {
+ return $this->maxLength;
+ }
+
function Field() {
$attributes = array(
'type' => 'text',
diff --git a/forms/TimeField.php b/forms/TimeField.php
index 3ac0eefc0..9a0a3985b 100755
--- a/forms/TimeField.php
+++ b/forms/TimeField.php
@@ -1,17 +1,52 @@
+ * field. Can optionally display a dropdown with predefined time ranges
+ * through `setConfig('showdropdown', true)`.
+ *
+ * # Configuration
+ *
+ * - 'timeformat' (string): Time format compatible with Zend_Date.
+ * Usually set to default format for {@link locale}
+ * through {@link Zend_Locale_Format::getTimeFormat()}.
+ * - 'use_strtotime' (boolean): Accept values in PHP's built-in strtotime() notation, in addition
+ * to the format specified in `timeformat`. Example inputs: 'now', '11pm', '23:59:59'.
+ * - 'showdropdown': Show a dropdown with suggested date values.
+ * CAUTION: The dropdown does not support localization.
+ *
+ * # Localization
+ *
+ * See {@link DateField}
+ *
+ * @todo Timezone support
+ * @todo 'showdropdown' localization
*
* @package forms
* @subpackage fields-datetime
*/
class TimeField extends TextField {
+ protected $config = array(
+ 'showdropdown' => false,
+ 'timeformat' => null,
+ 'use_strtotime' => true,
+ 'datavalueformat' => 'HH:mm:ss'
+ );
+
/**
- * @var string $timeformat Time description compatible with date() syntax.
+ * @var String
*/
- protected $timeformat = "g:ia";
+ protected $locale = null;
+ /**
+ * @var Zend_Date Just set if the date is valid.
+ * {@link $value} will always be set to aid validation,
+ * and might contain invalid values.
+ */
+ protected $valueObj = null;
+
/**
* Constructor saves the format difference. Timefields shouldn't
* have a problem with length as times can only be represented in on way.
@@ -19,42 +54,156 @@ class TimeField extends TextField {
* @param $name string The name of the field
* @param $title string The Title of the field
* @param $value string the value for the field
- * @param $timeformat string The Time format in date php format e.g. G:ia
+ * @param $timeformat string The Time format in ISO format (see Zend_Date)
*/
- function __construct($name, $title = null, $value = "",$timeformat = null){
+ function __construct($name, $title = null, $value = "",$timeformat = 'HH:mm:ss'){
+ if($timeformat) {
+ $this->setConfig('timeformat', $timeformat);
+ } else {
+ $this->setConfig('timeformat', Zend_Locale_Format::getTimeFormat($this->locale));
+ }
+
parent::__construct($name,$title,$value);
+ }
+
+ function Field() {
+ $html = parent::Field();
- if($timeformat) $this->timeformat = $timeformat;
+ $html = $this->FieldDriver($html);
+
+ return $html;
}
- function dataValue() {
- if($this->value) {
- return date($this->timeformat,strtotime($this->value));
- } else {
- return $this->value;
+ /**
+ * Internal volatile API.
+ *
+ * @see DateField->FieldDriver()
+ */
+ protected function FieldDriver($html) {
+ if($this->getConfig('showdropdown')) {
+ Requirements::javascript(SAPPHIRE_DIR . '/javascript/TimeField_dropdown.js');
+ Requirements::css(SAPPHIRE_DIR . '/css/TimeField_dropdown.css');
+
+ $html .= sprintf('', $this->id());
+ $html .= sprintf('', $this->id());
+ $html = '' . $html . '
';
}
+
+ return $html;
}
+ /**
+ * Sets the internal value to ISO date format.
+ *
+ * @param String|Array $val
+ */
function setValue($val) {
- if($val) {
- $this->value = date($this->timeformat,strtotime($val));
- } else {
- $this->value = $val;
+ // Fuzzy matching through strtotime() to support a wider range of times,
+ // e.g. 11am. This means that validate() might not fire.
+ // Note: Time formats are assumed to be less ambiguous than dates across locales.
+ if($this->getConfig('use_strtotime') && !empty($val)) {
+ if($parsedTimestamp = strtotime($val)) {
+ $parsedObj = new Zend_Date($parsedTimestamp, Zend_Date::TIMESTAMP);
+ $val = $parsedObj->get($this->getConfig('timeformat'));
+ unset($parsedObj);
+ }
}
-
+
+ if(empty($val)) {
+ $this->value = null;
+ $this->valueObj = null;
+ }
+ // load ISO time from database (usually through Form->loadDataForm())
+ else if(Zend_Date::isDate($val, $this->getConfig('datavalueformat'))) {
+ $this->valueObj = new Zend_Date($val, $this->getConfig('datavalueformat'));
+ $this->value = $this->valueObj->get($this->getConfig('timeformat'));
+ }
+ // Set in current locale (as string)
+ else if(Zend_Date::isDate($val, $this->getConfig('timeformat'), $this->locale)) {
+ $this->valueObj = new Zend_Date($val, $this->getConfig('timeformat'), $this->locale);
+ $this->value = $this->valueObj->get($this->getConfig('timeformat'));
+ }
+ // Fallback: Set incorrect value so validate() can pick it up
+ else {
+ $this->value = $val;
+ $this->valueObj = null;
+ }
}
+ /**
+ * @return String ISO 8601 date, suitable for insertion into database
+ */
+ function dataValue() {
+ if($this->valueObj) {
+ return $this->valueObj->toString($this->getConfig('datavalueformat'));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @return Boolean
+ */
+ function validate($validator) {
+ $valid = true;
+
+ // Don't validate empty fields
+ if(empty($this->value)) return true;
+
+ if(!Zend_Date::isDate($this->value, $this->getConfig('timeformat'), $this->locale)) {
+ $validator->validationError(
+ $this->name,
+ _t('DateField.VALIDDATEFORMAT', "Please enter a valid time format."),
+ "validation",
+ false
+ );
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return string
+ */
+ function getLocale() {
+ return $this->locale;
+ }
+
+ /**
+ * @param String $locale
+ */
+ function setLocale($locale) {
+ $this->locale = $locale;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $val
+ */
+ function setConfig($name, $val) {
+ $this->config[$name] = $val;
+ }
+
+ /**
+ * @param String $name
+ * @return mixed
+ */
+ function getConfig($name) {
+ return $this->config[$name];
+ }
+
/**
* Creates a new readonly field specified below
*/
function performReadonlyTransformation() {
- return new TimeField_Readonly( $this->name, $this->title, $this->dataValue(),$this->timeformat);
+ return new TimeField_Readonly($this->name, $this->title, $this->dataValue(), $this->getConfig('timeformat'));
}
}
/**
* The readonly class for our {@link TimeField}.
+ *
* @package forms
* @subpackage fields-datetime
*/
@@ -63,11 +212,22 @@ class TimeField_Readonly extends TimeField {
protected $readonly = true;
function Field() {
- if( $this->value )
- $val = $this->attrValue();
- else
+ if($this->valueObj) {
+ $val = Convert::raw2xml($this->valueObj->toString($this->getConfig('timeformat')));
+ } else {
+ // TODO Localization
$val = '(not set)';
+ }
return "id() . "\">$val";
}
-}
\ No newline at end of file
+
+ function jsValidation() {
+ return null;
+ }
+
+ function validate($validator) {
+ return true;
+ }
+}
+?>
\ No newline at end of file
diff --git a/javascript/DropdownTimeField.js b/javascript/TimeField_dropdown.js
similarity index 100%
rename from javascript/DropdownTimeField.js
rename to javascript/TimeField_dropdown.js
diff --git a/search/AdvancedSearchForm.php b/search/AdvancedSearchForm.php
index 6be5cf12b..074f8b34f 100755
--- a/search/AdvancedSearchForm.php
+++ b/search/AdvancedSearchForm.php
@@ -32,8 +32,8 @@ class AdvancedSearchForm extends SearchForm {
),
$chooseDate = new CompositeField(
new HeaderField('LastUpdatedHeader',_t('AdvancedSearchForm.LASTUPDATEDHEADER', 'LAST UPDATED')),
- new CompositeDateField("From", _t('AdvancedSearchForm.FROM', 'From')),
- new CompositeDateField("To", _t('AdvancedSearchForm.TO', 'To'))
+ new DateField("From", _t('AdvancedSearchForm.FROM', 'From')),
+ new DateField("To", _t('AdvancedSearchForm.TO', 'To'))
)
);
diff --git a/tests/forms/DateFieldTest.php b/tests/forms/DateFieldTest.php
index 161809102..cf0857dbe 100644
--- a/tests/forms/DateFieldTest.php
+++ b/tests/forms/DateFieldTest.php
@@ -5,34 +5,167 @@
*/
class DateFieldTest extends SapphireTest {
- function testDMYFormat() {
+ function setUp() {
+ parent::setUp();
+
+ $this->originalLocale = i18n::get_locale();
+ i18n::set_locale('en_NZ');
+ }
+
+ function tearDown() {
+ parent::tearDown();
+
+ i18n::set_locale($this->originalLocale);
+ }
+
+ function testValidateMinDate() {
+ $f = new DateField('Date');
+ $f->setConfig('min', '2009-03-31');
+ $f->setValue('2010-03-31');
+ $this->assertTrue($f->validate(new RequiredFields()), 'Date above min date');
+
+ $f = new DateField('Date');
+ $f->setConfig('min', '2009-03-31');
+ $f->setValue('1999-03-31');
+ $this->assertFalse($f->validate(new RequiredFields()), 'Date below min date');
+
+ $f = new DateField('Date');
+ $f->setConfig('min', '2009-03-31');
+ $f->setValue('2009-03-31');
+ $this->assertTrue($f->validate(new RequiredFields()), 'Date matching min date');
+ }
+
+ function testValidateMinDateStrtotime() {
+ $f = new DateField('Date');
+ $f->setConfig('min', '-7 days');
+ $f->setValue(strftime('%F', strtotime('-8 days')));
+ $this->assertFalse($f->validate(new RequiredFields()), 'Date below min date, with strtotime');
+
+ $f = new DateField('Date');
+ $f->setConfig('min', '-7 days');
+ $f->setValue(strftime('%F', strtotime('-7 days')));
+ $this->assertTrue($f->validate(new RequiredFields()), 'Date matching min date, with strtotime');
+ }
+
+ function testValidateMaxDateStrtotime() {
+ $f = new DateField('Date');
+ $f->setConfig('max', '7 days');
+ $f->setValue(strftime('%F', strtotime('8 days')));
+ $this->assertFalse($f->validate(new RequiredFields()), 'Date above max date, with strtotime');
+
+ $f = new DateField('Date');
+ $f->setConfig('max', '7 days');
+ $f->setValue(strftime('%F', strtotime('7 days')));
+ $this->assertTrue($f->validate(new RequiredFields()), 'Date matching max date, with strtotime');
+ }
+
+ function testValidateMaxDate() {
+ $f = new DateField('Date');
+ $f->setConfig('max', '2009-03-31');
+ $f->setValue('1999-03-31');
+ $this->assertTrue($f->validate(new RequiredFields()), 'Date above min date');
+
+ $f = new DateField('Date');
+ $f->setConfig('max', '2009-03-31');
+ $f->setValue('2010-03-31');
+ $this->assertFalse($f->validate(new RequiredFields()), 'Date above max date');
+
+ $f = new DateField('Date');
+ $f->setConfig('max', '2009-03-31');
+ $f->setValue('2009-03-31');
+ $this->assertTrue($f->validate(new RequiredFields()), 'Date matching max date');
+ }
+
+ function testConstructorWithoutArgs() {
+ $f = new DateField('Date');
+ $this->assertEquals($f->dataValue(), null);
+ }
+
+ function testConstructorWithDateString() {
+ $f = new DateField('Date', 'Date', '29/03/2003');
+ $this->assertEquals($f->dataValue(), '2003-03-29');
+ }
+
+ function testSetValueWithDateString() {
+ $f = new DateField('Date', 'Date');
+ $f->setValue('29/03/2003');
+ $this->assertEquals($f->dataValue(), '2003-03-29');
+ }
+
+ function testSetValueWithDateArray() {
+ $f = new DateField('Date', 'Date');
+ $f->setConfig('dmyfields', true);
+ $f->setValue(array('day' => 29, 'month' => 03, 'year' => 2003));
+ $this->assertEquals($f->dataValue(), '2003-03-29');
+ }
+
+ function testConstructorWithIsoDate() {
+ // used by Form->loadDataFrom()
+ $f = new DateField('Date', 'Date', '2003-03-29');
+ $this->assertEquals($f->dataValue(), '2003-03-29');
+ }
+
+ function testValidateDMY() {
+ $f = new DateField('Date', 'Date', '29/03/2003');
+ $this->assertTrue($f->validate(new RequiredFields()));
+
+ $f = new DateField('Date', 'Date', 'wrong');
+ $this->assertFalse($f->validate(new RequiredFields()));
+ }
+
+ function testValidateArray() {
+ $f = new DateField('Date', 'Date');
+ $f->setConfig('dmyfields', true);
+ $f->setValue(array('day' => 29, 'month' => 03, 'year' => 2003));
+ $this->assertTrue($f->validate(new RequiredFields()));
+
+ // TODO Fix array validation
+ // $f = new DateField('Date', 'Date', array('day' => 9999, 'month' => 9999, 'year' => 9999));
+ // $this->assertFalse($f->validate(new RequiredFields()));
+ }
+
+ function testValidateArrayValue() {
+ $f = new DateField('Date', 'Date');
+ $this->assertTrue($f->validateArrayValue(array('day' => 29, 'month' => 03, 'year' => 2003)));
+ $this->assertFalse($f->validateArrayValue(array('month' => 03, 'year' => 2003)));
+ $this->assertFalse($f->validateArrayValue(array('day' => 99, 'month' => 99, 'year' => 2003)));
+ }
+
+ function testFormatEnNz() {
/* We get YYYY-MM-DD format as the data value for DD/MM/YYYY input value */
- $dateField = new DateField('Date', 'Date', '04/03/2003');
- $this->assertEquals($dateField->dataValue(), '2003-03-04');
-
- /* Even if value hasn't got leading 0's in it we still get the correct data value */
- $dateField2 = new DateField('Date', 'Date', '4/3/03');
- $this->assertEquals($dateField2->dataValue(), '03-3-4');
+ $f = new DateField('Date', 'Date', '29/03/2003');
+ $this->assertEquals($f->dataValue(), '2003-03-29');
}
- function testYMDFormat() {
- /* We get YYYY-MM-DD format as the data value for YYYY-MM-DD input value */
- $dateField = new DateField('Date', 'Date', '2003/03/04');
- $this->assertEquals($dateField->dataValue(), '2003-03-04');
-
- /* Even if input value hasn't got leading 0's in it we still get the correct data value */
- $dateField2 = new DateField('Date', 'Date', '2003/3/4');
- $this->assertEquals($dateField2->dataValue(), '2003-03-04');
+ function testSetLocale() {
+ // should get en_NZ by default through setUp()
+ $f = new DateField('Date', 'Date', '29/03/2003');
+ $f->setLocale('de_DE');
+ $f->setValue('29.06.2006');
+ $this->assertEquals($f->dataValue(), '2006-06-29');
}
-
+
+ /**
+ * Note: This is mostly tested for legacy reasons
+ */
function testMDYFormat() {
- /* We get MM-DD-YYYY format as the data value for YYYY-MM-DD input value */
- $dateField = new DateField('Date', 'Date', '03/04/2003');
- $this->assertEquals($dateField->dataValue(), '2003-04-03');
-
- /* Even if input value hasn't got leading 0's in it we still get the correct data value */
- $dateField2 = new DateField('Date', 'Date', '3/4/03');
- $this->assertEquals($dateField2->dataValue(), '03-4-3');
+ $dateField = new DateField('Date', 'Date');
+ $dateField->setConfig('dateformat', 'd/M/Y');
+ $dateField->setValue('31/03/2003');
+ $this->assertEquals(
+ $dateField->dataValue(),
+ '2003-03-31',
+ "We get MM-DD-YYYY format as the data value for YYYY-MM-DD input value"
+ );
+
+ $dateField2 = new DateField('Date', 'Date');
+ $dateField2->setConfig('dateformat', 'd/M/Y');
+ $dateField2->setValue('04/3/03');
+ $this->assertEquals(
+ $dateField2->dataValue(),
+ '2003-03-04',
+ "Even if input value hasn't got leading 0's in it we still get the correct data value"
+ );
}
}
diff --git a/tests/forms/DatetimeFieldTest.php b/tests/forms/DatetimeFieldTest.php
new file mode 100644
index 000000000..31adbf411
--- /dev/null
+++ b/tests/forms/DatetimeFieldTest.php
@@ -0,0 +1,80 @@
+originalLocale = i18n::get_locale();
+ i18n::set_locale('en_NZ');
+ }
+
+ function tearDown() {
+ parent::tearDown();
+
+ i18n::set_locale($this->originalLocale);
+ }
+
+ function testConstructorWithoutArgs() {
+ $f = new DatetimeField('Datetime');
+ $this->assertEquals($f->dataValue(), null);
+ }
+
+ // /**
+ // * @expectedException InvalidArgumentException
+ // */
+ // function testConstructorWithLocalizedDateString() {
+ // $f = new DatetimeField('Datetime', 'Datetime', '29/03/2003 23:59:38');
+ // }
+
+ function testConstructorWithIsoDate() {
+ // used by Form->loadDataFrom()
+ $f = new DatetimeField('Datetime', 'Datetime', '2003-03-29 23:59:38');
+ $this->assertEquals($f->dataValue(), '2003-03-29 23:59:38');
+ }
+
+ // /**
+ // * @expectedException InvalidArgumentException
+ // */
+ // function testSetValueWithDateString() {
+ // $f = new DatetimeField('Datetime', 'Datetime');
+ // $f->setValue('29/03/2003');
+ // }
+
+ function testSetValueWithDateTimeString() {
+ $f = new DatetimeField('Datetime', 'Datetime');
+ $f->setValue('2003-03-29 23:59:38');
+ $this->assertEquals($f->dataValue(), '2003-03-29 23:59:38');
+ }
+
+ function testSetValueWithArray() {
+ $f = new DatetimeField('Datetime', 'Datetime');
+ // Values can only be localized (= non-ISO) in array notation
+ $f->setValue(array(
+ 'date' => '29/03/2003',
+ 'time' => '11pm'
+ ));
+ $this->assertEquals($f->dataValue(), '2003-03-29 23:00:00');
+ }
+
+ function testSetValueWithDmyArray() {
+ $f = new DatetimeField('Datetime', 'Datetime');
+ $f->getDateField()->setConfig('dmyfields', true);
+ $f->setValue(array(
+ 'date' => array('day' => 29, 'month' => 03, 'year' => 2003),
+ 'time' => '11pm'
+ ));
+ $this->assertEquals($f->dataValue(), '2003-03-29 23:00:00');
+ }
+
+ function testValidate() {
+ $f = new DatetimeField('Datetime', 'Datetime', '2003-03-29 23:59:38');
+ $this->assertTrue($f->validate(new RequiredFields()));
+
+ $f = new DatetimeField('Datetime', 'Datetime', 'wrong');
+ $this->assertFalse($f->validate(new RequiredFields()));
+ }
+}
\ No newline at end of file
diff --git a/tests/forms/TimeFieldTest.php b/tests/forms/TimeFieldTest.php
index fe9c69b02..37bfaeafe 100644
--- a/tests/forms/TimeFieldTest.php
+++ b/tests/forms/TimeFieldTest.php
@@ -4,38 +4,91 @@
* @subpackage tests
*/
class TimeFieldTest extends SapphireTest {
- function testDataValue12h() {
- $field12h = new TimeField('Time', 'Time');
+
+ function setUp() {
+ parent::setUp();
- $field12h->setValue('11pm');
- $this->assertEquals($field12h->dataValue(), '11:00pm');
-
- $field12h->setValue('23:59');
- $this->assertEquals($field12h->dataValue(), '11:59pm');
-
- $field12h->setValue('11:59pm');
- $this->assertEquals($field12h->dataValue(), '11:59pm');
-
- $field12h->setValue('11:59 pm');
- $this->assertEquals($field12h->dataValue(), '11:59pm');
+ $this->originalLocale = i18n::get_locale();
+ i18n::set_locale('en_NZ');
}
- function testDataValue24h() {
- $field24h = new TimeField('Time', 'Time', null, 'H:i');
+ function tearDown() {
+ parent::tearDown();
- $field24h->setValue('11pm');
- $this->assertEquals($field24h->dataValue(), '23:00');
-
- $field24h->setValue('23:59');
- $this->assertEquals($field24h->dataValue(), '23:59');
-
- $field24h->setValue('11:59pm');
- $this->assertEquals($field24h->dataValue(), '23:59');
-
- $field24h->setValue('11:59 pm');
- $this->assertEquals($field24h->dataValue(), '23:59');
+ i18n::set_locale($this->originalLocale);
}
+ function testConstructorWithoutArgs() {
+ $f = new TimeField('Time');
+ $this->assertEquals($f->dataValue(), null);
+ }
+
+ function testConstructorWithString() {
+ $f = new TimeField('Time', 'Time', '23:00:00');
+ $this->assertEquals($f->dataValue(), '23:00:00');
+ }
+
+ function testValidate() {
+ $f = new TimeField('Time', 'Time', '11pm');
+ $this->assertTrue($f->validate(new RequiredFields()));
+
+ $f = new TimeField('Time', 'Time', '23:59');
+ $this->assertTrue($f->validate(new RequiredFields()));
+
+ $f = new TimeField('Time', 'Time', 'wrong');
+ $this->assertFalse($f->validate(new RequiredFields()));
+ }
+
+ function testSetLocale() {
+ // should get en_NZ by default through setUp()
+ $f = new TimeField('Time', 'Time');
+ $f->setLocale('de_DE');
+ // TODO Find a hour format thats actually different
+ $f->setValue('23:59');
+ $this->assertEquals($f->dataValue(), '23:59:00');
+ }
+
+ function testSetValueWithUseStrToTime() {
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('11pm');
+ $this->assertEquals($f->dataValue(), '23:00:00',
+ 'Setting value to "11pm" parses with use_strtotime enabled'
+ );
+ $this->assertTrue($f->validate(new RequiredFields()));
+
+ $f = new TimeField('Time', 'Time');
+ $f->setConfig('use_strtotime', false);
+ $f->setValue('11pm');
+ $this->assertEquals($f->dataValue(), null,
+ 'Setting value to "11pm" parses with use_strtotime enabled'
+ );
+ $this->assertFalse($f->validate(new RequiredFields()));
+
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('11pm');
+ $this->assertEquals($f->dataValue(), '23:00:00');
+
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('11:59pm');
+ $this->assertEquals($f->dataValue(), '23:59:00');
+
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('11:59 pm');
+ $this->assertEquals($f->dataValue(), '23:59:00');
+
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('11:59:38 pm');
+ $this->assertEquals($f->dataValue(), '23:59:38');
+
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('23:59');
+ $this->assertEquals($f->dataValue(), '23:59:00');
+
+ $f = new TimeField('Time', 'Time');
+ $f->setValue('23:59:38');
+ $this->assertEquals($f->dataValue(), '23:59:38');
+ }
+
function testOverrideWithNull() {
$field = new TimeField('Time', 'Time');