cult3

Extending the Laravel 4 Validator

Jan 20, 2014

Table of contents:

  1. The two methods of extension
  2. Resolving from a closure
  3. Resolving from a class
  4. Conclusion

One of the best components that ships out of the box with Laravel 4 is the validation package. I’ve covered using the Laravel validation package a couple of times in the past whilst creating validation services and my own extension of Eloquent, but I haven’t really explored how to extend the package to add your own rules.

Fortunately, as with the majority of Laravel 4, the validation package is actually really easy to extend. In this tutorial I’ll be looking at how to extend the validator and where to organise your code within your project.

The two methods of extension

If you’ve ever looked at extending anything in Laravel 4, you will probably have noticed that there is usually two different ways to extend a lot of the components.

The first is by passing a closure to the extend method on the class. Remember, a closure is simply an anonymous function. This is often a good method for creating extensions when your project is likely going to stay small and so you want to keep the logic together.

Whilst I do like this method, for the majority of the time I actually prefer to pass in the name of class to use instead. This means you have to extend the validator in one place, whilst keeping the logic of your extension in another, but I find this method preferable, especially when a project is likely going to get pretty big and I’m likely going to have many extensions.

Let’s look at setting up both of these methods!

Resolving from a closure

As I mentioned above, the first method is where you simply pass a closure to the extend method on the validator class:

Validator::extend("hex", function ($attribute, $value, $parameters) {
    if (preg_match("/^#?([a-f0-9]{6}|[a-f0-9]{3})$/", $value)) {
        return true;
    }

    return false;
});

The first argument of the extend method is the name of the extension and the second is the closure. The closure accepts three arguments:

$attribute: The name of the attribute that you are validating.

$value: The value of the attribute you are validating.

$parameters: An array of parameters that can be passed to the rule.

So in the example above, I’m using a regex to verify that the value passed in to the Validator is a valid hex code.

As I mentioned above, the benefit of using this method is everything is kept in one place. You could place this code in a file or directory for your “extensions” and then all you would have to do is to ensure that it is loaded when Laravel boots up.

Resolving from a class

Whilst the closure method is a nice and neat little way of extending Laravel’s Validator package, I still much prefer to resolve from a class.

What are the benefits of resolving from a class? Well I think there are basically 2 reasons why you should consider this method:

  1. Easier to manage multiple extensions: Firstly, I find when I have many custom validation requirements, it is actually easier to manage them as methods on a class, rather than individual closure extensions.

  2. Always extend in a consistent way And secondly, whenever I look to extend Laravel in any way, I also prefer to use a Service Provider. This means whenever someone (or future me) needs to pick up the project and make a change, that person won’t have to search through files to find the extension because they will be stored in a consistent file structure.

So the first thing to do is to extend the Validator class with our own class:

<?php namespace App\Extension\Validation;

class CustomValidator extends \Illuminate\Validation\Validator
{
    public function validateHex($attribute, $value, $parameters)
    {
        if (preg_match("/^#?([a-f0-9]{6}|[a-f0-9]{3})$/", $value)) {
            return true;
        }

        return false;
    }
}

Next we can create a Service Provider to resolve our extension:

<?php namespace App\Extension\Validation;

use Illuminate\Support\ServiceProvider;

class ValidationServiceProvider extends ServiceProvider
{
    public function register()
    {
    }

    public function boot()
    {
        $this->app->validator->resolver(function (
            $translator,
            $data,
            $rules,
            $messages
        ) {
            return new CustomValidator($translator, $data, $rules, $messages);
        });
    }
}

You will notice that I’m using the boot method, rather than the register method. This is because Laravel’s validation package is actually set to deferred. This means if we tried to use the register method, it wouldn’t actually be there.

Next under app/config/app.php add your Service Provider to the providers array:

'providers' => array(
    'Illuminate\Validation\ValidationServiceProvider',
    'Illuminate\View\ViewServiceProvider',
    'Illuminate\Workbench\WorkbenchServiceProvider',
    'App\Extension\Validation\ValidationServiceProvider'
),

And finally, you can add your extension validation message to the array of messages under app/lang/en/validation.php. This makes it really easy to have multiple language variations of your extension.

Conclusion

One of my favourite things about Laravel is how easy it is to extend to meet your own requirements. I think every project I have ever worked on needed some extension in one form or another and so being able to effortlessly extend the core functionality of the components of Laravel is, in my opinion, a huge asset.

I also really love how Laravel doesn’t enforce a way in which you have to extend the components. As I’ve shown above, if your project is small and you only need one simple validation rule you are not forced to set up all of the boilerplate code of a Service Provider. Instead you can simple resolve from a closure. On the other hand, if your project is big and complex, Laravel makes it incredibly easy to organise and structure your code so that it is easy to work with and maintain as the project evolves.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.