Data Validation in Laravel: The Right Way

Amit Gupta
Tweet
This entry is part 1 of 2 in the series Data Validation in Laravel - The Right Way

Data Validation in Laravel - The Right Way

If an app was a world then data would be its currency. Every app, no matter what its purpose, deals in data. And almost every type of app works with user input, which means it expects some data from users and acts on it accordingly. But that data needs to be validated to make sure it is of correct type and a user (with nefarious intent) is not trying to break or crack into your app. Which, if you are making an application which requires user input, is why you would need to write code to validate that data as well before you do anything with it.

Once Upon a Time

At some point in time, you probably did your data validation like this:

<?php
$errors = array();

if ( empty( $_POST['name'] ) || ! is_string( $_POST['name'] ) ) {
    $errors[] = 'Name is required';
} elseif ( ! preg_match( "/^[A-Za-z\s-_]+$/", $_POST['name'] ) ) {
    $errors[] = 'Name can have only alphabets, spaces and dashes';
}

if ( empty( $_POST['email'] ) || ! is_string( $_POST['email'] ) ) {
    $errors[] = 'Email is required';
}

//...........
//.... some more code here
//...........

//display errors
if ( ! empty( $errors ) ) {
    for ( $i = 0; $i < count( $errors ); $i++ ) {
        echo '<div class="error">' . $errors[ $i ] . '</div>';
    }
}

Well, that was the stone age for you. Luckily, we have much better and more sophisticated validation packages these days (and have had them for quite some time in PHP).

If you use any application framework as the foundation of your app, chances are it will have its own or a recommended 3rd party data validation package, especially if it is a full stack framework. Since Laravel is a full stack framework, it comes with its own validation package. As always, you’re not constrained to use that and can use any other data validation package that you want. However, for the purpose of this tutorial, we will stick with what comes with Laravel by default.

Data Validation: The Laravel Way

The source code for this tutorial is available here. You just need to run composer install to install the Laravel framework inside the project directory before you are able to run this code.

Now continuing the previous example, let’s assume we have a form which has a Name and an Email field and we would like to validate that data before saving it. Here’s how the previous rudimentary attempt at validation would translate with Laravel.

<?php
$validation = Validator::make(
    array(
        'name' => Input::get( 'name' ),
        'email' => Input::get( 'email' ),
    ),
    array(
        'name' => array( 'required', 'alpha_dash' ),
        'email' => array( 'required', 'email' ),
    )
);

if ( $validation->fails() ) {
    $errors = $validation->messages();
}

//...........
//.... some more code here
//...........

//display errors
if ( ! empty( $errors ) ) {
    foreach ( $errors->all() as $error ) {
        echo '<div class="error">' . $error . '</div>';
    }
}

In the code above we Laravel-ified the data validation by making use of the Validator facade. We passed an array of the data that we want to validate and an array of validation rules according to which we want the data validated. We get an object returned to us and then we check if our data validation failed or not. If it failed then we grab the error messages object (an object of Laravel’s MessageBag class) and then looped over it to print out all the error messages. The validation rules we used are built into the validation package and there are many available, some would even check into the database.

Now, it is not uncommon to come across code where the data validation has been placed at odd places, like in Controller methods or in data Models. Data validation code does not belong in either of those places, as such placement defies the concepts of Single Responsibility and DRY (Don’t Repeat Yourself).

Single Responsibility: One class should have one and only one job to perform. A Controller’s job is to act as a glue between the business logic and the client. It should grab the request and pass it on to someone who can process the request, it should not start processing the request itself.

Similarly, a Model’s job is to act as a broker between data source and rest of the application. It should only accept data for saving and give it when asked.

There is more than one school of thought on this; some would add data validation to Models but even those would not put actual data validation code inside a Model class. It would most likely be outsourced to another class which would accept data and tell whether the data is valid or not.

So where do we put the code which does data validation and which can be used anywhere in the application?

Validation as a Service

The ideal choice is to move out the validation code into separate class(es) which can be used as needed.

