PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/system/library/PEAR/HTML/QuickForm2/Element/Date.php

https://bitbucket.org/spekkionu/passworddb
PHP | 398 lines | 231 code | 15 blank | 152 comment | 25 complexity | 7f599b71ffc52326ed11a8ebe3c4e092 MD5 | raw file
Possible License(s): BSD-2-Clause
  1. <?php
  2. /**
  3. * Date element
  4. *
  5. * PHP version 5
  6. *
  7. * LICENSE:
  8. *
  9. * Copyright (c) 2006-2012, Alexey Borzov <avb@php.net>,
  10. * Bertrand Mansion <golgote@mamasam.com>
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. *
  17. * * Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * * Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in the
  21. * documentation and/or other materials provided with the distribution.
  22. * * The names of the authors may not be used to endorse or promote products
  23. * derived from this software without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  26. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  27. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  28. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  29. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  30. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  31. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  32. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  33. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  34. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  35. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. * @category HTML
  38. * @package HTML_QuickForm2
  39. * @author Alexey Borzov <avb@php.net>
  40. * @author Bertrand Mansion <golgote@mamasam.com>
  41. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  42. * @version SVN: $Id: Date.php 323363 2012-02-19 15:09:07Z avb $
  43. * @link http://pear.php.net/package/HTML_QuickForm2
  44. */
  45. /**
  46. * Base class for HTML_QuickForm2 group of elements
  47. */
  48. require_once 'HTML/QuickForm2/Container/Group.php';
  49. /**
  50. * Base class for HTML_QuickForm2 select element
  51. */
  52. require_once 'HTML/QuickForm2/Element/Select.php';
  53. /**
  54. * Class for a group of elements used to input dates (and times).
  55. *
  56. * @category HTML
  57. * @package HTML_QuickForm2
  58. * @author Alexey Borzov <avb@php.net>
  59. * @author Bertrand Mansion <golgote@mamasam.com>
  60. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  61. * @version Release: 2.0.0
  62. * @link http://pear.php.net/package/HTML_QuickForm2
  63. */
  64. class HTML_QuickForm2_Element_Date extends HTML_QuickForm2_Container_Group
  65. {
  66. public function getType()
  67. {
  68. return 'date';
  69. }
  70. /**
  71. * Various options to control the element's display.
  72. * @var array
  73. */
  74. protected $data = array(
  75. 'format' => 'dMY',
  76. 'minYear' => 2001,
  77. 'maxYear' => null, // set in the constructor
  78. 'addEmptyOption' => false,
  79. 'emptyOptionValue' => '',
  80. 'emptyOptionText' => '&nbsp;',
  81. 'optionIncrement' => array('i' => 1, 's' => 1),
  82. // request #4061: max and min hours (only for 'H' modifier)
  83. 'minHour' => 0,
  84. 'maxHour' => 23,
  85. // request #5957: max and min months
  86. 'minMonth' => 1,
  87. 'maxMonth' => 12
  88. );
  89. /**
  90. * Language code
  91. * @var string
  92. */
  93. protected $language = null;
  94. /**
  95. * Message provider for option texts
  96. * @var callback|HTML_QuickForm2_MessageProvider
  97. */
  98. protected $messageProvider;
  99. /**
  100. * Class constructor
  101. *
  102. * The following keys may appear in $data array:
  103. * - 'messageProvider': a callback or an instance of a class implementing
  104. * HTML_QuickForm2_MessageProvider interface, this will be used to get
  105. * localized names of months and weekdays. Some of the default ones will
  106. * be used if not given.
  107. * - 'language': date language, use 'locale' here to display month / weekday
  108. * names according to the current locale.
  109. * - 'format': Format of the date, based on PHP's date() function.
  110. * The following characters are currently recognised in format string:
  111. * <pre>
  112. * D => Short names of days
  113. * l => Long names of days
  114. * d => Day numbers
  115. * M => Short names of months
  116. * F => Long names of months
  117. * m => Month numbers
  118. * Y => Four digit year
  119. * y => Two digit year
  120. * h => 12 hour format
  121. * H => 24 hour format
  122. * i => Minutes
  123. * s => Seconds
  124. * a => am/pm
  125. * A => AM/PM
  126. * </pre>
  127. * - 'minYear': Minimum year in year select
  128. * - 'maxYear': Maximum year in year select
  129. * - 'addEmptyOption': Should an empty option be added to the top of
  130. * each select box?
  131. * - 'emptyOptionValue': The value passed by the empty option.
  132. * - 'emptyOptionText': The text displayed for the empty option.
  133. * - 'optionIncrement': Step to increase the option values by (works for 'i' and 's')
  134. * - 'minHour': Minimum hour in hour select (only for 24 hour format!)
  135. * - 'maxHour': Maximum hour in hour select (only for 24 hour format!)
  136. * - 'minMonth': Minimum month in month select
  137. * - 'maxMonth': Maximum month in month select
  138. *
  139. * @param string $name Element name
  140. * @param string|array $attributes Attributes (either a string or an array)
  141. * @param array $data Element data (label, options and data used for element creation)
  142. */
  143. public function __construct($name = null, $attributes = null, array $data = array())
  144. {
  145. if (isset($data['messageProvider'])) {
  146. if (!is_callable($data['messageProvider'])
  147. && !$data['messageProvider'] instanceof HTML_QuickForm2_MessageProvider
  148. ) {
  149. throw new HTML_QuickForm2_InvalidArgumentException(
  150. "messageProvider: expecting a callback or an implementation"
  151. . " of HTML_QuickForm2_MessageProvider"
  152. );
  153. }
  154. $this->messageProvider = $data['messageProvider'];
  155. } else {
  156. if (isset($data['language']) && 'locale' == $data['language']) {
  157. HTML_QuickForm2_Loader::loadClass('HTML_QuickForm2_MessageProvider_Strftime');
  158. $this->messageProvider = new HTML_QuickForm2_MessageProvider_Strftime();
  159. } else {
  160. HTML_QuickForm2_Loader::loadClass('HTML_QuickForm2_MessageProvider_Default');
  161. $this->messageProvider = HTML_QuickForm2_MessageProvider_Default::getInstance();
  162. }
  163. }
  164. if (isset($data['language'])) {
  165. $this->language = $data['language'];
  166. }
  167. unset($data['messageProvider'], $data['language']);
  168. // http://pear.php.net/bugs/bug.php?id=18171
  169. $this->data['maxYear'] = date('Y');
  170. parent::__construct($name, $attributes, $data);
  171. $backslash = false;
  172. $separators = array();
  173. $separator = '';
  174. for ($i = 0, $length = strlen($this->data['format']); $i < $length; $i++) {
  175. $sign = $this->data['format'][$i];
  176. if ($backslash) {
  177. $backslash = false;
  178. $separator .= $sign;
  179. } else {
  180. $loadSelect = true;
  181. switch ($sign) {
  182. case 'D':
  183. // Sunday is 0 like with 'w' in date()
  184. $options = $this->messageProvider instanceof HTML_QuickForm2_MessageProvider
  185. ? $this->messageProvider->get(array('date', 'weekdays_short'), $this->language)
  186. : call_user_func($this->messageProvider, array('date', 'weekdays_short'), $this->language);
  187. break;
  188. case 'l':
  189. $options = $this->messageProvider instanceof HTML_QuickForm2_MessageProvider
  190. ? $this->messageProvider->get(array('date', 'weekdays_long'), $this->language)
  191. : call_user_func($this->messageProvider, array('date', 'weekdays_long'), $this->language);
  192. break;
  193. case 'd':
  194. $options = $this->createOptionList(1, 31);
  195. break;
  196. case 'M':
  197. case 'm':
  198. case 'F':
  199. $options = $this->createOptionList(
  200. $this->data['minMonth'],
  201. $this->data['maxMonth'],
  202. $this->data['minMonth'] > $this->data['maxMonth'] ? -1 : 1
  203. );
  204. if ('M' == $sign || 'F' == $sign) {
  205. $key = 'M' == $sign ? 'months_short' : 'months_long';
  206. $names = $this->messageProvider instanceof HTML_QuickForm2_MessageProvider
  207. ? $this->messageProvider->get(array('date', $key), $this->language)
  208. : call_user_func($this->messageProvider, array('date', $key), $this->language);
  209. foreach ($options as $k => &$v) {
  210. $v = $names[$k - 1];
  211. }
  212. }
  213. break;
  214. case 'Y':
  215. $options = $this->createOptionList(
  216. $this->data['minYear'],
  217. $this->data['maxYear'],
  218. $this->data['minYear'] > $this->data['maxYear']? -1: 1
  219. );
  220. break;
  221. case 'y':
  222. $options = $this->createOptionList(
  223. $this->data['minYear'],
  224. $this->data['maxYear'],
  225. $this->data['minYear'] > $this->data['maxYear']? -1: 1
  226. );
  227. array_walk($options, create_function('&$v,$k', '$v = substr($v,-2);'));
  228. break;
  229. case 'h':
  230. $options = $this->createOptionList(1, 12);
  231. break;
  232. case 'g':
  233. $options = $this->createOptionList(1, 12);
  234. array_walk($options, create_function('&$v,$k', '$v = intval($v);'));
  235. break;
  236. case 'H':
  237. $options = $this->createOptionList(
  238. $this->data['minHour'],
  239. $this->data['maxHour'],
  240. $this->data['minHour'] > $this->data['maxHour'] ? -1 : 1
  241. );
  242. break;
  243. case 'i':
  244. $options = $this->createOptionList(0, 59, $this->data['optionIncrement']['i']);
  245. break;
  246. case 's':
  247. $options = $this->createOptionList(0, 59, $this->data['optionIncrement']['s']);
  248. break;
  249. case 'a':
  250. $options = array('am' => 'am', 'pm' => 'pm');
  251. break;
  252. case 'A':
  253. $options = array('AM' => 'AM', 'PM' => 'PM');
  254. break;
  255. case 'W':
  256. $options = $this->createOptionList(1, 53);
  257. break;
  258. case '\\':
  259. $backslash = true;
  260. $loadSelect = false;
  261. break;
  262. default:
  263. $separator .= (' ' == $sign? '&nbsp;': $sign);
  264. $loadSelect = false;
  265. }
  266. if ($loadSelect) {
  267. if (0 < count($this)) {
  268. $separators[] = $separator;
  269. }
  270. $separator = '';
  271. // Should we add an empty option to the top of the select?
  272. if (!is_array($this->data['addEmptyOption']) && $this->data['addEmptyOption']
  273. || is_array($this->data['addEmptyOption']) && !empty($this->data['addEmptyOption'][$sign])
  274. ) {
  275. // Using '+' array operator to preserve the keys
  276. if (is_array($this->data['emptyOptionText']) && !empty($this->data['emptyOptionText'][$sign])) {
  277. $options = array($this->data['emptyOptionValue'] => $this->data['emptyOptionText'][$sign]) + $options;
  278. } else {
  279. $options = array($this->data['emptyOptionValue'] => $this->data['emptyOptionText']) + $options;
  280. }
  281. }
  282. $this->addSelect($sign, array('id' => self::generateId($this->getName() . "[{$sign}]"))
  283. + $this->getAttributes())
  284. ->loadOptions($options);
  285. }
  286. }
  287. }
  288. $separators[] = $separator . ($backslash? '\\': '');
  289. $this->setSeparator($separators);
  290. }
  291. /**
  292. * Creates an option list containing the numbers from the start number to the end, inclusive
  293. *
  294. * @param int $start The start number
  295. * @param int $end The end number
  296. * @param int $step Increment by this value
  297. *
  298. * @return array An array of numeric options.
  299. */
  300. protected function createOptionList($start, $end, $step = 1)
  301. {
  302. for ($i = $start, $options = array(); $start > $end? $i >= $end: $i <= $end; $i += $step) {
  303. $options[$i] = sprintf('%02d', $i);
  304. }
  305. return $options;
  306. }
  307. /**
  308. * Trims leading zeros from the (numeric) string
  309. *
  310. * @param string $str A numeric string, possibly with leading zeros
  311. *
  312. * @return string String with leading zeros removed
  313. */
  314. protected function trimLeadingZeros($str)
  315. {
  316. if (0 == strcmp($str, $this->data['emptyOptionValue'])) {
  317. return $str;
  318. }
  319. $trimmed = ltrim($str, '0');
  320. return strlen($trimmed)? $trimmed: '0';
  321. }
  322. /**
  323. * Tries to convert the given value to a usable date before setting the
  324. * element value
  325. *
  326. * @param int|string|array $value A timestamp, a string compatible with strtotime()
  327. * or an array that fits the element names
  328. *
  329. * @return HTML_QuickForm2_Element_Date
  330. */
  331. public function setValue($value)
  332. {
  333. if (empty($value)) {
  334. $value = array();
  335. } elseif (is_scalar($value)) {
  336. if (!is_numeric($value)) {
  337. $value = strtotime($value);
  338. }
  339. // might be a unix epoch, then we fill all possible values
  340. $arr = explode('-', date('w-j-n-Y-g-G-i-s-a-A-W', (int)$value));
  341. $value = array(
  342. 'D' => $arr[0],
  343. 'l' => $arr[0],
  344. 'd' => $arr[1],
  345. 'M' => $arr[2],
  346. 'm' => $arr[2],
  347. 'F' => $arr[2],
  348. 'Y' => $arr[3],
  349. 'y' => $arr[3],
  350. 'h' => $arr[4],
  351. 'g' => $arr[4],
  352. 'H' => $arr[5],
  353. 'i' => $this->trimLeadingZeros($arr[6]),
  354. 's' => $this->trimLeadingZeros($arr[7]),
  355. 'a' => $arr[8],
  356. 'A' => $arr[9],
  357. 'W' => $this->trimLeadingZeros($arr[10])
  358. );
  359. } else {
  360. $value = array_map(array($this, 'trimLeadingZeros'), $value);
  361. }
  362. return parent::setValue($value);
  363. }
  364. /**
  365. * Called when the element needs to update its value from form's data sources
  366. *
  367. * Since the date element also accepts a timestamp as value, the default
  368. * group behavior is changed.
  369. */
  370. protected function updateValue()
  371. {
  372. $name = $this->getName();
  373. foreach ($this->getDataSources() as $ds) {
  374. if (null !== ($value = $ds->getValue($name))) {
  375. $this->setValue($value);
  376. return;
  377. }
  378. }
  379. parent::updateValue();
  380. }
  381. }
  382. ?>