Giter Site home page Giter Site logo

laravel-extended-validator's Introduction

Laravel Extended Validator

Introduction

This package was created for several purposes:

  1. To ease the creation of validation services - we all know validaton should be moved out of the controller
  2. Provide an easy way to provide context for validations - such as providing a modified set of validation rules for edit vs. create
  3. Provide an easy way to group validations - that is, calling one 'passes()' method to validate multiple models

Installation

Install this package through Composer. Add the following to your composer.json file:

"require": {
    "crhayes/validation": "dev-master"
}

Next, run composer install

Finally, add the service provider and the facade to app/config/app.php.

'providers' => array(
    // ...

    'Crhayes\Validation\ValidationServiceProvider'
)

'aliases' => array(
    // ...

    'GroupedValidator' => 'Crhayes\Validation\Facade'
)

Validation as a Service

Most Basic Validator

To create a validation service simply extend the base abstract ContextualValidation class and provide an array of rules and messages (messages will override Laravel's default validation messages).

<?php

namespace App\Services\Validators;

use Crhayes\Validation\ContextualValidator;

class UserValidator extends ContextualValidator
{
    protected $rules = [
        'first_name' => 'required',
        'last_name' => 'required'
    ];

    protected $messages = [
        'first_name.required' => 'First name is required!'
    ];
}

This service is then instantiated and the validation works much the same as Laravel's built-in validation.

use App\Services\Validators\UserValidator;

...

$userValidator = new UserValidator(Input::all());
OR
$userValidator = UserValidator::make(Input::all());

...

if ($userValidator->passes()) {
  // yay, successful validation
}

// nay, get the errors
$errors = $userValidator->errors();

Contextual Validation

Providing Contexts

Sometimes you need to have different rules for the same model depending on the context you are using it within. For instance, maybe some fields are mandatory during registration, but may not be when the user is editing their profile.

We can turn our rules array into a multidimensional array, with unique keys for each of our contexts. The default key denotes our default rules, which will be used for every validation. Default rules can be overridden very easily by setting the rule in other contexts.

<?php

namespace App\Services\Validators;

use Crhayes\Validation\ContextualValidator;

class UserValidator extends ContextualValidator
{
    protected $rules = [
        'default' => [
            'first_name' => 'required',
            'last_name' => 'required'
        ],
        'create' => [
            'first_name' => 'required|max:255' // override default
        ],
        'edit' => [
            'website' => 'required|url' // add a new rule for website while editing
        ]
    ];
}

Let's see how we can use one of the contexts during the creation of a user:

use App\Services\Validators\UserValidator;

...

$userValidator = UserValidator::make(Input::all())->addContext('create');

if ($userValidator->passes()) {
  // yay, successful validation
}

// nay, get the errors
$errors = $userValidator->errors();

While editing a user, we would do this:

use App\Services\Validators\UserValidator;

$userValidator = UserValidator::make(Input::all())->addContext('edit');

if ($userValidator->passes()) {
  // yay, successful validation
}

// nay, get the errors
$errors = $userValidator->errors();

Multiple contexts can be added as well:

use App\Services\Validators\UserValidator;

$userValidator = UserValidator::make(Input::all())
    ->addContext(['create', 'profile']);

// or chained
$userValidator->addContext('create')->addContext('profile');

Providing Data to Contexts

Sometimes you need to provide data to your rules. For instance, you may have a unique rule on a field, but when editing the record you don't want an error to be thrown when the user submits a form with the value they previously had.

Luckily, we have a way to handle these instances.

<?php

namespace App\Services\Validators;

use Crhayes\Validation\ContextualValidator;

class UserValidator extends ContextualValidator
{
    protected $rules = [
        'default' => [
            'first_name' => 'required',
            'last_name' => 'required',
            'email' => 'required|email|unique:users,email'
        ],
        'edit' => [
            'email' => 'required|email|unique:users,email,@id'
        ]
    ];
} 

Notice that we have set the email field to be unique by default. However, when the users submits an edit form we want to ignore the current user's id. We use the @id placeholder, and then replace that with the desired value:

$userValidator = UserValidator::make(Input::all())
    ->addContext('edit')
    ->bindReplacement('email', ['id' => $currentUser->id]);

The method bindReplacement() takes the rule name as the first parameter; the second parameter is an array of bindings, with the key being the placeholder and value being the replacement value.

Grouped Validator

Have you ever had a form submit data that required two different models be created or updated? Validating both models can be a pain, but that's where the GroupedValidator class comes in.

Let's say we posted a form that is going to create a new user and their car; we therefore need to validate both a user and a car model.

use App\Services\Validators\UserValidator;
use App\Services\Validators\CarValidator;
use Crhayes\Validation\GroupedValidator;

$userValidator = UserValidator::make(Input::only('first_name', 'last_name'));
$carValidator = CarValidator::make(Input::only('make', 'model'));

$groupedValidator = GroupedValidator::make()
    ->addValidator($userValidator)
    ->addValidator($carValidator);

if ($groupedValidator->passes()) {
  // yay, successful validation
}

// nay, get the errors
$errors = $groupedValidator->errors(); // return errors for all validators

We can use validator contexts with grouped validation as well:

$userValidator = UserValidator::make(Input::only('first_name', 'last_name'))
    ->addContext('create');
$carValidator = CarValidator::make(Input::only('make', 'model'))
    ->addContext('create');

$groupedValidator = GroupedValidator::make()
    ->addValidator($userValidator)
    ->addValidator($carValidator);

We can also mix and match ContextualValidator services and native Laravel Validators:

$userValidator = UserValidator::make(Input::only('first_name', 'last_name'));
$carValidator = Validator::make(Input::only('make', 'model'), [
    'make' => 'required',
    'model' => 'required'
]);

$groupedValidator = GroupedValidator::make()
    ->addValidator($userValidator)
    ->addValidator($carValidator);

Adding Custom Complex Validation

Adding complex validation to your validation services is as easy as follows:

<?php

namespace App\Services\Validators;

use Crhayes\Validation\ContextualValidator;

class UserValidator extends ContextualValidator
{
    protected $rules = [
        'default' => [
            'first_name' => 'required',
            'last_name' => 'required',
            'email' => 'required|email|unique:users,email'
        ],
        'edit' => [
            'email' => 'required|email|unique:users,email,@id'
        ]
    ];
    
    protected function addConditionalRules($validator)
    {
        $validator->sometimes('some_field', 'required' function($input)
        {
            // perform a check
        });
    }
} 

All we do is add the addConditionalRules($validator) method to our validation service, which accepts an instance of Illuminate\Validation\Validator, allowing us to utilize Laravel's built-in support for complex validations.

laravel-extended-validator's People

Contributors

amhol avatar itsgoingd avatar jaspaul avatar joshuajabbour avatar sebastiaanluca avatar thebox193 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

laravel-extended-validator's Issues

Not able to set custom attribute names

It would be nice to set custom attribute names to the validator.

For now I have a little workaround, I extend your class and override the passes method, in which I've added a call to a function similar to the one to addConditionalRules that receives the Validator instance as parameter.
I named it extraValidatorOptions and in each validaor I override it and call setAttributeNames on it.

Do you think it's a good idea? Should I try and write a patch for it and do a pull request?

Laravel 4.2

Hi,
Can you upgrade the dependencies to accept laravel 4.2?
Thank you

Multiple models with identically named fields in a form

Just a quick question, but how would you handle multiple models in a form, when they have the same names? E.g. a club with a name and a manager with a name field?

You'd have to load the view with each field prefixed with the model name, and then validate it the same way, but overriding/passing all rules to the validator by hand. Which I think is quite cumbersome?

Another option, instead of the prefixing: use form arrays. For instance, all club fields as club[name] and the other as manager[name]. Post-processing would be a bit easier, but still, the validation…

Custom Validation Rules

My current code:

class UserValidator extends ContextualValidator
{
    protected $rules = [
        'default' => [
            'current_password'      => 'required|same_hash:@password',
            'password'              => 'required|confirmed|min:6',
            'password_confirmation' => 'required'
        ],
    ];

    protected $messages = [
        'current_password.same_hash' => 'Wrong current password'
    ];

    function __construct($attributes = null, $context = null)
    {
        parent::__construct($attributes, $context);

        Validator::extend('same_hash', function($attribute, $value, $parameters)
        {
            if( ! Hash::check( $value , $parameters[0] ) )
            {
                return false;
            }
            return true;
        });
    }
}

I think its better if we can handle custom rules by creating function like this:

function validateSameHash(){
    // logic here
}

Array syntax incompatible with minimum php dependency in composer.json

I recently got to using this package, which I think is terrific by the way, but noticed that the array syntax was of the newer style [ ] and the php dependency in composer was >= 5.3. If there is will to leave the inclusion of 5.3 then the syntax should be changed back to array() as it will throw an exception in 5.3.

Version for laravel 4.2

It would have been nice to have a final release for laravel 4.2, as I was using it in an application and the recent update that requires 5.0 broke my deps.

Edit: For now I've forked the repo and tagged this commit as 0.7.5: 271e27a

Input only return all the default rules message.

Hi,

The passes function in the ContextualValidator class return the error message for all the default rules even when only a certain input is validated using the input only fields.

In controller

  $userValidator = UserValidator::make(Input::only('email'));

 if ($userValidator->passes()) {

            echo "ok";
        }
        else{
            $errors = $userValidator->errors();
            dd($errors);
        }

The error message output


object(Illuminate\Support\MessageBag)#216 (2) { ["messages":protected]=> array(3) { ["first_name"]=> array(1) { [0]=> string(33) "The first name field is required." } ["last_name"]=> array(1) { [0]=> string(32) "The last name field is required." } ["email"]=> array(1) { [0]=> string(28) "The email format is invalid." } } ["format":protected]=> string(8) ":message" }

Laravel 5 Error

Getting the following error after installing with the provided instructions in the readme. Latest version of Laravel 5. Any help would be appreciated.

BadMethodCallException in ServiceProvider.php line 226:
Call to undefined method [package]
in ServiceProvider.php line 226
at ServiceProvider->__call('package', array('crhayes/validation')) in ValidationServiceProvider.php line 21
at ValidationServiceProvider->boot()
at call_user_func_array(array(object(ValidationServiceProvider), 'boot'), array()) in Container.php line 523
at Container->call(array(object(ValidationServiceProvider), 'boot')) in Application.php line 672
at Application->bootProvider(object(ValidationServiceProvider)) in Application.php line 654
at Closure$Illuminate\Foundation\Application::boot(object(ValidationServiceProvider))
at array_walk(array(object(EventServiceProvider), object(RoutingServiceProvider), object(AuthServiceProvider), object(ControllerServiceProvider), object(CookieServiceProvider), object(DatabaseServiceProvider), object(EncryptionServiceProvider), object(FilesystemServiceProvider), object(FormRequestServiceProvider), object(FoundationServiceProvider), object(PaginationServiceProvider), object(SessionServiceProvider), object(ValidationServiceProvider), object(ViewServiceProvider), object(AppServiceProvider), object(BusServiceProvider), object(ConfigServiceProvider), object(EventServiceProvider), object(RouteServiceProvider), object(SentinelServiceProvider), object(CorsServiceProvider), object(HashidsServiceProvider), object(RepositoryServiceProvider), object(ValidationServiceProvider), object(BusServiceProvider), object(TranslationServiceProvider)), object(Application::boot;1651806084)) in Application.php line 655
at Application->boot() in BootProviders.php line 15
at BootProviders->bootstrap(object(Application)) in Application.php line 167
at Application->bootstrapWith(array('Illuminate\Foundation\Bootstrap\DetectEnvironment', 'Illuminate\Foundation\Bootstrap\LoadConfiguration', 'Illuminate\Foundation\Bootstrap\ConfigureLogging', 'Illuminate\Foundation\Bootstrap\HandleExceptions', 'Illuminate\Foundation\Bootstrap\RegisterFacades', 'Illuminate\Foundation\Bootstrap\RegisterProviders', 'Illuminate\Foundation\Bootstrap\BootProviders')) in Kernel.php line 195
at Kernel->bootstrap() in Kernel.php line 106
at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 84
at Kernel->handle(object(Request)) in index.php line 53

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.