Continuing with our previous code example, let’s move it into its own class. Create a directory named RocketCandy inside app directory. This is our main directory (or domain directory) in which we will put all our custom stuff (services, exceptions, utility libraries, etc). Now create Services/Validation directory structure inside RocketCandy. Inside Validation directory, create Validator.php.

Now before we can proceed further, open up your composer.json and after the classmap in autoload node add RocketCandy namespace for PSR-4 autoloading. It would look something like this:

	"autoload": {
		"classmap": [
			"app/commands",
			"app/controllers",
			"app/models",
			"app/database/migrations",
			"app/database/seeds",
			"app/tests/TestCase.php"
		],
		"psr-4": {
			"RocketCandy\\": "app/RocketCandy"
		}
	},

Then in your terminal, run composer dump-autoload -o so that composer can generate the autoloader for our RocketCandy namespace.

Now open up RocketCandy/Services/Validation/Validator.php. After we move the validation code from above, it will look something like this:

<?php

namespace RocketCandy\Services\Validation;

class Validator {

    public function validate() {
        $validation = \Validator::make(
            array(
                'name' => \Input::get( 'name' ),
                'email' => \Input::get( 'email' ),
           ),
            array(
                'name' => array( 'required', 'alpha_dash' ),
                'email' => array( 'required', 'email' ),
            )
        );

        if ( $validation->fails() ) {
            return $validation->messages();
        }
        
        return true;
    }

}   //end of class

//EOF

Now we could use this as:

<?php

$validator = new \RocketCandy\Services\Validation\Validator;
$validation = $validator->validate();

if ( $validation !== true ) {
    //show errors
}

This is somewhat better than what we were doing earlier but it is still not ideal for the following reasons:

  1. Our Validation class still is not DRY enough. We would need to copy over all this validation code to another class to validate data of another entity.
  2. Why are we fetching input data inside the validation class? There is no reason to do it there because it would limit us as to which data we can validate. Here we would be able to validate this data only if it came from a form input.
  3. There is no way of overriding validation rules, they are set in stone.
  4. The mechanism by which we get to know whether the data validated or not is not clean. Sure, it serves the purpose but this can definitely be improved upon.
  5. We are using a pseudo static call to Laravel’s validation package. This can be improved upon as well.

Solution?

We abstract out the validation code a bit further and we make use of exceptions.

First, let’s make our own custom exceptions. Create the Exceptions directory under RocketCandy and create BaseException.php. Open it up and put the following code in it.

<?php

namespace RocketCandy\Exceptions;

use Exception;
use Illuminate\Support\MessageBag;

abstract class BaseException extends Exception {

	protected $_errors;

	public function __construct( $errors = null, $message = null, $code = 0, Exception $previous = null ) {
		$this->_set_errors( $errors );

		parent::__construct( $message, $code, $previous );
	}

	protected function _set_errors( $errors ) {
		if ( is_string( $errors ) ) {
			$errors = array(
				'error' => $errors,
			);
		}

		if ( is_array( $errors ) ) {
			$errors = new MessageBag( $errors );
		}

		$this->_errors = $errors;
	}

	public function get_errors() {
		return $this->_errors;
	}

}	//end of class


//EOF

Here we created an abstract class and all our custom exceptions would inherit this class. The first parameter for the constructor is what we are concerned with, so let’s look at that. We make use of Laravel’s MessageBag to store our errors (if they are not in it already) so that we would have a uniform way to loop through and display those errors irrespective of whether the exception was thrown by validation service or any other. The _set_errors() method thus checks if a single error message as a string was passed or an array of error messages was passed. Accordingly, it stores them in a MessageBag object (unless it is already inside in which case it would be stored as is). And we have a getter method get_errors() which just returns the contents of our class variable as is.

Now, in the same directory create ValidationException.php and its code will be:

<?php

namespace RocketCandy\Exceptions;

class ValidationException extends BaseException {
}	//end of class


//EOF

