Validations

Version 19 (Bill Zhao, 2013-10-07 09:57 PM)

1 1
h2. Validations
2 1
3 2 Kien La
*(#topic-list) "Is my model valid or not?":/projects/main/wiki/Validations#is-my-model-valid-or-not
4 2 Kien La
* "Commonalities":/projects/main/wiki/Validations#commonalities
5 2 Kien La
* "Available validations":/projects/main/wiki/Validations#available-validations
6 2 Kien La
* "validates_presence_of":/projects/main/wiki/Validations#validates_presence_of
7 2 Kien La
* "validates_size_of / validates_length_of":/projects/main/wiki/Validations#validates_size_of
8 2 Kien La
* "validates_(in|ex)clusion_of":/projects/main/wiki/Validations#validates_in_ex_clusion_of
9 2 Kien La
* "validates_format_of":/projects/main/wiki/Validations#validates_format_of
10 2 Kien La
* "validates_numericality_of":/projects/main/wiki/Validations#validates_numericality_of
11 2 Kien La
* "validates_uniqueness_of":/projects/main/wiki/Validations#validates_uniqueness_of
12 14 Jacques Fuentes
* "validate *custom":/projects/main/wiki/Validations#validate
13 2 Kien La
14 9 Ennio Wolsink
Validations offer a simple and powerful pattern to ensure the integrity of your data. By declaring validations on your models, you can be certain that only valid data will be saved to your database. No longer will you need to recall where you put that function which verifies the legitimacy of an e-mail and whether or not it will stop the record fom being saved. With validations, if your data is invalid, ActiveRecord will take care of marking the record as invalid instead of writing it to the database.
15 1
16 1
Validations will run for the following methods normally:
17 1
18 1
<pre class="code"><code class="php">
19 1
$book->save();
20 1
Book::create();
21 1
$book->update_attributes(array('title' => 'new title'));
22 1
</code></pre>
23 1
 
24 1
The following will skip validations and save the record:
25 1
26 1
<pre class="code"><code class="php">
27 1
$book->update_attribute();
28 1
$book->save(false); # anytime you pass false to save it will skip validations
29 1
</code></pre>
30 1
 
31 2 Kien La
h4(#is-my-model-valid-or-not). Is my model valid or not?
32 1
33 2 Kien La
You can determine whether or not your model is valid and can be saved to the database by issuing one of these methods: "Model::is_valid":/docs/ActiveRecord/Model#methodis_valid or "Model::is_invalid":/docs/ActiveRecord/Model#methodis_invalid. Both of these methods will run the validations for your model when invoked.
34 1
35 1
<pre class="code"><code class="php">
36 1
class Book extends ActiveRecord\Model
37 1
{
38 1
  static $validates_presence_of = array(
39 1
    array('title')
40 1
  );
41 1
}
42 1
43 1
# our book won't pass validates_presence_of
44 1
$book = new Book(array('title' => ''));
45 1
echo $book->is_valid(); # false
46 1
echo $book->is_invalid(); # true
47 1
</code></pre>
48 1
 
49 2 Kien La
If validation(s) fails for your model, then you can access the error message(s) like so. Let's assume that our validation was "validates_presence_of":/projects/main/wiki/Validations#validates_presence_of.
50 1
51 1
<pre class="code"><code class="php">
52 1
class Book extends ActiveRecord\Model
53 1
{
54 1
  static $validates_presence_of = array(
55 1
    array('title')
56 1
  );
57 1
}
58 1
 
59 1
$book = new Book(array('title' => ''));
60 1
$book->save();
61 1
$book->errors->is_invalid('title'); # => true
62 1
63 1
# if the attribute fails more than 1 validation,
64 1
# you would get an array of errors below
65 1
66 1
echo $book->errors->on('title'); # => can't be blank
67 1
</code></pre>
68 1
 
69 2 Kien La
Now let's assume our model failed two validations: "validates_presence_of":/projects/main/wiki/Validations#validates_presence_of and "validates_size_of":/projects/main/wiki/Validations#validates_size_of.
70 1
71 1
<pre class="code"><code class="php">
72 1
class Book extends ActiveRecord\Model
73 1
{
74 1
  static $validates_presence_of = array(
75 1
    array('title')
76 1
  );
77 1
 
78 1
  static $validates_size_of = array(
79 1
    array('title', 'within' => array(1,20))
80 1
  );
81 1
}
82 1
 
83 1
$book = new Book(array('title' => ''));
84 1
$book->save();
85 1
$book->errors->is_invalid('title'); # true
86 1
87 1
print_r($book->errors->on('title'));
88 1
 
89 1
# which would give us:
90 1
91 1
# Array
92 1
# (
93 1
#   [0] => can't be blank
94 1
#   [1] => is too short (minimum is 1 characters)
95 1
# )
96 17 Jason Miller
97 17 Jason Miller
# to access errors for all attributes, not just 'title'
98 17 Jason Miller
print_r($book->errors->full_messages());
99 17 Jason Miller
100 1
</code></pre>
101 1
102 3 Kien La
h4(#commonalities). Commonalities
103 1
104 1
Validations are defined with a common set of options and some of them have specific options. As you've seen above, creating a validation is as simple as declaring a static validation variable in your model class as a multi-dimensional array (to validate multiple attributes). Each validation will require you to put the attribute name in the 0 index of the array. You can configure the error message by creating a message key with the message string as the value. You can also add an option which will only run the validation on either creation or update. By default, your validation will run everytime Model#save() is called.
105 1
106 1
<pre class="code"><code class="php">
107 1
class Book extends ActiveRecord\Model
108 1
{
109 1
  # 0 index is title, the attribute to test against
110 1
  # message is our custom error msg
111 1
  # only run this validation on creation - not when updating
112 1
  static $validates_presence_of = array(
113 1
    array('title', 'message' => 'cannot be blank on a book!', 'on' => 'create')
114 1
  );
115 1
}
116 1
</code></pre>
117 1
118 1
In some validations you may use: in, is within. In/within designate a range whereby you use an array with the first and second elements representing the beginning and end of the range respectively. Is represents equality.
119 1
120 10 Kien La
Common options available to all validators:
121 10 Kien La
122 19 Bill Zhao
* *on:* run the validator during "save", "update"
123 10 Kien La
* *allow_null:* allow null to satisfy the validation
124 10 Kien La
* *allow_blank:* allow a blank string to satisfy the validation
125 10 Kien La
* *message:* specify a custom error message
126 10 Kien La
127 3 Kien La
h4(#available-validations). Available validations
128 1
129 1
There are a number of pre-defined validation routines that you can declare on your model for specific attributes.
130 1
131 3 Kien La
* "validates_presence_of":/projects/main/wiki/Validations#validates_presence_of
132 3 Kien La
* "validates_size_of":/projects/main/wiki/Validations#validates_size_of
133 6 Kien La
* "validates_length_of":/projects/main/wiki/Validations#validates_size_of
134 3 Kien La
* "validates_(in|ex)clusion_of":/projects/main/wiki/Validations#validates_in_ex_clusion_of
135 3 Kien La
* "validates_format_of":/projects/main/wiki/Validations#validates_format_of
136 3 Kien La
* "validates_numericality_of":/projects/main/wiki/Validations#validates_numericality_of
137 3 Kien La
* "validates_uniqueness_of":/projects/main/wiki/Validations#validates_uniqueness_of
138 12 Jacques Fuentes
* "validate *custom":/projects/main/wiki/Validations#validate
139 1
140 5 Kien La
h4(#validates_presence_of). validates_presence_of
141 4 Kien La
142 1
This is probably the simplest of all the validations. It will make sure that the value of the attribute is not null or a blank string. Available options:
143 1
144 1
* message: default: *can't be blank*
145 1
146 1
<pre class="code"><code class="php">
147 1
class Book extends ActiveRecord\Model
148 1
{
149 1
  static $validates_presence_of = array(
150 1
    array('title'),
151 1
    array('cover_blurb', 'message' => 'must be present and witty')
152 1
  );
153 1
}
154 1
 
155 1
$book = new Book(array('title' => ''));
156 1
$book->save();
157 1
 
158 1
echo $book->errors->on('cover_blurb'); # => must be present and witty
159 1
echo $book->errors->on('title'); # => can't be blank
160 1
</code></pre>
161 1
162 3 Kien La
h4(#validates_size_of). validates_size_of / validates_length_of
163 1
164 1
These two validations are one and the same. The purpose is to validate the length in characters of a given attribute. Available options:
165 1
166 3 Kien La
*is*: attribute should be *exactly* n characters long
167 8 Szymon W
*in/within*: attribute should be within an range array(n, m)
168 3 Kien La
*maximum/minimum*: attribute should not be above/below respectively
169 3 Kien La
170 1
Each of the options has a particular message and can be changed.
171 1
172 3 Kien La
* *is*: uses key 'wrong_length'
173 3 Kien La
* *in/within*: uses keys 'too_long' & 'too_short'
174 3 Kien La
* *maximum/minimum*: uses keys 'too_long' & 'too_short'
175 1
176 1
<pre class="code"><code class="php">
177 1
class Book extends ActiveRecord\Model
178 1
{
179 1
  static $validates_size_of = array(
180 1
    array('title', 'within' => array(1,5), 'too_short' => 'too short!'),
181 1
    array('cover_blurb', 'is' => 20),
182 1
    array('description', 'maximum' => 10, 'too_long' => 'should be short and sweet')
183 1
  );
184 1
}
185 1
 
186 1
$book = new Book;
187 1
$book->title = 'War and Peace';
188 1
$book->cover_blurb = 'not 20 chars';
189 1
$book->description = 'this description is longer than 10 chars';
190 1
$ret = $book->save();
191 1
 
192 1
# validations failed so we get a false return
193 1
if ($ret == false)
194 1
{
195 1
  # too short!
196 1
  echo $book->errors->on('title');
197 1
 
198 1
  # is the wrong length (should be 20 chars)
199 1
  echo $book->errors->on('cover_blurb');
200 1
 
201 1
  # should be short and sweet
202 1
  echo $book->errors->on('description');
203 1
}
204 1
</code></pre>
205 1
206 3 Kien La
h4(#validates_in_ex_clusion_of). validates_(in|ex)clusion_of
207 1
208 3 Kien La
As you can see from the names, these two are similar. In fact, this is just a white/black list approach to your validations. Inclusion is a whitelist that will require a value to be within a given set. Exclusion is the opposite: a blacklist that requires a value to *not* be within a given set. Available options:
209 1
210 3 Kien La
* *in/within*: attribute should/shouldn't be a value within an array
211 3 Kien La
* *message*: custom error message
212 1
213 1
<pre class="code"><code class="php">
214 1
class Car extends ActiveRecord\Model
215 1
{
216 1
  static $validates_inclusion_of = array(
217 7 Kien La
    array('fuel_type', 'in' => array('petroleum', 'hydrogen', 'electric')),
218 1
  );
219 1
}
220 1
 
221 1
# this will pass since it's in the above list
222 1
$car = new Car(array('fuel_type' => 'electric'));
223 1
$ret = $car->save();
224 1
echo $ret # => true
225 1
226 1
class User extends ActiveRecord\Model
227 1
{
228 1
  static $validates_exclusion_of = array(
229 1
    array('password', 'in' => array('god', 'sex', 'password', 'love', 'secret'),
230 1
      'message' => 'should not be one of the four most used passwords')
231 1
  );
232 1
}
233 1
 
234 1
$user = new User;
235 1
$user->password = 'god';
236 1
$user->save();
237 7 Kien La
238 7 Kien La
# => should not be one of the four most used passwords
239 7 Kien La
echo $user->errors->on('password');
240 1
</code></pre>
241 1
242 3 Kien La
h4(#validates_format_of). validates_format_of
243 1
244 3 Kien La
This validation uses "preg_match":http://www.php.net/preg_match to verify the format of an attribute. You can create a regular expression to test against. Available options:
245 1
246 3 Kien La
* *with*: regular expression
247 3 Kien La
* *message*: custom error message
248 1
249 1
<pre class="code"><code class="php">
250 1
class User extends ActiveRecord\Model
251 1
{
252 1
  static $validates_format_of = array(
253 1
    array('email', 'with' =>
254 1
      '/^[^0-9][A-z0-9_]+([.][A-z0-9_]+)*[@][A-z0-9_]+([.][A-z0-9_]+)*[.][A-z]{2,4}$/')
255 1
    array('password', 'with' =>
256 1
      '/^.*(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/', 'message' => 'is too weak')
257 1
  );
258 1
}
259 1
 
260 1
$user = new User;
261 1
$user->email = 'not_a_real_email.com';
262 1
$user->password = 'notstrong';
263 1
$user->save();
264 1
 
265 1
echo $user->errors->on('email'); # => is invalid
266 1
echo $user->errors->on('password'); # => is too weak
267 1
</code></pre>
268 1
269 3 Kien La
h4(#validates_numericality_of). validates_numericality_of
270 1
271 1
As the name suggests, this gem tests whether or not a given attribute is a number, and whether or not it is of a certain value. Available options:
272 1
273 3 Kien La
* *only_integer*: value must be an integer (e.g. not a float), message: "is not a number"
274 3 Kien La
* *even, message*: "must be even"
275 3 Kien La
* *odd, message*: "must be odd"
276 3 Kien La
* *greater_than*: >, message: "must be greater than %d"
277 3 Kien La
* *greater_than_or_equal_to*: >=, message: "must be greater than or equal to %d"
278 3 Kien La
* *equal_to*: ==, message: "must be equal to %d"
279 3 Kien La
* *less_than*: <, message: "must be less than %d"
280 3 Kien La
* *less_than_or_equal_to*: <=, message: "must be less than or equal to %d"
281 1
282 1
<pre class="code"><code class="php">
283 1
class Order extends ActiveRecord\Model
284 1
{
285 1
  static $validates_numericality_of = array(
286 1
    array('price', 'greater_than' => 0.01),
287 1
    array('quantity', 'only_integer' => true),
288 1
    array('shipping', 'greater_than_or_equal_to' => 0),
289 1
    array('discount', 'less_than_or_equal_to' => 5, 'greater_than_or_equal_to' => 0)
290 1
  );
291 1
}
292 1
 
293 1
$order = new Order;
294 1
$order->price = 0;
295 1
$order->quantity = 1.25;
296 1
$order->shipping = 5;
297 1
$order->discount = 2;
298 1
$order->save();
299 1
 
300 1
echo $order->errors->on('price'); # => must be greater than 0.01
301 1
echo $order->errors->on('quantity'); # => is not a number
302 1
echo $order->errors->on('shipping'); # => null
303 1
echo $order->errors->on('discount'); # => null
304 1
</code></pre>
305 1
306 3 Kien La
h4(#validates_uniqueness_of). validates_uniqueness_of
307 1
308 1
Tests whether or not a given attribute already exists in the table or not.
309 1
310 3 Kien La
* *message*: custom error message
311 1
312 1
<pre class="code"><code class="php">
313 1
class User extends ActiveRecord\Model
314 1
{
315 1
  static $validates_uniqueness_of = array(
316 1
    array('name'),
317 1
    array(array('blah','bleh'), 'message' => 'blah and bleh!')
318 1
  );
319 1
}
320 1
 
321 1
User::create(array('name' => 'Tito'));
322 1
$user = User::create(array('name' => 'Tito'));
323 1
$user->is_valid(); # => false
324 11 Jacques Fuentes
</code></pre>
325 11 Jacques Fuentes
326 11 Jacques Fuentes
327 11 Jacques Fuentes
h4(#validate). validate (custom)
328 11 Jacques Fuentes
329 16 Benjamin P
Generic method allows for custom business logic or advanced validation. You can add your own errors to errors object. This does not take any parameters. You place this logic in a *public* method  named *validate*. (This feature is available since v1.1 or nightly builds.)
330 11 Jacques Fuentes
331 11 Jacques Fuentes
<pre class="code"><code class="php">
332 11 Jacques Fuentes
class User extends ActiveRecord\Model
333 11 Jacques Fuentes
{
334 11 Jacques Fuentes
  public function validate() 
335 11 Jacques Fuentes
  {
336 11 Jacques Fuentes
    if ($this->first_name == $this->last_name)
337 11 Jacques Fuentes
    {
338 12 Jacques Fuentes
      $this->errors->add('first_name', "can't be the same as Last Name");
339 12 Jacques Fuentes
      $this->errors->add('last_name', "can't be the same as First Name");
340 11 Jacques Fuentes
    }
341 11 Jacques Fuentes
  }
342 11 Jacques Fuentes
}
343 11 Jacques Fuentes
 
344 11 Jacques Fuentes
$user = User::create(array('first_name' => 'Tito', 'last_name' => 'Tito'));
345 11 Jacques Fuentes
$user->is_valid(); # => false
346 11 Jacques Fuentes
echo $user->errors->on('first_name'); # => can't be the same as Last Name
347 1
</code></pre>