In below rules, I have my custom validation customRule: *date*
$rules = [
'my_date' => 'required|date_format: Y-m-d|customRule: someDate',
];
Inside my custom validation rules extension, I need to access the date_format attribute of the rule:
Validator::extend('customRule', function($attribute, $value, $parameters) {
$format = $attribute->getRules()['date_format']; // I need something like this
return $format == 'Y-m-d';
});
How can I get the rule value of certain attribute on an extended validator?
You can't access other rules. Validators are to be independent units - the only data they should use is:
value of field being validated
values passed to this validation rule as parameters
values of other attributes of object being validated
It seems that what you need is a custom validator that would wrap what is date_format and customRule doing:
Validator::extend('custom_date_format', function($attribute, $value, $parameters) {
$format = $parameters[0];
$someDate = $parameters[1];
$validator = Validator::make(['value' => $value], ['value' => 'date_format:' . $format]);
//validate dateformat
if ($validator->fails()) {
return false;
}
//validate custom rule using $format and $someDate and return true if passes
});
Once you have it, you can use it like that:
$rules = [
'my_date' => 'required|custom_date_format:Y-m-d,someDate',
];
Related
I am using the Lumen Framework, which utilizes the Laravel Validation
I wanted to create a Validator Rule to make the Request->input() json only contain specific keys at the root like "domain" and "nameservers". Not more and not less.
Example passing the rule:
{
"domain":"domain.tld",
"nameservers":
{...}
}
Example not passing the rule:
{
"domain":"domain.tld",
"nameservers":
{...},
"Hack":"executeSomething()"
}
I tried to use to use several default validation rules to achieve this but wasnt successful.
My approach was now to put the request in another array like this
$checkInput['input'] = $request->all();
to make the validator validate the "root" keys.
Now this is my Approach:
create the validator
$checkInput['input'] = $request->all();
$validator = Validator::make($checkInput, [
'input' => [
'onlyContains:domain,nameservers'
],
]);
creating the rule
Validator::extend('onlyContains', function($attribute, $value, $parameters, $validator){
$input = $validator->getData();
$ok = 0;
foreach ($parameters as $key => $value) {
if (Arr::has($input, $attribute . '.' . $value)) {
$ok++;
}
}
if (sizeof(Arr::get($input, $attribute)) - $ok > 0) {
return false;
}
return true;
});
It seems i got the desired result, but i am asking if there is maybe smarter solution to this with the default rules provided by Laravel/Lumen.
You are trying to do a blacklisting approach blocking out fields that are not intended. A simple approach, that is utilized a lot, is to only fetch out the validated. Also you are trying to do logic, that goes against normal validation logic, to do it a field at a time.
This is also a good time, to learn about FormRequest and how you can get that logic, into a place where it makes more sense.
public function route(MyRequest $request) {
$input = $request->validated();
}
With this approach, you will only ever have the validated fields in the $input variable. As an extra bonus, this approach will make your code way easier to pick up by other Laravel developers. Example form request below.
public class MyRequest extends FormRequest
{
public function rules()
{
return [
'domain' => ['required', 'string'],
'nameservers' => ['required', 'array'],
];
}
}
You should use prohibited rule.
For eg:
$allowedKeys = ['domain', 'nameservers'];
$inputData = $request->all();
$inputKeys = array_keys($inputData);
$diffKeys = array_diff($inputKeys, $allowedKeys);
$rules = [];
foreach($diffKeys as $value) {
$rules[$value] = ['prohibited'];
}
I want to check my request datetime with many format look like below format:
Y-m-d
Y-m-
Y-m
In Laravel, I use Validator to validate datetime, but Validator can not make checking with many format. This is my code:
Validator::make(['date' => $departureDate], [
'date' => 'required|date_format:Y-m-d, Y-m, Y-m-'
]);
How can I do it in laravel
Please help me! Many thanks!
You must write a custom validation format for that. Laravel's date_format expects only one parameter and not capable of handling multi-formats. There are Two ways to add custom validation. first, one is making a rule repository and add your validation logic there. Here Taylor Otwell explained this method.
The other way to doing that is extend validation in app service provider and add new rule there. add this code in app service provider:
use Illuminate\Support\Facades\Validator;
Validator::extend('multi_date_format', function ($attribute, $value, $parameters,$validator) {
$ok = true;
$result = [];
// iterate through all formats
foreach ($parameters as $parameter){
//validate with laravels standard date format validation
$result[] = $validator->validateDateFormat($attribute,$value,[$parameter]);
}
//if none of result array is true. it sets ok to false
if(!in_array(true,$result)){
$ok = false;
$validator->setCustomMessages(['multi_date_format' => 'The format must be one of Y-m-d ,Y-m or Y-m-']);
}
return $ok;
});
And here you can use it this way:
$validator = Validator::make(['date' => '2000-02-01'], [
'date' => 'required|multi_date_format:Y-m-d,Y-m,Y-m-'
]);
if($validator->fails()) {
$errors = $validator->errors()->all();
}
You can register custom validator in file app/Providers/AppServiceProvider.php in boot method.
Validator::extend('several_date_format', function ($attribute, $value, $parameters,$validator) {
foreach ($parameters as $parameter){
if (!$validator->validateDateFormat($attribute,$value,[$parameter]))
return false;
}
return true;
});
Now you can use it
'your_date' => 'required|several_date_format:Y-m-d,...'
Optional after it you can add custom message in resources/lang/en/validation.php
return [
...
'several_date_format' => 'Error text'
...
]
I'm trying to add custom validation logic for file uploads for my admin panel. Right now my file fields can return either Illuminate\Http\UploadedFile or string|null if the file is not uploaded or changed or whatever. What I'm doing is, I created a custom rule that looks like this:
'image' => [
'required',
'admin_file:mimes:jpeg;png,dimensions:min_width=800;min_height=600'
]
I then parse all the arguments I pass, and the thing is, I naturally want all of them applied only if my value is an instance of UploadedFile. I use the following code for my custom validation:
<?php
class AdminFileValidator
{
public function validate($attribute, $value, $parameters, Validator $validator)
{
$rules = implode(
"|",
array_map(function($item) {
return str_replace(";", ",", $item);
}, $parameters)
);
$validator->sometimes($attribute, $rules, function() use ($value) {
return $value instanceof UploadedFile;
});
return true;
}
}
The problem is with adding additional rules to an attribute via sometimes doesn't work that way. The added rules are not being processed by a validator.
Is there any way to validate these rules without revalidating the whole thing manually?
What I see is that your are using sometimes inside of a rule. From my perspective you need to take it out, even better without use a custom class.
Using Validator object:
$validator = Validator::make($data, [
'image' => 'required',
]);
$validator->sometimes('image', 'mimes:jpeg;png,dimensions:min_width=800', function($value) {
return $value instanceof UploadedFile;
});
If you are using a Request class you could override the function getValidatorInstance in order apply the conditional rules:
protected function getValidatorInstance(){
$validator = parent::getValidatorInstance();
$validator->sometimes('image', 'mimes:jpeg;png,dimensions:min_width=800', function($value) {
return $value instanceof UploadedFile;
});
return $validator;
}
I have been using the following validation for my form in Laravel:
public function isValid($data, $rules)
{
$validation = Validator::make($data, $rules);
if($validation->passes()){
return true;
}
$this->messages = $validation->messages();
return false;
}
The rules passed to it are simple:
$rules = [
'name' => 'required',
'type' => 'required'
];
And $data is the input post data. Now I need to add a custom validation extension to this, specifically to make sure that the value of input field round2 is greater than the value of input field round1. Looking at the docs, I have tried the following syntax which I think should be correct, but I keep getting an error.
$validation->extend('manual_capture', function($attribute, $value, $parameters)
{
return $value > $parameters[0];
});
Then I could call this with $attribute = 'round1', $value = $data['round1'] and $parameters = [$data['round2']].
The error is Method [extend] does not exist. - I'm not sure if my understanding of this whole concept is correct, so can someone tell me how to make it work? The docs only have about 2 paragraphs about this.
Put the following in your route.php
Validator::extend('manual_capture', function($attribute, $value, $parameters)
{
return $value > $parameters[0];
});
Additional documentation here
Then use it like so:
$rules = [ 'foo' => 'manual_capture:30'];
I've created a custom Validation rule that accepts one input argument.
Validator::extend('dns', function($attribute, $host, $parameters)
{
return ($host !== gethostbyname($host));
});
The rules
public static $rules = array(
'nameserver' => 'dns'
);
I have created a new file called validators.php and include it in the global.php file in order to be global.
I want to pass two input arguments in order to make some more checks compare to each other.
How can I succeed this?
send extra parameters like:
public static $rules = array(
'nameserver' => 'dns:foobar'
);
and access those via:
$parameters[0]
in the closure.
[edit]
A way to seed the validator rules with input:
// model
static $rules = array(
'valOne' => 'required|custom:%s'
,'valTwo' => 'required'
);
// controller
$inputValues = Input::only(array(
'valOne'
,'valTwo'
));
$rules = MyModel::$rules;
$rules['valOne'] = sprintf($rules['valOne'], Input::get('valTwo'));
$validator = Validator::make($inputValues, $rules);