PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/fields/class.DateField.php

https://github.com/reshadf/Library
PHP | 712 lines | 421 code | 76 blank | 215 comment | 97 complexity | d1e869d181cc9c0b07870ed89ae4c415 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * class DateField
  4. *
  5. * Create a datefield
  6. *
  7. * @author Teye Heimans
  8. * @package FormHandler
  9. * @subpackage Fields
  10. */
  11. class DateField extends Field
  12. {
  13. var $_sMask; // string: how to display the fields (d-m-y) or other
  14. var $_oDay; // SelectField or TextField: object of the day selectfield
  15. var $_oMonth; // SelectField or TextField: object of the month selectfield
  16. var $_oYear; // SelectField or TextField: object of the year selectfield
  17. var $_sInterval; // string: interval of the year
  18. var $_bRequired; // boolean: if the field is required or if we have to give the option to leave this field empty
  19. /**
  20. * DateField::DateField()
  21. *
  22. * Constructor: create a new datefield object
  23. *
  24. * @param object &$oForm: the form where the datefield is located on
  25. * @param string $sName: the name of the datefield
  26. * @param string $sMask: the mask which is used to display the fields
  27. * @return DateField
  28. * @access public
  29. * @author Teye Heimans
  30. */
  31. function DateField( &$oForm, $sName, $sMask = null, $bRequired = null, $sInterval = null )
  32. {
  33. // set the default date display
  34. $this -> setMask( !is_null( $sMask ) ? $sMask : FH_DATEFIELD_DEFAULT_DISPLAY );
  35. // set the default interval
  36. $this -> setInterval( !is_null( $sInterval ) ? $sInterval : FH_DATEFIELD_DEFAULT_DATE_INTERVAL);
  37. // set if the field is required
  38. $this->setRequired( !is_null( $bRequired ) ? $bRequired : FH_DATEFIELD_DEFAULT_REQUIRED );
  39. // d = selectfield day
  40. // m = selectfield month
  41. // y = selectfield year
  42. // D = textfield day
  43. // M = textfield month
  44. // Y = textfield year
  45. // generate the objects for the fields
  46. $fields = $this -> _getFieldsFromMask();
  47. $len = strlen( $fields );
  48. for( $x = 0; $x < $len; $x++ )
  49. {
  50. $c = $fields{$x};
  51. switch ( $c ) {
  52. // year selectfield
  53. case 'y':
  54. $this -> _oYear = new SelectField( $oForm, $sName.'_year');
  55. // get the year interval
  56. list( $iStart, $iEnd ) = $this->_getYearInterval();
  57. $iEnd = intval($iEnd);
  58. $iStart = intval( $iStart );
  59. $iYear = date('Y');
  60. // set the years
  61. $aYears = array();
  62. if(!$bRequired) $aYears[''] = ''; // was 0000
  63. // calculate the difference between the years
  64. $iDiff = ($iYear + $iEnd) - ($iYear - $iStart);
  65. $iCounter = 0;
  66. while( $iDiff != $iCounter )
  67. {
  68. $i = ($iYear + $iEnd) - $iCounter;
  69. $aYears[$i] = $i;
  70. $iCounter += $iCounter < $iDiff ? 1 : -1;
  71. }
  72. // set the options
  73. $this -> _oYear -> setOptions( $aYears );
  74. break;
  75. // year textfield
  76. case 'Y':
  77. $this -> _oYear = new TextField ( $oForm, $sName.'_year');
  78. $this -> _oYear -> setSize( 4 );
  79. $this -> _oYear -> setMaxlength( 4 );
  80. $this -> _oYear -> setValidator( _FH_DIGIT );
  81. break;
  82. // month selectfield
  83. case 'm':
  84. $this -> _oMonth = new SelectField( $oForm, $sName.'_month');
  85. // set the months in the field
  86. $aMonths = array(
  87. '01' => $oForm->_text( 1 ),
  88. '02' => $oForm->_text( 2 ),
  89. '03' => $oForm->_text( 3 ),
  90. '04' => $oForm->_text( 4 ),
  91. '05' => $oForm->_text( 5 ),
  92. '06' => $oForm->_text( 6 ),
  93. '07' => $oForm->_text( 7 ),
  94. '08' => $oForm->_text( 8 ),
  95. '09' => $oForm->_text( 9 ),
  96. '10' => $oForm->_text( 10 ),
  97. '11' => $oForm->_text( 11 ),
  98. '12' => $oForm->_text( 12 )
  99. );
  100. if(!$bRequired )
  101. {
  102. $aMonths[''] = ''; // was 00
  103. ksort($aMonths);
  104. }
  105. // set the options
  106. $this -> _oMonth -> setOptions( $aMonths );
  107. break;
  108. // month textfield
  109. case 'M':
  110. $this -> _oMonth = new TextField ( $oForm, $sName.'_month' );
  111. $this -> _oMonth -> setSize( 2 );
  112. $this -> _oMonth -> setMaxlength( 2 );
  113. $this -> _oMonth -> setValidator( _FH_DIGIT );
  114. break;
  115. // day selectfield
  116. case 'd':
  117. $this -> _oDay = new SelectField( $oForm, $sName.'_day');
  118. // get the days
  119. $aDays = array();
  120. if(!$bRequired) $aDays[''] = ''; // was 00
  121. for($i = 1; $i <= 31; $i++)
  122. {
  123. $aDays[sprintf('%02d', $i)] = sprintf('%02d', $i);
  124. }
  125. $this -> _oDay -> setOptions( $aDays );
  126. break;
  127. // day textfield
  128. case 'D':
  129. $this -> _oDay = new TextField( $oForm, $sName.'_day' );
  130. $this -> _oDay -> setSize( 2 );
  131. $this -> _oDay -> setMaxlength( 2 );
  132. $this -> _oDay -> setValidator( _FH_DIGIT );
  133. break;
  134. }
  135. }
  136. // call the Field constructor
  137. parent::Field( $oForm, $sName );
  138. }
  139. /**
  140. * DateField::setRequired()
  141. *
  142. * Set if the datefield is required or if we have to give the user
  143. * the option to select empty value
  144. *
  145. * @param boolean $bStatus: the status
  146. * @return void
  147. * @access public
  148. * @author Teye Heimans
  149. */
  150. function setRequired( $bStatus )
  151. {
  152. $this->_bRequired = $bStatus;
  153. if( isset( $this -> _oYear ) && is_object( $this -> _oYear ) )
  154. $this -> _oYear -> setValidator( $bStatus ? FH_DIGIT : _FH_DIGIT );
  155. if( isset( $this -> _oMonth ) && is_object( $this -> _oMonth ) )
  156. $this -> _oMonth -> setValidator( $bStatus ? FH_DIGIT : _FH_DIGIT );
  157. if( isset( $this -> _oDay ) && is_object( $this -> _oDay ) )
  158. $this -> _oDay -> setValidator( $bStatus ? FH_DIGIT : _FH_DIGIT );
  159. }
  160. /**
  161. * DateField::setDisplay()
  162. *
  163. * Set the display of the fields
  164. * (use d,m,y and t for positioning, like "d-m-y", "t, d d" or "y/m/d" )
  165. *
  166. * @param string $sMast: how we have to display the datefield (day-month-year combination)
  167. * @return void
  168. * @access public
  169. * @author Teye Heimans
  170. */
  171. function setMask( $sMask )
  172. {
  173. $this->_sMask = $sMask ;
  174. }
  175. /**
  176. * DateField::setInterval()
  177. *
  178. * Set the year range of the years
  179. * The interval between the current year and the years to start/stop.
  180. * Default the years are beginning at 90 yeas from the current. It is also possible to have years in the future.
  181. * This is done like this: "90:10" (10 years in the future).
  182. *
  183. * @param string/int $sInterval: the interval we should use
  184. * @return void
  185. * @access public
  186. * @author Teye Heimans
  187. */
  188. function setInterval( $sInterval )
  189. {
  190. $this->_sInterval = $sInterval;
  191. }
  192. /**
  193. * DateField::setExtra()
  194. *
  195. * Set some extra tag information of the fields
  196. *
  197. * @param string $sExtra: The extra information to inglude with the html tag
  198. * @return void
  199. * @access public
  200. * @author Teye Heimans
  201. */
  202. function setExtra( $sExtra )
  203. {
  204. if( isset( $this -> _oYear ) && is_object( $this -> _oYear ) )
  205. $this -> _oYear -> setExtra ( $sExtra );
  206. if( isset( $this -> _oMonth ) && is_object( $this -> _oMonth ) )
  207. $this -> _oMonth -> setExtra ( $sExtra );
  208. if( isset( $this -> _oDay ) && is_object( $this -> _oDay ) )
  209. $this -> _oDay -> setExtra ( $sExtra );
  210. }
  211. /**
  212. * DateField::getValue()
  213. *
  214. * return the value of the field (in d-m-Y format!) or when a
  215. * field is given, the value of that field
  216. * @param string $fld: the field where you want to value of
  217. * @return string: the current value of the field
  218. * @access public
  219. * @author Teye Heimans
  220. */
  221. function getValue( $fld = null)
  222. {
  223. // when no specific field is requested..
  224. if( $fld == null )
  225. {
  226. // get the values of all fields
  227. $d = $this -> getValue('d');
  228. $m = $this -> getValue('m');
  229. $y = $this -> getValue('y');
  230. // return the value of the datefield
  231. if( $d == '' && $m == '' && $y == '')
  232. {
  233. return '';
  234. }
  235. else
  236. {
  237. return $this->_fillMask( $d, $m, $y );
  238. }
  239. }
  240. // a specific field is requested
  241. else
  242. {
  243. // which field is requested ?
  244. switch ( strtolower( $fld ) )
  245. {
  246. case 'y':
  247. if( isset( $this -> _oYear ) && is_object( $this -> _oYear ) )
  248. return $this -> _oYear -> getValue();
  249. break;
  250. case 'm':
  251. if( isset( $this -> _oMonth ) && is_object( $this -> _oMonth ) )
  252. return $this -> _oMonth -> getValue();
  253. break;
  254. case 'd':
  255. if( isset( $this -> _oDay ) && is_object( $this -> _oDay ) )
  256. return $this -> _oDay -> getValue();
  257. break;
  258. }
  259. // no field matched. Return an empty value
  260. return '';
  261. }
  262. }
  263. /**
  264. * DateField::getAsArray()
  265. *
  266. * Get the date value as an array: array(y,m,d)
  267. *
  268. * @return array
  269. * @access public
  270. * @author Teye Heimans
  271. * @since 25/11/2005
  272. */
  273. function getAsArray()
  274. {
  275. $d = $this -> getValue('d');
  276. $m = $this -> getValue('m');
  277. $y = $this -> getValue('y');
  278. return array( $y, $m, $d );
  279. }
  280. /**
  281. * DateField::isValid()
  282. *
  283. * Check if the date is valid (eg not 31-02-2003)
  284. *
  285. * @return boolean: true if the field is correct, false if not
  286. * @access public
  287. * @author Teye Heimans
  288. */
  289. function isValid()
  290. {
  291. // the result has been requested before..
  292. if( isset($this->_isValid))
  293. {
  294. return $this->_isValid;
  295. }
  296. // check if the year field is valid
  297. if( isset( $this -> _oYear ) && is_object( $this->_oYear) )
  298. {
  299. if( ! $this -> _oYear -> isValid() )
  300. {
  301. // get the error
  302. $this -> _sError = $this -> _oYear -> getError();
  303. return false;
  304. }
  305. }
  306. // check if the month field is valid
  307. if( isset( $this -> _oMonth ) && is_object( $this->_oMonth) )
  308. {
  309. if( ! $this -> _oMonth -> isValid() )
  310. {
  311. // get the error
  312. $this -> _sError = $this -> _oMonth -> getError();
  313. return false;
  314. }
  315. }
  316. // check if the day field is valid
  317. if( isset( $this -> _oDay ) && is_object( $this->_oDay) )
  318. {
  319. if( ! $this -> _oDay -> isValid() )
  320. {
  321. // get the error
  322. $this -> _sError = $this -> _oDay -> getError();
  323. return false;
  324. }
  325. }
  326. $d = $this -> getValue('d');
  327. $m = $this -> getValue('m');
  328. $y = $this -> getValue('y');
  329. $mask = strtolower( $this->_sMask );
  330. if( $y != '' && strlen( $y ) != 4 )
  331. {
  332. $this->_sError = $this->_oForm->_text( 13 );
  333. return false;
  334. }
  335. // first of al check if the date is right when a valid date is submitted
  336. // (but only when all fields are displayed (d m and y or t in the display string!)
  337. if( strpos( $mask, 'd') !== false &&
  338. strpos( $mask, 'm') !== false &&
  339. strpos( $mask, 'y') !== false &&
  340. ($d != '00' && $d != '') &&
  341. ($m != '00' && $m != '') &&
  342. ($y != '0000' && $y != '') &&
  343. !checkdate( $m, $d, $y ))
  344. {
  345. $this->_sError = $this->_oForm->_text( 13 );
  346. $this->_isValid = false;
  347. return $this->_isValid;
  348. }
  349. // if validator given, check the value with the validator
  350. if(isset($this->_sValidator) && !empty($this->_sValidator))
  351. {
  352. $this->_isValid = parent::isValid();
  353. }
  354. // no validator is given.. value is always valid
  355. else
  356. {
  357. $this->_isValid = true;
  358. }
  359. return $this->_isValid;
  360. }
  361. /**
  362. * DateField::getField()
  363. *
  364. * return the field
  365. *
  366. * @return string: the field
  367. * @access public
  368. * @author Teye Heimans
  369. */
  370. function getField()
  371. {
  372. // set the date when:
  373. // - the field is empty
  374. // - its not an edit form
  375. // - the form is not posted
  376. // - the field is required
  377. // - there is no value set...
  378. if( !$this->_oForm->isPosted() && # not posted
  379. (!isset($this->_oForm->edit) || !$this->_oForm->edit) && # no edit form
  380. ($this->getValue() == $this->_fillMask() || # empty values
  381. $this->getValue() == '') && # there is no value
  382. $this->_bRequired ) # field is required
  383. {
  384. // set the current date if wanted
  385. if( FH_DATEFIELD_SET_CUR_DATE )
  386. {
  387. $this->setValue( date('d-m-Y') );
  388. }
  389. }
  390. // view mode enabled ?
  391. if( $this -> getViewMode() )
  392. {
  393. // get the view value..
  394. return $this -> _getViewValue();
  395. }
  396. $year = isset( $this -> _oYear ) && is_object( $this -> _oYear ) ?
  397. $this -> _oYear -> getField() : '';
  398. $month = isset( $this -> _oMonth ) && is_object( $this -> _oMonth ) ?
  399. $this -> _oMonth -> getField() : '';
  400. $day = isset( $this -> _oDay ) && is_object( $this -> _oDay ) ?
  401. $this -> _oDay -> getField() : '';
  402. // replace the values by the fields..
  403. return $this->_fillMask(
  404. ' '.$day.' ', #day
  405. ' '.$month.' ', #month
  406. ' '.$year.' ' #year
  407. ) .
  408. (isset($this->_sExtraAfter) ? $this->_sExtraAfter :'');
  409. }
  410. /**
  411. * DateField::setValue()
  412. *
  413. * Set the value of the field. The value can be 4 things:
  414. * - "d-m-Y" like 02-04-2004
  415. * - "Y-m-d" like 2003-12-24
  416. * - Unix timestamp like 1104421612
  417. * - Mask style. If you gave a mask like d/m/y, this is valid: 02/12/2005
  418. *
  419. * @param string $sValue: the time to set the current value
  420. * @return void
  421. * @access public
  422. * @author Teye Heimans
  423. */
  424. function setValue( $sValue )
  425. {
  426. // remove the time part if the date is coming from a datetime field
  427. $aMatch = array();
  428. if( preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2}) [0-9]{2}:[0-9]{2}:[0-9]{2}$/', $sValue, $aMatch) )
  429. {
  430. $sValue = $aMatch[1];
  431. }
  432. // replace the d, m and y values
  433. $regex = $this->_fillMask( '%%2%%', '%%2%%', '%%4%%' );
  434. // next, escape dangerous characters for the regex
  435. $metachar = array( '\\', '/', '^', '$', '.', '[', ']', '|', '(', ')', '?', '*', '+', '{', '}' );
  436. $escape = array( '\\\\', '\/', '\^', '\$', '\.', '\[', '\]', '\|', '\(', '\)', '\?', '\*', '\+', '\{', '\}' );
  437. $regex = str_replace( $metachar, $escape, $regex );
  438. // now add the (\d+) for matching the day, month and year values
  439. $regex = str_replace('%%2%%', '(\d+){1,2}', $regex );
  440. $regex = str_replace('%%4%%', '(\d{4})', $regex );
  441. $regex = '/'.$regex.'/';
  442. // now find the results
  443. $match = array();
  444. if( preg_match($regex, $sValue, $match ) )
  445. {
  446. // get the fields from the mask
  447. $str = $this->_getFieldsFromMask();
  448. // get the length of the buffer (containing the dmy order)
  449. $len = strlen( $str );
  450. // save the results in the vars $d, $m and $y
  451. for( $i = 0; $i < $len; $i++ )
  452. {
  453. $c = $str{$i};
  454. $$c = $match[$i+1];
  455. }
  456. }
  457. // the given value does not match the mask... is it dd-mm-yyyy style ?
  458. elseif( preg_match( '/^(\d{2})-(\d{2})-(\d{4})$/', $sValue, $match ) )
  459. {
  460. $d = $match[1];
  461. $m = $match[2];
  462. $y = $match[3];
  463. }
  464. // is the given value in yyyy-mm-dd style ?
  465. elseif( preg_match( '/^(\d{4})-(\d{2})-(\d{2})$/', $sValue, $match ) )
  466. {
  467. $d = $match[3];
  468. $m = $match[2];
  469. $y = $match[1];
  470. }
  471. // is the given value a timestamp ?
  472. elseif( strlen( $sValue ) >= 8 && Validator::IsDigit($sValue) )
  473. {
  474. $d = date('d', $sValue );
  475. $m = date('m', $sValue );
  476. $y = date('Y', $sValue );
  477. }
  478. if( !empty( $t ) ) $y = $t;
  479. // save the dates for the fields
  480. if( isset( $this -> _oYear ) && is_object( $this -> _oYear ) && isset( $y ) )
  481. $this -> _oYear -> setValue( $y );
  482. if( isset( $this -> _oMonth ) && is_object( $this -> _oMonth ) && isset( $m ) )
  483. $this -> _oMonth -> setValue( $m );
  484. if( isset( $this -> _oDay ) && is_object( $this -> _oDay ) && isset( $d ))
  485. $this -> _oDay -> setValue( $d );
  486. }
  487. /**
  488. * DateField::_getFieldsFromMask()
  489. *
  490. * Get the fields from the mask.
  491. * For example: "select the \da\y: d" will result in "d".
  492. * "y/m/d" will result in "ymd"
  493. *
  494. * @param string $mask: The mask where we should get the fields from
  495. * @return string
  496. * @access private
  497. * @author Teye Heimans
  498. */
  499. function _getFieldsFromMask( $mask = null)
  500. {
  501. // when no mask is given, use the default mask
  502. if( is_null( $mask ) )
  503. {
  504. $mask = $this->_sMask;
  505. }
  506. // buffer
  507. $str = '';
  508. $len = strlen( $mask );
  509. $placeholders = array( 'd', 'D', 'm', 'M', 'y', 'Y' );
  510. // walk each character in the mask
  511. for( $i = 0; $i < $len; $i++ )
  512. {
  513. // get the character
  514. $c = $mask{ $i };
  515. // day, month or year ?
  516. if( in_array( $c, $placeholders ) )
  517. {
  518. // not the first char ?
  519. if( $i != 0 )
  520. {
  521. // was the char not escaped?
  522. if( $mask{ $i - 1 } != '\\' )
  523. {
  524. $str .= $c;
  525. }
  526. }
  527. // the first char
  528. else
  529. {
  530. // just add it to the buffer
  531. $str .= $c;
  532. }
  533. }
  534. }
  535. return $str;
  536. }
  537. /**
  538. * DateField::_fillMask()
  539. *
  540. * Return the mask filled with the given values
  541. *
  542. * @param string $d: The replacement for the "d"
  543. * @param string $m: The replacement for the "m"
  544. * @param string $y: The replacement for the "y"
  545. * @return string
  546. * @access private
  547. * @author Teye Heimans
  548. */
  549. function _fillMask( $d = '', $m = '', $y = '', $mask = null )
  550. {
  551. // when no mask is given, use the default mask
  552. if( is_null( $mask ) )
  553. {
  554. $mask = $this->_sMask;
  555. }
  556. $placeholders = array( 'd', 'D', 'm', 'M', 'y', 'Y' );
  557. // make sure that the fields are not replacing other fields characters
  558. // and that escaped chars are possible, like "the \da\y is: d"
  559. $len = strlen( $mask );
  560. $str = '';
  561. for( $i = 0; $i < $len; $i++ )
  562. {
  563. $c = $mask{$i};
  564. // field char ?
  565. if( in_array( $c, $placeholders))
  566. {
  567. // first char ?
  568. if( $i == 0 )
  569. {
  570. $str .= '%__'.strtolower($c).'__%';
  571. }
  572. else
  573. {
  574. // check if the char is escaped.
  575. if( $mask{$i - 1} == '\\' )
  576. {
  577. // the char is escaped, display the char without slash
  578. $str = substr($str, 0, -1).$c;
  579. }
  580. // the char is not escaped
  581. else
  582. {
  583. $str .= '%__'.strtolower($c).'__%';
  584. }
  585. }
  586. }
  587. else
  588. {
  589. $str .= $c;
  590. }
  591. }
  592. // replace the values by the new values
  593. return str_replace(
  594. array('%__d__%', '%__m__%', '%__y__%' ),
  595. array( $d, $m, $y ),
  596. $str
  597. );
  598. }
  599. /**
  600. * DateField::_getYearInterval()
  601. *
  602. * Get the year interval
  603. *
  604. * @return array
  605. * @access private
  606. * @author Teye Heimans
  607. */
  608. function _getYearInterval ()
  609. {
  610. $sInterval = $this->_sInterval;
  611. // get the year interval for the dates in the field
  612. if( strpos($sInterval, ':') )
  613. {
  614. list( $iStart, $iEnd ) = explode( ':', $sInterval, 2 );
  615. }
  616. // no splitter found, just change the start interval
  617. elseif( is_string($sInterval) || is_integer($sInterval) && !empty($sInterval) )
  618. {
  619. $iStart = $sInterval;
  620. $iEnd = 0;
  621. }
  622. // no interval given.. use the default
  623. else
  624. {
  625. $iStart = 90;
  626. $iEnd = 0;
  627. }
  628. return array( $iStart, $iEnd );
  629. }
  630. }
  631. ?>