Almost every interactive web application needs to validate data. For instance, a registration form probably requires the password to be confirmed. Maybe the e-mail address must be unique. Validating data can be a cumbersome process. Thankfully, it isn't in Laravel. The Validator class provides an awesome array of validation helpers to make validating your data a breeze. Let's walk through an example:
$input = Input::all();
$rules = array(
'name' => 'required|max:50',
'email' => 'required|email|unique:users',
);
$validation = Validator::make($input, $rules);
if ($validation->fails())
{
return $validation->errors;
}
With the errors property, you can access a simple message collector class that makes working with your error messages a piece of cake. Of course, default error messages have been setup for all validation rules. The default messages live at language/en/validation.php.
Now you are familiar with the basic usage of the Validator class. You're ready to dig in and learn about the rules you can use to validate your data!
'name' => 'required'
'last_name' => 'required_with:first_name'
'name' => 'alpha'
'username' => 'alpha_num'
'username' => 'alpha_dash'
'name' => 'size:10'
'payment' => 'between:10,50'
Note: All minimum and maximum checks are inclusive.
'payment' => 'min:10'
'payment' => 'max:50'
'payment' => 'numeric'
'payment' => 'integer'
'size' => 'in:small,medium,large'
'language' => 'not_in:cobol,assembler'
The confirmed rule validates that, for a given attribute, a matching attribute_confirmation attribute exists.
'password' => 'confirmed'
Given this example, the Validator will make sure that the password attribute matches the password_confirmation attribute in the array being validated.
The accepted rule validates that an attribute is equal to yes or 1. This rule is helpful for validating checkbox form fields such as "terms of service".
'terms' => 'accepted'
'token1' => 'same:token2'
'password' => 'different:old_password',
The match rule validates that an attribute matches a given regular expression.
'username' => 'match:/[a-z]+/';
'email' => 'unique:users'
In the example above, the email attribute will be checked for uniqueness on the users table. Need to verify uniqueness on a column name other than the attribute name? No problem:
'email' => 'unique:users,email_address'
Many times, when updating a record, you want to use the unique rule, but exclude the row being updated. For example, when updating a user's profile, you may allow them to change their e-mail address. But, when the unique rule runs, you want it to skip the given user since they may not have changed their address, thus causing the unique rule to fail. It's easy:
'email' => 'unique:users,email_address,10'
'state' => 'exists:states'
'state' => 'exists:states,abbreviation'
'birthdate' => 'before:1986-28-05';
'birthdate' => 'after:1986-28-05';
Note: The before and after validation rules use the strtotime PHP function to convert your date to something the rule can understand.
'address' => 'email'
Note: This rule uses the PHP built-in filter_var method.
'link' => 'url'
'link' => 'active_url'
Note: The active_url rule uses checkdnsr to verify the URL is active.
The mimes rule validates that an uploaded file has a given MIME type. This rule uses the PHP Fileinfo extension to read the contents of the file and determine the actual MIME type. Any extension defined in the config/mimes.php file may be passed to this rule as a parameter:
'picture' => 'mimes:jpg,gif'
Note: When validating files, be sure to use Input::file() or Input::all() to gather the input.
'picture' => 'image'
'picture' => 'image|max:100'
Laravel makes working with your error messages a cinch using a simple error collector class. After calling the passes or fails method on a Validator instance, you may access the errors via the errors property. The error collector has several simple functions for retrieving your messages:
if ($validation->errors->has('email'))
{
// The e-mail attribute has errors...
}
echo $validation->errors->first('email');
Sometimes you may need to format the error message by wrapping it in HTML. No problem. Along with the :message place-holder, pass the format as the second parameter to the method.
echo $validation->errors->first('email', '<p>:message</p>');
$messages = $validation->errors->get('email');
$messages = $validation->errors->get('email', '<p>:message</p>');
$messages = $validation->errors->all();
$messages = $validation->errors->all('<p>:message</p>');
Once you have performed your validation, you need an easy way to get the errors back to the view. Laravel makes it amazingly simple. Let's walk through a typical scenario. We'll define two routes:
Route::get('register', function()
{
return View::make('user.register');
});
Route::post('register', function()
{
$rules = array(...);
$validation = Validator::make(Input::all(), $rules);
if ($validation->fails())
{
return Redirect::to('register')->with_errors($validation);
}
});
Great! So, we have two simple registration routes. One to handle displaying the form, and one to handle the posting of the form. In the POST route, we run some validation over the input. If the validation fails, we redirect back to the registration form and flash the validation errors to the session so they will be available for us to display.
But, notice we are not explicitly binding the errors to the view in our GET route. However, an errors variable ($errors) will still be available in the view. Laravel intelligently determines if errors exist in the session, and if they do, binds them to the view for you. If no errors exist in the session, an empty message container will still be bound to the view. In your views, this allows you to always assume you have a message container available via the errors variable. We love making your life easier.
For example, if email address validation failed, we can look for 'email' within the $errors session var.
$errors->has('email')
Using Blade, we can then conditionally add error messages to our view.
{{ $errors->has('email') ? 'Invalid Email Address' : 'Condition is false. Can be left blank' }}
This will also work great when we need to conditionally add classes when using something like Twitter Bootstrap. For example, if the email address failed validation, we may want to add the "error" class from Bootstrap to our div class="control-group" statement.
<div class="control-group {{ $errors->has('email') ? 'error' : '' }}">
When the validation fails, our rendered view will have the appended error class.
<div class="control-group error">
Want to use an error message other than the default? Maybe you even want to use a custom error message for a given attribute and rule. Either way, the Validator class makes it easy.
$messages = array(
'required' => 'The :attribute field is required.',
);
$validation = Validator::make(Input::get(), $rules, $messages);
Great! Now our custom message will be used anytime a required validation check fails. But, what is this :attribute stuff in our message? To make your life easier, the Validator class will replace the :attribute place-holder with the actual name of the attribute! It will even remove underscores from the attribute name.
You may also use the :other, :size, :min, :max, and :values place-holders when constructing your error messages:
$messages = array(
'same' => 'The :attribute and :other must match.',
'size' => 'The :attribute must be exactly :size.',
'between' => 'The :attribute must be between :min - :max.',
'in' => 'The :attribute must be one of the following types: :values',
);
So, what if you need to specify a custom required message, but only for the email attribute? No problem. Just specify the message using an attribute_rule naming convention:
$messages = array(
'email_required' => 'We need to know your e-mail address!',
);
In the example above, the custom required message will be used for the email attribute, while the default message will be used for all other attributes.
However, if you are using many custom error messages, specifying inline may become cumbersome and messy. For that reason, you can specify your custom messages in the custom array within the validation language file:
'custom' => array(
'email_required' => 'We need to know your e-mail address!',
)
Laravel provides a number of powerful validation rules. However, it's very likely that you'll need to eventually create some of your own. There are two simple methods for creating validation rules. Both are solid so use whichever you think best fits your project.
Validator::register('awesome', function($attribute, $value, $parameters)
{
return $value == 'awesome';
});
In this example we're registering a new validation rule with the validator. The rule receives three arguments. The first is the name of the attribute being validated, the second is the value of the attribute being validated, and the third is an array of parameters that were specified for the rule.
Here is how your custom validation rule looks when called:
$rules = array(
'username' => 'required|awesome',
);
Of course, you will need to define an error message for your new rule. You can do this either in an ad-hoc messages array:
$messages = array(
'awesome' => 'The attribute value must be awesome!',
);
$validator = Validator::make(Input::get(), $rules, $messages);
Or by adding an entry for your rule in the language/en/validation.php file:
'awesome' => 'The attribute value must be awesome!',
As mentioned above, you may even specify and receive a list of parameters in your custom rule:
// When building your rules array...
$rules = array(
'username' => 'required|awesome:yes',
);
// In your custom rule...
Validator::register('awesome', function($attribute, $value, $parameters)
{
return $value == $parameters[0];
});
In this case, the parameters argument of your validation rule would receive an array containing one element: "yes".
Another method for creating and storing custom validation rules is to extend the Validator class itself. By extending the class you create a new version of the validator that has all of the pre-existing functionality combined with your own custom additions. You can even choose to replace some of the default methods if you'd like. Let's look at an example:
First, create a class that extends Laravel\Validator and place it in your application/libraries directory:
<?php
class Validator extends Laravel\Validator {}
Next, remove the Validator alias from config/application.php. This is necessary so that you don't end up with 2 classes named "Validator" which will certainly conflict with one another.
Next, let's take our "awesome" rule and define it in our new class:
<?php
class Validator extends Laravel\Validator {
public function validate_awesome($attribute, $value, $parameters)
{
return $value == 'awesome';
}
}
Notice that the method is named using the validate_rule naming convention. The rule is named "awesome" so the method must be named "validate_awesome". This is one way in which registering your custom rules and extending the Validator class are different. Validator classes simply need to return true or false. That's it!
Keep in mind that you'll still need to create a custom message for any validation rules that you create. The method for doing so is the same no matter how you define your rule!