root/branches/0.11/src/validator/AgaviDateTimeValidator.class.php

Revision 2602, 9.9 KB (checked in by dominik, 5 months ago)

allow using the AgaviDateDefinitions? constants in addition to the constant names when creating the datetime validator manually
closes #760

  • Property keywords set to Id
  • Property svn:keywords set to Id
Line 
1<?php
2
3// +---------------------------------------------------------------------------+
4// | This file is part of the Agavi package.                                   |
5// | Copyright (c) 2005-2008 the Agavi Project.                                |
6// |                                                                           |
7// | For the full copyright and license information, please view the LICENSE   |
8// | file that was distributed with this source code. You can also view the    |
9// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
10// |   vi: set noexpandtab:                                                    |
11// |   Local Variables:                                                        |
12// |   indent-tabs-mode: t                                                     |
13// |   End:                                                                    |
14// +---------------------------------------------------------------------------+
15
16/**
17 * AgaviDateTimeValidator verifies that a parameter is of a date and or time
18 * format.
19 *
20 * Arguments:
21 *   This can be:
22 *    * a single argument which will then be parsed with the formats in the
23 *      'formats' parameter.
24 *    * multiple arguments with the calendar constants
25 *      (AgaviDateDefinitions::MONTH, etc) as key and the argument field as
26 *      value.
27 *    * multiple arguments and the 'arguments_format' parameter defined. This
28 *      will use the string in 'arguments_format' as input string to sprintf and
29 *      will use the arguments in the given order as argument to sprintf.
30 *
31 * Parameters:
32 *   'check'       check date if the specified day really exists
33 *   'formats'     an array of arrays with these keys:
34 *     'type'       The type of the string in 'format'.
35 *     'format'     The input string dependent on the type. These types are
36 *                  allowed:
37 *                    format:   The value is a date format string.
38 *                    time:     The value is a time specifier (full,...) or null
39 *                    date:     The value is a date specifier or null
40 *                    datetime: The value is a date specifier or null
41 *                    translation_domain: The value will be translated in the
42 *                              domain given in the 'translation_domain' key.
43 *                   
44 *     'locale'     The optional locale which will be used for this format.
45 *     'translation_domain' Only applicable when the type is translation_domain
46 *   'cast_to'     Only useful in combination with the export parameter.
47 *                 This can either be a string or an array. If its an string it
48 *                 can be one of 'unix' (converts the date to a unix timestamp),
49 *                 'string' (converts it to a string using the default format),
50 *                 'calendar' (will return the AgaviCalendar object),
51 *                 'datetime' (case sensitive, will return a PHP DateTime
52 *                 object, requires PHP 5.1.x with DateTime explicitly enabled
53 *                 or >= PHP 5.2).
54 *                 If it's an array it can have these keys:
55 *     'type'        The type of the format (format, time, date, datetime)
56 *     'format'      see in 'formats' above.
57 *   'arguments_format' A string which will be used as the format string for
58 *                 sprintf.
59 *   'min'         Either an string or an array. When its a string the the
60 *                 its assumed to be in the format 'yyyy-MM-dd[ HH:mm:ss[.S]]'.
61 *                 When its an array it will take the minimum value from a
62 *                 request field. These indizes apply:
63 *     'format'      A custom format string which should be used when the field
64 *                   is an string.
65 *     'field'       The name of the field to use as minimum value (could be a
66 *                   previous exported calendar object). Do NOT use unvalidated
67 *                   fields here. Lax parsing will be used.
68 *                 This value is inclusive.
69 *   'max'         The same as min except that the max is exclusive.
70 *
71 * @package    agavi
72 * @subpackage validator
73 *
74 * @author     Dominik del Bondio <ddb@bitxtender.com>
75 * @copyright  Authors
76 * @copyright  The Agavi Project
77 *
78 * @since      0.11.0
79 *
80 * @version    $Id$
81 */
82class AgaviDateTimeValidator extends AgaviValidator
83{
84  /**
85   * Validates the input.
86   *
87   * @return     bool True if the input was a valid date.
88   *
89   * @author     Dominik del Bondio <ddb@bitxtender.com>
90   * @since      0.11.0
91   */
92  protected function validate()
93  {
94    if(!AgaviConfig::get('core.use_translation')) {
95      throw new AgaviConfigurationException('The datetime validator can only be used with use_translation on');
96    }
97    $tm = $this->getContext()->getTranslationManager();
98    $cal = null;
99
100    $check = $this->getParameter('check', true);
101    $locale = $this->hasParameter('locale') ? $tm->getLocale($this->getParameter('locale')) : $tm->getCurrentLocale();
102
103    if($this->hasMultipleArguments() && !$this->getParameter('arguments_format')) {
104      $cal = $tm->createCalendar();
105      $cal->clear();
106      $cal->setLenient(!$check);
107      foreach($this->getArguments() as $calField => $field) {
108        $param = $this->getData($field);
109        if(defined($calField)) {
110          $calField = constant($calField);
111        } elseif(!is_numeric($calField)) {
112          throw new AgaviValidatorException('Unknown argument name "' . $calField . '" for argument "' . $field . '" supplied. This needs to be one of the constants defined in AgaviDateDefinitions.');
113        }
114
115        if($calField == AgaviDateDefinitions::MONTH) {
116          $param -= 1;
117        }
118
119        $cal->set($calField, (float) $param);
120      }
121
122      try {
123        $cal->getTime();
124      } catch(Exception $e) {
125        $this->throwError('check');
126        return false;
127      }
128    } else {
129      if($argFormat = $this->getParameter('arguments_format')) {
130        $values = array();
131        foreach($this->getArguments() as $field) {
132          $values[] = $this->getData($field);
133        }
134        $param = vsprintf($argFormat, $values);
135      } else {
136        $param = $this->getData($this->getArgument());
137      }
138
139      $matchedFormat = false;
140      foreach((array)$this->getParameter('formats', array()) as $key => $item) {
141        if(!is_array($item)) {
142          $item = array((is_int($key) ? 'format' : $key) => $item);
143        }
144       
145        $itemLocale = empty($item['locale']) ? $locale : $tm->getLocale($item['locale']);
146        $type = empty($item['type']) ? 'format' : $item['type'];
147
148        if($type == 'format') {
149          $formatString = $item['format'];
150        } elseif($type == 'time' || $type == 'date' || $type == 'datetime') {
151          $format = isset($item['format']) ? $item['format'] : null;
152          $formatString = AgaviDateFormatter::resolveFormat($format, $itemLocale, $type);
153        } elseif($type == 'translation_domain') {
154          $td = $item['translation_domain'];
155          $formatString = $tm->_($item['format'], $td, $itemLocale);
156        }
157
158        try {
159          $format = new AgaviDateFormat($formatString);
160          $cal = $format->parse($param, $itemLocale, $check);
161
162          // no exception got thrown so the parsing was successful
163          $matchedFormat = true;
164          break;
165        } catch(Exception $e) {
166          // nop
167        }
168      }
169
170      if(!$matchedFormat) {
171        $this->throwError('format');
172        return false;
173      }
174    }
175
176    $cal->setLenient(true);
177    $value = $cal;
178
179    if($cast = $this->getParameter('cast_to')) {
180      // an array means the user wants it custom formatted
181      if(is_array($cast)) {
182        $type = empty($cast['type']) ? 'format' : $cast['type'];
183        if($type == 'format') {
184          $formatString = $cast['format'];
185        } elseif($type == 'time' || $type == 'date' || $type == 'datetime') {
186          $format = isset($cast['format']) ? $cast['format'] : null;
187          $formatString = AgaviDateFormatter::resolveFormat($format, $locale, $type);
188        }
189
190        $format = new AgaviDateFormat($formatString);
191        $value = $format->format($cal, $cal->getType(), $locale);
192      } else {
193        $cast = strtolower($cast);
194        if($cast == 'unix') {
195          $value = $cal->getUnixTimestamp();
196        } elseif($cast == 'string') {
197          $value = $tm->_d($cal);
198        } elseif($cast == 'datetime') {
199          $value = $cal->getNativeDateTime(); 
200        } else {
201          $value = $cal;
202        }
203      }
204    }
205
206    $defaultParseFormat = new AgaviDateFormat('yyyy-MM-dd HH:mm:ss.S');
207
208    if($this->hasParameter('min')) {
209      $min = $this->getMinOrMaxValue('min', $defaultParseFormat, $locale);
210
211      $isAfterEqual = $cal->after($min) || $cal->equals($min);
212      if(!$isAfterEqual) {
213        $this->throwError('min');
214        return false;
215      }
216    }
217
218    if($this->hasParameter('max')) {
219      $max = $this->getMinOrMaxValue('max', $defaultParseFormat, $locale);
220
221      $isBefore = $cal->before($max);
222      if(!$isBefore) {
223        $this->throwError('max');
224        return false;
225      }
226    }
227
228    if($this->hasParameter('export')) {
229      $export = $this->getParameter('export');
230      if(is_string($export)) {
231        $this->export($value);
232      } elseif(is_array($export)) {
233        foreach($export as $calField => $field) {
234          if(defined($calField)) {
235            $this->export($cal->get(constant($calField)), $field);
236          }
237        }
238      }
239    }
240
241    return true;
242  }
243
244  /**
245   * Returns the calendar object for a max or min definition.
246   *
247   * @param      string 'min' or 'max'
248   * @param      AgaviDateFormat The default format when parsing strings.
249   * @param      AgaviLocale The locale to use.
250   *
251   * @return     AgaviCalendar The calendar object storing the date.
252   *
253   * @author     Dominik del Bondio <ddb@bitxtender.com>
254   * @since      0.11.0
255   */
256  protected function getMinOrMaxValue($minMax, $defaultParseFormat, $locale)
257  {
258    $format = $defaultParseFormat;
259
260    $minMax = $this->getParameter($minMax);
261    if(is_array($minMax)) {
262      $minMaxValue = $this->validationParameters->getParameter($minMax['field']);
263      if(!$minMaxValue instanceof AgaviCalendar) {
264        if(isset($minMax['format'])) {
265          $format = new AgaviDateFormat($minMax['format']);
266        }
267        $result = $format->parse($minMaxValue, $locale, false);
268      } else {
269        $result = $minMaxValue;
270      }
271    } else {
272      $result = $format->parse($minMax, $locale, false);
273    }
274
275    return $result;
276  }
277
278}
279
280?>
Note: See TracBrowser for help on using the browser.