This title was written for Laravel version 4. If you're looking for material on the latest version of Laravel, then please check out Code Smart.
A few months ago I was getting really stressed out. Work was mounting for the release of Laravel 4, which meant designing and building the new site, responding to documentation alterations, along with the typical support role that any framework developer will have to assume. They were hard times. On top of all of that work, I also had the pressure of trying to build Code Bright into as much of a success as Code Happy was so that I could bring a bunch of new developers into the community.
What I should have done is taken a short break at one of Phill's Parks. You see, Phill's Parks are a number of holiday parks located around the world that are holiday destinations for developers. They were originally opened by the CEO of Phill's Parks, Phill Sparks, back in the year two thousand. The parks are now the only place that developers can go to unwind and feel comfortable in a bathing suit.
Phill's Parks offer a wide variety of activities for developers wishing to wind down after a hard year of work. These events include competitive FizzBuzz tournaments, tabs versus spaces debates, and neck-beard pageants.
If I had known about Phill's Parks, I would have been able to chill out and enjoy the weeks leading up to the Laravel four launch. Oh well, at least you know about them right? As a lucky reader of Code Bright, you have access to a coupon that will allow a 90% discount off entry to the parks. To take advantage of this deal, simply track down Phill Sparks on IRC, Twitter, E-Mail or in person, and quote coupon code 'CODEBRIGHTTROLLS_YOU'. If he doesn't respond right away, just keep spamming him with it. Sooner or later he will hook you up with a coding holiday.
So what does this have to do with Validation?
Well, when I started writing this chapter, I had a wonderful, magnificent plan in mind. Sadly, I have gotten completely distracted by the fun and games offered by Phill's Parks and now I have no idea. I'll just make something up. It's turned out fine so far right?
Phill's Parks are a very special place for developers, and developers only. The problem with developers is that, without care an attention, they can be hard to determine from other roles within the web development industry. For example, designers.
We don't want designers sneaking into Phill's Parks posing as developers. They will start judging the choice of decoration and complaining about the use of Comic Sans on the cafeteria menus. It will completely ruin the atmosphere! No, we don't want them in the park at all. What we need is some way of validating our visitors to ensure that they are developers. See, I told you I could bring it back.
What we validate is a set of attributes. Let's think about some of the attributes of a park visitor. Oh, oh, I know. We can create a list! Lists are fun!
- Favourite beverage.
- Choice of web browser.
- Facial hair type.
- Ability to talk to females.
Excellent, we have a number of attributes that can be used to describe visitors to the park. Using some validation constraints or rules, we can be sure that our visitor is a developer. For the park, we will just make sure that the attributes of a park visitor match the following requirements.
- Favourite beverage: Beer.
- Choice of web browser: Google Chrome.
- Facial hair type: Neck-beard.
- Ability to talk to females: None.
Disclaimer: These values are just for fun. For example, I know many female web developers who are fantastic at what they do, and I'm fairly sure they have the ability to talk to other females. Also, I'm sporting a rather fabulous van dyke facial hair combo right now and not the traditional neck-beard. It does have beer soaked into it though...
Anyway, by ensuring that the attributes of a park visitor match those of a developer, we can go ahead and let them into the park. However, if a shifty fella steps up to the reception with the following attributes...
- Favourite beverage: Starbuck Frappechino.
- Choice of web browser: Mobile Safari.
- Facial hair type: None.
- Ability to talk to females: Talk at females, sure.
...then oh no, we have a designer, or a Ruby developer, and we can't let them through the gates.
Once more, this is just a bit of fun. Please don't send me hate mail. Wait until I kill off a main character in a later chapter... erm, I mean, just forget it.
What we have done is implemented validation so that we can be sure that the people who enter the park are developers and not imposters.
Phill's Parks are now safe, but what about your applications? Let's have a look at how we can use validation in Laravel to make sure that we get exactly what we expect.
Simple Validation
Don't trust your users. If there's one thing that I have learned working in the IT industry, is that if you have a point of weakness in your application, then your users will find it. Trust me when I say that they will exploit it. Don't give them the opportunity. Use validation to ensure that you receive good input.
What do we mean by good input? Well let's have a look at an example.
Let's say that we have an HTML form that is used to collect registration information for our application. In fact, it's always great to have a little review session. Let's create the form with the Blade templating engine and the form builder.
Here's our view.
<!-- app/views/form.blade.php -->
<h1>Registration form for Phill's Parks</h1>
{{ Form::open(array('url' => 'registration')) }}
{{-- Username field. ------------------------}}
{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}
{{-- Email address field. -------------------}}
{{ Form::label('email', 'Email address') }}
{{ Form::email('email') }}
{{-- Password field. ------------------------}}
{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}
{{-- Password confirmation field. -----------}}
{{ Form::label('password_confirmation', 'Password confirmation') }}
{{ Form::password('password_confirmation') }}
{{-- Form submit button. --------------------}}
{{ Form::submit('Register') }}
{{ Form::close() }}
Woah, how beautiful is that view?
That is one beautiful view.
Excellent, I'm glad to see that you're still mentally conditioned from reading Code Happy.
You can see that our registration form is targeting the /registration
route and will by default use the POST
request verb.
We have a textfield for a username, an email field for a user's email address, and two password fields to collect a password and a password confirmation. At the bottom of the form we have a submit button that we can use to send the form on its merry way.
You may have noticed the blade comments I have added to the source. This is a habit of mine which I find it makes it easier to browse for the field I want if I have to return to the form. You can feel free to do the same, but if you don't want to, then don't worry about it! Code your own way!
Right, now we are going to need a couple of routes to display and handle this form. Let's go ahead and add them into our routes.php
file now.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
$data = Input::all();
// handle the form...
});
We have a GET /
route that will be used to display our form and a POST /registration
route to handle its submission.
In the form handler route we have collected all the data from the form, but we can't use it yet. Why? Well OK then, I guess I'll show you.
Go ahead and load up the /
route and you should see the form. Right, don't fill it in, just hit the 'Register' button. The screen will go blank as the second route is triggered and our form has posted blank information. If we were to use the blank information then it could cause severe problems for our application or even a security vulnerability. This is bad data.
We can avoid this hassle by implementing validation to ensure that our data is instead good data. Before we perform the validation, we first need to provide a list of validation constraints. We can do this in the form of an array. Are you ready? Great, let's take a look.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
$data = Input::all();
$rules = array(
'username' => 'alpha_num'
);
});
Right, let's start small. A set of validation rules takes the form of an associative array. The array key represents the field that is being validated. The array value will consist of one or many rules that will be used to validate. We will start by looking at a single validation constraint on a single field.
array(
'username' => 'alpha_num'
)
In the above example, we wish to validate that the 'username' field conforms to the alpha_num
validation rule. The alpha_num
rule can be used to ensure that a value consists of only alphanumeric characters.
Let's set up the validation object to make sure our rule is working correctly. To perform validation within Laravel, we first need to create an instance of the Validation
object. Here we go.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'alpha_num'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
});
We can use the Validator::make()
method to create a new instance of our validator. The first parameter to the make()
method is an array of data that will be validated. In this example we intend to validate our request data, but we could just as easily validate any other array of data. The second parameter to the method is the set of rules that will be used to validate the data.
Now that our validator instance has been created, we can use it to check whether or not the data we provided conforms to the validation constraints that we have provided. Let's set up an example.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'alpha_num'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/');
});
To test the result of the validation we can use the passes()
method on the validator instance. This method will return a boolean response to show whether or not the validation has passed. A true
response indicates that the data conforms to all of the validation rules. A false
indicates that the data does not meet the validation requirements.
We use an if
statement in the above example to decide whether to store the data or to redirect to the entry form. Let's test this by visiting the /
URI.
First enter the value 'johnzoidberg' into the username field and hit the submit button. We know that the username 'johnzoidberg' consists of alphanumeric characters, so the validation will pass. We are presented with the following sentence.
Data was saved.
Great, that's what we expected. Now let's invert the result of the validation. Go ahead and visit the /
URI once again. This time, enter the value '!!!'. We know that an exclamation mark is not an alphabetical or numerical character, so the validation should fail. Hit the submit button, and we should be redirected back to the registration form.
I love that passes()
method, it's really useful. The only problem is that it's a little optimistic. The world isn't a perfect place, let's be honest with ourselves. We aren't all Robert Downey Jr. Let's allow ourselves to be a little more pessimistic shall we? Excellent, wait... satisfactory. Let's try the fails()
method instead.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'alpha_num'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
return Redirect::to('/');
}
// Normally we would do something with the data.
return 'Data was saved.';
});
The fails()
method returns the boolean opposite to the passes()
method. How wonderfully pessimistic! Feel free to use whichever method suits your current mood. If you like, you could also write about your feelings using PHP comments.
Some validation rules are able to accept parameters. Let's swap out our alpha_num
rule for the min
one. Here's the source.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'min:3'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/');
});
The min
validation rule ensures that the value is greater than or equal to the parameter provided. The parameter is provided after the colon :
. This validation rule is a little special. It will react differently depending on the data that has been provided.
For example, on a string value, our parameter '3' will ensure that the value is at least 3 characters long. On a numerical value, it will ensure that the value is mathematically greater than or equal to our parameter. Finally, on uploaded files, the min
validation rule will ensure that the uploaded file's size in bytes is greater than or equal to the provided parameter.
Let's test out our new validation rule. First visit the /
page and enter the value 'Jo' into the username field. If you submit the form, you will be redirected back to the registration form. This is because our value is not long enough.
That's what she s...
Oh no you don't. This is a serious book, we aren't going to soil it with 'she said' jokes.
Right, we have now used two validation constrains, but what if we want to use them together? That's not a problem. Laravel will allow us to use any number of validation rules on our fields. Let's take a look at how this can be done.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'alpha_num|min:3'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/');
});
As you can see, we are able to pass a number of validation constraints within the value portion of our rules array by separating them with pipe |
characters. This chapter would have arrived much sooner, however, I use Linux in work and a Mac at home, and it just took me 30 seconds to find the pipe key.
Anyway, there's an alternative way to provide multiple validation rules. If you aren't a 60s grandfather then you might not appreciate pipes. If you like, you can use a multidimensional array to specify additional validation rules.
Here's an example.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => array('alpha_num', 'min:3')
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/');
});
Laravel is a flexible framework, and it gives its users options. Use whichever method of assigning multiple validation rules that you prefer. I'll be using the pipe, to emulate a distinguished British gentleman.
Validation Rules
Right people, listen up. There are a bunch of validation rules, so if we are going to get through this in one go then I'm going to need your full attention. If you are reading this on your Kindle while in bed, put the book down and go to sleep. You are going to need to be more awake.
Here are the available validation rules in alphabetical order.
accepted
This rule can be used to ensure that a positive confirmation has been provided. It will pass if the value under validation is one of the following values: 'yes', 'on' or a numeric 1. Its intended purpose is for when you wish to ensure that the user has agreed to something, for example, a terms and conditions checkbox.
array(
'field' => 'accepted'
);
active_url
The 'active_url' validation will check to make sure that the value is a valid URL. To do this, it uses PHP's own checkdnsrr()
method, which not only checks the structure of the URL but also confirms that the URL is available within your DNS records.
array(
'field' => 'active_url'
);
after
The 'after' validation rule accepts a single parameter, a string representation of a time. The rule will ensure that the field contains a date that occurs after the given parameter. Laravel will use the strtotime()
PHP method to convert both the value and the rule's parameter to a timestamp for comparison.
array(
'field' => 'after:12/12/13'
);
alpha
The 'alpha' validation rule ensures that the provided value consists entirely of alphabetical characters.
array(
'field' => 'alpha'
);
alpha_dash
The 'alpha_dash' rule will ensure that the provided value consists of alphabetical characters and also dashes -
and/or underscores _
. This validation rule is very useful for validating URL portions such as 'slugs'.
array(
'field' => 'alpha_dash'
);
alpha_num
The 'alpha_num' rule will ensure that the provided value consists of alphabetical and numeric characters. I like to use this rule to validate username fields.
array(
'field' => 'alpha_num'
);
before
The 'before' rule accepts a single parameter. The value under question must occur before the parameter when both values are converted to timestamps using PHP's strtotime()
method. It is the exact opposite of the 'after' rule.
array(
'field' => 'before:12/12/13'
);
between
The 'between' rule accepts two parameters. The value that is being validated must have a size that exists between these two parameters. The type of comparison depends on the type of data being compared. For example, on numerical fields the comparison will be a mathematical one. On a string, the comparison will be based upon the length of the string in characters. On a file, the comparison will be based upon the size of the file in bytes.
array(
'field' => 'between:5,7'
);
confirmed
The 'confirmed' validation rule can be used to ensure that another field exists that matches the current name of the current field appended with _confirmation
. The value being validated must match the value of this other field. One use for this rule is for password field confirmations to ensure that the user has not inserted a typographical error into either of the fields. The following example will ensure that 'field' matches the value of 'field_confirmation'.
array(
'field' => 'confirm'
);
date
The 'date' validation rule will ensure that our value is a valid date. It will be confirmed by running the value through PHP's own strtotime()
method.
array(
'field' => 'date'
);
date_format
The 'date_format' validation rule will ensure that our value is a date string that matches the format provided as a parameter. To learn how to construct a date format string, take a look at the PHP documentation for the date()
method.
array(
'field' => 'date_format:d/m/y'
);
different
The 'different' validation rule will ensure that the value being validated is different to the value contained in the field described by the rule parameter.
array(
'field' => 'different:another_field'
);
The 'email' validation rule will ensure that the value being validated is a valid email address. This rule is very useful when constructing registration forms.
array(
'field' => 'email'
);
exists
The 'exists' validation rule will ensure that the value is present within a database table identified by the rule parameter. The column that will be searched will be of the same name as the field being validated. Alternatively, you can provide an optional second parameter to specify a column name.
This rule can be very useful for registration forms to check whether a username has already been taken by another user.
array(
'field' => 'exists:users,username'
);
Any additional pairs of parameters passed to the rule will be added to the query as additional where
clauses. Like this:
array(
'field' => 'exists:users,username,role,admin'
);
The above example will check to see if the value exists within the username column of the users table. The role column must also contain the value 'admin'.
image
The 'image' validation rule will ensure that the file that has been uploaded is a valid image. For example, the extension of the file must be one of the following: .bmp
, .gif
, .jpeg
or .png
.
array(
'field' => 'image'
);
in
The 'in' validation rule will ensure that the value of the field matches one of the provided parameters.
array(
'field' => 'in:red,brown,white'
);
integer
This is an easy one! The 'integer' validation rule will ensure that the value of the field is an integer. That's it!
array(
'field' => 'integer'
);
ip
The 'ip' validation rule will check to make sure that the value of the field contains a well formatted IP address.
array(
'field' => 'ip'
);
max
The 'max' validation rule is the exact opposite of the 'min' rule. It will ensure that the size of the field being validated is less than or equal to the supplied parameter. If the field is a string, the parameter will refer to the length of the string in characters. For numerical values, the comparison will be made mathematically. For file upload fields the comparison will be made upon the size of the file in bytes.
array(
'field' => 'max:3'
);
mimes
The 'mimes' validation rule ensures that the provided string is the name of a French mime. Just kidding. This rule will check the mime type of an uploaded file to ensure that it matches one of the parameters provided.
array(
'field' => 'mimes:pdf,doc,docx'
);
min
The 'min' validation rule is the direct opposite of the 'max' rule. It can be used to ensure that a field value is greater than or equal to the provided parameter. If the field is a string, the parameter will refer to the length of the string in characters. For numerical values, the comparison will be made mathematically. For file upload fields the comparison will be made upon the size of the file in bytes.
array(
'field' => 'min:5'
);
not_in
As the name suggests, this validation rule is the exact opposite of the 'in' rule. It will ensure that the field's value does not exist within the list of supplied parameters.
array(
'field' => 'not_in:blue,green,pink'
);
numeric
The 'numeric' rule will check to make sure that the field being validated contains a numeric value.
array(
'field' => 'numeric'
);
regex
The 'regex' validation rule is the most flexible rule available within Laravel's validation component. With this rule you can provide a custom regular expression as a parameter that the field under validation must match. This book will not cover regular expressions in detail since it is a very large topic worthy of a book of its own.
You should note that because pipe |
characters can be used within regular expressions, you should use nested arrays rather than pipes to attach multiple validation rules when using the 'regex' rule.
array(
'field' => 'regex:[a-z]'
);
required
The 'required' validation rule can be used to ensure that the current field exists within the validation data array.
array(
'field' => 'required'
);
required_if
The 'required_if' validation rule ensures that the current field must be present only if a field defined by the first parameter of the rule matches the value supplied by the second parameter.
array(
'field' => 'required_if:username,zoidberg'
);
required_with
The 'required_with' is used to ensure that the current value is present only if one or more fields defined by the rule parameters are also present.
array(
'field' => 'required_with:age,height'
);
required_without
The 'requiredwithout' rule is the direct opposite to the 'requiredwith' rule. It can be used to ensure that the current field is present only when the fields defined by the rule parameters are not present.
array(
'field' => 'required_without:age,height'
);
same
The 'same' validation rule is the direct opposite of the 'different' rule. It is used to ensure that the value of the current field is the same as another field defined by the rule parameter.
array(
'field' => 'same:age'
);
size
The 'size' rule can be used to ensure that the value of the field is of a given size provided by the rule parameter. If the field is a string, the parameter will refer to the length of the string in characters. For numerical values, the comparison will be made mathematically. For file upload fields the comparison will be made upon the size of the file in bytes.
array(
'field' => 'size:8'
);
unique
The 'unique' rule ensures that the value of the current field is not already present within the database table defined by the rule parameter. By default, the rule will use the name of the field as the table column in which to look for the value, however, you can provide an alternate column within the second rule parameter. This rule is useful for checking whether a users provide username is unique when handling registration forms.
array(
'field' => 'unique:users,username'
);
You can provide extra optional parameters to list a number of IDs for rows that will be ignored by the unique rule.
array(
'field' => 'unique:users,username,4,3,2,1'
);
url
The 'url' validation rule can be used to ensure that the field contains a valid URL. Unlike the 'active_url' validation rule, the 'url' rule only checks the format of the string and does not check DNS records.
array(
'field' => 'url'
);
Well that's all of them. That wasn't so bad right? We aren't done yet though. Let's take a look at error messages.
Error Messages
In the first chapter we learned how we can perform validation and how to redirect back to a form upon failure. However, that method doesn't offer the user much in the way of constructive feedback.
Fortunately, Laravel collects a number of error messages describing why the validation attempt failed. Let's take a look at how we can access this information.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'alpha_num'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
// Collect the validation error messages object.
$errors = $validator->messages();
return Redirect::to('/');
});
In the above example, you will see that we can access the validation error messages object using the messages()
method of our validator instance. Now, since we are redirecting to our form route, how do we access the error messages within our forms?
Well, I think we could probably use the withErrors()
method for this.
I don't believe you, you keep lying to me!
Oh yeah? Well check this out.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'alpha_num'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/')->withErrors($validator);
});
You will notice that we pass the validator instance to the withErrors()
chained method. This method flashes the errors from the form to the session. Before we continue any further, let's add more validation rules to our example.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'required|alpha_num|min:3|max:32',
'email' => 'required|email',
'password' => 'required|confirm|min:3'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/')->withErrors($validator);
});
Now let's see how we can access our error messages from the form view.
<!-- app/views/form.blade.php -->
<h1>Registration form for Phill's Parks</h1>
{{ Form::open(array('url' => 'registration')) }}
<ul class="errors">
@foreach($errors->all() as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
{{-- Username field. ------------------------}}
{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}
{{-- Email address field. -------------------}}
{{ Form::label('email', 'Email address') }}
{{ Form::email('email') }}
{{-- Password field. ------------------------}}
{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}
{{-- Password confirmation field. -----------}}
{{ Form::label('password_confirmation', 'Password confirmation') }}
{{ Form::password('password_confirmation') }}
{{-- Form submit button. --------------------}}
{{ Form::submit('Register') }}
{{ Form::close() }}
When our view is loaded the $errors
variable is added to the view data. It's always there, and it's always an error messages container instance, so you don't have to worry about checking for its existence or contents. If we have used withErrors()
to flash our error messages to the session in a previous request then Laravel will automatically add them to the errors object. How convenient!
We can access an array of all error messages by using the all()
method on the $errors
error messages instance. In the above view, we loop through the entire array of messages outputting each of them within a list element.
Right, thats enough yapping. Let's give it a try. Go ahead and visit the /
URL. Submit the form without entering any information to see what happens.
We are redirected back to the form. This time however, a set of error messages are displayed.
- The username field is required.
- The email field is required.
- The password field is required.
Great! Now our application's users are aware of any validation errors upon registration. However, it's more convenient for our users if the error messages are nearer to the fields that they describe. Let's alter the view a little.
<!-- app/views/form.blade.php -->
<h1>Registration form for Phill's Parks</h1>
{{ Form::open(array('url' => 'registration')) }}
{{-- Username field. ------------------------}}
<ul class="errors">
@foreach($errors->get('username') as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}
{{-- Email address field. -------------------}}
<ul class="errors">
@foreach($errors->get('email') as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
{{ Form::label('email', 'Email address') }}
{{ Form::email('email') }}
{{-- Password field. ------------------------}}
<ul class="errors">
@foreach($errors->get('password') as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}
{{-- Password confirmation field. -----------}}
{{ Form::label('password_confirmation', 'Password confirmation') }}
{{ Form::password('password_confirmation') }}
{{-- Form submit button. --------------------}}
{{ Form::submit('Register') }}
{{ Form::close() }}
We can use the get()
method on the validation errors object to retrieve an array of errors for a single field. Simply pass the name of the field as the first parameter to the get()
method.
Let's resubmit the form. This time, place a single exclamation !
mark within the username field. Let's take a look at the errors that appear above the username field.
- The username may only contain letters and numbers.
- The username must be at least 3 characters.
That's better. Well... it's a little bit better. Most forms only show a single validation error per field, so as not to overwhelm the application's user.
Let's take a look at how this is done with the Laravel validation errors object.
<!-- app/views/form.blade.php -->
<h1>Registration form for Phill's Parks</h1>
{{ Form::open(array('url' => 'registration')) }}
{{-- Username field. ------------------------}}
<span class="error">{{ $errors->first('username') }}</span>
{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}
{{-- Email address field. -------------------}}
<span class="error">{{ $errors->first('email') }}</span>
{{ Form::label('email', 'Email address') }}
{{ Form::email('email') }}
{{-- Password field. ------------------------}}
<span class="error">{{ $errors->first('password') }}</span>
{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}
{{-- Password confirmation field. -----------}}
{{ Form::label('password_confirmation', 'Password confirmation') }}
{{ Form::password('password_confirmation') }}
{{-- Form submit button. --------------------}}
{{ Form::submit('Register') }}
{{ Form::close() }}
By using the first()
method on the validation errors object and passing the field name as a parameter, we can retrieve the first error message for that field.
Once again, submit the form with only an exclamation !
mark within the username field. This time we receive only a single error message for the first field.
- The username may only contain letters and numbers.
By default the validation messages instance's methods return an empty array or null
if no messages exist. This means that you can use it without having to check for the existence of messages. However, if for some reason you wish to check whether or not an error message exists for a field, you can use the has()
method.
@if($errors->has('email'))
<p>Yey, an error!</p>
@endif
In the previous examples for the all()
and first()
methods you will have noticed that we wrapped our error messages within HTML elements. However, if one of our methods return null, the HTML would still be displayed.
We can avoid having empty HTML elements appearing in our view source code by passing the containing HTML in string format as the second parameter to the all()
and first()
methods. For example, here's the all()
method with the wrapping list elements as a second parameter.
<!-- app/views/form.blade.php -->
<h1>Registration form for Phill's Parks</h1>
{{ Form::open(array('url' => 'registration')) }}
<ul class="errors">
@foreach($errors->all('<li>:message</li>') as $message)
{{ $message }}
@endforeach
</ul>
{{-- Username field. ------------------------}}
{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}
{{-- Email address field. -------------------}}
{{ Form::label('email', 'Email address') }}
{{ Form::email('email') }}
{{-- Password field. ------------------------}}
{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}
{{-- Password confirmation field. -----------}}
{{ Form::label('password_confirmation', 'Password confirmation') }}
{{ Form::password('password_confirmation') }}
{{-- Form submit button. --------------------}}
{{ Form::submit('Register') }}
{{ Form::close() }}
The :message
portion of the second parameter to the all()
method will be replaced by the actual error message when the array is constructed.
The first()
method has a similar optional parameter.
<!-- app/views/form.blade.php -->
<h1>Registration form for Phill's Parks</h1>
{{ Form::open(array('url' => 'registration')) }}
{{-- Username field. ------------------------}}
{{ $errors->first('username', '<span class="error">:message</span>') }}
{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}
{{-- Email address field. -------------------}}
{{ $errors->first('email', '<span class="error">:message</span>') }}
{{ Form::label('email', 'Email address') }}
{{ Form::email('email') }}
{{-- Password field. ------------------------}}
{{ $errors->first('password', '<span class="error">:message</span>') }}
{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}
{{-- Password confirmation field. -----------}}
{{ Form::label('password_confirmation', 'Password confirmation') }}
{{ Form::password('password_confirmation') }}
{{-- Form submit button. --------------------}}
{{ Form::submit('Register') }}
{{ Form::close() }}
Custom Validation Rules
Oh I see, you're not happy with all that Laravel has given you? You wish to have your own validation methods do you? Very well, time to bring out the big guns. Laravel is flexible enough to let you specify your own rules.
Let's have a look at how this can be done.
<?php
// app/routes.php
Validator::extend('awesome', function($field, $value, $params)
{
return $value == 'awesome';
});
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'awesome',
);
// Create a new validator instance.
$validator = Validator::make($data, $rules);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/')->withErrors($validator);
});
There's no default location for custom validation rules to be defined, so I have added it within the routes.php
file to simplify the example. You could include a validators.php
file and provide custom validations in there if you like.
We have attached our 'awesome' validation rule to our username field. Let's take a closer look at how the validation rule is created.
<?php
// app/routes.php
Validator::extend('awesome', function($field, $value, $params)
{
return $value == 'awesome';
});
To create a custom validation rule we use the Validator::extend()
method. The first parameter to the method is the nickname that will be given to the validation rule. This is what we will use to attach it to a field. The second parameter to the method is a closure. Should the closure return a boolean result of true
then the validation attempt will have passed. If a boolean false
is returned from the closure then the validation attempt will have failed.
The parameters that are handed to the closure are as follows. The first parameter is a string containing the name of the field that is being validated. In the above example the first parameter would contain the string 'username'.
The second parameter to the extend closure contains the value of the field.
The third parameter contains an array of any parameters that have been passed to the validation rule. Use them to customise your validation rules as required.
If you prefer to define your custom validation rule within a class, rather than a closure, then you won't be able to. Stop wanting things.
Now wait, I'm just kidding. Laravel can do that. Let's create a class that will accomplish this.
<?php
// app/validators/CustomValidation.php
class CustomValidation
{
public function awesome($field, $value, $params)
{
return $value == 'awesome';
}
}
As you can see, our validation class contains any number of methods that have the same method signature as our validation closure. This means that a custom validator class can have as many validation rules as we like.
Once again there's no perfect location for these classes, so you will have to define your own project structure. I chose to put my validation class within the app/validators
folder and classmap that folder with Composer.
Well that's everything covered.
Wait, the validation class doesn't contain the validation nickname.
Ah yes, I almost forgot. Well done observant reader! You see, for the validation rule to be discovered, we need to use the Validator::extend()
method again. Let's take a look.
<?php
// app/routes.php
Validator::extend('awesome', 'CustomValidation@awesome');
This time the Validator::extend()
method is given a string as a second parameter. Just like when routing to a controller, the string consists of the class name of the validation rule class and the action representing the rule separated by an @
symbol.
In a later chapter we will learn how to extend the Validation class as an alternative, more advanced method of providing custom validation rules.
Custom Validation Messages
Laravel has provided default validation messages for all the inbuilt validation rules, but what if you don't like the default ones or want want to write your application for a region that doesn't use English as its primary language.
Well don't panic! Laravel will let you override the inbuilt validation messages. We just need to build an additional array and pass it to the make()
method of the validator instance.
Hey, we already looked at the
Validator::make()
method?!
That's true, but once again I lied to you.
Why do you keep tormenting me?
I'm not really sure. I guess I think of it as a hobby at this point. Anyway, let's take a look at an example array of custom validation messages.
<?php
// app/routes.php
Route::get('/', function()
{
return View::make('form');
});
Route::post('/registration', function()
{
// Fetch all request data.
$data = Input::all();
// Build the validation constraint set.
$rules = array(
'username' => 'min:3',
);
// Build the custom messages array.
$messages = array(
'min' => 'Yo dawg, this field aint long enough.'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules, $messages);
if ($validator->passes()) {
// Normally we would do something with the data.
return 'Data was saved.';
}
return Redirect::to('/')->withErrors($validator);
});
That's a big example, let's hit the focus button.
I can't find the focus button on my keyboard.
Well, if you have a Mac, it's that one above the tab key. It looks like this ±
.
Are you sure?
Well, do you have any other ideas of what that button means?
Ah, I see your point.
Right, let's focus on the example.
<?php
// Build the custom messages array.
$messages = array(
'min' => 'Yo dawg, this field aint long enough.'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules, $messages);
The messages array is an optional third parameter to the Validator::make()
method. It contains any custom validation messages that you wish to provide and will also override the default validation messages. The key for the validation message array represents the name of the validation rule, and the value is the message to display if the validation rule fails.
In the above example we have overridden the failed validation message for the min
validation rule.
We can also use this method to provide validation errors for our custom validation rule. Our custom rules won't have validation error messages by default, so it's normally a good idea to do so.
<?php
// Build the custom messages array.
$messages = array(
'awesome' => 'Please enter a value that is awesome enough.'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules, $messages);
If we want to provide a custom error message for a specific field, we can do so by providing the name of the field, a period .
character, and the type of validation as the key within the array.
<?php
// Build the custom messages array.
$messages = array(
'username.min' => 'Hmm, that looks a little small.'
);
// Create a new validator instance.
$validator = Validator::make($data, $rules, $messages);
The message in the above example will only be shown when the min
validation rule fails for the 'username' field. All other min
failures will use the default error message.
That's all I have to offer on validation right now. In a later chapter we will learn how to extend Laravel's validator class and how to provide translatable validation error messages, but, for now, let's move on to the next chapter to learn about databases.
My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.
It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new books from the comfort of my sofa!