Laravel conditional validation rule for array items - laravel

I have the following working validation rule which checks to make sure each recipient,cc,bcc list of emails contain valid email addresses:
return [
'recipients.*' => 'email',
'cc.*' => 'email',
'bcc.*' => 'email',
];
I need to also be able to allow the string ###EMAIL### as well as email validation for each of these rules and struggling to create a custom validation rule in Laravel 5.8 (it can't be upgraded at this time).
Any idea how to go about this? If it were a higher version of Laravel I was thinking something like (not tested) to give you an idea of what I'm trying to do:
return [
'recipients.*' => 'exclude_if:recipients.*,###EMAIL###|email',
'cc.*' => 'exclude_if:recipients.*,###EMAIL###|email',
'bcc.*' => 'exclude_if:recipients.*,###EMAIL###|email',
];

In 5.8 you can create Custom Rule Object Let's see how we can actually make it work.
Create your rule with php artisan make:rule EmailRule
Make it to look like this
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class EmailRule implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if ($value === '###EMAIL###' or filter_var($value, FILTER_VALIDATE_EMAIL)) {
return true;
}
return false;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute must be valid email or ###EMAIL###.';
}
}
Include in your rules so it looks like
return [
'recipients.*' => [new EmailRule()],
'cc.*' => [new EmailRule()],
'bcc.*' => [new EmailRule()],
];
Write a test (optional)

Related

laravel validation check if input value exists in emails or users

please I want know if there is any method to validate an input if exists in column email or username
without deal with code just validation system in laravel like
'username'=>'required|exists:App\Models\User,email OR exists:App\Models\User,username'
I want to make a 'LOST PASSWORD' like wordpress
wordpress lost password system ask the users for email or username if exits it's okey if it's not display an error message
If you really need to check if the username exists as a users.email or as a users.username, you should make a Custom Validation Rule - since the exists rule can't cover both of these. Something like this should work:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Models\User;
class EmailOrUsername implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
return User::where(function($q) use($value) {
$q->orWhere('email', $value)->orWhere('username', $value);
})->count() > 0;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'Sorry, your credentials do not match our records.';
}
}
When you need to use it, you do it like this:
<?php
use App\Rules\EmailOrUsername;
$request->validate([
'username' => ['required', 'string', new EmailOrUsername],
]);

How to set only one NULLABLE out of two input fields

I have two input fields one as mobile_no and other as email, i want to set a condition that out of two fields if mobile_no is not given them email must be required and vice versa.
How to set nullable condition on laravel validation that only one field out of two must be required.
You can create a custom rule. So your need is opposite of what required_if rule does, so please try this one and let me know.
First create custom rule, I call it NullableIf
php artisan make:rule NullableIf
Then the implementation should be something like this:
class NullableIf implements Rule
{
private $otherField;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct( $otherField )
{
$this->otherField = $otherField;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if($this->otherField === null)
{
return $value !== null;
}
return true;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
}
}
To use it you do:
$request->validate([
'field1' => [ new NullableIf(request('field2')) ],
'field2' => [ new NullableIf(request('field1')) ]
]);
I hope at least it gives you direction unless this exact implementation does not suits your needs.

How to override the message of the custom validation rule in Laravel?

I am developing a Laravel application. What I am doing in my application is that I am trying to override the custom validation rule message.
I have validation rules like this in the request class:
[
'name'=> [ 'required' ],
'age' => [ 'required', new OverAge() ],
];
Normally, we override the error message of the rules like this:
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
But how can I do that to the custom validation rule class?
You cannot simply overwrite it with the custom messages of the request. If you take a look at the Validator class:
/**
* Validate an attribute using a custom rule object.
*
* #param string $attribute
* #param mixed $value
* #param \Illuminate\Contracts\Validation\Rule $rule
* #return void
*/
protected function validateUsingCustomRule($attribute, $value, $rule)
{
if (! $rule->passes($attribute, $value)) {
$this->failedRules[$attribute][get_class($rule)] = [];
$this->messages->add($attribute, $this->makeReplacements(
$rule->message(), $attribute, get_class($rule), []
));
}
}
As you can see, it's simply adding the $rule->message() directly to the message bag.
However, you can add a parameter for the message in your custom rule's class:
public function __construct(string $message = null)
{
$this->message = $message;
}
Then in your message function:
public function message()
{
return $this->message ?: 'Default message';
}
And finally in your rules:
'age' => ['required', new OverAge('Overwritten message')];
Working with Laravel 9, overriding the message is supported, but you must supply the FQDN for the validation class. So your OverAge custom message may look like this:
return [
'age.required' => 'An age is required',
'age.App\\Rules\\OverAge' => 'The age must be less than 65',
];
You may also want to support place-holders for the message, so the 65 can be replaced by something like :max-age. Many ways to do that are published, none of which look particularly clean.

How to validate images array type using rule object with custom message in Laravel

Actually, I tried to create rule object which is able to validate every image type in array of images and not only enough but also, I must to show custom message in override message function in rule object.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class ImagesArray implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
return [$attribute => 'mimes:jpeg,jpg,png' ];
here i need to validate these file types.
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
here, I need to show my custom messgae.
}
}
You should use Request.
For example, create q request class: php artisan make:request MyRequest.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyRequest extends FormRequest
{
/**
* 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 [
'image' => 'mimes:jpeg,jpg,png',
];
}
public function messages()
{
return [
'image.mimes' => 'This image is not supported.',
];
}
}
In your controller import class MyRequest and in the method use MyRequest
e.g:
public function store(MyRequest $request)
{ // your code
}
Let me know if that was helpful. Thanks!
When validating arrays or nested parameters, you should use . in your rules access a specific array index. but if you want to apply a rule to every index on that array, you can use .*.
$validator = Validator::make($request->all(), [
'image.*' => 'mimes:jpeg,jpg,png',
], [
'image.*' => 'Invalid file type.',
]);
Or if you're using Request Forms
public function rules(){
return [
'image.*' => 'mimes:jpeg,jpg,png',
];
}
public function mesages(){
return [
'image.*' => 'Invalid file type.',
];
}
For more info, see Laravel's Documentation on Validation Arrays

Laravel validation using class

I am trying to use Laravel validation : as described here
I am not going to place entire rule class, as it is straight from artisan make:rule.
PROBLEM:
When I try to test 'false' here:
function passes($attribute, $value)
{
return false; //testing 'false' logs me out
}
This is how I use it in controller:
$this->validate($request, [
'image_64' => ['required', new \App\Rules\Base64Rule]
]);
It is like redirect isn't going to form page, but index page - which in my case logs user out (among other things).
Is there any protected var to mark proper redirect route, when method 'passes' returns false?
Anyone came across something like this?
EDIT
Sam,
As I mentioned, rule class is pristine - freshly generated:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Base64Rule implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
return false;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
}
}
If I run on top of my controller anything like:
use App\Rules\Base64Rule;
$rule = new Base64Rule;
dd($rule->passes('image_64', 'udfshjbfisuusoshgosghosh'));
I get whatever I have in rule's method passes().
If I use in rule's method passes() return true; it works right.
If I use in rule's method passes() dd('some'), I get 'some' in that controller test.
When test is 'false' and regular validation code is used:
use App\Rules\Base64Rule;
$this->validate($request, [
'image_64' => ['required', new Base64Rule]
]);
... I get redirected to index page.
I have to follow request/response and see, where Laravel fails and why ... I guess. And is it my code, or a bug.

Resources