That’s it, we don’t need anything else in here, it will be an empty shell because all that we need done will be handled by BaseException.

Now, we proceed with re-tooling our Validator class. We need to abstract out the validation code, throw ValidationException on error(s) and allow overriding of validation rules. So it would look like this:

<?php

namespace RocketCandy\Services\Validation;

use Illuminate\Validation\Factory as IlluminateValidator;
use RocketCandy\Exceptions\ValidationException;

/**
 * Base Validation class. All entity specific validation classes inherit
 * this class and can override any function for respective specific needs
 */
abstract class Validator {

	/**
	 * @var Illuminate\Validation\Factory
	 */
	protected $_validator;

	public function __construct( IlluminateValidator $validator ) {
		$this->_validator = $validator;
	}

	public function validate( array $data, array $rules = array(), array $custom_errors = array() ) {
		if ( empty( $rules ) && ! empty( $this->rules ) && is_array( $this->rules ) ) {
			//no rules passed to function, use the default rules defined in sub-class
			$rules = $this->rules;
		}

		//use Laravel's Validator and validate the data
		$validation = $this->_validator->make( $data, $rules, $custom_errors );

		if ( $validation->fails() ) {
			//validation failed, throw an exception
			throw new ValidationException( $validation->messages() );
		}

		//all good and shiny
		return true;
	}

} //end of class

//EOF

Here in this abstract class we have:

  1. Abstracted out the validation code. It can be used as is for validating data of any entity.
  2. Removed data fetching from the class. Validation class does not need to know where the data is coming from. It accepts an array of data to validate as a parameter.
  3. Removed validation rules from this class. Each entity can have its own set of validation rules either defined in the class or they can be passed as array to validate(). If you want to define rules in the child classes and want to be sure they’re present, I wrote about emulating abstract properties in PHP sometime back.
  4. Improved the mechanism by which validation failure can be determined. If the data validation fails the validation service would throw ValidationException and we can get the errors from that instead of checking for returned data type or values etc. This also means that we can throw another exception if validation rules are not defined. It would be a different exception and we would know immediately that we messed up somewhere.
  5. Removed the usage of static call for data validation. In here we now inject Laravel’s validation class in our class constructor. If we resolve our validation service out of Laravel’s IoC container (which we would) then we would not have to worry about the dependency injection into constructor here.

Now we would create a validation class for our form which would extend this abstract class. In the same directory create TestFormValidator.php and add following code into it:

<?php

namespace RocketCandy\Services\Validation;

class TestFormValidator extends Validator {

	/**
	 * @var array Validation rules for the test form, they can contain in-built Laravel rules or our custom rules
	 */
	public $rules = array(
		'name' => array( 'required', 'alpha_dash', 'max:200' ),
		'email' => array( 'required', 'email', 'min:6', 'max:200' ),
		'phone' => array( 'required', 'numeric', 'digits_between:8,25' ),
		'pin_code' => array( 'required', 'alpha_num', 'max:25' ),
	);

}	//end of class


//EOF

This is the class that we will instantiate to validate our form data. We have set the validation rules in this class and so we would just need to call validate() method on its object and pass our form data to it.

Note: If you have not made the artisan tool in your project directory an executable then you would need to replace ./artisan from the artisan commands in this tutorial and replace with /path/to/php artisan.

It is recommended you make artisan an executable, it saves the needless hassle to prefix php on every command.

Let’s make a Controller and a form properly to take this for a spin. In your terminal, navigate to your project directory and run

./artisan controller:make DummyController --only=create,store

It would create app/controllers/DummyController.php with two methods – create() and store(). Open up app/routes.php and add the following route directive.

Route::resource( 'dummy', 'DummyController', array(
	'only' => array( 'create', 'store' ),
) );

This will set up our Controller to work in a RESTful way; /dummy/create/ would accept GET requests and /dummy/store/ would accept POST requests. We can remove the only directive from both route and artisan command and the Controller would accept PUT and DELETE requests too but for the current exercise we don’t need them.

