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.
Related
I have a simple route in Laravel 8 to return some request data. But when I send the request in Postman with POST selected, I get an error of "The GET method is not supported for this route." Keep in mind, I have POST selected in Postman, not GET.
Here is the route:
Route::post('post-route', 'UserController#postFunction');
Here is is the function being called in UserController:
public function postFunction(Request $request) {
return [
'id1' => $request->id1,
'id2' => $request->id2,
];
}
In Postman I am passing the data as json:
{
'id1': 1234,
'id2': 4321
}
I am simply trying to make sure I am passing the correct data in the request but I am getting this error. Why is it trying to hit a GET request?
You can't test your POST, PUT or DELETE routes with Postman because Laravel uses the CSRF middleware protection.
If you really want to use Postman, you need to comment it to disable this middleware temporarly in app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
(...)
//\App\Http\Middleware\VerifyCsrfToken::class,
],
(...)
];
But don't forget to enable it again once you want to deploy your project in production!
If you don't want to disable temporarly the CSRF middleware, you can follow the steps mentioned here https://gist.github.com/ethanstenis/3cc78c1d097680ac7ef0, but it's a little longer.
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();
I'm pretty out of any ideas right now.
The case is: I have a route for an API-endpoint (working fine, responding JSON etc.).
If I now apply the built-in 'auth' middleware to the route, I'm redirected ALWAYS to the /home route. Looks like I'm doing sth. wrong with the auth? I think wrong, because:
This curious redirect also kicks in, if I don't use 'auth' but a custom middleware, that contains NOTHING but
public function handle($request, Closure $next)
{
print "WTF";
throw new AuthenticationException('Unauthenticated.');
}
[the print and the Exception are never thrown! I'm landing again without errors at /home.]
Not all middleware is producing this error: For example, 'auth.basic' and 'web' are just working fine with this route.
I also applied 'web' and my own middleware both to the route according to some results I found, that said that using 'web' solved similar problems for them, but guess what, nothing changed.
TL:DR: If I use my own middleware or 'auth' I'm getting redirected, BEFORE the middleware itself is executed.
Update:
After fiddling around with the code and the great tipp from mnies, I found this very curious Bug:
If I just uncomment AuthenticationException, suddenly my code is working as intended. It may be that loading the Exception-Class calls RedirectIfAuthenticated Middleware?! - which is definitely called!
The easy solution is now, using a different Exception for my custom middleware, but the Problem is that the default 'auth'-MW is also using this Exception and so causing the same Bug.
Remember: I am not using other middleware than just this own one, the bug seems really loading the Exception, like WTF?
So I still need help why this is happening!
Bug: using
throw new AuthenticationException('Unauthenticated.', []);
causes 'guest'-MW (RedirectIfAuthenticated) being called instead of intended MW-stack! (nothing of the original MW-stack is being executed, no matter the order.
Update 2:
It seems that RedirectIfAuthenticated is thrown only because I got redirected before to the /login route (and from there as described to /home through it), but that doesn't change the issue that this random redirect occurs.
[I'm trying atm to reproduce this Bug in a fresh installation]
Update 3: I was not able to reproduce the bug in a fresh installation with Laravel 5.4.19.... Trying to compare both installations now. D:
Using Laravel 5.3.30.
Some of my code for context:
Route:
Route::get('/admin/user/get', ['middleware' => ['simpleauth', 'web'], 'uses' => 'UserEditAdmin\Controllers\Controller#get']);
Custom middleware:
class SimpleAuth
{
public function __construct(){}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
* #throws AuthenticationException
*/
public function handle($request, Closure $next)
{
print "WTF";
throw new AuthenticationException('Unauthenticated.');
}
}
'web' from Kernel.php:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
Have a look at your \App\Http\Kernel.php. It looks like you're always calling the \App\Http\Middleware\RedirectIfAuthenticated middleware (aliased to guest). It you want to debug, you could just throw an exception in that middleware to get a stacktrace of what is called when.
I am trying to display validation errors when going back to a View, in Laravel 5.2. The $errors variable is empty and in a similar question Laravel 5.2 $errors not appearing in Blade it has been proposed to:
(1) move the ShareErrorsFromSession middleware to the $middleware property
or
(2) wrap the relevant route with web middleware.
Of course, solution 1 (which works) is not applicable in my case because I have some API routes, as it is well stated in Laravel 5.2 validation errors.
To be more specific, I am using multiple authentication guard drivers and routes that use token authentication are stateless. So what us left is solution 2. It should work, but it doesn't work (OR I am missing something).
No matter if I place my routes (the ones in which I want to display validation errors) inside the group:
Route::group(['middleware' => ['web','auth:web']], function () {
...
}
or just inside:
Route::group(['middleware' => 'web'], function () {
...
}
the $errors variable seems empty. Dumping the variable gives:
object(Illuminate\Support\ViewErrorBag)#209 (1) {
["bags":protected]=>
array(0) {
}
}
The web group is typically defined in kernel.php as:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
My controller looks like:
$form = Input::all();
$rules = Config::get('validation.contact');
$validation = Validator::make($form,$rules);
if ($validation->fails()){
return Redirect::back()->withErrors($validation);
} else {
...
}
Any ideas?
UPDATE (after answered):
You were right Alexander! I missed that recent change. But what about API routes that need not invoke these middlewares? Should we revert this change as described in Web middleware being applied to API routes in Laravel 5.2 ? If yes, then maybe it is better to strip middlewares from web group and put them in a new group (e.g myweb). This way we are not messing with the framework.
If you are running Laravel 5.2.27 and later, you don't need to include "web" middleware in your routes. Because, starting from the mentioned version, it is already implicitly included by default. In fact, re-including that middleware can cause some odd issues. Source: Validation error in Laravel - $errors array does not get populated after the validation failure
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);
}