Continuing discussion from here
If we have two Requests like:
public function store(FirstRequest $request, SecondRequest $request)
{ ... }
is it possible to run both Requests and not one after another. This way if validation doesn't pass for FirstRequest, SecondRequest won't start and it will create error messages only after FirstRequest passes without any errors.
I think that you can "manually creating validators"
http://laravel.com/docs/5.1/validation#other-validation-approaches
Basically in your method instead of use a a Request injection, use the rules directly in the method and call the $validator->fails() method for every set of rules.
Something like this:
public function store(Request $request){
$rulesFirstRequest = ['field1' => 'required', 'field2' => 'required'];
$rulesSecondRequest = ['field12' => 'required', 'field22' => 'required'];
$validator1 = Validator::make($request->all(), $rulesFirstRequest);
$validator2 = Validator::make($request->all(), $rulesSecondRequest);
if ($validator1->fails() && $validator2->fails()) {
//Do stuff and return with errors
}
// return with success
}
Hope it helps
Related
I have a problem with the laravel validation.
Call to a member function fails() on array
Symfony\Component\Debug\Exception\FatalThrowableError thrown with message "Call to a member function fails() on array"
Stacktrace:
`#0 Symfony\Component\Debug\Exception\FatalThrowableError in
C:\laragon\www\frontine\app\Http\Controllers\authController.php:37
public function postRegister(Request $request)
{
$query = $this->validate($request, [
'user' => 'string|required|unique:users|min:4|max:24',
'email' => 'email|string|required|unique:users',
'pass' => 'string|required|min:8',
'cpass' => 'string|required|min:8|same:pass',
'avatar' => 'image|mimes:jpeg,jpg,png|max:2048',
]);
if ($query->fails())
{
return redirect('/registrar')
->withErrors($query)
->withInput();
}
}
The error is because what the ->validate() method returns an array with the validated data when applied on the Request class. You, on the other hand, are using the ->fails() method, that is used when creating validators manually.
From the documentation:
Manually Creating Validators
If you do not want to use the validate method on the request, you may
create a validator instance manually using the Validator facade. The
make method on the facade generates a new validator instance:
use Validator; // <------
use Illuminate\Http\Request;
class PostController extends Controller
{
public function store(Request $request)
{
$validator = Validator::make($request->all(), [ // <---
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// Store the blog post...
}
}
The ->fails() is called in the response of the Validator::make([...]) method that return a Validator instance. This class has the fails() method to be used when you try to handled the error response manually.
On the other hand, if you use the validate() method on the $request object the result will be an array containing the validated data in case the validation passes, or it will handle the error and add the error details to your response to be displayed in your view for example:
public function store(Request $request)
{
$validatedData = $request->validate([
'attribute' => 'your|rules',
]);
// I passed!
}
Laravel will handled the validation error automatically:
As you can see, we pass the desired validation rules into the validate
method. Again, if the validation fails, the proper response will
automatically be generated. If the validation passes, our controller
will continue executing normally.
What this error is telling you is that by doing $query->fails you're calling a method fails() on something (i.e. $query) that's not an object, but an array. As stated in the documentation $this->validate() returns an array of errors.
To me it looks like you've mixed a bit of the example code on validation hooks into your code.
If the validation rules pass, your code will keep executing normally;
however, if validation fails, an exception will be thrown and the
proper error response will automatically be sent back to the user. In
the case of a traditional HTTP request, a redirect response will be
generated, [...]
-Laravel Docs
The following code should do the trick. You then only have to display the errors in your view. You can read all about that, you guessed it, in... the docs.
public function postRegister(Request $request)
{
$query = $request->validate($request, [
'user' => 'string|required|unique:users|min:4|max:24',
'email' => 'email|string|required|unique:users',
'pass' => 'string|required|min:8',
'cpass' => 'string|required|min:8|same:pass',
'avatar' => 'image|mimes:jpeg,jpg,png|max:2048',
]);
}
I'm trying to validate a request like this.
public function reply(CustomRequest $request)
{
$request->validated();
}
The issue is that it will automatically redirect to the previous page if the validation fails. Whereas I want to do some custom logic.
For example
if($request->validation->fails()) {
// Do things
}
But I can't find a way to do this without passing in validation rules, whereas I want to use the rules from the "CustomRequest" class.
Using the Validator::make(), you can redirect your customised stuff.
Here is an example how you can return the first error in the ErrorBag:
$validator = Validator::make($request->all(), [
'field' => ['required']
]);
if ($validator->fails()) {
return redirect()->back()->with('custom_error', $validator->errors()->first());
};
i have example object with fields
name => John
surname => Dow
job => engineer
and output form with placeholders. some required, some not.
what is best practice for check if it requred and show error with null fields?
There are multiple ways actually you can do that inside of controller method or make use of Laravels Request Classes for me I prefer to use Request Classes
look below I will list the two examples
Validate inside the controller's method
public function test(Request $request){
if($request->filled('name){
/*filled will check that name is set on the current
request and not empty*/
//Do your logic here
}
}
Second way is by using the Validator Facade inside your controller
use Validator;
class TestController{
public function test(Request $request){
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
/*continue with your logic here if the request failed on
validator test Laravel will automatically redirect back
with errors*/
}
}
Third way my favorite one personally
you can generate a Request class using this command
php artisan make:request AddBookRequest
that will generate the request class under "app/Http/Requests/AddBookRequest" , inside of any generated request class you will find two methods authorize() and rules()
in the authorized method you have to return truthy or falsy value this will detect if the current user making the request has authorization to fire this request inside of the rules method you do pretty much as you did in the Validator in the second way check the example
public function authorize(){
return true;
}
public function rules(){
return [
'title' => 'required|string',
'author_id' => 'required|integer'
];
}
then simply in your controller you can use the generated request like this
use App\Http\Requests\AddBookRequest;
public function store(AddBookRequest $request){
/* do your logic here since we uses a request class if it fails
then redirect back with errors will be automatically returned*/
}
Hope this helps you can read more about validation at
https://laravel.com/docs/5.6/validation
I think "simple is the best", just through object and check if properties exists
Ref: property_exists
Example:
if (property_exists($object, 'name')) {
//...do something for exists property
} else {
//...else
}
I would like to make a validator through the usage of Laravel requests, and validation is working fine. But if I don't do them in the controller I can't return back to view with errors if validator fails.
Is it possible to implement this:
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
within the custom request? Something like this maybe:
public function rules()
{
return [
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:6|confirmed',
]; // ->withErrors()
}
FormRequest by default returns the user back to the previous page with the errors and input. You don't have to specify it manually. Just set the rules and use the newly created FormRequest in your controller method instead of using the Request object.
This is what happens under the hood.
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
I'm learning Laravel 5 and trying to validate if an email exists in database yet then add some custom message if it fails. I found the After Validation Hook in Laravel's documentation
$validator = Validator::make(...);
$validator->after(function($validator) use ($email) {
if (emailExist($email)) {
$validator->errors()->add('email', 'This email has been used!');
}
});
if ($validator->fails()) {
return redirect('somewhere')
->withErrors($validator);
}
but I don't really understand what this is. Because I can simply do this:
//as above
if (emailExist($email)) {
$validator->errors()->add('email', 'This email has been used!');
}
//redirect as above
It still outputs the same result. When should I use the 1st one to validate something instead of the 2nd one?
The point of the first method is just to keep everything contained inside of that Validator object to make it more reusable.
Yes, in your case it does the exact same thing. But imagine if you wanted to validate multiple items.
foreach ($inputs as $input) {
$validator->setData($input);
if ($validator->fails()) { ... }
}
In your case you will have to add that "if" check into the loop. Now imagine having to run this validation in many different places (multiple controllers, maybe a console script). Now you have this if statement in 3 different files, and next time you go to modify it you have 3x the amount of work, and maybe you forget to change it in one place...
I can't think of many use cases for this but that is the basic idea behind it.
By the way there is a validation rule called exists that will probably handle your emailExist() method
$rules = [
'email' => 'exists:users,email',
];
http://laravel.com/docs/5.1/validation#rule-exists
There may be many scenarios where you may feel it's requirement.
Just assume that you are trying to build REST api for a project. And you have decided that update request method will not have any required rule validation for any field in request (as there maybe many parameters and you do not want to pass them all just to change one column or maybe you do not have all the columns because you aren't allowed access to it) .
So how will you handle this validation in UpdatePostRequest.php class where you have put all the validation rules in rules() method as given in code.
Further more there may be requirement that sum of values of two or more request fields should be greater or less than some threshold quantity. Then what?
I agree that you can just check it in controller and redirect it from there but wouldn't it defeat the purpose of creating a dedicated request class if we were to do these checks in controllers.
What I feel is controllers should be clean and should not have multiple exit points based on validation. These small validation checks can be handled in request class itself by creating a new Rule or extending your own custom validation or creating after validation hooks and all of them have their unique usage in Laravel.
Therefore what you may want to to do here is create a validation hook where it's assigned is to check whether request is empty or not like the example given below
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (empty($this->toArray())) {
$validator->errors()->add('body', 'Request body cannot be empty');
}
if (!$this->validateCaptcha()) {
$validator->errors()->add('g-recaptcha-response', 'invalid');
}
});
}
And here is the full example for it.
<?php
namespace App\Http\Requests\Posts;
use App\Helpers\General\Tables;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdatePostRequest extends FormRequest
{
public function authorize()
{
return auth()->user()->can('update-post', $this);
}
public function rules()
{
return [
'name' => ['string', 'min:3', 'max:255'],
'email' => ['string', 'email', 'min:3', 'max:255'],
'post_data' => ['string', 'min:3', 'max:255'],
];
}
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (empty($this->toArray())) {
$validator->errors()->add('body', 'Request body cannot be empty');
}
});
}
}
Thanks..
passedValidation method will trigger if the validation passes in FormRequest class. Actually this method is rename of afterValidation method. See: method rename Commit
So you can do like
class RegistrationRequest extends FormRequest
{
/**
* Handle a passed validation attempt.
*
* #return void
*/
protected function passedValidation()
{
$this->merge(
[
'password' => bcrypt($this->password),
]
);
}
}