# Source for file Validator.php

Documentation is available at Validator.php

1. <?php
2. /*
3. * $Id: Validator.php 2193 2007-08-10 06:01:54Z nicobn $
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. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
27. * @category Object Relational Mapping
28. * @link www.phpdoctrine.com
29. * @since 1.0
30. * @version $Revision: 2193 $
31. * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
32. */
33. class Doctrine_Validator extends Doctrine_Object
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. }
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();
70. $errorStack = $record->getErrorStack();
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();
76. $err = array();
77. foreach ($data as $key => $value) {
78. if ($value === self::$_null) {
79. $value = null;
80. } elseif ($value instanceof Doctrine_Record) {
81. $value = $value->getIncremented();
82. }
84. $column = $columns[$key];
86. if ($column['type'] == 'enum') {
87. $value = $record->getTable()->enumIndex($key, $value);
89. if ($value === false) {
90. $errorStack->add($key, 'enum');
91. continue;
92. }
93. }
95. if ($record->getTable()->getAttribute(Doctrine::ATTR_AUTO_LENGTH_VLD)) {
96. if (!$this->validateLength($column, $key, $value)) {
97. $errorStack->add($key, 'length');
99. continue;
100. }
101. }
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. continue;
113. }
115. if (strtolower($name) === 'notnull' && isset($column['autoincrement'])) {
116. continue;
117. }
119. if (strtolower($name) == 'length') {
120. if (!$record->getTable()->getAttribute(Doctrine::ATTR_AUTO_LENGTH_VLD)) {
121. if (!$this->validateLength($column, $key, $value)) {
122. $errorStack->add($key, 'length');
123. }
124. }
125. continue;
126. }
128. if (strtolower($name) == 'type') {
129. if (!$record->getTable()->getAttribute(Doctrine::ATTR_AUTO_TYPE_VLD)) {
130. if ( ! self::isValidType($value, $column['type'])) {
131. $errorStack->add($key, 'type');
132. }
133. }
134. continue;
135. }
137. $validator = self::getValidator($name);
138. if ( ! $validator->validate($record, $key, $value, $args)) {
139. $errorStack->add($key, $name);
141. //$err[$key] = 'not valid';
143. // errors found quit validation looping for this column
144. //break;
145. }
146. }
148. if ($record->getTable()->getAttribute(Doctrine::ATTR_AUTO_TYPE_VLD)) {
149. if ( ! self::isValidType($value, $column['type'])) {
150. $errorStack->add($key, 'type');
151. continue;
152. }
153. }
154. }
155. }
156. /**
157. * Validates the length of a field.
158. */
159. private function validateLength($column, $key, $value)
160. {
161. if ($column['type'] == 'timestamp' || $column['type'] == 'integer') {
162. return true;
163. } elseif ($column['type'] == 'array' || $column['type'] == 'object') {
164. $length = strlen(serialize($value));
165. } else {
166. $length = strlen($value);
167. }
169. if ($length > $column['length']) {
170. return false;
171. }
172. return true;
173. }
174. /**
175. * whether or not this validator has errors
176. *
177. * @return boolean
178. */
179. public function hasErrors()
180. {
181. return (count($this->stack) > 0);
182. }
183. /**
184. * converts a doctrine type to native php type
185. *
186. * @param $doctrineType
187. * @return string
188. */
189. public static function phpType($doctrineType)
190. {
191. switch ($doctrineType) {
192. case 'enum':
193. return 'integer';
194. case 'blob':
195. case 'clob':
196. case 'mbstring':
197. case 'timestamp':
198. case 'date':
199. case 'gzip':
200. return 'string';
201. break;
202. default:
203. return $doctrineType;
204. }
205. }
206. /**
207. * returns whether or not the given variable is
208. * valid type
209. *
210. * @param mixed $var
211. * @param string $type
212. * @return boolean
213. */
214. public static function isValidType($var, $type)
215. {
216. if ($type == 'boolean') {
217. return true;
218. }
220. $looseType = self::gettype($var);
221. $type = self::phpType($type);
223. switch ($looseType) {
224. case 'float':
225. case 'double':
226. case 'integer':
227. if ($type == 'string' || $type == 'float') {
228. return true;
229. }
230. case 'string':
231. case 'array':
232. case 'object':
233. return ($type === $looseType);
234. break;
235. case 'NULL':
236. return true;
237. break;
238. };
239. }
240. /**
241. * returns the type of loosely typed variable
242. *
243. * @param mixed $var
244. * @return string
245. */
246. public static function gettype($var)
247. {
248. $type = gettype($var);
249. switch ($type) {
250. case 'string':
251. if (preg_match("/^[0-9]+$/",$var)) {
252. return 'integer';
253. } elseif (is_numeric($var)) {
254. return 'float';
255. } else {
256. return $type;
257. }
258. break;
259. default:
260. return $type;
261. };
262. }
263. }