I am upgrading my Laravel application from 4 to 5. However, I have a custom validator that I cannot get to work.
In L4, I made a validators.php file and included it in global.php using require app_path().'/validators.php';.
I tried doing somewhat the same in L5. I dropped a validator in app/Validators/Validators.php, and updated my composer.json.
"files": [
"app/Validators/Validators.php"
]
However, now nothing renders on any page. What've I done wrong?
Try the following:
Make a bind class where you can implement each rule you want extending Validator class.
Make a service provider that extends ServiceProvider.
Add your custom validator provider at config/app.php file.
You can create the bind at Services folder like this:
namespace MyApp\Services;
class Validator extends \Illuminate\Validation\Validator{
public function validateFoo($attribute, $value, $parameters){
return $value == "foo"
}
}
Then, use a service provider to extends the core:
namespace MyApp\Providers;
use MyApp\Services\Validator;
use Illuminate\Support\ServiceProvider;
class ValidatorServiceProvider extends ServiceProvider{
public function boot()
{
\Validator::resolver(function($translator, $data, $rules, $messages)
{
return new Validator($translator, $data, $rules, $messages);
});
}
public function register()
{
}
}
Finally, import your service provider at config/app.php like so:
'providers' => [
...
...
'MyApp\Providers\ValidatorServiceProvider';
]
so here's what I did on adding a custom validation. this is for laravel 5.1
run PHP Artisan make:request MyFormValidationRequest file is created under app\Requests\MyFormValidationRequest.php
Here's the initial code:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class MyFormValidationRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
//
];
}
}
IMPORTANT: Change the return value of authorize() method to true, if you're not doing any authentication. it's initial value is false. else you get a white page with a "Forbidden" error message.
I added a rule under the function rules(), here's what it looks like
public function rules() {
return [
'activeuntil' => 'today_onwards'
];
}
today_onwards is my new validation.
I created a folder named 'Services' under App folder
I created a file named 'ValidatorExtended.php' under App\Services folder , here's the code below:
<?php
namespace App\Services;
use Illuminate\Validation\Validator;
use Carbon\Carbon;
class ValidatorExtended extends Validator {
private $_custom_messages = array(
"today_onwards" => "The :attribute must be today onwards",
);
public function __construct( $translator, $data, $rules, $messages = array(), $customAttributes = array() ) {
parent::__construct( $translator, $data, $rules, $messages, $customAttributes );
$this->_set_custom_stuff();
}
protected function _set_custom_stuff() {
//setup our custom error messages
$this->setCustomMessages( $this->_custom_messages );
}
protected function validateTodayOnwards( $attribute, $value ) {
$now = strtotime('-1 day');
$valueDateFormat = strtotime($value);
if($valueDateFormat > $now){
return true;
}
else {
return false;
}
}
}
Note: the validateTodayOnwards method is where you put your logic.
the name of the method should always start in "validate" then the name of your new validation key which should be in title case,
Another note your validation key should be separated by underscore and all small letters, in this case, "today_onwards". the underscore should be put before all first capital letters in the method name. I hope I explained it good.
TodayOnwards method is equivalent to validation name of "today_onwards",
another example, if I created validateOldPassword, your validation key should be "old_password".
I added below code in app\Providers\AppServiceProvider.php inside boot() method.
Validator::resolver(function($translator, $data, $rules, $messages = array(), $customAttributes = array())
{
return new ValidatorExtended($translator, $data, $rules, $messages, $customAttributes);
});
Don't forget to add below library, one is the Validator class and the other is your own class which is the "ValidatorExtended".
use App\Services\ValidatorExtended;
use Illuminate\Support\Facades\Validator;
Here's what the whole file looks like, [app\Providers\AppServiceProvider.php]
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\ValidatorExtended;
use Illuminate\Support\Facades\Validator;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
Validator::resolver(function($translator, $data, $rules, $messages = array(), $customAttributes = array())
{
return new ValidatorExtended($translator, $data, $rules, $messages, $customAttributes);
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
That's it. done. you created your own custom validation.
Additionally, if you want to use it in your controller, below is the code:
class testController extends Controller
{
public function updatePass(MiscValidation $request){
//code here
}
}
Instead of using Request Class you use your own class which is an extension of the Request class.
Related
I am trying to implement a custom validation rule within lumen and I am following the docs for lumen 5.6. It says to refer to laravel validation to see how to use the validation. I am currently trying to make a validation to check if the value is a true null or not. So $x === "" would mean it fails Here is my rule located in App\Rules folder I created.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class TrueNull implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if($value === "") {
return false;
} else {
return true;
}
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute cannot be an empty string.';
}
}
I copied this straight from lumen docs and make my modification to the passes function. Within my modal have
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;
use App\Rules\TrueNull;
use Validator;
Then
public function validate($data)
{
// make a new validator object
$v = Validator::make($data,
[
'x' => ['regex:/^(?=.+)(?:[1-9]\d*|0)?(?:\.\d+)?$/', new TrueNull]
]
}
But the validation for TrueNull never happens am I missing a connection or something its really frustrating because the docs says this should work.
Here is my controller calling the update I am validating.
public function update(Request $request, $id)
{
/*
In middleware need to add community id to request.
*/
try {
$site = Site::findOrFail($id);
if ($site->validate($request->all())) {
$site->fill($request->all());
// save
$site->save();
} else {
return response()->json($site->errors(), 422);
}
} catch (Exception $e) {
return response()->json($e, 422);
}
return response()->json($site, 200);
}
For future reference I found a random snippet of code that offset the basic docs of Lumen. In my class for TrueNull instead of implements Rule I changed this to implements ImplicitRule and changed the use to \ImplicitRule and it is now catching that "" is not a null.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\ImplicitRule;
class TrueNull implements ImplicitRule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if($value === "") {
return false;
} else {
return true;
}
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute cannot be an empty string.';
}
}
The answer is greate by #Alexander Beyers but it doesn't work for Lumen 5.3. Here is how to create organised custom rules for the Lumen 5.3.
Create a Directory name Rules under app dir and Create the Following File:
namespace App\Rules;
use Illuminate\Support\Facades\Validator;
class AlphaSpace
{
public static function validate(){
//Extending the custom validation rule.
Validator::extend('alpha_spaces', function ($attribute, $value) {
// This will only accept alpha and spaces.
// If you want to accept hyphens use: /^[\pL\s-]+$/u.
return preg_match('/^[\pL\s]+$/u', $value);
});
}
}
Open the file resources/lang/en/validation and add the following under the Custom Validation:
Note:(under the Custom Validation is only for maintenance)
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'alpha_spaces' => 'The :attribute may only contain letters and spaces.',
Call the rule in app/Providers/AppServiceProvider::boot():
use HRM\Core\Rules\AlphaSpace;
class AppServiceProvider extends ServiceProvider
{
public function boot() {
AlphaSpace::validate();
}
// class will carry on with the stuffs!
Now you can use it anywhere you want to like this:
'first_name' => 'required|alpha_spaces|min:3|max:50',
'last_name' => 'required|alpha_spaces|min:3|max:50',
Version: Lumen 7.X
First, declare your rule in app/Providers/AppServiceProvider.php.
Create a boot() with your rule method as following (I registered a rule for phone number).
public function register()
{
//
}
public function boot()
{
app('validator')->extend('phone', function ($attribute, $value) {
return preg_match('%^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$%i', $value) && strlen($value) >= 10;
});
app('validator')->replacer('phone', function ($message, $attribute, $rule, $parameters) {
return 'Phone number has wrong format.';
});
}
Different part in opposite of Laravel, and most important is, that AppServiceProvider is not registered in Lumen by default.
You need to go to bootstrap/app.php and uncomment following line:
$app->register(App\Providers\AppServiceProvider::class);
Maybe you would like to do composer dumpautoload, just in case, but it should work without it.
Then, in your code:
$validator = Validator::make(
$request->all(),
[
'tel' => 'required|phone'
],
[
'tel.required' => 'Phone is required',
'tel.phone' => 'Phone has wrong format'
]
);
That should be it!
I'm trying to use a custom validator of laravel 5, I intend to validate two fields so that one is greater than the other. Follow the steps in this link http://goo.gl/3236xn but could not make the application call the validation method. Can anyone give any tips?
Step 1: Make a bind class where you can implement each rule you want extending Validator class, as follow:
<?php
namespace App\Services;
use \Illuminate\Validation\Validator;
class GreaterThanValidator extends Validator
{
public function validateGreaterThan($attribute, $value, $parameters)
{
if (isset($parameters[1])) {
$other = $parameters[1];
return (floatval($value) > floatval($other)) ;
} else {
return true;
}
}
}
Step 2:Make a service provider that extends ServiceProvider, as follow:
<?php
namespace App\Providers;
use Illuminate\Validation\Validator;
use Illuminate\Support\ServiceProvider;
use App\Services\GreaterThanValidator;
class ValidatorsServiceProvider extends ServiceProvider
{
public function boot()
{
Log::info('passando pelo provider...');
\Validator::resolver(function($translator, $data, $rules, $messages) {
Log::info('chamando new...');
return new \App\Services\GreaterThanValidator($translator, $data, $rules, $messages);
});
}
public function register()
{
}
}
Step 3:Add your custom validator provider at config/app.php file.
/*
* Application Service Providers...
*/
'App\Providers\AppServiceProvider',
'App\Providers\BusServiceProvider',
'App\Providers\ConfigServiceProvider',
'App\Providers\EventServiceProvider',
'App\Providers\RouteServiceProvider',
'App\Providers\ValidatorsServiceProvider',
I forgot to specify, but the controller have the following rule
$rules = array(
'vlFixado' => 'greater_than:vl_anulacao,' . $vlAnulacao,
);
To validate:
$validator = Validator::make(Input::all(), $rules, $messages);
I'm using laravel 5 to develop an app that allow every user to update his profile.
in order to update password, the user needs to first enter his old password and if the old password matched then his newly entered password will be hashed and stored in DB.
how can I validate this, using laravel form request validation?
I created a custom validator and added it to AppServiceProvider like this:
<?php
namespace App\Providers;
use Validator;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Hash ;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Validator::extend('password_hash_check', function($attribute, $value, $parameters, $validator) {
return Hash::check($value , $parameters[0]) ;
});
}
then I used it in my form request validator like this:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class UpdateUserProfileRequest extends Request
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$hashed_password = $this->user()->password ;
return [
'oldPassword'=> "password_hash_check:$hashed_password|string|min:6",
'newPassword' => 'required_with:oldPassword|confirmed|min:6',
];
}
When you want to check a Hashed value generated by
Hash::make()
you need to use
Hash::check('unhashed', $hashed)
Every time you run Hash::make('string'), a different hash is made and will not match the previous one. For example:
// Generate a hash
$password = Hash::make('password');
// $password == $2y$08$T9r9qUxrr6ejs9Ne.nLzMet8l0A8BM5QvLjhaaJasgsbMBdX4JjRu
// Generate a new hash
$new_password = Hash::make('password');
// $new_password == $2y$08$3KBlYKIMpIvk.TWwim9oPuwGA.Pzv1iF7BsDyYkz7kQlhkA/ueULe
// Compare hashes the WRONG way
$password === $new_password; // false
// Compare hash the RIGHT way
Hash::check('password', $password); // true
Hash::check('password', $new_password); // true
So Use Hash::make() method of Hash class.
I'm not sure but I think that there is no native way to do this in Laravel. If so, you can implement a custom "hash" validator:
class CustomValidator extends \Illuminate\Validation\Validator {
public function validateHash($attribute, $value, $parameters)
{
$expected = $parameters[0];
return Hash::check($value, $expected);
}
}
Register it in a provider:
class AppServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
require_once __DIR__ . '/../Http/helpers.php';
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new CustomValidator($translator, $data, $rules, $messages);
});
}
// ...
}
And use it in a form request:
class MyFormRequest extends FormRequest {
public function rules()
{
$password = Auth::user()->password;
return [
'old_password' => "required|hash:" . $password
]
}
// ...
}
Link to documentation:
http://laravel.com/docs/5.0/validation#custom-validation-rules
I would like to know if there is a magic method to use this scenario :
If I call a page via an AJAX request the controller returns a JSON object, otherwise it returns a view, i'm trying to do this on all my controllers without changin each method.
for example i know that i can do this :
if (Request::ajax()) return compact($object1, $object2);
else return view('template', compact($object, $object2));
but I have a lot of controllers/methods, and I prefer to change the basic behavior instead of spending my time to change all of them. any Idea ?
The easiest way would be to make a method that is shared between all of your controllers.
Example:
This is your controller class that all other controllers extend:
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
abstract class Controller extends BaseController
{
protected function makeResponse($template, $objects = [])
{
if (\Request::ajax()) {
return json_encode($objects);
}
return view($template, $objects);
}
}
And this is one of the controllers extending it:
<?php namespace App\Http\Controllers;
class MyController extends Controller
{
public function index()
{
$object = new Object1;
$object2 = new Object2;
return $this->makeResponse($template, compact($object, $object2));
}
}
Update for Laravel 5+
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
protected function makeResponse($request, $template, $data = [])
{
if ($request->ajax()) {
return response()->json($data);
}
return view($template, $data);
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MyController extends Controller
{
public function index(Request $request)
{
$object = new Object1;
$object2 = new Object2;
return $this->makeResponse($request, $template, compact($object, $object2));
}
}
There is no magic but you can easily override ViewService in 3 steps:
1.create your view factory (your_project_path/app/MyViewFactory.php)
<?php
/**
* Created by PhpStorm.
* User: panos
* Date: 5/2/15
* Time: 1:35 AM
*/
namespace App;
use Illuminate\View\Factory;
class MyViewFactory extends Factory {
public function make($view, $data = array(), $mergeData = array())
{
if (\Request::ajax()) {
return $data;
}
return parent::make($view, $data, $mergeData);
}
}
2.create your view service provider (your_project_path/app/providers/MyViewProvider.php)
<?php namespace App\Providers;
use App\MyViewFactory;
use Illuminate\View\ViewServiceProvider;
class MyViewProvider extends ViewServiceProvider {
/**
* Register the application services.
*
* #return void
*/
public function register()
{
parent::register();
}
/**
* Overwrite original so we can register MyViewFactory
*
* #return void
*/
public function registerFactory()
{
$this->app->singleton('view', function($app)
{
// Next we need to grab the engine resolver instance that will be used by the
// environment. The resolver will be used by an environment to get each of
// the various engine implementations such as plain PHP or Blade engine.
$resolver = $app['view.engine.resolver'];
$finder = $app['view.finder'];
// IMPORTANT in next line you should use your ViewFactory
$env = new MyViewFactory($resolver, $finder, $app['events']);
// We will also set the container instance on this view environment since the
// view composers may be classes registered in the container, which allows
// for great testable, flexible composers for the application developer.
$env->setContainer($app);
$env->share('app', $app);
return $env;
});
}
}
3.in your_project_path/config/app.php:
change 'Illuminate\View\ViewServiceProvider',
to 'App\Providers\MyViewProvider',
What this do:
it tells your application to use another view provider which will register your view factory
$env = new MyViewFactory($resolver, $finder, $app['events']);
in line 33 of MyViewProvider.php which will check if request is AJAX and return if true or continue with original behavior
return parent::make($view, $data, $mergeData);
in MyViewFactory.php line 19
Hope this help you,
In laravel 5.1, this is the best way:
if (\Illuminate\Support\Facades\Request::ajax())
return response()->json(compact($object1, $object2));
else
return view('template', compact($object, $object2));
The solution suggested by #ryanwinchester is really good. I, however, wanted to use it for the responses from update() and delete(), and there naturally return view() at the end doesn't make a lot of sense as you mostly want to use return redirect()->route('whatever.your.route.is'). I thus came up with that idea:
// App\Controller.php
/**
* Checks whether request is ajax or not and returns accordingly
*
* #param array $data
* #return mixed
*/
protected function forAjax($data = [])
{
if (request()->ajax()) {
return response()->json($data);
}
return false;
}
// any other controller, e.g. PostController.php
public function destroy(Post $post)
{
// all stuff that you need until delete, e.g. permission check
$comment->delete();
$r = ['success' => 'Wohoo! You deleted that post!']; // if necessary
// checks whether AJAX response is required and if not returns a redirect
return $this->forAjax($r) ?: redirect()->route('...')->with($r);
}
I am using form request validation method for validating request in laravel 5.I would like to add my own validation rule with form request validation method.My request class is given below.I want to add custom validation numeric_array with field items.
protected $rules = [
'shipping_country' => ['max:60'],
'items' => ['array|numericarray']
];
My cusotom function is given below
Validator::extend('numericarray', function($attribute, $value, $parameters) {
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
});
How can use this validation method with about form request validation in laravel5?
While the above answer is correct, in a lot of cases you might want to create a custom validation only for a certain form request. You can leverage laravel FormRequest and use dependency injection to extend the validation factory. I think this solution is much simpler than creating a service provider.
Here is how it can be done.
use Illuminate\Validation\Factory as ValidationFactory;
class UpdateMyUserRequest extends FormRequest {
public function __construct(ValidationFactory $validationFactory)
{
$validationFactory->extend(
'foo',
function ($attribute, $value, $parameters) {
return 'foo' === $value;
},
'Sorry, it failed foo validation!'
);
}
public function rules()
{
return [
'username' => 'foo',
];
}
}
Using Validator::extend() like you do is actually perfectly fine you just need to put that in a Service Provider like this:
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ValidatorServiceProvider extends ServiceProvider {
public function boot()
{
$this->app['validator']->extend('numericarray', function ($attribute, $value, $parameters)
{
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
});
}
public function register()
{
//
}
}
Then register the provider by adding it to the list in config/app.php:
'providers' => [
// Other Service Providers
'App\Providers\ValidatorServiceProvider',
],
You now can use the numericarray validation rule everywhere you want
The accepted answer works for global validation rules, but many times you will be validating certain conditions that are very specific to a form. Here's what I recommend in those circumstances (that seems to be somewhat intended from Laravel source code at line 75 of FormRequest.php):
Add a validator method to the parent Request your requests will extend:
<?php namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Validator;
abstract class Request extends FormRequest {
public function validator(){
$v = Validator::make($this->input(), $this->rules(), $this->messages(), $this->attributes());
if(method_exists($this, 'moreValidation')){
$this->moreValidation($v);
}
return $v;
}
}
Now all your specific requests will look like this:
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class ShipRequest extends Request {
public function rules()
{
return [
'shipping_country' => 'max:60',
'items' => 'array'
];
}
// Here we can do more with the validation instance...
public function moreValidation($validator){
// Use an "after validation hook" (see laravel docs)
$validator->after(function($validator)
{
// Check to see if valid numeric array
foreach ($this->input('items') as $item) {
if (!is_int($item)) {
$validator->errors()->add('items', 'Items should all be numeric');
break;
}
}
});
}
// Bonus: I also like to take care of any custom messages here
public function messages(){
return [
'shipping_country.max' => 'Whoa! Easy there on shipping char. count!'
];
}
}
Custom Rule Object
One way to do it is by using Custom Rule Object, this way you can define as many rule as you want without need to make changes in Providers and in controller/service to set new rules.
php artisan make:rule NumericArray
In NumericArray.php
namespace App\Rules;
class NumericArray implements Rule
{
public function passes($attribute, $value)
{
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
}
public function message()
{
return 'error message...';
}
}
Then in Form request have
use App\Rules\NumericArray;
.
.
protected $rules = [
'shipping_country' => ['max:60'],
'items' => ['array', new NumericArray]
];
Alternatively to Adrian Gunawan's solution this now also can be approached like:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreBlogPost extends FormRequest
{
public function rules()
{
return [
'title' => ['required', 'not_lorem_ipsum'],
];
}
public function withValidator($validator)
{
$validator->addExtension('not_lorem_ipsum', function ($attribute, $value, $parameters, $validator) {
return $value != 'lorem ipsum';
});
$validator->addReplacer('not_lorem_ipsum', function ($message, $attribute, $rule, $parameters, $validator) {
return __("The :attribute can't be lorem ipsum.", compact('attribute'));
});
}
}
You need to override getValidatorInstance method in your Request class, for example this way:
protected function getValidatorInstance()
{
$validator = parent::getValidatorInstance();
$validator->addImplicitExtension('numericarray', function($attribute, $value, $parameters) {
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
});
return $validator;
}
You don't need to extend the validator to validate array items, you can validate each item of a array with "*" as you can see in
Array Validation
protected $rules = [
'shipping_country' => ['max:60'],
'items' => ['array'],
'items.*' => 'integer'
];
All answers on this page will solve you the problem, but... But the only right way by the Laravel conventions is solution from Ganesh Karki
One example:
Let’s take an example of a form to fill in Summer Olympic Games events – so year and city. First create one form.
<form action="/olimpicyear" method="post">
Year:<br>
<input type="text" name="year" value=""><br>
City:<br>
<input type="text" name="city" value=""><br><br>
<input type="submit" value="Submit">
</form>
Now, let’s create a validation rule that you can enter only the year of Olympic Games. These are the conditions
Games started in 1896
Year can’t be bigger than current year
Number should be divided by 4
Let’s run a command:
php artisan make:rule OlympicYear
Laravel generates a file app/Rules/OlympicYear.php. Change that file to look like this:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class OlympicYear implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
// Set condition that should be filled
return $value >= 1896 && $value <= date('Y') && $value % 4 == 0;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
// Set custom error message.
return ':attribute should be a year of Olympic Games';
}
}
Finally, how we use this class? In controller's store() method we have this code:
public function store(Request $request)
{
$this->validate($request, ['year' => new OlympicYear]);
}
If you want to create validation by Laravel conventions follow tutorial in link below. It is easy and very well explained. It helped me a lot. Link for original tutorial is here Tutorial link.
For me works the solution that give us lukasgeiter, but with a difference that we create a class with our custom validations ,like this, for laravel 5.2.* The next example is for add a validation to a range of date in where the second date has to be equals or more big that the first one
In app/Providers create ValidatorExtended.php
<?php
namespace App\Providers;
use Illuminate\Validation\Validator as IlluminateValidator;
class ValidatorExtended extends IlluminateValidator {
private $_custom_messages = array(
"after_or_equal" => ":attribute debe ser una fecha posterior o igual a
:date.",
);
public function __construct( $translator, $data, $rules, $messages = array(),
$customAttributes = array() ) {
parent::__construct( $translator, $data, $rules, $messages,
$customAttributes );
$this->_set_custom_stuff();
}
protected function _set_custom_stuff() {
//setup our custom error messages
$this->setCustomMessages( $this->_custom_messages );
}
/**
* La fecha final debe ser mayor o igual a la fecha inicial
*
* after_or_equal
*/
protected function validateAfterOrEqual( $attribute, $value, $parameters,
$validator) {
return strtotime($validator->getData()[$parameters[0]]) <=
strtotime($value);
}
} //end of class
Ok. now lets create the Service Provider. Create ValidationExtensionServiceProvider.php inside app/Providers, and we code
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;
class ValidationExtensionServiceProvider extends ServiceProvider {
public function register() {}
public function boot() {
$this->app->validator->resolver( function( $translator, $data, $rules,
$messages = array(), $customAttributes = array() ) {
return new ValidatorExtended( $translator, $data, $rules, $messages,
$customAttributes );
} );
}
} //end of class
Now we to tell Laravel to load this Service Provider, add to providers array at the end in config/app.php and
//Servicio para extender validaciones
App\Providers\ValidationExtensionServiceProvider::class,
now we can use this validation in our request in function rules
public function rules()
{
return [
'fDesde' => 'date',
'fHasta' => 'date|after_or_equal:fDesde'
];
}
or in Validator:make
$validator = Validator::make($request->all(), [
'fDesde' => 'date',
'fHasta' => 'date|after_or_equal:fDesde'
], $messages);
you have to notice that the name of the method that makes the validation has the prefix validate and is in camel case style validateAfterOrEqual but when you use the rule of validation every capital letter is replaced with underscore and the letter in lowercase letter.
All this I take it from https://www.sitepoint.com/data-validation-laravel-right-way-custom-validators// here explain in details. thanks to them.