Now we need to add the code to our Controller, so open up app/controllers/DummyController.php. It would be an empty shell with create() and store() methods. We need to make create() render a view, so make it like this:

	/**
	 * Show the form for creating a new resource.
	 *
	 * @return Response
	 */
	public function create() {
		return View::make( 'dummy/create' );
	}

We now need the view which we are rendering here and which will render our form.

First let’s create a layout file where we can put the HTML boilerplate code. Create layouts directory inside app/views and create default.blade.php inside it. Note the .blade suffix of the view name here. It tells Laravel that this view uses Laravel’s Blade templating syntax and should be parsed as such. Open it up and add the following boilerplate code to it:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1">

		<title>Advanced Data Validations Demo</title>

		<!-- Bootstrap core CSS -->
		<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">

		<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
		<!--[if lt IE 9]>
			<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
			<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
		<![endif]-->
	</head>

	<body>
		<div class="row">
			<h1 class="col-md-6 col-md-offset-3">Advanced Data Validations Demo</h1>
		</div>
		<p>&nbsp;</p>

		<div class="container">
			@yield( "content" )
		</div><!-- /.container -->

		<!-- Bootstrap core JavaScript -->
		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
		<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
	</body>
</html>

It is simple boilerplate code for an HTML page which uses Bootstrap. The only thing to notice here is the placeholder where we would inject our view code; @yield( "content" ) will tell Laravel’s Blade parser that our view’s content section code should be injected at this place.

Now create app/views/dummy/create.blade.php and add following code to it:

@extends( "layouts/default" )

@section( "content" )
	<div class="row">
		<h3 class="col-md-6 col-md-offset-2">Test Form</h3>
	</div>
	<p>&nbsp;</p>
	@if ( ! $errors->isEmpty() )
	<div class="row">
		@foreach ( $errors->all() as $error )
		<div class="col-md-6 col-md-offset-2 alert alert-danger">{{ $error }}</div>
		@endforeach
	</div>
	@elseif ( Session::has( 'message' ) )
	<div class="row">
		<div class="col-md-6 col-md-offset-2 alert alert-success">{{ Session::get( 'message' ) }}</div>
	</div>
	@else
		<p>&nbsp;</p>
	@endif

	<div class="row">
		<div class="col-md-offset-2 col-md-6">
			{{ Form::open( array(
				'route' => 'dummy.store',
				'method' => 'post',
				'id' => 'test-form',
			) ) }}
				<div class="form-group">
					{{ Form::label( 'name', 'Name:' ) }}
					{{ Form::text( 'name', '', array(
						'id' => 'name',
						'placeholder' => 'Enter Your Full Name',
						'class' => 'form-control',
						'maxlength' => 200,
					) ) }}
				</div>
				<div class="form-group">
					{{ Form::label( 'email', 'Email:' ) }}
					{{ Form::text( 'email', '', array(
						'id' => 'email',
						'placeholder' => 'Enter Your Email',
						'class' => 'form-control',
						'maxlength' => 200,
					) ) }}
				</div>
				<div class="form-group">
					{{ Form::label( 'phone', 'Phone:' ) }}
					{{ Form::text( 'phone', '', array(
						'id' => 'phone',
						'placeholder' => 'Enter Your Phone Number',
						'class' => 'form-control',
						'maxlength' => 25,
					) ) }}
				</div>
				<div class="form-group">
					{{ Form::label( 'pin_code', 'Pin Code:' ) }}
					{{ Form::text( 'pin_code', '', array(
						'id' => 'pin_code',
						'placeholder' => 'Enter Your Pin Code',
						'class' => 'form-control',
						'maxlength' => 25,
					) ) }}
				</div>
				<div class="form-group">
					{{ Form::submit( '&nbsp; Submit &nbsp;', array(
						'id' => 'btn-submit',
						'class' => 'btn btn-primary',
					) ) }}
				</div>
			{{ Form::close() }}
		</div>
	</div>
@stop

