Coverage for Doctrine_Validator

Back to coverage report

1 <?php
2 /*
3  *  $Id: Validator.php 2753 2007-10-07 20:58:08Z zYne $
4  *
5  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16  *
17  * This software consists of voluntary contributions made by many individuals
18  * and is licensed under the LGPL. For more information, see
19  * <http://www.phpdoctrine.com>.
20  */
21 /**
22  * Doctrine_Validator
23  * Doctrine_Validator performs validations in record properties
24  *
25  * @package     Doctrine
26  * @subpackage  Validator
27  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
28  * @link        www.phpdoctrine.com
29  * @since       1.0
30  * @version     $Revision: 2753 $
31  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
32  */
33 class Doctrine_Validator extends Doctrine_Locator_Injectable
34 {
35     /**
36      * @var array $validators           an array of validator objects
37      */
38     private static $validators  = array();
39     /**
40      * returns a validator object
41      *
42      * @param string $name
43      * @return Doctrine_Validator_Interface
44      */
45     public static function getValidator($name)
46     {
47         if ( ! isset(self::$validators[$name])) {
48             $class = 'Doctrine_Validator_' . ucwords(strtolower($name));
49             if (class_exists($class)) {
50                 self::$validators[$name] = new $class;
51             } else {
52                 throw new Doctrine_Exception("Validator named '$name' not available.");
53             }
54
55         }
56         return self::$validators[$name];
57     }
58     /**
59      * validates a given record and saves possible errors
60      * in Doctrine_Validator::$stack
61      *
62      * @param Doctrine_Record $record
63      * @return void
64      */
65     public function validateRecord(Doctrine_Record $record)
66     {
67         $columns   = $record->getTable()->getColumns();
68         $component = $record->getTable()->getComponentName();
69
70         $errorStack = $record->getErrorStack();
71
72         // if record is transient all fields will be validated
73         // if record is persistent only the modified fields will be validated
74         $data = ($record->exists()) ? $record->getModified() : $record->getData();
75
76         $err      = array();
77         foreach ($data as $key => $value) {
78             if ($value === self::$_null) {
79                 $value = null;
80             } else if ($value instanceof Doctrine_Record) {
81                 $value = $value->getIncremented();
82             }
83
84             $column = $columns[$key];
85
86             if ($column['type'] == 'enum') {
87                 $value = $record->getTable()->enumIndex($key, $value);
88
89                 if ($value === false) {
90                     $errorStack->add($key, 'enum');
91                     continue;
92                 }
93             }
94
95             if ($record->getTable()->getAttribute(Doctrine::ATTR_VALIDATE) & Doctrine::VALIDATE_LENGTHS) {
96                 if ( ! $this->validateLength($column, $key, $value)) {
97                     $errorStack->add($key, 'length');
98
99                     continue;
100                 }
101             }
102
103             foreach ($column as $name => $args) {
104                 if (empty($name)
105                     || $name == 'primary'
106                     || $name == 'protected'
107                     || $name == 'autoincrement'
108                     || $name == 'default'
109                     || $name == 'values'
110                     || $name == 'sequence'
111                     || $name == 'zerofill'
112                     || $name == 'scale') {
113                     continue;
114                 }
115
116                 if (strtolower($name) === 'notnull' && isset($column['autoincrement'])) {
117                     continue;
118                 }
119
120                 if (strtolower($name) == 'length') {
121                     if ( ! ($record->getTable()->getAttribute(Doctrine::ATTR_VALIDATE) & Doctrine::VALIDATE_LENGTHS)) {
122                         if ( ! $this->validateLength($column, $key, $value)) {
123                             $errorStack->add($key, 'length');
124                         }
125                     }
126                     continue;
127                 }
128
129                 if (strtolower($name) == 'type') {
130                     if ( ! ($record->getTable()->getAttribute(Doctrine::ATTR_VALIDATE) & Doctrine::VALIDATE_TYPES)) {
131                         if ( ! self::isValidType($value, $column['type'])) {
132                             $errorStack->add($key, 'type');
133                         }
134                     }
135                     continue;
136                 }
137
138                 $validator = self::getValidator($name);
139                 $validator->invoker = $record;
140                 $validator->field   = $key;
141                 $validator->args    = $args;
142
143                 if ( ! $validator->validate($value)) {
144                     $errorStack->add($key, $name);
145
146                     //$err[$key] = 'not valid';
147
148                     // errors found quit validation looping for this column
149                     //break;
150                 }
151             }
152
153             if ($record->getTable()->getAttribute(Doctrine::ATTR_VALIDATE) & Doctrine::VALIDATE_TYPES) {
154                 if ( ! self::isValidType($value, $column['type'])) {
155                     $errorStack->add($key, 'type');
156                     continue;
157                 }
158             }
159         }
160     }
161     /**
162      * Validates the length of a field.
163      */
164     private function validateLength($column, $key, $value)
165     {
166         if ($column['type'] == 'timestamp' || $column['type'] == 'integer') {
167             return true;
168         } elseif ($column['type'] == 'array' || $column['type'] == 'object') {
169             $length = strlen(serialize($value));
170         } else {
171             $length = strlen($value);
172         }
173
174         if ($length > $column['length']) {
175             return false;
176         }
177         return true;
178     }
179     /**
180      * whether or not this validator has errors
181      *
182      * @return boolean
183      */
184     public function hasErrors()
185     {
186         return (count($this->stack) > 0);
187     }
188     /**
189      * phpType
190      * converts a doctrine type to native php type
191      *
192      * @param $portableType     portable doctrine type
193      * @return string
194      *//*
195     public static function phpType($portableType)
196     {
197         switch ($portableType) {
198             case 'enum':
199                 return 'integer';
200             case 'blob':
201             case 'clob':
202             case 'mbstring':
203             case 'timestamp':
204             case 'date':
205             case 'gzip':
206                 return 'string';
207                 break;
208             default:
209                 return $portableType;
210         }
211     }*/
212     /**
213      * returns whether or not the given variable is
214      * valid type
215      *
216      * @param mixed $var
217      * @param string $type
218      * @return boolean
219      */
220      /*
221     public static function isValidType($var, $type)
222     {
223         if ($type == 'boolean') {
224             return true;
225         }
226
227         $looseType = self::gettype($var);
228         $type      = self::phpType($type);
229
230         switch ($looseType) {
231             case 'float':
232             case 'double':
233             case 'integer':
234                 if ($type == 'string' || $type == 'float') {
235                     return true;
236                 }
237             case 'string':
238             case 'array':
239             case 'object':
240                 return ($type === $looseType);
241                 break;
242             case 'NULL':
243                 return true;
244                 break;
245         }
246     }*/
247     
248     
249     /**
250      * returns whether or not the given variable is
251      * valid type
252      *
253      * @param mixed $var
254      * @param string $type
255      * @return boolean
256      */
257      public static function isValidType($var, $type)
258      {
259          if ($var === null) {
260              return true;
261          } else if (is_object($var)) {
262              return $type == 'object';
263          }
264      
265          switch ($type) {
266              case 'float':
267              case 'double':
268                  return (String)$var == strval(floatval($var));
269              case 'integer':
270                  return (String)$var == strval(intval($var));
271              case 'string':
272                  return is_string($var) || is_int($var) || is_float($var);
273              case 'blob':
274              case 'clob':
275              case 'gzip':
276                  return is_string($var);
277              case 'array':
278                  return is_array($var);
279              case 'object':
280                  return is_object($var);
281              case 'boolean':
282                  return is_bool($var);
283              case 'timestamp':
284                  // todo: validate the timestamp is in YYYY-MM-DD HH:MM:SS format
285                  return true;
286              case 'date':
287                  $validator = self::getValidator('date');
288                  return $validator->validate($var);
289              case 'enum':
290                  return is_string($var) || is_int($var);
291              default:
292                  return false;
293          }
294      }
295     
296     
297     /**
298      * returns the type of loosely typed variable
299      *
300      * @param mixed $var
301      * @return string
302      *//*
303     public static function gettype($var)
304     {
305         $type = gettype($var);
306         switch ($type) {
307             case 'string':
308                 if (preg_match("/^[0-9]+$/",$var)) {
309                     return 'integer';
310                 } elseif (is_numeric($var)) {
311                     return 'float';
312                 } else {
313                     return $type;
314                 }
315                 break;
316             default:
317                 return $type;
318         }
319     }*/
320 }