redirect route for validation in laravel - php

I have a problem with the redirectRoute property in Laravel. What I want to do is: after the validation of the request, for example, the register request fails, redirect to another view with the proper errors. I have tried with protected $redirectRoute = '/route-name' in the RegisterController but it's not working. I'm using Laravel 5.4

See here: https://laravel.com/docs/5.4/validation#manually-creating-validators
You'll need to manually create the validator and then you can tell it exactly where to redirect to if the validation fails:
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
And if you are using Form Requests, you can override the following properties to redirect to a custom location:
protected $redirect; // A simple URL. ex: google.com
protected $redirectRoute; // A route name to redirect to.
protected $redirectAction; // A controller action to redirect to.

Updated answer, tested in Laravel 8. it is possible to create a ValidationException and set a custom redirect on it.
Summary:
use Illuminate\Validation\ValidationException;
$validator->setException( (new ValidationException($validator))->redirectTo('your/custom/location'));
$validator->validate();

Related

Laravel : How can I modify auth:sanctum middleware to return a 401 instead of redirect to login route?

Good evening,
I encounter a problem using Laravel and Sanctum to build an Api for a Mobile application.
I followed the documentation and define a route to get a token :
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
Route::post('/sanctum/token', function (Request $request) {
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return $user->createToken($request->device_name)->plainTextToken;
});
Tested it with postman, everything works fine, if I pass the right login and password, I'm able to get my token.
Now the problem I'm facing : I protected a route as the documentation said by using this middleware :
Route::middleware('auth:sanctum')->get(' ....'
If I pass my token in headers, it works, but if I don't, Laravel tries to redirect me to /login route, which I don't want of course because I'm creating a mobile application.
** What I want is to receive a 401 if my token isn't valid. **
I tried to define a new middleware and copy the verification of the 'auth:sanctum' but I can't even find where this is defined, since it is not in the Kernel.php file.
I hope someone could explain me how I could find the code of 'auth:sanctum', so I can understand it and create a middleware with the comportement I need, but any help would be appreciate.
Thanks you in advance.

FormRequest not populating $request->old() after validation failure

My request object isn't receiving old() data when the form fails validation. I am receiving the error messages, but none of the old input data.
I've read a few solutions on similar questions that reference making changes to the redirect on the controller, but that won't solve this problem because the redirect is done by the function referenced below within the FormRequest Class and not the Controller.
Has anyone else experienced this same issue? I've upgraded my instance as I read a few forums that referenced existing bugs, but the issue still exists.
Any help would be appreciated.
Versions: I've tried this on laravel 5.4, 5.7 and 5.8 and none of them are rendering old data.
How I'm doing Request Validation
The validation is being done via the standard Requests file that extends FormRequest.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CustomerManagementRequest 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 [
'first_name' => 'required|min:2',
'last_name' => 'required|min:2',
'email' => 'required|min:4',
];
}
}
How I'm trying to access the old data on my view:
value="{{old('first_name')}}"
The Redirect and validation being done in FormRequest
The redirect is being done via the Laravel standard FormRequest class.
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
The Validator Response: This is what I see when I vardump the above function. It does have my form data.
Validator {#629 ▼
#data: array:11 [▼
"_token" => "1ynKXxi551UBGbJq6ftLsW6VsClZzmbZdHiHIxyt"
"active_from_date" => "04/04/2019 10:58 PM"
"last_sync_date" => "04/04/2019 11:00 PM"
"first_name" => "Pizza"
"last_name" => "Dough"
"email" => null
"full_phone" => null
"phone" => null
]
}
vardumping the old() parameter in the view returns an empty array
[]
After validation you should check all validation is passed or not. In controller's method you can do like this,
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
$messages = $validator->errors()->getMessages();
return back()
->withErrors($messages)
->withInput();
}
Hope this helps :)
I found the solution to this and thought I'd share it in case it helps anyone out there wracking their brains trying to figure a similar issue out.
I had a custom middleware called ViewData that had a session()->save() command at the end of it which was saving over flashed data, thus causing my array of old inputs to be empty.
Here is how I stepped through it for those of you debugging a similar issue.
First I tried to create a manual validation in my controller to overrule an issue with FormRequest. I then followed the validator to the ShareErrorsFromSession middleware in the kernel.
I realized I had a middleware that ran after this middleware (I call it ViewData) and that middleware stores some variables to session.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
//\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\ViewData::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
I scrolled through and found a session()->save(). This save saved over the work being done by the withInput, essentially keeping old empty. I removed the save session (as it wasn't of value) and now old() contains the data expected.

Laravel api route validation not validating

I did move from Lumen to Laravel and now converting my project over. Everything is working except the validation. For some reason, if I try to validate, it just redirects to the welcome.blade.php view. What could cause this?
I am using only the API part of routes, not the view. I am not dealing with views. I am using the stateless part of Laravel.
According to documentation, I can validate like this:
$this->validate($request, [
'title' => 'required|unique|max:255',
'body' => 'required',
]);
If validation passes, your code will keep executing normally. However,
if validation fails, an
Illuminate\Contracts\Validation\ValidationException will be thrown.
I also tried to force it to return JSON response without success:
$validator = $this->validate($request, ['email' => 'required']);
if ($validator->fails()) {
$messages = $validator->errors();
return new JsonResponse(['status' => 'error', 'messages' => $messages]);
}
However, mine doesn't fail but just returns the welcome view with response code of 200. I have tried pretty much all the possible validation methods from the documentation and from google. Non of them are working.
I even tried with clean laravel install, declared one test route and test controller which had the validation and the result is the exact same.
Is the validation even meant to be compatible with the restful/stateless part of Laravel?
Any suggestion is much appreciated.
1- first the unique key needs a table, per example if you want the email to be unique in the users table you do as follows:
'email' => 'required|unique:users',
I think may be you have placed your route in route/web.php file. Replace that code from web.php to api.php
Try to place your API endpoints in route/api.php file.
And remember you need to add prefix /api in your route.
Ex : test.com/api/users.

Laravel : BadMethodCallException Method [show] does not exist

(1/1) BadMethodCallException
Method [show] does not exist. in Controller.php (line 82)
I am new to Laravel and PHP and have been stuck on this error for a very long time with other questions not providing a solution. I was following an example (where the example worked) and made very little changes beside name changes.
Here is the code:
web.php file
Route::get('/', 'PagesController#home');
Route::get('faq', 'PagesController#faq');
Route::resource('support', 'UserInfoController');
UserInfoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\UserInfo;
class UserInfoController extends Controller
{
//
public function create(){
$userInfo = new UserInfo;
return view('contact', ['userInfo' => $userInfo]);
}
public function store(Request $request){
$this->validate($request, [
'name' => 'required',
'email' => 'required',
'subject' => 'required',
'description' => 'required',
]);
UserInfo::create($request->all());
return redirect()->route('contact')->with('success','Enquiry has been
submitted successfully');
}
}
UserInfo.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class UserInfo extends Model {
protected $fillable = [
'name','email','subject','description',
];
}
The Route::resource is the one giving me the problem as I am trying to access the page support/contact. Would be very grateful if someone knew how to solve this.
That is because you are doing resource routes in your routes.php file that generates all the routes for the CRUD functions when you have to generate a route for the show method you find that it does not exist.
To solve it only creates the methods that you ask or, also you can define only the routes that you need.
The controller is trying to invoke the 'show' method - which you should have defined if you're going to load /support/{id} via GET in your browser. You can see the expected methods for a resource here:
https://laravel.com/docs/5.4/controllers#resource-controllers
You can also make your life somewhat easier by starting with a valid controller by using the built in generator:
php artisan make:controller UserInfoController --resource
If you don't want to supply ALL the methods, you have to specify, for example:
Route::resource('support', 'UserInfoController', ['only' => [
'create', 'store'
]]);
Have you added method Show to your Controller ? Route::Resource has 7 basic routes:
Verb Path Action Route Name
GET /support index support.index
GET /support/create create support.create
POST /support store support.store
GET /support/{support} show support.show
GET /support/{support}/edit edit support.edit
PUT /support/{support} update support.update
DELETE /support/{support} destroy support.destroy
As you see there is a route called show which will be default when you route to support so you must connect this route to it's method in the controller which is in resource case CONTROLLER/show, however in your case you're trying to get a static page from a prefix called support which is different from resources because show in resource handling dynamic results.
Use this syntax to get a page called contact from prefix called support
Route::prefix('support')->group(function () {
Route::get('contact', function () {
// Matches The "/UserInfoController/contact" URL
});
});

Using ValidatesRequests trait in Laravel

Here's the code from my AuthController:
public function postRegister(Request $request)
{
$this->validate($request, [
'name' => 'required|min:3',
'email' => 'required|email|unique:users',
'password' => 'required|min:5|max:15',
]);
}
If the validation fails I'm getting redirected to the previous page. Is there a way to pass additional data along with the input and the errors (which are handled by the trait)?
Edit: Actually, the trait does exactly what I want, except the additional data I want to pass. As #CDF suggested in the answers I should modify the buildFailedValidationResponse method which is protected.
Should I create a new custom trait, which will have the same functionality as the ValidatesRequests trait (that comes with Laravel) and edit the buildFailedValidationResponse method to accept one more argument or traits can be easily modified following another approach (if any exists)?
Sure you can, check the example in the documentation:
http://laravel.com/docs/5.1/validation#other-validation-approaches1
Using the fails(); method, you can flash the errors and inputs values in the session and get them back with after redirect. To pass other datas just flash them with the with(); method.
if ($validator->fails()) {
return back()->withErrors($validator)
->withInput()
->with($foo);
}

Categories