I need to make my own validator that extends Illuminate\Validation\Validator
I have read an example given in an answer here: Custom validation in Laravel 4
But the problem is it doesn't clearly show how to use the custom validator. It doesn't call the custom validator explicitly. Could you give me an example how to call the custom validator.
After Laravel 5.5 you can create you own Custom Validation Rule object.
In order to create the new rule, just run the artisan command:
php artisan make:rule GreaterThanTen
laravel will place the new rule class in the app/Rules directory
An example of a custom object validation rule might look something like:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class GreaterThanTen implements Rule
{
// Should return true or false depending on whether the attribute value is valid or not.
public function passes($attribute, $value)
{
return $value > 10;
}
// This method should return the validation error message that should be used when validation fails
public function message()
{
return 'The :attribute must be greater than 10.';
}
}
With the custom rule defined, you might use it in your controller validation like so:
public function store(Request $request)
{
$request->validate([
'age' => ['required', new GreaterThanTen],
]);
}
This way is much better than the old way of create Closures on the AppServiceProvider Class
I don't know if this is what you want but to set customs rules you must first you need to extend the custom rule.
Validator::extend('custom_rule_name',function($attribute, $value, $parameters){
//code that would validate
//attribute its the field under validation
//values its the value of the field
//parameters its the value that it will validate againts
});
Then add the rule to your validation rules
$rules = array(
'field_1' => 'custom_rule_name:parameter'
);
Related
I have a form field that can either be a username or an email. When the user submits this form I want to validate this field to see if it is a valid username or a valid email address. I already have a custom Username rule I created. But for this form, I want to create another custom rule called UsernameOrEmail. Inside this rule, I want to use the existing default email validation rule and my custom Username rule. How can I do this in Laravel 9?
I already saw in the docs that I can get the Validator instance as follows:
protected $validator;
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
But then how do I actually make use of it?
Inside the Illuminate/Validation/Validator class, there's a method called validateAttribute that looks like it should solve my problem, but it's a protected method and so I can't actually call it from my custom rule class. It looks like I can only use the validator to validate all my rules at once, but not specific rules individually.
Ideally, I'd like to be able to do something like the following in my custom rule class:
public function __invoke($attribute, $value, $fail)
{
$is_email = $this->validator->validateAttribute($attribute, 'email');
$is_username = $this->validator->validateAttribute($attribute, new Username);
if (!$is_username && !$is_email) {
$fail('The :attribute is not a valid username or email.');
}
}
By creating new laravel model with api resourceful controller and from new auto-generated create and update form request classes, it always fails the validation.
With custom classes it works with post/get but for put and patch it returns validation invalid data. Without custom classes it works for any methods.
Any ideas?
There is probably an easier/better way that I don't know about (please let me know), at the moment what I do is override validationData() in the FormRequest, and then call it from the controller:
public function validationData()
{
$payload = request()->json()->all(); // get payload for PUT/PATCH method
$attrs = array_keys($this->attributes());
return array_filter($payload, function($key) use ($attrs) {
return in_array($key, $attrs);
}, ARRAY_FILTER_USE_KEY);
}
and then in the controller:
$input = $request->validated();
I would like to validate the get parameter where i passed throug the route to my controller.
api/route
get /order/{id} -> OrderController::order
public function order($id) {
// validation here (rules= require,between 1 and 1000)
return Order::find($id);
}
how can I validate inside my controller without creating a separate request class?
which validation class do i have to import? (this one: Illuminate\Support\Facades\Validator ? )
Is this a good or common solution?
As #lagbox already wrote, you can check all of your questions inside the Laravel documentation.
Validation inside the controller
use Illuminate\Http\Request;
class MyController extends Controller
{
public function order(Request $request, int $id)
{
$validated = $this->validate([
// .. put your fields and rules here
]);
}
}
If your controller extends the base controller, that is shipped with every Laravel installation you have direct access to the validator via $this->validate.
With injecting the $request you have access to the fields that are send (POSTed) to your server.
If this is a good solution heavily depends on the projects size and other factors. It is definitely a good solution to start with. If your project grows and you need to have the same validation logic in various places you can again think about additional Form Request Validation.
To apply certain rules to the route parameter, f. ex. id, you can use Regular Expression Constraints.
Futher processing of request data
I personally would leave the validation inside the controller (or a form request class).
If there is any problem with the request data, then it should fail there and not continue to the service class.
You could say this is a kind of fail fast approach. Why moving more and more inside your code, if your request items might have an error (are not valid)?
$id is always present so required validation always passes.
So you only need to check between 1 and 1000 condition.
I think using regex constraints in the route is a good idea here.
Route::get('/order/{id}','OrderController#order')
->where(['id'=> '1000|^[1-9]{0,2}[1-9]$']);
If id is less than 1 or more than 1000 or any other random string it won't match the route and if there isn't any other matching routes too, it gives 404 error.
If you really want to validate the route parameter in the controller, you can use this:
$validator = \Illuminate\Support\Facades\Validator::make(['id' => $id],
[
'id' => 'required|integer|between:1,1000'
]
);
$validator->validate();
I am new to Laravel and would like to know the best pracitse method to handle duplicate code.
I have nearly in all functions of my api-controllers this code at beginning:
// Validate parameters
$validator = Validator::make($request->all(), $this->validationRules);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
So normally I would put it in some function. But this code also used in lot of other controllers. so this function should be called also by other controllers.
What is best practise to handle that in Laravel 5? My first idea was to make some own Controller with this function and my other controllers would extend this.
Like:
class MyController extends Controller
{
protected function handleFailByPrameter($params)
{
....
}
}
class Api1Controller extends MyController
{
public function apicall1()
{
$this->handleFailByPrameter($this->validationRules());
}
}
But maybe there are some other methods to handle that kind of things?
You may create a validation function in your helper this will help you do that and then call this new function from anywhere in your laravel app(literally anywhere). Second thing you can do is create custom requests which will validate your data before it is passed to your function in the following way :
first generate a new requests class from artisan
php artisan make:request ExplicitRequestName
this will create a new file named ExplicitRequestName.php under app/Http/Requests folder open it, toggle false to true in your authorize function and then define your validation rules in following manner:
public function rules()
{
return [
'email' => 'required',
'password' => 'required',
];
}
call this requests object in your function :
public function someFunction(Requests\ExplicitRequestName $request)
{
}
Laravel 5.1 has a method attached to the Controller:
$this->validate($request, [your rules]);
It will redirect back with errors if anythings wrong, or send an error response if it's ajax.
To not defined your rules in every method, you can set in your models:
public static $rules = ['Your rules']
Then you can simply do your validation in your controllers, forexample:
$this->validate($request, Post::rules);
I think you are already on the right track. I implemented the validation and authentication for every API this way, although on laravel 4
.
I have one table, which i have divided in two section for each i have mention two action under controller, i wanted to separate validation rule for both action, so i don't want use common model rule.
Is there any way by which i can write rule in action.
I have user controller there i have defined two action called frontuser and backenduser.
my action in controller
public function actionfrontuserCreate()
{
// want to write rule here
}
public function actionbackenduserCreate()
{
// want to write rule here
}
Thanks
Hi i hope i can help you:
rules should be declared in the model even if the model is shared between one or more controllers with different kind of actions ...
but you do not want a rule to be executed in all of those actions so you specify wich actions can take that rule using scenarios, i leave you an example:
array('password_repeat', 'required', 'on'=>'register'),
code above only makes pasword_repeat required on scenario register
then in your controller you will specify wich scenario will be used...
$modelA = User::model()->findByPk(1); // $model->scenario = 'update'
$modelB = new User(); // $model->scenario = 'insert'
$modelB->scenario = 'light'; // custom scenario
if ($modelB->validate()) { ...
i hope this solve your issue, for bonus i suggest to check default yii scenarios insert, update, delete ....
Validation rules go in the model not in the controller. What you want to do is use scenarios.
When you put a rules in the model you can do something like:
array('username', 'required', 'on'=>'frontUserCreate'),
By using the 'on'=>'...' part you can tell in what scenario the rule must be applied.
In your controller when you create a new model you should give the scenario as a parameter:
public function actionfrontuserCreate()
{
$model = new User('frontUserCreate');
if (isset($_POST['User']) {
....
}
$this->render('viewname', array('model'=>$model));
}