Laravel Custom Validation Order - laravel

I add a custom Validation Rule
Validator::extend('validate_timezone', function($attribute, $value, $parameters, $validator) {
$items = request('items');
$from_date = Carbon::createFromFormat('Y-m-d H:i:s', $item['from_date']);
// my code below depend on $from_date
......
......
return true;
);
validation rule
"from_date" => "required|date_format:Y-m-d H:i:s|validate_timezone",
The problem, custom validation validate_timezone run before 'date_format:Y-m-d H:i:s', so if the format of date is wrong, I will get error inside validate_timezone function
How can I force to validate date_format:Y-m-d H:i:s before the custom validation validate_timezone?

In the documentation the following can be found:
Rules will be validated in the order they are assigned.
Meaning the code is working as expected.
You're probably looking for the bail option:
Sometimes you may wish to stop running validation rules on an attribute after the first validation failure. To do so, assign the bail rule to the attribute
Which would mean you should try this:
"from_date" => "bail|required|date_format:Y-m-d H:i:s|validate_timezone",

The custom extended validation rule is running first because it's probably defined in the boot function of a service provider which runs on every request, so you need to catch the Carbon exception and return false accordingly
public function boot()
{
\Validator::extend('validate_timezone', function ($attribute, $value, $parameters, $validator) {
try {
$from_date = Carbon::createFromFormat('Y-m-d H:i:s', $value);
return true;
} catch (Exception $ex) {
logger()->warning($ex->getMessage());
return false;
}
});
}
Now if carbon can't create from the format passed, it will thrown an exception that we catch, log and return false
And as #PtrTon mentioned, you need to bail on first validation fail
Now assuming a validation logic like this
Route::post('/', function () {
$validate = request()->validate([
"from_date" => "bail|required|date_format:Y-m-d H:i:s|validate_timezone",
]);
dd($validate);
});
And a view form like this
<form action="/" method="post">
#csrf
<input type="datetime" name="from_date" value="2019-10-16 15:03">
<button type="submit">Submit</button>
</form>
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
The value of the date_from is not valid for both date_format and validate_timezone but only the validation error message of date_format will be returned
Hope this helps

Related

How do you send validation errors to a blade view using the Validator facade? Error: Serialization of 'Closure' is not allowed

How do I use validateWithBag90 in Laravel 9? I tried a lot of combinations and I'm getting a bit frustrated.
$validator = Validator::make($request->all(), [
'old' => 'required',
'new' => 'required|string|confirmed',
]);
if ($validator->fails()) {
return redirect()->back()->with('error', $validator);
}
I'm getting this error.
Serialization of 'Closure' is not allowed
Any ideas?
Manually Creating Validators
After determining whether the request validation failed, you may use
the withErrors method to flash the error messages to the session. When
using this method, the $errors variable will automatically be shared
with your views after redirection, allowing you to easily display them
back to the user. The withErrors method accepts a validator, a
MessageBag, or a PHP array.
Instead of:
// ...
->with('error', $validator); ❌
// ...
Use this:
// ...
if ($validator->fails()) {
return redirect()
->back()
->withErrors($validator) ✅
->withInput();
}
// ...
Addendum
Displaying The Validation Errors
An $errors variable is shared with all of your application's views
by the Illuminate\View\Middleware\ShareErrorsFromSession middleware,
which is provided by the web middleware group. When this middleware is
applied an $errors variable will always be available in your views,
allowing you to conveniently assume the $errors variable is always
defined and can be safely used. The $errors variable will be an
instance of Illuminate\Support\MessageBag.
<!-- /resources/views/post/create.blade.php -->
<h1>Create Post</h1>
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
<!-- Create Post Form -->

Problem on setting error message if insert fails

When doing add activity inside store method, after passing validation I am calling a method that returns success or failure.
But on failure, I am not able to handle the code properly.
If I redirect, am not getting the old value.
So How do i return to create method with error message & old value both?
Any way to populate the $errors array?
Am new to Laravel. Thanks in advance
public function store(Request $request, AppMailer $mailer)
{
$validatedData=$request->validate([
.......
........
]);
$tracking_model = new Tracking;
$result = $tracking_model->add($request->all());
if ($result === true) {
return redirect('posts')->with('success', 'Created Successfully');
}
else{
$err_msgs = $result;
//what to do here ???????
// return redirect('posts/create')->with('error', $err_msgs);
}
}
try this
in the controller
return redirect('posts/create')->withInput()->withErrors($err_msgs);
and in view .blade
#if ($errors->any())
#foreach ($errors as $error)
...
#endforeach
#else
No tags
#endif

How do i separate two error message in laravel using one error blade file?

Say,i have two form in one page.I have included one error blade file bellow both of the form. Now when i make wrong in one form & submit it the error message is showing bellow the both form.Its normal.But my question is, how do i separate this two error message,how can i differentiate by giving them two different name?
Give this a try
return redirect()->back()->withErrors([
'form1.name' => 'name is required in Form 1',
'form1.email' => 'email is required in Form 1',
'form2.city' => 'city is required in form 2'
]);
in your view
#if($errors->any())
#foreach ($errors->get('form1.*') as $error) {
{{ $error }}
#endforeach
#endif
So you can group errors by form using array notation form.name and get all with $errors->get('form.*).
Read more about errors here: https://laravel.com/docs/5.4/validation#working-with-error-messages
If you're using Form Request Validation, you can change the errorBag property to get a unique array of errors for your view file.
In your Request file:
class MyFormRequest {
protected $errorBag = 'foobar';
public function rules() { // ... }
}
In your controller:
public function store(MyFormRequest $request) {
// Store entry.
}
Then in your view file:
#if ($errors->foobar->isNotEmpty())
// Work with the errors
#endif
You can use the named error bags.
$validator = Validator::make($request->all(), [
'field1' => 'required',
'field2' => 'required|digits:1',
]);
if ($validator->fails()) {
return back()
->withErrors($validator, 'form1error')
->withInput();
}
To print the error in blade file use-
#if(count($errors->form1error)>0)
<ul>
#foreach($errors->form1error->all() as $error)
<li>{{$error}}</li>
#endforeach
</ul>
#endif

Laravel 5.2 Custom validation message with custom validation function

I want to create custom validation rule with custom validation error message. For this I created a rule:
$rule => [
'app_id' => 'isValidTag'
]
And for custom message:
$message => [
app_id.isValidTag => 'Not a Valid id'
];
After that I created Service Provider:
class CustomValidationServiceProvider extends ServiceProvider
{
public function boot() {
//parent::boot();
$this->app->validator->resolver(function($transator,$data,$rules,$messages){
return new CustomValidator($transator,$data,$rules,$messages);
});
}
}
And my Custom validation class is:
class CustomValidator extends Validator {
if(empty($parameters)) {
return true;
}
$conext = $parameters[0];
$tag = Tag::where('id', $value)->where('context', $conext)->get();
$flag = false;
if($tag->count() > 0) {
$flag = true;
}
return $flag;
}
All is working fine but the issue is my custom message for app_id.isValidTag is not working even all other message are working fine.
Please suggest me what I missing here or in Laravel 5.2 there is some change to display message. Any idea will be appreciated.
Here is a great tutorial for this: http://itsolutionstuff.com/post/laravel-5-create-custom-validation-rule-exampleexample.html
I think you did it Laravel 4.* way. This is how it is done in Laravel 5.2
in my example where i was making registration authorisation form so files like AuthController.php was premade:
AuthController.php
Validator::make($data, [
...
// add your field for validation
'name_of_the_field' => 'validation_tag', // validation tag from validation.php
...
CustomAuthProvider.php
// if you didn't make a custom provider use Providers/AppServiceProvider.php
public function boot() {
...
Validator::extend('validation_tag', function($attribute, $value, $parameters, $validator) {
// handle here your validation
if ( your_query ) {
return true;
}
return false;
});
validation.php
...
// add your validation tag and message to be displayed
'validation_tag' => 'The field :attribute isn't good',
...
file.blade.php
// to add at the end of the page all your errors add
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif

Call to a member function isEmpty() on a non-object?

I make my view in the controller via:
$data = Lib::index();
$view = View::make('index')
->with('data', $data)
->render();
return $view;
I can check if data is empty in the controller via:
$data->isEmpty();
But when I try the same thing in the view I get the error:
Call to a member function isEmpty() on a non-object
Why?
Here's the code for Lib::index():
$page = isset($_GET['page']) ? ($_GET['page']) : 1;
Paginator::setCurrentPage($page);
try {
$data = Asset::with(array('sizes'=> function($query){
$query->select('width', 'height', 'asset_id');
}))->where('active', 1)->orderBy('updated_at', 'DESC')->paginate(Config::get('p.results_per_page'), array('id', 'alt'));
}
catch (QueryException $e) {
App::abort(404);
}
return $data;
isEmpty() is a Collection method. For some weird reasons, in views, it sometimes refer to an empty Collection as null. The safest check, in my opinion would be to do a counts check, like so:
if (count($data)) {...}
This works well both in Controllers and Views.
consider you are getting some information as collection;
$UserInfo = User::where('phone', $phone_number)->first();
use this code to for error check
if(empty($UserInfo)){
return redirect()->back()->withErrors('we don't have a user with this phone number ');
}
and add below code into your blade
#if(count($errors)>0)
<div class="alert alert-danger">
<ul>
#foreach($errors->all() as $error)
<li>{{$error}}</li>
#endforeach
</ul>
</div>
#endif
best regards
Try
> var_dump($data);
in the view.
See what it shows up. This might help further investigate the error.
Then In accordance go ahead with
> foreach($data as $moredata){
> $moredata->isEmpty(); }
Should work.

Resources