Reputation: 4705
I would like to move this code to the App\Rule:
//Currently in class AppServiceProvider extends ServiceProvider
Validator::extend('empty_if', function ($attribute, $value, $parameters, $validator) {
return ($value != '' && request($parameters[0]) != '') ? false : true;
});
So that it should be this:
//in: App\Rules\EmptyIf
public function passes($attribute, $value, $parameters)
{
return ($value != '' && request($parameters[0]) != '') ? false : true;
}
But my problem is, that I cannot pass $parameters with
Validator::extend('empty_if', 'App\Rules\EmptyIf@passes');
How would you pass parameters to Laravel Rule?
Upvotes: 14
Views: 30040
Reputation: 79
You can pass parameters with constructor in Rule
public function __construct($params)
{
$this->params = $params;
}
Then access parameters in passes method
public function passes($attribute, $value)
{
//access params with $this->params
}
Upvotes: 6
Reputation: 257
Here is a simpler and updated way of accomplishing this, without extending the validator. You can access the passed param in the Rule's constructor, so just set a globally scoped variable and now you can reference it inside of the passes() method. You could even use the same approach to have the value in the validator message.
The validate call:
case 'measurement':
$request->validate([
'updates.*.value' => [
new Measurement('foo-bar'),
],
]);
break;
The Rule:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Measurement implements Rule
{
/**
* Create a new rule instance.
*
* @param $param
*/
public function __construct($param)
{
$this->type = $param;
}
public $type;
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @return bool
*/
public function passes($attribute, $value)
{
dd($this->type, 'params');
return;
}
Upvotes: 22
Reputation: 8706
You can do this by passing the parameter(s) into the constructor for your Rule
:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Http\Request;
class EmptyIf implements Rule
{
public $otherParameter;
public function passes($attribute, $value)
{
if (Request::get($this->otherParameter) != '') {
return ($value == '');
}
return true;
}
public function message()
{
return 'The :attribute cannot be empty if ' . $this->otherParameter . ' is set';
}
}
And in the service provider:
<?php
namespace App\Providers;
use App\Rules\EmptyIf;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*/
public function boot(): void
{
Validator::extend('empty_if', function($attribute, $value, $parameters, $validator) {
$rule = new EmptyIf($parameters[0]);
return $rule->passes();
});
}
}
So now you can use the string form in your validator:
'sometimes|nullable|empty_if:about_image|max:200|url'
Upvotes: 3
Reputation: 31088
When using a rule class with required $parameters
, you'll get an error:
PHP Fatal error:
Declaration of App\Rules\AgeAt::passes($attribute, $value, $parameters)
must be compatible with Illuminate\Contracts\Validation\Rule::passes($attribute, $value)
You can simply make that $parameters
optional, and you will get the parameters passed in Laravel 5.5+ automatically:
public function passes($attribute, $value, $parameters = [])
{
//do something here
}
Upvotes: 6
Reputation: 40683
If I understand what you need correctly you don't need to extend the validator.
You seem to have class:
class EmptyIf extends Rule {
public function passes($attribute, $value, $parameters) { }
}
Then you can just use this as:
$this->validate($data, [ "entry" => [ new EmptyIf() ] ]);
You might be able to do both using:
Validator::extend('empty_if', function ($attribute, $value, $parameters) {
return (new EmptyIf())->passes($atribute, $value, $parameters);
});
Upvotes: 6