Laravel 5.2: withErrors on redirect not working - laravel

I'm currently struggling with a Laravel problem I can't fix myself. If I pass errors using withErrors() the errors are not passed to the Error Bag ($errors).
My Controller (FormController):
public function contact(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'message' => 'required',
]);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput($request->all());
}
return redirect()->back();
}
The thing is, also withInput() is not working. Where could the problem come from? I appreciate your help!
(Part of) the defined routes.php:
Route::group(['middleware' => 'web'], function(){
Route::post('/contact', 'FormController#contact');
});
Session config
return [
'driver' => env('SESSION_DRIVER', 'memcached'),
'lifetime' => 120,
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => null,
'table' => 'sessions',
'lottery' => [2, 100],
'cookie' => 'session',
'path' => '/',
'domain' => null,
'secure' => false,
];

In Laravel 5.2 you need to use the web middleware in your routes to pass the errors to the view.
Route::group(['middleware' => ['web']], function () {
Route::get('/', function() {
return view('welcome');
});
});

Don't pass anything to the withInput
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
and use the old function to get the flashed data
$name = $request->old('name');
or
{{old('name')}}
Hope it helps

If the controller that you are redirecting to is also using withErrors() function, the error messages in redirect()->back()->withErrors($validator) will be overwritten.
But, the old messages are still in session. So you can still read and display them with session('errors'):
#if ($errors->any())
<div class="alert alert-danger">
<ul class="my-0">
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#elseif (null !== session('errors') && session('errors')->any())
<div class="alert alert-danger">
<ul class="my-0">
#foreach (session('errors')->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif

This can be due to session problem. To diagnose this problem use print_r($request->session()). if you are getting different id in session object that means session is not setting up properly.
To get it done open Kernel.php
dont specify below line in $middleware array
specify these below line in web middleware group and $middlewarePriority array
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,

Related

Using the redirect method, errors are not sent to view

