my-simon 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore.orig +55 -0
- data/DOC/Launch Check List.docx +0 -0
- data/DOC/Launch Check List.pdf +0 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +44 -0
- data/LICENSE.txt +20 -0
- data/README.md +21 -0
- data/README.rdoc +19 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/build/rakefile.rb +12 -0
- data/config.rb +24 -0
- data/lib/simon.rb +0 -5
- data/my-simon.gemspec +141 -0
- data/scaffolding/simon/controller.tpl +9 -0
- data/scaffolding/simon/model.tpl +10 -0
- data/scaffolding/simon/view.tpl +5 -0
- data/scaffolding/standards/html_template.html +44 -0
- data/scaffolding/standards/html_template.php +44 -0
- data/scaffolding/standards/jquery_plugin_template.js +45 -0
- data/scaffolding/standards/js_template.js +43 -0
- data/simon +282 -0
- data/test/helper.rb +18 -0
- data/test/test_simon.rb +7 -0
- data/www/.htaccess +488 -0
- data/www/404.html +32 -0
- data/www/crossdomain.xml +25 -0
- data/www/favicon.ico +0 -0
- data/www/index.php +17 -0
- data/www/lib/js/homePage.js +43 -0
- data/www/lib/js/jquery/JQbook.js +809 -0
- data/www/lib/js/jquery/jquery-1.8.0.min.js +27 -0
- data/www/lib/js/jquery/jquery.alphanumeric.js +82 -0
- data/www/lib/js/jquery/jquery.cookie.js +96 -0
- data/www/lib/js/jquery/jquery.easing.1.3.js +207 -0
- data/www/lib/js/main.js +117 -0
- data/www/lib/js/master.js +6 -0
- data/www/lib/js/plugins/handlebars-1.0.rc.1.js +1920 -0
- data/www/lib/js/plugins/modernizr-1.7.min.js +2 -0
- data/www/lib/js/plugins/swfobject.js +777 -0
- data/www/lib/js/plugins_mod/README.txt +3 -0
- data/www/lib/php/app.php +53 -0
- data/www/lib/php/controller/index.php +10 -0
- data/www/lib/php/controller/regex.php +23 -0
- data/www/lib/php/model/Book.php +8 -0
- data/www/lib/php/model/Model.php +8 -0
- data/www/lib/php/plugins/php-activerecord/ActiveRecord.php +44 -0
- data/www/lib/php/plugins/php-activerecord/lib/CallBack.php +226 -0
- data/www/lib/php/plugins/php-activerecord/lib/Column.php +155 -0
- data/www/lib/php/plugins/php-activerecord/lib/Config.php +288 -0
- data/www/lib/php/plugins/php-activerecord/lib/Connection.php +456 -0
- data/www/lib/php/plugins/php-activerecord/lib/ConnectionManager.php +38 -0
- data/www/lib/php/plugins/php-activerecord/lib/DateTime.php +45 -0
- data/www/lib/php/plugins/php-activerecord/lib/Exceptions.php +137 -0
- data/www/lib/php/plugins/php-activerecord/lib/Expressions.php +183 -0
- data/www/lib/php/plugins/php-activerecord/lib/Inflector.php +115 -0
- data/www/lib/php/plugins/php-activerecord/lib/Model.php +1673 -0
- data/www/lib/php/plugins/php-activerecord/lib/Reflections.php +86 -0
- data/www/lib/php/plugins/php-activerecord/lib/Relationship.php +637 -0
- data/www/lib/php/plugins/php-activerecord/lib/SQLBuilder.php +396 -0
- data/www/lib/php/plugins/php-activerecord/lib/Serialization.php +302 -0
- data/www/lib/php/plugins/php-activerecord/lib/Singleton.php +57 -0
- data/www/lib/php/plugins/php-activerecord/lib/Table.php +547 -0
- data/www/lib/php/plugins/php-activerecord/lib/Utils.php +351 -0
- data/www/lib/php/plugins/php-activerecord/lib/Validations.php +833 -0
- data/www/lib/php/plugins/php-activerecord/lib/adapters/MysqlAdapter.php +73 -0
- data/www/lib/php/plugins/php-activerecord/lib/adapters/OciAdapter.php +121 -0
- data/www/lib/php/plugins/php-activerecord/lib/adapters/PgsqlAdapter.php +104 -0
- data/www/lib/php/plugins/php-activerecord/lib/adapters/SqliteAdapter.php +81 -0
- data/www/lib/php/system/Config.php +174 -0
- data/www/lib/php/system/config.routes.php +29 -0
- data/www/lib/php/system/router.php +220 -0
- data/www/lib/php/template/footer.php +59 -0
- data/www/lib/php/template/header.php +74 -0
- data/www/lib/php/view/index.php +5 -0
- data/www/media/images/facebook_share.jpg +0 -0
- data/www/robots.txt +5 -0
- data/www/sandbox/readme.txt +3 -0
- data/www/sass/javascript.scss +1 -0
- data/www/sass/layout.scss +128 -0
- data/www/sass/master.scss +4 -0
- data/www/sass/reset.scss +47 -0
- data/www/sass/typography.scss +24 -0
- data/www/styles/javascript.css +1 -0
- data/www/styles/layout.css +186 -0
- data/www/styles/master.css +4 -0
- data/www/styles/reset.css +60 -0
- data/www/styles/typography.css +24 -0
- metadata +179 -7
@@ -0,0 +1,833 @@
|
|
1
|
+
<?php
|
2
|
+
/**
|
3
|
+
* These two classes have been <i>heavily borrowed</i> from Ruby on Rails' ActiveRecord so much that
|
4
|
+
* this piece can be considered a straight port. The reason for this is that the vaildation process is
|
5
|
+
* tricky due to order of operations/events. The former combined with PHP's odd typecasting means
|
6
|
+
* that it was easier to formulate this piece base on the rails code.
|
7
|
+
*
|
8
|
+
* @package ActiveRecord
|
9
|
+
*/
|
10
|
+
|
11
|
+
namespace ActiveRecord;
|
12
|
+
use ActiveRecord\Model;
|
13
|
+
use IteratorAggregate;
|
14
|
+
use ArrayIterator;
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Manages validations for a {@link Model}.
|
18
|
+
*
|
19
|
+
* This class isn't meant to be directly used. Instead you define
|
20
|
+
* validators thru static variables in your {@link Model}. Example:
|
21
|
+
*
|
22
|
+
* <code>
|
23
|
+
* class Person extends ActiveRecord\Model {
|
24
|
+
* static $validates_length_of = array(
|
25
|
+
* array('name', 'within' => array(30,100),
|
26
|
+
* array('state', 'is' => 2)
|
27
|
+
* );
|
28
|
+
* }
|
29
|
+
*
|
30
|
+
* $person = new Person();
|
31
|
+
* $person->name = 'Tito';
|
32
|
+
* $person->state = 'this is not two characters';
|
33
|
+
*
|
34
|
+
* if (!$person->is_valid())
|
35
|
+
* print_r($person->errors);
|
36
|
+
* </code>
|
37
|
+
*
|
38
|
+
* @package ActiveRecord
|
39
|
+
* @see Errors
|
40
|
+
* @link http://www.phpactiverecord.org/guides/validations
|
41
|
+
*/
|
42
|
+
class Validations
|
43
|
+
{
|
44
|
+
private $model;
|
45
|
+
private $options = array();
|
46
|
+
private $validators = array();
|
47
|
+
private $record;
|
48
|
+
|
49
|
+
private static $VALIDATION_FUNCTIONS = array(
|
50
|
+
'validates_presence_of',
|
51
|
+
'validates_size_of',
|
52
|
+
'validates_length_of',
|
53
|
+
'validates_inclusion_of',
|
54
|
+
'validates_exclusion_of',
|
55
|
+
'validates_format_of',
|
56
|
+
'validates_numericality_of',
|
57
|
+
'validates_uniqueness_of'
|
58
|
+
);
|
59
|
+
|
60
|
+
private static $DEFAULT_VALIDATION_OPTIONS = array(
|
61
|
+
'on' => 'save',
|
62
|
+
'allow_null' => false,
|
63
|
+
'allow_blank' => false,
|
64
|
+
'message' => null,
|
65
|
+
);
|
66
|
+
|
67
|
+
private static $ALL_RANGE_OPTIONS = array(
|
68
|
+
'is' => null,
|
69
|
+
'within' => null,
|
70
|
+
'in' => null,
|
71
|
+
'minimum' => null,
|
72
|
+
'maximum' => null,
|
73
|
+
);
|
74
|
+
|
75
|
+
private static $ALL_NUMERICALITY_CHECKS = array(
|
76
|
+
'greater_than' => null,
|
77
|
+
'greater_than_or_equal_to' => null,
|
78
|
+
'equal_to' => null,
|
79
|
+
'less_than' => null,
|
80
|
+
'less_than_or_equal_to' => null,
|
81
|
+
'odd' => null,
|
82
|
+
'even' => null
|
83
|
+
);
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Constructs a {@link Validations} object.
|
87
|
+
*
|
88
|
+
* @param Model $model The model to validate
|
89
|
+
* @return Validations
|
90
|
+
*/
|
91
|
+
public function __construct(Model $model)
|
92
|
+
{
|
93
|
+
$this->model = $model;
|
94
|
+
$this->record = new Errors($this->model);
|
95
|
+
$this->validators = array_intersect(array_keys(Reflections::instance()->get(get_class($this->model))->getStaticProperties()), self::$VALIDATION_FUNCTIONS);
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Returns validator data.
|
100
|
+
*
|
101
|
+
* @return array
|
102
|
+
*/
|
103
|
+
public function rules()
|
104
|
+
{
|
105
|
+
$data = array();
|
106
|
+
$reflection = Reflections::instance()->get(get_class($this->model));
|
107
|
+
|
108
|
+
foreach ($this->validators as $validate)
|
109
|
+
{
|
110
|
+
$attrs = $reflection->getStaticPropertyValue($validate);
|
111
|
+
|
112
|
+
foreach ($attrs as $attr)
|
113
|
+
{
|
114
|
+
$field = $attr[0];
|
115
|
+
|
116
|
+
if (!isset($data[$field]) || !is_array($data[$field]))
|
117
|
+
$data[$field] = array();
|
118
|
+
|
119
|
+
$attr['validator'] = $validate;
|
120
|
+
unset($attr[0]);
|
121
|
+
array_push($data[$field],$attr);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
return $data;
|
125
|
+
}
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Runs the validators.
|
129
|
+
*
|
130
|
+
* @return Errors the validation errors if any
|
131
|
+
*/
|
132
|
+
public function validate()
|
133
|
+
{
|
134
|
+
$reflection = Reflections::instance()->get(get_class($this->model));
|
135
|
+
|
136
|
+
foreach ($this->validators as $validate)
|
137
|
+
$this->$validate($reflection->getStaticPropertyValue($validate));
|
138
|
+
|
139
|
+
$this->record->clear_model();
|
140
|
+
return $this->record;
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Validates a field is not null and not blank.
|
145
|
+
*
|
146
|
+
* <code>
|
147
|
+
* class Person extends ActiveRecord\Model {
|
148
|
+
* static $validates_presence_of = array(
|
149
|
+
* array('first_name'),
|
150
|
+
* array('last_name')
|
151
|
+
* );
|
152
|
+
* }
|
153
|
+
* </code>
|
154
|
+
*
|
155
|
+
* Available options:
|
156
|
+
*
|
157
|
+
* <ul>
|
158
|
+
* <li><b>message:</b> custom error message</li>
|
159
|
+
* </ul>
|
160
|
+
*
|
161
|
+
* @param array $attrs Validation definition
|
162
|
+
*/
|
163
|
+
public function validates_presence_of($attrs)
|
164
|
+
{
|
165
|
+
$configuration = array_merge(self::$DEFAULT_VALIDATION_OPTIONS, array('message' => Errors::$DEFAULT_ERROR_MESSAGES['blank'], 'on' => 'save'));
|
166
|
+
|
167
|
+
foreach ($attrs as $attr)
|
168
|
+
{
|
169
|
+
$options = array_merge($configuration, $attr);
|
170
|
+
$this->record->add_on_blank($options[0], $options['message']);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
/**
|
175
|
+
* Validates that a value is included the specified array.
|
176
|
+
*
|
177
|
+
* <code>
|
178
|
+
* class Car extends ActiveRecord\Model {
|
179
|
+
* static $validates_inclusion_of = array(
|
180
|
+
* array('fuel_type', 'in' => array('hyrdogen', 'petroleum', 'electric')),
|
181
|
+
* );
|
182
|
+
* }
|
183
|
+
* </code>
|
184
|
+
*
|
185
|
+
* Available options:
|
186
|
+
*
|
187
|
+
* <ul>
|
188
|
+
* <li><b>in/within:</b> attribute should/shouldn't be a value within an array</li>
|
189
|
+
* <li><b>message:</b> custome error message</li>
|
190
|
+
* </ul>
|
191
|
+
*
|
192
|
+
* @param array $attrs Validation definition
|
193
|
+
*/
|
194
|
+
public function validates_inclusion_of($attrs)
|
195
|
+
{
|
196
|
+
$this->validates_inclusion_or_exclusion_of('inclusion', $attrs);
|
197
|
+
}
|
198
|
+
|
199
|
+
/**
|
200
|
+
* This is the opposite of {@link validates_include_of}.
|
201
|
+
*
|
202
|
+
* @param array $attrs Validation definition
|
203
|
+
* @see validates_inclusion_of
|
204
|
+
*/
|
205
|
+
public function validates_exclusion_of($attrs)
|
206
|
+
{
|
207
|
+
$this->validates_inclusion_or_exclusion_of('exclusion', $attrs);
|
208
|
+
}
|
209
|
+
|
210
|
+
/**
|
211
|
+
* Validates that a value is in or out of a specified list of values.
|
212
|
+
*
|
213
|
+
* @see validates_inclusion_of
|
214
|
+
* @see validates_exclusion_of
|
215
|
+
* @param string $type Either inclusion or exclusion
|
216
|
+
* @param $attrs Validation definition
|
217
|
+
*/
|
218
|
+
public function validates_inclusion_or_exclusion_of($type, $attrs)
|
219
|
+
{
|
220
|
+
$configuration = array_merge(self::$DEFAULT_VALIDATION_OPTIONS, array('message' => Errors::$DEFAULT_ERROR_MESSAGES[$type], 'on' => 'save'));
|
221
|
+
|
222
|
+
foreach ($attrs as $attr)
|
223
|
+
{
|
224
|
+
$options = array_merge($configuration, $attr);
|
225
|
+
$attribute = $options[0];
|
226
|
+
$var = $this->model->$attribute;
|
227
|
+
|
228
|
+
if (isset($options['in']))
|
229
|
+
$enum = $options['in'];
|
230
|
+
elseif (isset($options['within']))
|
231
|
+
$enum = $options['within'];
|
232
|
+
|
233
|
+
if (!is_array($enum))
|
234
|
+
array($enum);
|
235
|
+
|
236
|
+
$message = str_replace('%s', $var, $options['message']);
|
237
|
+
|
238
|
+
if ($this->is_null_with_option($var, $options) || $this->is_blank_with_option($var, $options))
|
239
|
+
continue;
|
240
|
+
|
241
|
+
if (('inclusion' == $type && !in_array($var, $enum)) || ('exclusion' == $type && in_array($var, $enum)))
|
242
|
+
$this->record->add($attribute, $message);
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
/**
|
247
|
+
* Validates that a value is numeric.
|
248
|
+
*
|
249
|
+
* <code>
|
250
|
+
* class Person extends ActiveRecord\Model {
|
251
|
+
* static $validates_numericality_of = array(
|
252
|
+
* array('salary', 'greater_than' => 19.99, 'less_than' => 99.99)
|
253
|
+
* );
|
254
|
+
* }
|
255
|
+
* </code>
|
256
|
+
*
|
257
|
+
* Available options:
|
258
|
+
*
|
259
|
+
* <ul>
|
260
|
+
* <li><b>only_integer:</b> value must be an integer (e.g. not a float)</li>
|
261
|
+
* <li><b>even:</b> must be even</li>
|
262
|
+
* <li><b>odd:</b> must be odd"</li>
|
263
|
+
* <li><b>greater_than:</b> must be greater than specified number</li>
|
264
|
+
* <li><b>greater_than_or_equal_to:</b> must be greater than or equal to specified number</li>
|
265
|
+
* <li><b>equal_to:</b> ...</li>
|
266
|
+
* <li><b>less_than:</b> ...</li>
|
267
|
+
* <li><b>less_than_or_equal_to:</b> ...</li>
|
268
|
+
* </ul>
|
269
|
+
*
|
270
|
+
* @param array $attrs Validation definition
|
271
|
+
*/
|
272
|
+
public function validates_numericality_of($attrs)
|
273
|
+
{
|
274
|
+
$configuration = array_merge(self::$DEFAULT_VALIDATION_OPTIONS, array('only_integer' => false));
|
275
|
+
|
276
|
+
// Notice that for fixnum and float columns empty strings are converted to nil.
|
277
|
+
// Validates whether the value of the specified attribute is numeric by trying to convert it to a float with Kernel.Float
|
278
|
+
// (if only_integer is false) or applying it to the regular expression /\A[+\-]?\d+\Z/ (if only_integer is set to true).
|
279
|
+
foreach ($attrs as $attr)
|
280
|
+
{
|
281
|
+
$options = array_merge($configuration, $attr);
|
282
|
+
$attribute = $options[0];
|
283
|
+
$var = $this->model->$attribute;
|
284
|
+
|
285
|
+
$numericalityOptions = array_intersect_key(self::$ALL_NUMERICALITY_CHECKS, $options);
|
286
|
+
|
287
|
+
if ($this->is_null_with_option($var, $options))
|
288
|
+
continue;
|
289
|
+
|
290
|
+
if (true === $options['only_integer'] && !is_integer($var))
|
291
|
+
{
|
292
|
+
if (!preg_match('/\A[+-]?\d+\Z/', (string)($var)))
|
293
|
+
{
|
294
|
+
if (isset($options['message']))
|
295
|
+
$message = $options['message'];
|
296
|
+
else
|
297
|
+
$message = Errors::$DEFAULT_ERROR_MESSAGES['not_a_number'];
|
298
|
+
|
299
|
+
$this->record->add($attribute, $message);
|
300
|
+
continue;
|
301
|
+
}
|
302
|
+
}
|
303
|
+
else
|
304
|
+
{
|
305
|
+
if (!is_numeric($var))
|
306
|
+
{
|
307
|
+
$this->record->add($attribute, Errors::$DEFAULT_ERROR_MESSAGES['not_a_number']);
|
308
|
+
continue;
|
309
|
+
}
|
310
|
+
|
311
|
+
$var = (float)$var;
|
312
|
+
}
|
313
|
+
|
314
|
+
foreach ($numericalityOptions as $option => $check)
|
315
|
+
{
|
316
|
+
$option_value = $options[$option];
|
317
|
+
|
318
|
+
if ('odd' != $option && 'even' != $option)
|
319
|
+
{
|
320
|
+
$option_value = (float)$options[$option];
|
321
|
+
|
322
|
+
if (!is_numeric($option_value))
|
323
|
+
throw new ValidationsArgumentError("$option must be a number");
|
324
|
+
|
325
|
+
if (isset($options['message']))
|
326
|
+
$message = $options['message'];
|
327
|
+
else
|
328
|
+
$message = Errors::$DEFAULT_ERROR_MESSAGES[$option];
|
329
|
+
|
330
|
+
$message = str_replace('%d', $option_value, $message);
|
331
|
+
|
332
|
+
if ('greater_than' == $option && !($var > $option_value))
|
333
|
+
$this->record->add($attribute, $message);
|
334
|
+
|
335
|
+
elseif ('greater_than_or_equal_to' == $option && !($var >= $option_value))
|
336
|
+
$this->record->add($attribute, $message);
|
337
|
+
|
338
|
+
elseif ('equal_to' == $option && !($var == $option_value))
|
339
|
+
$this->record->add($attribute, $message);
|
340
|
+
|
341
|
+
elseif ('less_than' == $option && !($var < $option_value))
|
342
|
+
$this->record->add($attribute, $message);
|
343
|
+
|
344
|
+
elseif ('less_than_or_equal_to' == $option && !($var <= $option_value))
|
345
|
+
$this->record->add($attribute, $message);
|
346
|
+
}
|
347
|
+
else
|
348
|
+
{
|
349
|
+
if (isset($options['message']))
|
350
|
+
$message = $options['message'];
|
351
|
+
else
|
352
|
+
$message = Errors::$DEFAULT_ERROR_MESSAGES[$option];
|
353
|
+
|
354
|
+
if ( ('odd' == $option && !( Utils::is_odd($var))) || ('even' == $option && ( Utils::is_odd($var))))
|
355
|
+
$this->record->add($attribute, $message);
|
356
|
+
}
|
357
|
+
}
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
/**
|
362
|
+
* Alias of {@link validates_length_of}
|
363
|
+
*
|
364
|
+
* @param array $attrs Validation definition
|
365
|
+
*/
|
366
|
+
public function validates_size_of($attrs)
|
367
|
+
{
|
368
|
+
$this->validates_length_of($attrs);
|
369
|
+
}
|
370
|
+
|
371
|
+
/**
|
372
|
+
* Validates that a value is matches a regex.
|
373
|
+
*
|
374
|
+
* <code>
|
375
|
+
* class Person extends ActiveRecord\Model {
|
376
|
+
* static $validates_format_of = array(
|
377
|
+
* array('email', 'with' => '/^.*?@.*$/')
|
378
|
+
* );
|
379
|
+
* }
|
380
|
+
* </code>
|
381
|
+
*
|
382
|
+
* Available options:
|
383
|
+
*
|
384
|
+
* <ul>
|
385
|
+
* <li><b>with:</b> a regular expression</li>
|
386
|
+
* <li><b>message:</b> custom error message</li>
|
387
|
+
* </ul>
|
388
|
+
*
|
389
|
+
* @param array $attrs Validation definition
|
390
|
+
*/
|
391
|
+
public function validates_format_of($attrs)
|
392
|
+
{
|
393
|
+
$configuration = array_merge(self::$DEFAULT_VALIDATION_OPTIONS, array('message' => Errors::$DEFAULT_ERROR_MESSAGES['invalid'], 'on' => 'save', 'with' => null));
|
394
|
+
|
395
|
+
foreach ($attrs as $attr)
|
396
|
+
{
|
397
|
+
$options = array_merge($configuration, $attr);
|
398
|
+
$attribute = $options[0];
|
399
|
+
$var = $this->model->$attribute;
|
400
|
+
|
401
|
+
if (is_null($options['with']) || !is_string($options['with']) || !is_string($options['with']))
|
402
|
+
throw new ValidationsArgumentError('A regular expression must be supplied as the [with] option of the configuration array.');
|
403
|
+
else
|
404
|
+
$expression = $options['with'];
|
405
|
+
|
406
|
+
if ($this->is_null_with_option($var, $options) || $this->is_blank_with_option($var, $options))
|
407
|
+
continue;
|
408
|
+
|
409
|
+
if (!@preg_match($expression, $var))
|
410
|
+
$this->record->add($attribute, $options['message']);
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
/**
|
415
|
+
* Validates the length of a value.
|
416
|
+
*
|
417
|
+
* <code>
|
418
|
+
* class Person extends ActiveRecord\Model {
|
419
|
+
* static $validates_length_of = array(
|
420
|
+
* array('name', 'within' => array(1,50))
|
421
|
+
* );
|
422
|
+
* }
|
423
|
+
* </code>
|
424
|
+
*
|
425
|
+
* Available options:
|
426
|
+
*
|
427
|
+
* <ul>
|
428
|
+
* <li><b>is:</b> attribute should be exactly n characters long</li>
|
429
|
+
* <li><b>in/within:</b> attribute should be within an range array(min,max)</li>
|
430
|
+
* <li><b>maximum/minimum:</b> attribute should not be above/below respectively</li>
|
431
|
+
* </ul>
|
432
|
+
*
|
433
|
+
* @param array $attrs Validation definition
|
434
|
+
*/
|
435
|
+
public function validates_length_of($attrs)
|
436
|
+
{
|
437
|
+
$configuration = array_merge(self::$DEFAULT_VALIDATION_OPTIONS, array(
|
438
|
+
'too_long' => Errors::$DEFAULT_ERROR_MESSAGES['too_long'],
|
439
|
+
'too_short' => Errors::$DEFAULT_ERROR_MESSAGES['too_short'],
|
440
|
+
'wrong_length' => Errors::$DEFAULT_ERROR_MESSAGES['wrong_length']
|
441
|
+
));
|
442
|
+
|
443
|
+
foreach ($attrs as $attr)
|
444
|
+
{
|
445
|
+
$options = array_merge($configuration, $attr);
|
446
|
+
$range_options = array_intersect(array_keys(self::$ALL_RANGE_OPTIONS), array_keys($attr));
|
447
|
+
sort($range_options);
|
448
|
+
|
449
|
+
switch (sizeof($range_options))
|
450
|
+
{
|
451
|
+
case 0:
|
452
|
+
throw new ValidationsArgumentError('Range unspecified. Specify the [within], [maximum], or [is] option.');
|
453
|
+
|
454
|
+
case 1:
|
455
|
+
break;
|
456
|
+
|
457
|
+
default:
|
458
|
+
throw new ValidationsArgumentError('Too many range options specified. Choose only one.');
|
459
|
+
}
|
460
|
+
|
461
|
+
$attribute = $options[0];
|
462
|
+
$var = $this->model->$attribute;
|
463
|
+
$range_option = $range_options[0];
|
464
|
+
|
465
|
+
if ($this->is_null_with_option($var, $options) || $this->is_blank_with_option($var, $options))
|
466
|
+
continue;
|
467
|
+
|
468
|
+
if ('within' == $range_option || 'in' == $range_option)
|
469
|
+
{
|
470
|
+
$range = $options[$range_options[0]];
|
471
|
+
|
472
|
+
if (!(Utils::is_a('range', $range)))
|
473
|
+
throw new ValidationsArgumentError("$range_option must be an array composing a range of numbers with key [0] being less than key [1]");
|
474
|
+
|
475
|
+
if (is_float($range[0]) || is_float($range[1]))
|
476
|
+
throw new ValidationsArgumentError("Range values cannot use floats for length.");
|
477
|
+
|
478
|
+
if ((int)$range[0] <= 0 || (int)$range[1] <= 0)
|
479
|
+
throw new ValidationsArgumentError("Range values cannot use signed integers.");
|
480
|
+
|
481
|
+
$too_short = isset($options['message']) ? $options['message'] : $options['too_short'];
|
482
|
+
$too_long = isset($options['message']) ? $options['message'] : $options['too_long'];
|
483
|
+
|
484
|
+
$too_short = str_replace('%d', $range[0], $too_short);
|
485
|
+
$too_long = str_replace('%d', $range[1], $too_long);
|
486
|
+
|
487
|
+
if (strlen($this->model->$attribute) < (int)$range[0])
|
488
|
+
$this->record->add($attribute, $too_short);
|
489
|
+
elseif (strlen($this->model->$attribute) > (int)$range[1])
|
490
|
+
$this->record->add($attribute, $too_long);
|
491
|
+
}
|
492
|
+
|
493
|
+
elseif ('is' == $range_option || 'minimum' == $range_option || 'maximum' == $range_option)
|
494
|
+
{
|
495
|
+
$option = $options[$range_option];
|
496
|
+
|
497
|
+
if ((int)$option <= 0)
|
498
|
+
throw new ValidationsArgumentError("$range_option value cannot use a signed integer.");
|
499
|
+
|
500
|
+
if (is_float($option))
|
501
|
+
throw new ValidationsArgumentError("$range_option value cannot use a float for length.");
|
502
|
+
|
503
|
+
if (!is_null($this->model->$attribute))
|
504
|
+
{
|
505
|
+
$messageOptions = array('is' => 'wrong_length', 'minimum' => 'too_short', 'maximum' => 'too_long');
|
506
|
+
|
507
|
+
if (isset($options[$messageOptions[$range_option]]))
|
508
|
+
$message = $options[$messageOptions[$range_option]];
|
509
|
+
else
|
510
|
+
$message = $options['message'];
|
511
|
+
|
512
|
+
$message = str_replace('%d', $option, $message);
|
513
|
+
$attribute_value = $this->model->$attribute;
|
514
|
+
$len = strlen($attribute_value);
|
515
|
+
$value = (int)$attr[$range_option];
|
516
|
+
|
517
|
+
if ('maximum' == $range_option && $len > $value)
|
518
|
+
$this->record->add($attribute, $message);
|
519
|
+
|
520
|
+
if ('minimum' == $range_option && $len < $value)
|
521
|
+
$this->record->add($attribute, $message);
|
522
|
+
|
523
|
+
if ('is' == $range_option && $len !== $value)
|
524
|
+
$this->record->add($attribute, $message);
|
525
|
+
}
|
526
|
+
}
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
/**
|
531
|
+
* Validates the uniqueness of a value.
|
532
|
+
*
|
533
|
+
* <code>
|
534
|
+
* class Person extends ActiveRecord\Model {
|
535
|
+
* static $validates_uniqueness_of = array(
|
536
|
+
* array('name'),
|
537
|
+
* array(array('blah','bleh'), 'message' => 'blech')
|
538
|
+
* );
|
539
|
+
* }
|
540
|
+
* </code>
|
541
|
+
*
|
542
|
+
* @param array $attrs Validation definition
|
543
|
+
*/
|
544
|
+
public function validates_uniqueness_of($attrs)
|
545
|
+
{
|
546
|
+
$configuration = array_merge(self::$DEFAULT_VALIDATION_OPTIONS, array(
|
547
|
+
'message' => Errors::$DEFAULT_ERROR_MESSAGES['unique']
|
548
|
+
));
|
549
|
+
|
550
|
+
foreach ($attrs as $attr)
|
551
|
+
{
|
552
|
+
$options = array_merge($configuration, $attr);
|
553
|
+
$pk = $this->model->get_primary_key();
|
554
|
+
$pk_value = $this->model->$pk[0];
|
555
|
+
|
556
|
+
if (is_array($options[0]))
|
557
|
+
{
|
558
|
+
$add_record = join("_and_", $options[0]);
|
559
|
+
$fields = $options[0];
|
560
|
+
}
|
561
|
+
else
|
562
|
+
{
|
563
|
+
$add_record = $options[0];
|
564
|
+
$fields = array($options[0]);
|
565
|
+
}
|
566
|
+
|
567
|
+
$sql = "";
|
568
|
+
$conditions = array("");
|
569
|
+
|
570
|
+
if ($pk_value === null)
|
571
|
+
$sql = "{$pk[0]} is not null";
|
572
|
+
else
|
573
|
+
{
|
574
|
+
$sql = "{$pk[0]}!=?";
|
575
|
+
array_push($conditions,$pk_value);
|
576
|
+
}
|
577
|
+
|
578
|
+
foreach ($fields as $field)
|
579
|
+
{
|
580
|
+
$field = $this->model->get_real_attribute_name($field);
|
581
|
+
$sql .= " and {$field}=?";
|
582
|
+
array_push($conditions,$this->model->$field);
|
583
|
+
}
|
584
|
+
|
585
|
+
$conditions[0] = $sql;
|
586
|
+
|
587
|
+
if ($this->model->exists(array('conditions' => $conditions)))
|
588
|
+
$this->record->add($add_record, $options['message']);
|
589
|
+
}
|
590
|
+
}
|
591
|
+
|
592
|
+
private function is_null_with_option($var, &$options)
|
593
|
+
{
|
594
|
+
return (is_null($var) && (isset($options['allow_null']) && $options['allow_null']));
|
595
|
+
}
|
596
|
+
|
597
|
+
private function is_blank_with_option($var, &$options)
|
598
|
+
{
|
599
|
+
return (Utils::is_blank($var) && (isset($options['allow_blank']) && $options['allow_blank']));
|
600
|
+
}
|
601
|
+
}
|
602
|
+
|
603
|
+
/**
|
604
|
+
* Class that holds {@link Validations} errors.
|
605
|
+
*
|
606
|
+
* @package ActiveRecord
|
607
|
+
*/
|
608
|
+
class Errors implements IteratorAggregate
|
609
|
+
{
|
610
|
+
private $model;
|
611
|
+
private $errors;
|
612
|
+
|
613
|
+
public static $DEFAULT_ERROR_MESSAGES = array(
|
614
|
+
'inclusion' => "is not included in the list",
|
615
|
+
'exclusion' => "is reserved",
|
616
|
+
'invalid' => "is invalid",
|
617
|
+
'confirmation' => "doesn't match confirmation",
|
618
|
+
'accepted' => "must be accepted",
|
619
|
+
'empty' => "can't be empty",
|
620
|
+
'blank' => "can't be blank",
|
621
|
+
'too_long' => "is too long (maximum is %d characters)",
|
622
|
+
'too_short' => "is too short (minimum is %d characters)",
|
623
|
+
'wrong_length' => "is the wrong length (should be %d characters)",
|
624
|
+
'taken' => "has already been taken",
|
625
|
+
'not_a_number' => "is not a number",
|
626
|
+
'greater_than' => "must be greater than %d",
|
627
|
+
'equal_to' => "must be equal to %d",
|
628
|
+
'less_than' => "must be less than %d",
|
629
|
+
'odd' => "must be odd",
|
630
|
+
'even' => "must be even",
|
631
|
+
'unique' => "must be unique",
|
632
|
+
'less_than_or_equal_to' => "must be less than or equal to %d",
|
633
|
+
'greater_than_or_equal_to' => "must be greater than or equal to %d"
|
634
|
+
);
|
635
|
+
|
636
|
+
/**
|
637
|
+
* Constructs an {@link Errors} object.
|
638
|
+
*
|
639
|
+
* @param Model $model The model the error is for
|
640
|
+
* @return Errors
|
641
|
+
*/
|
642
|
+
public function __construct(Model $model)
|
643
|
+
{
|
644
|
+
$this->model = $model;
|
645
|
+
}
|
646
|
+
|
647
|
+
/**
|
648
|
+
* Nulls $model so we don't get pesky circular references. $model is only needed during the
|
649
|
+
* validation process and so can be safely cleared once that is done.
|
650
|
+
*/
|
651
|
+
public function clear_model()
|
652
|
+
{
|
653
|
+
$this->model = null;
|
654
|
+
}
|
655
|
+
|
656
|
+
/**
|
657
|
+
* Add an error message.
|
658
|
+
*
|
659
|
+
* @param string $attribute Name of an attribute on the model
|
660
|
+
* @param string $msg The error message
|
661
|
+
*/
|
662
|
+
public function add($attribute, $msg)
|
663
|
+
{
|
664
|
+
if (is_null($msg))
|
665
|
+
$msg = self :: $DEFAULT_ERROR_MESSAGES['invalid'];
|
666
|
+
|
667
|
+
if (!isset($this->errors[$attribute]))
|
668
|
+
$this->errors[$attribute] = array($msg);
|
669
|
+
else
|
670
|
+
$this->errors[$attribute][] = $msg;
|
671
|
+
}
|
672
|
+
|
673
|
+
/**
|
674
|
+
* Adds an error message only if the attribute value is {@link http://www.php.net/empty empty}.
|
675
|
+
*
|
676
|
+
* @param string $attribute Name of an attribute on the model
|
677
|
+
* @param string $msg The error message
|
678
|
+
*/
|
679
|
+
public function add_on_empty($attribute, $msg)
|
680
|
+
{
|
681
|
+
if (empty($msg))
|
682
|
+
$msg = self::$DEFAULT_ERROR_MESSAGES['empty'];
|
683
|
+
|
684
|
+
if (empty($this->model->$attribute))
|
685
|
+
$this->add($attribute, $msg);
|
686
|
+
}
|
687
|
+
|
688
|
+
/**
|
689
|
+
* Retrieve error message for an attribute.
|
690
|
+
*
|
691
|
+
* @param string $attribute Name of an attribute on the model
|
692
|
+
* @return string
|
693
|
+
*/
|
694
|
+
public function __get($attribute)
|
695
|
+
{
|
696
|
+
if (!isset($this->errors[$attribute]))
|
697
|
+
return null;
|
698
|
+
|
699
|
+
return $this->errors[$attribute];
|
700
|
+
}
|
701
|
+
|
702
|
+
/**
|
703
|
+
* Adds the error message only if the attribute value was null or an empty string.
|
704
|
+
*
|
705
|
+
* @param string $attribute Name of an attribute on the model
|
706
|
+
* @param string $msg The error message
|
707
|
+
*/
|
708
|
+
public function add_on_blank($attribute, $msg)
|
709
|
+
{
|
710
|
+
if (!$msg)
|
711
|
+
$msg = self::$DEFAULT_ERROR_MESSAGES['blank'];
|
712
|
+
|
713
|
+
if (($value = $this->model->$attribute) === '' || $value === null)
|
714
|
+
$this->add($attribute, $msg);
|
715
|
+
}
|
716
|
+
|
717
|
+
/**
|
718
|
+
* Returns true if the specified attribute had any error messages.
|
719
|
+
*
|
720
|
+
* @param string $attribute Name of an attribute on the model
|
721
|
+
* @return boolean
|
722
|
+
*/
|
723
|
+
public function is_invalid($attribute)
|
724
|
+
{
|
725
|
+
return isset($this->errors[$attribute]);
|
726
|
+
}
|
727
|
+
|
728
|
+
/**
|
729
|
+
* Returns the error message for the specified attribute or null if none.
|
730
|
+
*
|
731
|
+
* @param string $attribute Name of an attribute on the model
|
732
|
+
* @return string
|
733
|
+
*/
|
734
|
+
public function on($attribute)
|
735
|
+
{
|
736
|
+
if (!isset($this->errors[$attribute]))
|
737
|
+
return null;
|
738
|
+
|
739
|
+
$errors = $this->errors[$attribute];
|
740
|
+
|
741
|
+
if (null === $errors)
|
742
|
+
return null;
|
743
|
+
else
|
744
|
+
return count($errors) == 1 ? $errors[0] : $errors;
|
745
|
+
}
|
746
|
+
|
747
|
+
/**
|
748
|
+
* Returns all the error messages as an array.
|
749
|
+
*
|
750
|
+
* <code>
|
751
|
+
* $model->errors->full_messages();
|
752
|
+
*
|
753
|
+
* # array(
|
754
|
+
* # "Name can't be blank",
|
755
|
+
* # "State is the wrong length (should be 2 chars)"
|
756
|
+
* # )
|
757
|
+
* </code>
|
758
|
+
*
|
759
|
+
* @param array $options Options for messages
|
760
|
+
* @return array
|
761
|
+
*/
|
762
|
+
public function full_messages()
|
763
|
+
{
|
764
|
+
$full_messages = array();
|
765
|
+
|
766
|
+
if ($this->errors)
|
767
|
+
{
|
768
|
+
foreach ($this->errors as $attribute => $messages)
|
769
|
+
{
|
770
|
+
foreach ($messages as $msg)
|
771
|
+
{
|
772
|
+
if (is_null($msg))
|
773
|
+
continue;
|
774
|
+
|
775
|
+
$full_messages[] = Utils::human_attribute($attribute) . ' ' . $msg;
|
776
|
+
}
|
777
|
+
}
|
778
|
+
}
|
779
|
+
return $full_messages;
|
780
|
+
}
|
781
|
+
|
782
|
+
/**
|
783
|
+
* Returns true if there are no error messages.
|
784
|
+
* @return boolean
|
785
|
+
*/
|
786
|
+
public function is_empty()
|
787
|
+
{
|
788
|
+
return empty($this->errors);
|
789
|
+
}
|
790
|
+
|
791
|
+
/**
|
792
|
+
* Clears out all error messages.
|
793
|
+
*/
|
794
|
+
public function clear()
|
795
|
+
{
|
796
|
+
$this->errors = array();
|
797
|
+
}
|
798
|
+
|
799
|
+
/**
|
800
|
+
* Returns the number of error messages there are.
|
801
|
+
* @return int
|
802
|
+
*/
|
803
|
+
public function size()
|
804
|
+
{
|
805
|
+
if ($this->is_empty())
|
806
|
+
return 0;
|
807
|
+
|
808
|
+
$count = 0;
|
809
|
+
|
810
|
+
foreach ($this->errors as $attribute => $error)
|
811
|
+
$count += count($error);
|
812
|
+
|
813
|
+
return $count;
|
814
|
+
}
|
815
|
+
|
816
|
+
/**
|
817
|
+
* Returns an iterator to the error messages.
|
818
|
+
*
|
819
|
+
* This will allow you to iterate over the {@link Errors} object using foreach.
|
820
|
+
*
|
821
|
+
* <code>
|
822
|
+
* foreach ($model->errors as $msg)
|
823
|
+
* echo "$msg\n";
|
824
|
+
* </code>
|
825
|
+
*
|
826
|
+
* @return ArrayIterator
|
827
|
+
*/
|
828
|
+
public function getIterator()
|
829
|
+
{
|
830
|
+
return new ArrayIterator($this->full_messages());
|
831
|
+
}
|
832
|
+
};
|
833
|
+
?>
|