djekl
5/1/2014 - 3:06 PM

Demonstration of a simple wrapper for Laravel's Validator that allows rules to be altered based on input before validating and exceptions as

Demonstration of a simple wrapper for Laravel's Validator that allows rules to be altered based on input before validating and exceptions as transports for validation errors

<?php
use Illuminate\Support\MessageBag;

/**
 * An exception class that acts as a transport for validation input and failures
 */
class ValidationFailureException extends InvalidArgumentException
{
    protected $errors;

    protected $input = array();

    public function __construct($message = '', $code = 0, Exception $previous = null)
    {
        parent::__construct($message, $code, $previous);
        $this->errors = new MessageBag;
    }

    public function setErrors(MessageBag $errors)
    {
        $this->errors = $errors;

        return $this;
    }

    public function getErrors()
    {
        return $this->errors;
    }

    public function setInput(array $input)
    {
        $this->input = $input;

        return $this;
    }

    public function getInput()
    {
        return $this->input;
    }

}
<?php

class SampleUserValidator extends LaravelValidator
{
    protected $rules = array(
        'username'  => 'required|min:8',
        'password'  => 'required|min:8',
        'first'     => 'required|min:2',
        'last'      => 'required|min:2',
        'email'     => 'required|email'
    );

    protected function modifyRules(array $input, array $rules)
    {
        $id = isset($input['id']) ? $input['id'] : null;
        $rules['username'] .= ($id) ? "|unique:users,username,$id" : '|unique:users';
        $rules['email'] .= ($id) ? "|unique:users,email,$id" : '|unique:email';
        return $rules;
    }
}
<?php

use Illuminate\Support\MessageBag,
    Illuminate\Validation\Factory;

/**
 * A simple wrapper for Laravel's native validator. Allows
 * validation rules to be modified pre-validation based on
 * input and can be used to throw an exception with the
 * input and validation failures
 */
abstract class LaravelValidator
{
    /**
     * Validation messages to use per rule when failures occur
     * @var array
     */
    protected $messages = array();

    /**
     * Validation rules to be tested against the provided input
     * @var array
     */
    protected $rules = array();

    /**
     * Any failures from the last validation
     * @var MessageBag
     */
    protected $errors;

    public function __construct(Factory $validatorFactory)
    {
        $this->factory = $validatorFactory;
        $this->errors = new MessageBag;
    }

    /**
     * This function can be overridden to modify the validation rules based on input
     * for example to exclude an id from a uniqueness constraint
     * @param array $input The input to be validated
     * @param array $rules The initial rules
     * @return array       The modified rules based on input
     */
    protected function modifyRules(array $input, array $rules)
    {
        return $rules;
    }

    /**
     * Performs the actual validation
     * @param array $input The input to validate
     * @return bool        True if validation passes, false otherwise
     */
    public function validate(array $input)
    {
        $rules = $this->modifyRules($input, $this->rules);
        $validator = $this->factory->make($input, $rules, $this->messages);
        $passes = $validator->passes();
        $this->errors = ($passes) ? new MessageBag : $validator->messages();
        return $passes;
    }

    /**
     * Returns any errors that occurred during the last validation attempt
     * @return MessageBag
     */
    public function getErrors()
    {
        return $this->errors;
    }

    /**
     * Performs validation and throws a ValidationFailureException with errors
     * and input if validation fails
     * @param array $input
     */
    public function assertValid(array $input)
    {
        if(!$this->validate($input)) {
            $this->throwValidationException($input, $this->errors);
        }
    }

    /**
     * Creates, configures, and throws a validation exception
     * @param array      $input  The validated input
     * @param MessageBag $errors The validation failures
     * @throws ValidationFailureException The thrown exception
     */
    protected function throwValidationException(array $input, MessageBag $errors)
    {
        $exception = new ValidationFailureException('Validation Failed.');
        $exception->setErrors($errors)->setInput($input);
        throw $exception;
    }

}