When I use return view('login')->withErrors($validator->errors());, I get the errors returned if any. Now, if I use the Redirect method/class, it doesn't return the data.
I need to use redirect. I tested it in several ways, going through the different errors, but nothing works. I've read documentation, blogs and everything I do doesn't work.
I already tried return Redirect::back()->withErrors(['msg' => 'The Message']); and in the blade `{{ session()->get('msg') }}, but nothing .
I need some help as I have tried many things and nothing works.
Controller:
public function checkUserExists(Request $request)
{
$email = $request->input('email');
$validator = Validator::make(
$request->all(),
[
'email' => ['required', 'max:255', 'string', 'email'],
'g-recaptcha-response' => ['required', new RecaptchaRule],
],
$this->messages
);
if ($validator->fails()) {
// return view('login')->withErrors($validator->errors());
// return Redirect::back()->withErrors(['msg' => 'The Message']);
return Redirect::route('login')->withErrors($validator->errors());
// return Redirect::route('login')->withErrors($validator);
// return redirect()->back()->withErrors($validator->errors());
// return Redirect::back()->withErrors($validator)->withInput();
}
...
}
At the moment my bucket is just with this:
{{-- Errors --}}
#if ($errors->any())
<div class="alert alert-danger" role="alert">
<ul>
#foreach ($errors->all() as $key => $error)
<li>
{{ $error }}
</li>
#endforeach
</ul>
</div>
#endif
Version of Laravel: "laravel/framework": "^7.29",
try this code to pass the errors back to the view:
public function checkUserExists(Request $request)
{
$email = $request->input('email');
$validator = Validator::make(
$request->all(),
[
'email' => ['required', 'max:255', 'string', 'email'],
'g-recaptcha-response' => ['required', new RecaptchaRule],
],
$this->messages
);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
...
}
& in your view, you can access the errors using with:
{{-- Errors --}}
#if ($errors->any())
<div class="alert alert-danger" role="alert">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
this should work if your view is correct
and you are using the correct path to your view
in your redirect()->back() method

Why Validator passes wrong request?

There is method:
public function index(RolesService $customServiceInstance, Request $request)
{
$validator = Validator::make($request->all(), [
'email.*' => 'required|email',
'name.*' => 'required|string'
]);
if ($validator->fails()) {
dd('wrong request');
//throw new ValidationException($validator);
}
dd('good request');
}
I do POST request without body (email[], name[]), why despite this I always get
dd('good request');?
Why if ($validator->fails()) {} is false?
I send Content-Type: application/json
* is used to check the values in array. But what if that array doesn't even exist? Check the array first and then the values in array. So it would be like
$validator = Validator::make($request->all(), [
'email' => 'required|array',
'email.*' => 'required|email',
'name' => 'required|array',
'name.*' => 'required|string'
]);
I recommend to use built in validator in the controller itself like this:
$this->validate($request, [
'email' => 'required|email',
'name' => 'required|name'
]);
and you can even surround it with try catch so you can get the exception and handle it in your own way. Or leave it as it is and laravel will redirect you back to the page with a variable which contains the errors of course if the validator fail. you can access like this:
#if ($errors->any())
<div class="alert alert-{{ session('message-status') }} alert-dismissible">
<button type="button" class="close" data-dismiss="alert"><span>×</span></button>
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
Or you can do it in a way which is much more neat and maintainable by using Form-Request:
php artisan make:request MyRequest
and put all those validations in that form request.
I don't know your request object but i'll try to explain.
asterisk * going into inner array objects like this:
Request:[
[...],
[...],
[...],
]
In your code, laravel searching for
Request:[
email: [
***everything inside email
],
]
If your request is looks like this:
Request:[
email: [
"test#gmail.com",
"test2#gmail.com",
"test3#gmail.com",
...,
],
]
There won't be an problem. Just i need to see what request sending you if you can provide it then i can help you better.

Laravel & Ajax send HTML form with errors

Here is an action:
public function postMessageAjax(Request $request)
{
$this->validate($request, [
'username' => 'required|string|regex:/^[a-zA-Z\d]+$/',
'email' => 'required|string|email',
'homepage' => 'nullable|string|url',
'text' => 'string',
'captcha' => 'required|captcha',
],
[
'captcha.captcha' => 'The captcha is incorrect',
'username.regex' => 'Use English letters and digits only',
]);
$message = new Message();
$message->username = $request->get('username');
$message->email = $request->get('email');
$message->homepage = $request->get('homepage');
$message->text = strip_tags($request->get('text'));
$message->ip = $request->ip();
$message->browser = get_browser($request->header('User-Agent'))->browser;
$message->save();
return view('Guestbook.postMessage');
}
And here is the view:
{!! BootForm::open(['id' => 'messageForm']) !!}
{!! BootForm::text('username') !!}
{!! BootForm::email('email') !!}
{!! BootForm::text('homepage') !!}
{!! BootForm::textarea('text') !!}
{!! captcha_img('flat') !!}
{!! BootForm::text('captcha') !!}
{!! BootForm::submit('Send') !!}
{!! BootForm::close() !!}
The problem is that Laravel somehow determines that that is an Ajax request and set an JSON of errors (if they're present) to Response instead of retrieving HTML code of form plus errors messages for each input individually. The question is: how do I force it to render the view with errors like if it weren't through Ajax?
UPDATE: this is what I want to get (the form itself and errors if they're present):
For #OuailB:
I've just noticed that when I do a normal POST request, it redirects me to the same page through a GET request so it seems like the error messages actually appear in the GET's body, not POST's so maybe there is no way. I'll think about it, thanks for your help!
You can create validator manually, and if it fails return what you want:
$validator = Validator::make($request->all(), [
'username' => 'required|string|regex:/^[a-zA-Z\d]+$/',
'email' => 'required|string|email',
'homepage' => 'nullable|string|url',
'text' => 'string',
'captcha' => 'required|captcha',
],
[
'captcha.captcha' => 'The captcha is incorrect',
'username.regex' => 'Use English letters and digits only',
]);
if ($validator->fails()) {
return Redirect::back()
->withErrors($validator)
->withInput($request->all());
}
Try this code:
public function postMessageAjax(Request $request)
{
$validator = Validator::make($request->all(), [
'username' => 'required|string|regex:/^[a-zA-Z\d]+$/',
'email' => 'required|string|email',
'homepage' => 'nullable|string|url',
'text' => 'string',
'captcha' => 'required|captcha',
],
[
'captcha.captcha' => 'The captcha is incorrect',
'username.regex' => 'Use English letters and digits only',
]);
if ($validator->fails()) {
return view('Guestbook.postMessage')
->withErrors($validator);
}
// Store your message here
}
Edit :
For displaying the errors, you can add this code into your view :
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif

Laravel 5.2 - not show errors

It's impossible to show errors in views
here is my Controller:
public function create(){
return view('articles.create');
}
public function store(Request $request){
$this->validate($request, [
'title' => 'required|max:5',
'content' => 'required',
]);
}
this is my view create.blade.php:
#if (count($errors) > 0)
<!-- Form Error List -->
<div class="alert alert-danger">
<strong>Whoops!</strong> Something went wrong!.<br><br>
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
Kernel.php
ShareErrorsFromSession already there
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,
],
here is the route.php
i have added the route in web
Route::group(['middleware' => ['web']], function () {
Route::get('articles/create', 'ArticlesController#create'); // Display a form to create an article...
});
Route::get('articles', 'ArticlesController#index'); // Display all articles...
Route::post('articles', 'ArticlesController#store'); // Store a new article...
Route::get('articles/{id}', 'ArticlesController#show');
You can try something like this.
$data = array();
$messages=array(
'required' => "You can't leave this empty",
);
$datavalidate = array(
'name' => $request->name,
);
$rules = array(
'name' => 'required',
);
$validator = Validator::make($datavalidate,$rules,$messages);
if($validator->fails()){
return Redirect::back()->withErrors($validator);
}
And now print it on the view file.
{!! dd($errors) !!}

Laravel 5.2 validation errors

I have some trouble with validation in Laravel 5.2
When i try validate request in controller like this
$this->validate($request, [
'title' => 'required',
'content.*.rate' => 'required',
]);
Validator catch error, but don't store them to session, so when i'm try to call in template this code
#if (isset($errors) && count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
Laravel throw the error
Undefined variable: errors (View: /home/vagrant/Code/os.dev/resources/views/semantic/index.blade.php)
When i'm try validate with this code
$validator = Validator::make($request->all(), [
'title' => 'required',
'content.*.rate' => 'required'
]);
if ($validator->fails()) {
return redirect()
->back()
->withInput($request->all())
->withErrors($validator, 'error');
}
Variable $error also not available in template but if i try to display errors in controller
if ($validator->fails()) {
dd($validator->errors()->all());
}
Errors displays but i can't access to them from template.
What's wrong?
Update as of Laravel 5.2.27
Laravel now supports the web middleware by default as you can see here: source
In other words, you no longer need to wrap your routes around the web middleware group because it does it for you in the RouteServiceProvider file. However, if you are using a version of Laravel between 5.2.0 and 5.2.26, then refer to the method below:
Below only applies to Laravel 5.2.0 to 5.2.26
Without seeing your routes.php or Kernel.php file, here is what I suspect is happening.
The way middlewares work has changed from 5.2 and 5.1. In 5.1, you will see this in your app/Http/Kernel.php file:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\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,
];
This array is your application's global HTTP middleware stack. In other words, they run on every request. Take a note at this particular middleware: Illuminate\View\Middleware\ShareErrorsFromSession. This is what adds the $errors variable on every request.
However, in 5.2, things have changed to allow for both a web UI and an API within the same application. Now, you will see this in that same file:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
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',
],
];
The global middleware stack now only checks for maintenance. You now have a middleware group called "web" that includes a bulk of the previous global middleware. Remember that it is like this to allow for both a web UI and an API within the same application.
So how do we get that $errors variable back?
In your routes file, you need to add your routes within the "web" middleware group for you to have access to that $errors variable on every request. Like this:
Route::group(['middleware' => ['web']], function () {
// Add your routes here
});
If you aren't going to build an API, another option is to move the "web" middlewares to the global middleware stack like in 5.1.
Try using
return redirect()->back()
->withInput($request->all())
->withErrors($validator->errors()); // will return only the errors
Try to replace:
->withErrors($validator, 'error');
with:
->withErrors($validator);
// Replace
Route::group(['middleware' => ['web']], function () {
// Add your routes here
});
// with
Route::group(['middlewareGroups' => ['web']], function () {
// Add your routes here
});
I have my working validation code in laravel 5.2 like this
first of all create a function in model like this
In model add this line of code at starting
use Illuminate\Support\Facades\Validator;
public static function validate($input) {
$rules = array(
'title' => 'required',
'content.*.rate' => 'required',
);
return Validator::make($input, $rules);
}
and in controller call this function to validate the input
use Illuminate\Support\Facades\Redirect;
$validate = ModelName::validate($inputs);
if ($validate->passes()) {
///some code
}else{
return Redirect::to('Route/URL')
->withErrors($validate)
->withInput();
}
Now here comes the template part
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
and Above all the things you must write your Route like this
Route::group(['middleware' => ['web']], function () {
Route::resource('RouteURL', 'ControllerName');
});
Wrap you Routes in web middleware like below:
Route::group(['middleware' => ['web']], function () {
// Add your routes here
});
and In app\Http\Kernel.php move \Illuminate\Session\Middleware\StartSession::class from the web $middlewareGroups to $middleware
Hope it will solve your problem.
Route
Route::group(['middlewareGroups' => ['web']], function () {
// Add your routes here
Route::resource('/post', 'PostController');
});
Functions
public function store(Request $request){
$this->validate($request, [
//input field names
'title' => 'required|max:20',
'body' => 'required',
]);
}
View
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
This will work
Route::group(['middlewareGroups' => ['web']], function () {
// Add your routes here
});
as well as this also works
Route::post('location',array(
'as'=>'location',
'middlewareGroups'=>'web',
'uses'=>'myController#function'
));
// Controller
$this->validateWith([
'title' => 'required',
'content.*.rate' => 'required',
]);
// Blade Template
#if ($errors->has('title'))
<span class="error">
<strong>{{ $errors->first('title') }}</strong>
</span>
#endif
#if ($errors->has('anotherfied'))
<span class="error">
<strong>{{ $errors->first('anotherfied') }}</strong>
</span>
#endif
Find the documentation.

Resources