├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app └── Validators │ └── Validator.php ├── composer.json ├── phpunit.xml ├── src ├── Commands │ ├── ValidatorMakeCommand.php │ └── stubs │ │ └── validator.stub ├── ValidationServiceProvider.php └── Validator.php └── tests ├── .gitkeep └── ValidatorTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | *.sublime-* 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5.9 5 | - 5.5 6 | - 5.6 7 | - 7.0 8 | - hhvm 9 | 10 | sudo: false 11 | 12 | install: 13 | - travis_retry composer install --no-interaction --prefer-source 14 | 15 | script: vendor/bin/phpunit 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Sam Rapaport 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Validation 2 | 3 | [![StyleCI](https://styleci.io/repos/59241241/shield?style=flat)](https://styleci.io/repos/59241241) 4 | [![Build Status](https://travis-ci.org/samrap/laravel-validation.svg?branch=master)](https://travis-ci.org/samrap/laravel-validation) 5 | [![Latest Stable Version](https://poser.pugx.org/samrap/laravel-validation/v/stable)](https://packagist.org/packages/samrap/laravel-validation) 6 | [![Total Downloads](https://poser.pugx.org/samrap/laravel-validation/downloads)](https://packagist.org/packages/samrap/laravel-validation) 7 | [![Latest Unstable Version](https://poser.pugx.org/samrap/laravel-validation/v/unstable)](https://packagist.org/packages/samrap/laravel-validation) 8 | [![License](https://poser.pugx.org/samrap/laravel-validation/license)](https://packagist.org/packages/samrap/laravel-validation) 9 | 10 | ### Laravel Validation 11 | --- 12 | Laravel Validation is a bare-bones, minimal validation package for the Laravel framework. Its only purpose is to provide a way to separate your request validation rules from your models and controllers, neither of which should contain such information. It accomplishes this by essentially acting as a broker between your validation rules and a Laravel validator instance. 13 | 14 | ```php 15 | public function store(Request $request, ModelValidator $validator) 16 | { 17 | $validator = $validator->validate($request->all()); 18 | $this->validateWith($validator, $request); 19 | 20 | ... 21 | } 22 | ``` 23 | 24 | ### But I'm Using Form Requests 25 | --- 26 | If you're using [Form Requests](https://laravel.com/docs/5.2/validation#form-request-validation), then this package won't be of use. If you prefer to explicitly validate requests from within your controllers but want to keep your validation rules separate, then give Laravel Validation a try! 27 | 28 | ### Installation 29 | --- 30 | Install via Composer: 31 | 32 | `composer require samrap/laravel-validation` 33 | 34 | Then add the service provider to your providers array in `config/app.php`: 35 | 36 | ```php 37 | Samrap\Validation\ValidationServiceProvider::class 38 | ``` 39 | 40 | Finally, the base `Validator` class needs to be published to a new `app/Validators` directory. This can be done using the `vendor:publish` command: 41 | 42 | `php artisan vendor:publish --provider="Samrap\Validation\ValidationServiceProvider"` 43 | 44 | ### Usage 45 | --- 46 | All validators reside in the `app/Validators` directory and extend the class `App\Validators\Validator`. There should be one validator class per model. For example, the validator for a `User` model could be called `UserValidator`. 47 | 48 | Laravel Validation provides a useful artisan command for generating new validators on the fly. Let's create a validator for our `User` model and define some rules: 49 | 50 | `php artisan make:validator UserValidator` 51 | 52 | This will create a new `UserValidator` class in the `app/Validators` directory that looks like this: 53 | 54 | ```php 55 | namespace App\Validators; 56 | 57 | use App\Validators\Validator; 58 | 59 | class UserValidator extends Validator 60 | { 61 | /** 62 | * The validation rules. 63 | * 64 | * @var array 65 | */ 66 | protected $rules = []; 67 | } 68 | ``` 69 | 70 | Each validator has a `rules` property which (suitably) houses all the validation rules for the intended model. Let's define some basic rules for this validator: 71 | 72 | ```php 73 | /** 74 | * The validation rules. 75 | * 76 | * @var array 77 | */ 78 | protected $rules = [ 79 | 'email' => 'email|required|max:255|unique:user', 80 | 'password' => 'min:8|confirmed', 81 | ]; 82 | ``` 83 | 84 | Great! We now have a validator class named `UserValidator` with the rules we intend to validate with in our controller. Let's jump over to the `UserController` and see how to use this new validator class. 85 | 86 | First, we will want to import this class into our controller: 87 | 88 | `use App\Validators\UserValidator` 89 | 90 | Now, let's validate a POST request for the controller's `store` method: 91 | 92 | ```php 93 | public function store(Request $request, UserValidator $validator) 94 | { 95 | $validator = $validator->validate($request->all()); 96 | $this->validateWith($validator, $request); 97 | 98 | ... 99 | } 100 | ``` 101 | 102 | A few things are going on here. Let's go line by line. 103 | 104 | First, in addition to the current request, we are type hinting an instance of our `UserValidator` as it has dependencies that should be resolved via the service container: 105 | 106 | ```php 107 | public function store(Request $request, UserValidator $validator) 108 | ``` 109 | 110 | Our validator inherits a `validate` method from its parent class, `Samrap\Validation\Validator`, which we can use to obtain an `Illuminate\Validation\Validator` instance. Our `validate` method takes the same arguments as if we were [manually creating a validator](https://laravel.com/docs/5.2/validation#manually-creating-validators) using Laravel's `Validator::make` method (more on this later). So, we will simply pass the request input to the `$validator->validate()` method: 111 | 112 | ```php 113 | $validator = $validator->validate($request->all()); 114 | ``` 115 | 116 | Finally, we can make use of Laravel's `ValidatesRequests` trait, included by default on all controllers. It provides us with a `validateWith` method, which expects a validator instance and the request and will handle redirection if the validation fails: 117 | 118 | ``` 119 | $this->validateWith($validator, $request); 120 | ``` 121 | 122 | That's it! That is all you need to do to validate your requests. The validator will use the rules defined in your `UserValidator` to validate the request, in two lines of code in your controller. Obviously, this cleans up your controllers dramatically as the amount of validation you need increases. 123 | 124 | Of course, there may be times in a certain request when you need to add to or override some of the rules you defined in your validator. No worries, it's super easy! 125 | 126 | ```php 127 | $validator = $validator->validate($request->all(), [ 128 | 'name' => 'string|required', 129 | ]); 130 | ``` 131 | 132 | In this case, we are adding a rule for a `name` field, which will be merged with our rules defined in the `UserValidator`. By default, any rules passed explicitly to the `validate` method will override the rules defined in the validator if they exist. 133 | 134 | ### Additional Features 135 | --- 136 | ##### Multiple Rulesets 137 | Laravel Validation expects a `rules` property on your validator class, but it is possible to define additional properties and use those in specific cases. You may have different requirements when updating a record vs storing, or have unique rules if a user is of a specific role. 138 | 139 | Let's define an `updating` property on the `App\Validators\UserValidator` class with specific rules for updating a user: 140 | 141 | ```php 142 | protected $updating = [ 143 | // rules... 144 | ]; 145 | ``` 146 | 147 | Then in our controller's `update` method, we can call the validator's `using` method and pass the name of the property we want to validate with: 148 | 149 | ```php 150 | public function update(Request $request, UserValidator $validator) 151 | { 152 | $validator = $validator->using('updating')->validate($request->all()); 153 | $this->validateWith($validator, $request); 154 | 155 | ... 156 | } 157 | ``` 158 | 159 | By calling the `using` method before `validate`, we are telling the validator to use the `updating` property instead of the default `rules`. 160 | 161 | ### Contributing 162 | --- 163 | Contributions are more than welcome! You can submit feature requests to [rapaport.sam7@gmail.com](mailto:rapaport.sam7@gmail.com), or fork the repo yourself! 164 | -------------------------------------------------------------------------------- /app/Validators/Validator.php: -------------------------------------------------------------------------------- 1 | =5.5.9", 19 | "illuminate/support": "~5.1", 20 | "illuminate/validation": "^5.2", 21 | "phpunit/phpunit": "^4.8", 22 | "illuminate/console": "^5.2" 23 | }, 24 | "require-dev": { 25 | "mockery/mockery": "^0.9.4" 26 | }, 27 | "minimum-stability": "dev" 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | ./tests 21 | 22 | 23 | 24 | 25 | ./src 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Commands/ValidatorMakeCommand.php: -------------------------------------------------------------------------------- 1 | publishes([ 17 | __DIR__.'/../app/' => app_path(), 18 | ], 'app'); 19 | } 20 | 21 | /** 22 | * Register the service provider. 23 | * 24 | * @return void 25 | */ 26 | public function register() 27 | { 28 | $this->commands([ 29 | 'Samrap\Validation\Commands\ValidatorMakeCommand', 30 | ]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Validator.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 39 | } 40 | 41 | /** 42 | * Get the errors from the previous validation attempt. 43 | * 44 | * @return array 45 | */ 46 | public function getErrors() 47 | { 48 | return $this->errors; 49 | } 50 | 51 | /** 52 | * Get the validator's rules. 53 | * 54 | * @return array 55 | */ 56 | public function getRules() 57 | { 58 | if (count($this->next)) { 59 | $rules = $this->next; 60 | $this->next = []; 61 | 62 | return $rules; 63 | } 64 | 65 | return $this->rules; 66 | } 67 | 68 | /** 69 | * Use a property on this class other than the default for the next validation 70 | * rules. This is useful for instances when you need a separate set of 71 | * validation rules for a certain operation, such as updating. 72 | * 73 | * @param string $property 74 | * @return \Samrap\Validation\Validator 75 | */ 76 | public function using($property) 77 | { 78 | if (property_exists($this, $property)) { 79 | $this->next = $this->$property; 80 | } else { 81 | throw new Exception('The property ['.$property.'] does not exist on this validator.'); 82 | } 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * Create a new validator. 89 | * 90 | * @param array $data 91 | * @param array $rules 92 | * @param array $messages 93 | * @param array $customAttributes 94 | * @return \Illuminate\Validation\Validator 95 | */ 96 | public function validate(array $data, array $rules = [], array $messages = [], array $customAttributes = []) 97 | { 98 | // Here we allow rules to be set as a property of the child class. Any rules 99 | // passed to this method will take precedence over the rules property. 100 | $rules = array_merge($this->getRules(), $rules); 101 | 102 | // We persist the validation errors to this class for easier access. 103 | $validator = $this->factory->make($data, $rules, $messages, $customAttributes); 104 | $this->errors = $validator->errors(); 105 | 106 | // We will return the validator instance and leave handling the success 107 | // or failure of that validation to the controller. 108 | return $validator; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samrap/laravel-validation/3b03d8b7ca06d777106d6545950ffc8105d88d20/tests/.gitkeep -------------------------------------------------------------------------------- /tests/ValidatorTest.php: -------------------------------------------------------------------------------- 1 | getValidator(); 16 | 17 | $rules = ['foo' => 'bar']; 18 | $this->assertEmpty($validator->validate($rules)->errors()); 19 | } 20 | 21 | public function testValidatorFails() 22 | { 23 | $errors = ['foo' => 'baz']; 24 | $validator = $this->getValidator($errors); 25 | 26 | $rules = ['foo' => 'bar']; 27 | $this->assertEquals($errors, $validator->validate($rules)->errors()); 28 | } 29 | 30 | public function testValidatorUsesCustomPropertyOnce() 31 | { 32 | $validator = $this->getValidator(); 33 | $customRules = ['bar' => 'baz']; 34 | $validator->custom = $customRules; 35 | 36 | $this->assertEquals($customRules, $validator->using('custom')->getRules()); 37 | $this->assertEquals($validator->rules, $validator->getRules()); 38 | } 39 | 40 | /** 41 | * @expectedException \Exception 42 | */ 43 | public function testValidatorThrowsExceptionIfUsingCustomPropertyDoesNotExist() 44 | { 45 | $validator = $this->getValidator(); 46 | 47 | $validator->using('undefined')->validate(); 48 | } 49 | 50 | protected function getValidator($errors = []) 51 | { 52 | $laravelValidator = m::mock('\Illuminate\Validation\Validator'); 53 | $laravelValidator->shouldReceive('errors')->andReturn($errors); 54 | 55 | $factory = m::mock('Illuminate\Validation\Factory'); 56 | $factory->shouldReceive('make')->andReturn($laravelValidator); 57 | 58 | $validator = new Validator($factory); 59 | $validator->rules = ['foo' => 'bar']; 60 | 61 | return $validator; 62 | } 63 | } 64 | --------------------------------------------------------------------------------