Article: Validating your data with Respect Validation

An excerpt from http://www.sitepoint.com/validating-your-data-with-respect-validation/, by Younes Rafie

Validation is an important aspect of every application’s interaction with data. Instead of reinventing the wheel every time, the community collaborated on some useful packages like Symfony, Laravel, Zend, etc. In this article, we’re going to introduce a lesser known package called Respect Validation, which provides some nice new features. Let’s get started.

Popular Validation Packages

When using a framework, there is a great chance that you have a validation component shipped with it. The Symfony Validator Component provides a set of standard validation rules that you’ll need for your application.

class UserSubscriptionForm
{
    protected $email;
 
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('email', new \Assert\Email([
            'message' => 'Invalid email.'
        ]));
    }
}

I’m sure your subscription form contains more than just an email, but let’s keep it simple. Inside your controller you’ll have to trigger the validation like so:

public function store(Request $request){
    $userSubscriptionForm = UserSubscriptionForm::fromInput($request->all());
    $validator = $this->get('validator');
    $errors = $validator->validate($userSubscriptionForm);
 
    if (count($errors) > 0) {
        // redirect with errors
    }
     
    // return success
}

After creating a new UserSubscriptionForm from the user input, we will trigger the validation and collect the validation errors if we found any.

Laravel also ships with the Illuminate validation package. It does the same job, but in a different way. Let’s use our previous validation example and convert it to Laravel.

class UserSubscriptionController extends Controller
{
    public function store(Request $request)
    {
        $validator = \Validator::make(
            [
                'email' => $request->get('email')
            ],
            [
                'email' => 'required|email'
            ]
        );
     
        if($validator->fails()){
            $errors = $validator->messages();
     
            // redirect with errors
        }
         
        // return success
    }
}

The Zend validator package is not much different from the others. For the same previous example, we can do the following:

class UserSubscriptionController extends Controller
{
    public function store(Request $request)
    {
        $validator = new Zend\Validator\EmailAddress();
 
        if(!$validator->isValid($request->get('email'))){
            $errors = $validator->getMessages();
 
            // redirect with errors
        }
 
        // return success
    }
}

I’m sure you’re already familiar with at least one of the packages mentioned above. In this article, we are going to introduce Respect/Validation and we will highlight the main differences from the other packages.

Respect Validation

The Respect validator introduces a simple way of validating your data. Let’s start by completing the same previous example.

class UserSubscriptionController extends Controller
{
    public function store(Request $request)
    {
        $emailValidator = \Respect\Validation\Validator::email();
 
        if (!$emailValidator->validate($email)) {
            // redirect with errors
        }
 
        // return success
    }
}

So, nothing new! The first thing you’ll notice is that we didn’t retrieve the list of errors after a validation failure. To retrieve the list of errors, we need to use the assert method which throws an exception containing the list of error messages.

class UserSubscriptionController extends Controller
{
    public function store(Request $request)
    {
        $emailValidator = \Respect\Validation\Validator::email();
 
       try{
           $emailValidator->assert($request->get('email'));
       }
       catch(\Respect\Validation\Exceptions\NestedValidationExceptionInterface $ex){
           $errors = $ex->getMainMessage();
           // redirect with errors
       }
 
        // return success
    }
}

We also have the ability to add multiple rules to the same value by chaining methods.

Validator::string()->noWhitespace()->length(4, 10);
Validator::numeric()->between(5, 10);
Validator::date()->between(5, 10);

Another way to validate multiple rules is to use the allOf rule which accepts a list of rules.

$inputValidator = \Respect\Validation\Validator::allOf(
    new String(),
    new Length(4, 10)
);

You probably need to validate some data to match at least one of your business rules. Let’s take the login form as an example where the user can either enter their email address or username. The username must be alpha numeric and between 4 and 16 characters long. You can check the documentation for more details about the list of available rules.

$usernameOrEmailValidator = \Respect\Validation\Validator::oneOf(
    new \Respect\Validation\Rules\Email(),
    \Respect\Validation\Validator::string()->alnum()->noWhitespace()->length(4, 16)
);

One feature that you don’t often see in validation packages is the rule negation functionality. You can specify the rules that you don’t want to match, for example.

$inputValidator = \Respect\Validation\Validator::not(\Respect\Validation\Validator::numeric());

Custom Error Messages

As mentioned earlier, when an assertion exception is thrown, you can get error messages using one of the following methods.

getFullMessage: returns a general error message with a list of the failing rules. Asserting Validator::email()->assert('notAValidEmail') will throw the following message.

\-These rules must pass for "notAValidEmail"
  \-"notAValidEmail" must be valid email

getMainMessage: returns a general error message without specifying the failing rules. The email example returns These rules must pass for "notAValidEmail.
findMessages: accepts an array as a parameter containing the list of messages for the failing rules.

    $this->messages = [
        'alpha'                 => '{{name}} must only contain alphabetic characters.',
        'alnum'                 => '{{name}} must only contain alpha numeric characters and dashes.',
        'numeric'               => '{{name}} must only contain numeric characters.',
        'noWhitespace'          => '{{name}} must not contain white spaces.',
        'length'                => '{{name}} must length between {{minValue}} and {{maxValue}}.',
        'email'                 => 'Please make sure you typed a correct email address.',
        'creditCard'            => 'Please make sure you typed a valid card number.',
        'date'                  => 'Make sure you typed a valid date for the {{name}} ({{format}}).',
        'password_confirmation' => 'Password confirmation doesn\'t match.'
    ];

 
// inside the try catch block
 
try {
    $this->rules[$input]->assert($value);
} catch (\Respect\Validation\Exceptions\NestedValidationExceptionInterface $ex) {
    dump($ex->findMessages($this->messages));
}

This will return a custom message if one the failing rules exists inside our messages array. You can read more about custom messages in the documentation.

To make things a little more practical, we will be validating a user subscription form. The form contains a set of fields to identify the user, and a small section for the billing info.

Continue reading this article on SitePoint!

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.