PageRenderTime 41ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/forms/TimeField.php

http://github.com/silverstripe/sapphire
PHP | 267 lines | 136 code | 36 blank | 95 comment | 24 complexity | 037ed7d6c35329874d1246aeb10b29ad MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
  1. <?php
  2. require_once 'Zend/Date.php';
  3. /**
  4. * Form field to display editable time values in an <input type="text"> field.
  5. *
  6. * # Configuration
  7. *
  8. * - 'timeformat' (string): Time format compatible with Zend_Date.
  9. * Usually set to default format for {@link locale}
  10. * through {@link Zend_Locale_Format::getTimeFormat()}.
  11. * - 'use_strtotime' (boolean): Accept values in PHP's built-in strtotime() notation, in addition
  12. * to the format specified in `timeformat`. Example inputs: 'now', '11pm', '23:59:59'.
  13. *
  14. * # Localization
  15. *
  16. * See {@link DateField}
  17. *
  18. * @todo Timezone support
  19. *
  20. * @package forms
  21. * @subpackage fields-datetime
  22. */
  23. class TimeField extends TextField {
  24. /**
  25. * @config
  26. * @var array
  27. */
  28. private static $default_config = array(
  29. 'timeformat' => null,
  30. 'use_strtotime' => true,
  31. 'datavalueformat' => 'HH:mm:ss'
  32. );
  33. /**
  34. * @var array
  35. */
  36. protected $config;
  37. /**
  38. * @var String
  39. */
  40. protected $locale = null;
  41. /**
  42. * @var Zend_Date Just set if the date is valid.
  43. * {@link $value} will always be set to aid validation,
  44. * and might contain invalid values.
  45. */
  46. protected $valueObj = null;
  47. protected $schemaDataType = FormField::SCHEMA_DATA_TYPE_TIME;
  48. public function __construct($name, $title = null, $value = ""){
  49. if(!$this->locale) {
  50. $this->locale = i18n::get_locale();
  51. }
  52. $this->config = $this->config()->default_config;
  53. if(!$this->getConfig('timeformat')) {
  54. $this->setConfig('timeformat', Config::inst()->get('i18n', 'time_format'));
  55. }
  56. parent::__construct($name,$title,$value);
  57. }
  58. public function Field($properties = array()) {
  59. $config = array(
  60. 'timeformat' => $this->getConfig('timeformat')
  61. );
  62. $config = array_filter($config);
  63. $this->addExtraClass(Convert::raw2json($config));
  64. return parent::Field($properties);
  65. }
  66. public function Type() {
  67. return 'time text';
  68. }
  69. /**
  70. * Parses a time into a Zend_Date object
  71. *
  72. * @param string $value Raw value
  73. * @param string $format Format string to check against
  74. * @param string $locale Optional locale to parse against
  75. * @param boolean $exactMatch Flag indicating that the date must be in this
  76. * exact format, and is unchanged after being parsed and written out
  77. *
  78. * @return Zend_Date Returns the Zend_Date, or null if not in the specified format
  79. */
  80. protected function parseTime($value, $format, $locale = null, $exactMatch = false) {
  81. // Check if the date is in the correct format
  82. if(!Zend_Date::isDate($value, $format)) return null;
  83. // Parse the value
  84. $valueObject = new Zend_Date($value, $format, $locale);
  85. // For exact matches, ensure the value preserves formatting after conversion
  86. if($exactMatch && ($value !== $valueObject->get($format))) {
  87. return null;
  88. } else {
  89. return $valueObject;
  90. }
  91. }
  92. /**
  93. * Sets the internal value to ISO date format.
  94. *
  95. * @param String|Array $val
  96. */
  97. public function setValue($val) {
  98. // Fuzzy matching through strtotime() to support a wider range of times,
  99. // e.g. 11am. This means that validate() might not fire.
  100. // Note: Time formats are assumed to be less ambiguous than dates across locales.
  101. if($this->getConfig('use_strtotime') && !empty($val)) {
  102. if($parsedTimestamp = strtotime($val)) {
  103. $parsedObj = new Zend_Date($parsedTimestamp, Zend_Date::TIMESTAMP);
  104. $val = $parsedObj->get($this->getConfig('timeformat'));
  105. unset($parsedObj);
  106. }
  107. }
  108. if(empty($val)) {
  109. $this->value = null;
  110. $this->valueObj = null;
  111. }
  112. // load ISO time from database (usually through Form->loadDataForm())
  113. // Requires exact format to prevent false positives from locale specific times
  114. else if($this->valueObj = $this->parseTime($val, $this->getConfig('datavalueformat'), null, true)) {
  115. $this->value = $this->valueObj->get($this->getConfig('timeformat'));
  116. }
  117. // Set in current locale (as string)
  118. else if($this->valueObj = $this->parseTime($val, $this->getConfig('timeformat'), $this->locale)) {
  119. $this->value = $this->valueObj->get($this->getConfig('timeformat'));
  120. }
  121. // Fallback: Set incorrect value so validate() can pick it up
  122. elseif(is_string($val)) {
  123. $this->value = $val;
  124. $this->valueObj = null;
  125. }
  126. else {
  127. $this->value = null;
  128. $this->valueObj = null;
  129. }
  130. return $this;
  131. }
  132. /**
  133. * @return String ISO 8601 date, suitable for insertion into database
  134. */
  135. public function dataValue() {
  136. if($this->valueObj) {
  137. return $this->valueObj->toString($this->getConfig('datavalueformat'));
  138. } else {
  139. return null;
  140. }
  141. }
  142. /**
  143. * Validate this field
  144. *
  145. * @param Validator $validator
  146. * @return bool
  147. */
  148. public function validate($validator) {
  149. // Don't validate empty fields
  150. if(empty($this->value)) return true;
  151. if(!Zend_Date::isDate($this->value, $this->getConfig('timeformat'), $this->locale)) {
  152. $validator->validationError(
  153. $this->name,
  154. _t(
  155. 'TimeField.VALIDATEFORMAT', "Please enter a valid time format ({format})",
  156. array('format' => $this->getConfig('timeformat'))
  157. ),
  158. "validation",
  159. false
  160. );
  161. return false;
  162. }
  163. return true;
  164. }
  165. /**
  166. * @return string
  167. */
  168. public function getLocale() {
  169. return $this->locale;
  170. }
  171. /**
  172. * @param String $locale
  173. */
  174. public function setLocale($locale) {
  175. $this->locale = $locale;
  176. return $this;
  177. }
  178. /**
  179. * @param string $name
  180. * @param mixed $val
  181. */
  182. public function setConfig($name, $val) {
  183. $this->config[$name] = $val;
  184. return $this;
  185. }
  186. /**
  187. * @param String $name Optional, returns the whole configuration array if empty
  188. * @return mixed|array
  189. */
  190. public function getConfig($name = null) {
  191. if($name) {
  192. return isset($this->config[$name]) ? $this->config[$name] : null;
  193. } else {
  194. return $this->config;
  195. }
  196. }
  197. /**
  198. * Creates a new readonly field specified below
  199. */
  200. public function performReadonlyTransformation() {
  201. return $this->castedCopy('TimeField_Readonly');
  202. }
  203. public function castedCopy($class) {
  204. $copy = parent::castedCopy($class);
  205. if($copy->hasMethod('setConfig')) {
  206. $config = $this->getConfig();
  207. foreach($config as $k => $v) {
  208. $copy->setConfig($k, $v);
  209. }
  210. }
  211. return $copy;
  212. }
  213. }
  214. /**
  215. * The readonly class for our {@link TimeField}.
  216. *
  217. * @package forms
  218. * @subpackage fields-datetime
  219. */
  220. class TimeField_Readonly extends TimeField {
  221. protected $readonly = true;
  222. public function Field($properties = array()) {
  223. if($this->valueObj) {
  224. $val = Convert::raw2xml($this->valueObj->toString($this->getConfig('timeformat')));
  225. } else {
  226. // TODO Localization
  227. $val = '<i>(not set)</i>';
  228. }
  229. return "<span class=\"readonly\" id=\"" . $this->id() . "\">$val</span>";
  230. }
  231. }