In this view we first tell Laravel that we want to use the default.blade.php layout using the directive @extends( "layouts/default" ). Then we create the content section as that is the one we have set to be injected in the layout. The view renders a form with Name, Email, Phone and Pin Code fields using Laravel’s form builder (we could use HTML5 fields here with the basic browser validation enabled, like for Email we could use Form::email(), but since we want to check our server side validation we are using normal text fields for input). Also above the form we check whether we have anything in the $errors var and to display it if there are any errors. Also we check for any flash message that we might have.

If we now navigate to http://<your-project-domain>/dummy/create (the assumption here is that you have already setup a domain on your development stack for this project) then we will have the form rendered for us. Now we need to be able to accept the data from this form and have the data validated. So back in our DummyController we would inject our TestFormValidator in the constructor and accept the data in store() and validate it. So the Controller would look like this now:

<?php

use RocketCandy\Exceptions\ValidationException;
use RocketCandy\Services\Validation\TestFormValidator;

class DummyController extends BaseController {

	/**
	 * @var RocketCandy\Services\Validation\TestFormValidator
	 */
	protected $_validator;

	public function __construct( TestFormValidator $validator ) {
		$this->_validator = $validator;
	}

	/**
	 * Show the form for creating a new resource.
	 *
	 * @return Response
	 */
	public function create() {
		return View::make( 'dummy/create' );
	}


	/**
	 * Store a newly created resource in storage.
	 *
	 * @return Response
	 */
	public function store() {
		$input = Input::all();

		try {
			$validate_data = $this->_validator->validate( $input );

			return Redirect::route( 'dummy.create' )->withMessage( 'Data passed validation checks' );
		} catch ( ValidationException $e ) {
			return Redirect::route( 'dummy.create' )->withInput()->withErrors( $e->get_errors() );
		}
	}


}	//end of class

//EOF

Laravel will take care of the dependency injection in the constructor as all Controllers are resolved out of its IoC container by default, so we don’t have to worry about that. In the store() method we grab all the form input in a var and inside try/catch we pass the data to our validation service. If the data validates then it will redirect us back to the form page with a success message else it will throw ValidationException which we will catch, grab the errors and return back to the form to display what went wrong.

Summary

In this first part, we learned how to do data validations the Laravel way and how to abstract out validation to a service which can be used to validate data for each entity anywhere in the app. In the next and final part we will learn how to extend Laravel’s validation package to have our own custom rules.


Got thoughts? Questions? Fire away in the comments.

Data Validation in Laravel - The Right Way

Data Validation in Laravel: The Right Way – Custom Validators >>

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.dolcy.com/ Shaughn Dolcy

    Absolutely awesome article Amit. Going to apply this modular approach alongside Ardent, which is great as well. Cheers.

    • http://amitgupta.in/ Amit Gupta

      Glad you liked it Shaughn. :)

  • M S

    “If you use any application framework as the foundation of your app,
    chances are it will have its own or a recommended 3rd party data
    validation package”

    And if i don’t?

    I think your example seems enormously more obtuse and complicated, than the first bit of code that you call “stone age”.
    It looks like some crazy gobbledygook of different syntaxes and serverside- code, and clientside-code, all mixed up in one bowl.
    I have no idea on how to even start making sense of it.

    If i understand correctly, i need at least 3-5 levels of different frameworks piled ontop of each-other to make this work?

    What exactly is wrong with simple, easy to understand, dependency-free code anyway?
    And why again, is that “stone age”?

    • http://amitgupta.in/ Amit Gupta

      > And if i don’t?

      Then don’t. Nobody is forcing you to. This article is specifically about Laravel and generally about if you’re using a framework. Even if you’re not then also separation of concerns is a good practice.

      > It looks like some crazy gobbledygook of different syntaxes and serverside- code,
      > and clientside-code, all mixed up in one bowl.

      The only *client side* code in the article is the form creation which is used to test data validation service that is created.

      > If i understand correctly, i need at least 3-5 levels of different frameworks piled
      > ontop of each-other to make this work?

      No you didn’t understand it, not even close. The code in this article (& its conclusive 2nd part) is only about Laravel, no other framework referenced or required. The layout I created pulls in Bootstrap from its CDN however thats not needed at all, it’ll just make your form look good when you try it out.

      > What exactly is wrong with simple, easy to understand, dependency-free code anyway?
      > And why again, is that “stone age”?

      You’ll have to ask an anthropologist why they call that period of human history “stone age” when people used simple tools like a sharpened shard of rock as a knife or similar shard tied to a wood stick to use as spear. They were very simple tools, effective & totally uncomplicated! One might have to wonder why did we bother making computers at all, they’re utterly complicated contraptions which can bamboozle brightest of minds! :)

      • master_chef

        // off topic

        ‘when people used simple tools like a sharpened shard of rock as a knife’
        – well these days ceramic blade knifes are the high end in kitchen you now :)

        • http://amitgupta.in/ Amit Gupta

          //off-topic
          Indeed, what with laser edged knives & all! ;)

          Now that you mention it, ceramic is synthetic material, not same as rock/stone. I don’t think humans created ceramic knives/spear heads back then given that ceramic objects from that period were made of clay hardened in fire (not strong enough for a weapon). :)

  • Adrian Voicu

    I was just about to say “Are you for real???”, but then, M S said it better than me… After this, I think I will stick with what you call “stone age” level :))

  • http://martinbean.co.uk/ Martin Bean

    I think this is a bit over-engineered. At the moment, I have a $rules property in my model classes, and each model class has a isValid() method that creates a validation object and validates the currently-set attributes against the rules, and returns either true or false. Then in my controller, I can set the attributes on the model, and then call $model->isValid() to validate it.

    Simple, and cuts out the need for multiple classes per domain object. This is Laravel, not Zend Framework or Symfony—code should be concise and simple.

    • http://amitgupta.in/ Amit Gupta

      > This is Laravel, not Zend Framework or Symfony—code should be concise and simple.

      That would be like saying Laravel shouldn’t be used for anything but a small app. When a project expands, a DDD approach saves lot of headache in development and in maintenance as well. For that, the basic idea is separation of concerns.

      • http://martinbean.co.uk/ Martin Bean

        Not at all. You missed my point. Large apps can be built with Laravel, but without over-engineering things so you’re lumbered with a monolithic codebase like you would be if you were using the aforementioned frameworks.

        If I need to change how validation works, I’d rather do it in one class than across several.

        • http://amitgupta.in/ Amit Gupta

          No actually I got what you were implying. The small app comment was a jest. :)

          But really, bundling up a lot of stuff in single class doesn’t work in long run when you have a ton of people working on the codebase. I used to do that years ago and then got to the point where classes became bloated with too many responsibilities being handled by every class (not to mention a lot of repetitive code) and maintaining the code was a hellish chore.

  • Tony Marston

    You may think that this is the right way to perform data validation, but I do not.

    Firstly I have to disagree with your statement that data validation does not belong in the Model whose job, you say, is to act as a broker between data source and rest of the application. It should only accept data for saving and give it when asked. What you are describing here is not the Model but the Data Access Object. It is the DAO which generates the queries which access the physical database, not the Model. The Controller communicates with the Model, and the Model applies all the rules and communicates with the DAO as and when necessary. This approach allows the DAO to be switched between one DBMS and another without having to change anything in any Model class. This means that each Model contains all the information regarding its respective application entity which in turn means that neither the Controller nor the View components contain any knowledge about the application at all. This means that when the Controller tells a Model to insert some data, the Model will validate it and will only pass that request on to the DAO if all validation passes. When the Controller is reactivated it checks to see in the Model contains any error messages so that it can take the appropriate action.

    Your definition of the Single Responsibility Principle is that each class should have one and only one *JOB* to perform. I disagree completely. It should mean that each class is responsible for a single ENTITY, not JOB, and that class should contain all the properties and all the methods for that entity. This means that the class should have methods for Create, Read, Update and Delete and these methods may require different levels of validation before the request is passed on to the DAO.

    Secondly I am surprised at the amount of code which you have to write to validate the data. In my own framework I don’t have to write any at all. How do I manage this? My data validation is all performed in a single validation object which accepts
    two arguments – an array of data and an array of validation rules. I do not have to write out the rules by hand for the simple reason that my framework generates them for me automatically from the database schema. This identifies each field/column which exists in each table along with its size and type and if it’s optional or required, et cetera, and this information is all I need to validate the data.

    My approach is simpler to understand and quicker to build, so your way has absolutely no appeal for me.

    • http://amitgupta.in/ Amit Gupta

      > In my own framework I don’t have to write any at all.

      Ah yes, the magical framework. You just will it and it performs without you having to write any code. It also does the trans-warp beaming right? Would be beneficial to know if anyone wanted to go to Kronos for some R&R.

      • Tony Marston

        It is not magic, it is basic programming. All the possible rules for validating data, such as type, size, optional/required, et cetera, are well known, so instead of writing a fresh piece of code within each entity to apply those rules you write a single validation function which has two input arrays – one containing data and another containing the rules – and call this central function each time you want to validate some data. The next step is to have the framework generate the validation rules for you from the database schema so that you don’t have to code them yourself.
        This is why I say that I don’t have to write any code to perform data validation – I wrote a validation function once so that I can follow the DRY principle and not have to write another ever again. I don’t have to write the validation rules for each entity because the framework generates it for me.
        There is nothing magical or mystical about it. Any competent programmer can do it.

    • PFY

      There are some validations that do belong in the model such as constraints that match the column definitions, however there are easily validations that don’t fit which may be related to business logic. A simple example is a field which users may not enter a non foreign phone number into, but a customer service representative is allowed more flexibility. I don’t think it’s a matter of where the validation belongs, but where the validation belongs for your project.

      • Tony Marston

        As far as I am concerned *ALL* validation belongs in the Model for the simple reason that *NO* validation should ever be performed in either the Controller, the View or the Data Access Object.
        In the 3-Tier Architecture *ALL* validation is performed in the Business layer and *NONE* is performed in either the Presentation or Data Access layers.

  • Charles Bryant

    I mainly agree with this method of abstracting your validation class, I use the same concept that I took from Jeffery Way’s net tut plus video tutorial on validation.

    Your addition of throwing exceptions I do not really agree with, throwing an exception. As per wikipedia’s definition:

    “Exception handling is the process of responding to the occurrence, during computation, of exceptions – anomalous or exceptional events requiring special processing – often changing the normal flow of program execution.”

    I think you would expect input to be invalid.

    I would have a method that asks isValid ? If it is not valid your error messages should be available in your class, to be returned to the user.

    • Tony Marston

      I with you on this, Charles. Using exceptions for simple validation errors is wrong. Why? Apart from the fact that they are *normal* and not “exceptional* errors, you can only throw one exception whereas an array of data (such as the $_POST array) may produce multiple errors.
      As for an isValid() method – totally redundant. The validation object produces an errors property which is either empty or not.

      • Charles Bryant

        Did not specifically mean an isValid method just more the question you are asking in this case I believe the method is “validate”, but essentially that should return false and give you a reason to look at your error messages:

        if(!$foo->validate())
        {
        // do something amazing here ;-)
        }

    • http://amitgupta.in/ Amit Gupta

      I think it would depend more on thought process taken by the developer. In my opinion throwing an exception allows for more flexibility than just the plain TRUE/FALSE returned by if ( $foo->isValid() ). So like what if the rules aren’t defined in the service class or something else, an exception should be thrown then. So instead of doing

      try {
      if ( $foo->is_valid( $data ) ) {
      $entity->save( $data );
      return Redirect::route( ‘registration’ )->withMessage( ‘success’ );
      } else {
      return Redirect::route( ‘registration’ )->withInput()->withErrors( $foo->get_errors() );
      }
      } catch ( RulesNotFoundException $e ) {
      return Redirect::route( ‘registration’ )->withInput()->withErrors( $e->get_errors() );
      }

      I find it more convenient to do this

      try {
      $foo->validate( $data );
      $entity->save( $data );
      return Redirect::route( ‘registration’ )->withMessage( ‘success’ );
      } catch ( ValidationException $e ) {
      return Redirect::route( ‘registration’ )->withInput()->withErrors( $e->get_errors() );
      } catch ( RulesNotFoundException $e ) {
      return Redirect::route( ‘registration’ )->withInput()->withErrors( $e->get_errors() );
      }

      but yeah its just personal preference I’d say.

  • Roy

    This is a fantastic way of massively overcomplicating what is really a rather simple problem.

  • http://amitgupta.in/ Amit Gupta

    > So much for Laravels ease of use

    Laravel does not mandate you to do it this way. The 2nd code example in the article is all you need to do data validation in Laravel, ie., pass your validation rules & your data and thats it. It doesn’t get much simpler than that.

    The methodology highlighted in this tutorial is one which saves the effort of writing quite a bit of boiler-plate everytime you need data to be validated. The boilerplate code will need to be written one time atleast and thats what I’ve shown. For subsequent uses just extend the RocketCandyServicesValidationValidator class (created in the article above) & set validation rules for data. Thats it.

  • Ryan Exlay

    Great tutorial Gupta!
    May I ask one question?
    How to add custom error message in TestFormValidator.php

    • http://amitgupta.in/ Amit Gupta

      The validate() function accepts 3 parameters – $data, $rules & $custom_errors – in this order. The $rules have been defined in the TestFormValidator. For $custom_errors you have couple of options. Either you can set them in TestFormValidator itself then override the validator() function and pass the custom errors in there like:

      public function validate( array $data ) {

      return parent::validate( $data, $this->rules, $this->custom_errors );

      }

      Or you can pass them at run time when you call the validate(). Custom errors need to be an associative array with the key being the rule for which you’re setting custom error & value being your custom error. If you place “:attribute” (without quotes) anywhere inside your error message then Laravel will replace that placeholder with the name of the data field for which the error is raised.

      Don’t forget to check out the 2nd part of the tutorial: http://www.sitepoint.com/data-validation-laravel-right-way-custom-validators/

  • Tony Marston

    I have dealt with this very situation and it is surprisingly easy. I create a subclass of the USER class to contain the logic that applies in these circumstances, and I update the field specifications (after they have been loaded into memory) to include a second password field. I then insert extra validation code to validate that pasword2 is the same as password1. This extra code all goes in the Model – not the View, not the Controller and certainly not the DAO.

    Your statement that form validation is the responsibility of the form is misleading. The “form” is the HTML form which is a representation of the Model as generated by the View, but the View cannot contain any validation rules. Neither can the Controller. The Controller performs an action on the Model, and it is the responsibility of the Model to perform all the validation. If the validation succeeds it then passes control to the DAO so that it can update the database. If the validation fails it goes back to the Controller with one or more error messages.

    You are correct in saying that my framework is an elegant solution to my problem. My “problem” is that I only write enterprise applications which use forms to view and maintain the contents of an organisation’s database, which usually has a large amount of data spread across hundreds of database tables, and thousands of different forms/screens to view that data. My framework makes the generation of software components very easy because it can generate the basic components to perform Create/Read/Update/Delete operations without me having to write a single line of code – no PHP, no HTML, no SQL. Can your framework do that? The only classes which I have to modify to perform custom or non-standard processing are the Model classes.

  • Andres

    I am new to Laravel and see a very complicated approach for me at the time for data validation. I am currently validating data in the Model. Nonetheless, I think it is a good approach to decouple responsibilities and would definitely try this once I work more with Laravel. Thanks Amit for the tutorial. :D

    I read some discussion about where to handle validation in comments below. My opinion: everyone has its way for doing things. One could agree or disagree with the approach Amit is using but it doesn’t mean !isValid() (had to use the method here. lol)