Laravel 5.2 validation errors
Asked Answered
S

9

22

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?

Suellensuelo answered 22/12, 2015 at 16:44 Comment(2)
Try "->withErrors($validator, 'error');" without the 'error' so: ->withErrors($validator);Talich
in v5.2 you only put Route in to : Route::group(['middleware' => ['web']], function () { // Add your routes here });Celestina
G
50

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.

Gilemette answered 22/12, 2015 at 17:28 Comment(9)
Indeed, this works! I totally forgot about web middleware!Syconium
Just as a heads up, if your routes are automatically cached you will need to run php artisan route:clear upon this change.Kab
@Suellensuelo please check this answer as the correct one if it solved your problem, it helps others who come here looking for a solution to the same problem!Thekla
thanks, that's a better explanation than anything in the documentation. I think the Laravel guys try to be too smart for their own good. I've found 5.2 to be a real pain to understand via the docs.Camelot
By this, do you mean move all functions (including headers and body) into this function?Duvetyn
@cid, Answering my own question above, yeah, copy them exactly... see laravel.com/docs/5.1/controllers#controller-middlewareDuvetyn
or add public function __construct(){ $this->middleware('web'); } to controllerCornice
@Cornice That will actually not work because "terminatable" middlewares are not supported in the controller. However, there has been a recent change so that web middlewares are supported by default, which I will update in my answer.Gilemette
Far better explanation than Laravel guys on their website >:( @ThomasKimHereon
J
5

Try using

return redirect()->back()
              ->withInput($request->all())
              ->withErrors($validator->errors()); // will return only the errors
Jaxartes answered 30/4, 2016 at 8:15 Comment(0)
N
3

Try to replace:

->withErrors($validator, 'error');

with:

->withErrors($validator);
Newspaperman answered 22/12, 2015 at 17:7 Comment(0)
S
2
// Replace

Route::group(['middleware' => ['web']], function () {
    // Add your routes here
});

// with 

Route::group(['middlewareGroups' => ['web']], function () {
    // Add your routes here
});
Siberia answered 30/5, 2016 at 19:10 Comment(3)
It would be better if you add a description as to why the latter works and what does middleware vs middlewareGroups. Thanks!Stagg
I don’t know exactly (I’m new in PHP and Laravel too) but if you take a look in app\Http\Kernel.php the “web” is defined in $middlewareGroups array. I follow a Laravel tutorial and there is used with “middleware” but in my case it function with “middlewareGroups”. :o)Siberia
This works! The clue (I think) is the naming of the protected variables in the app/Http/Kernel. The given by Thomas Kim contains this, but it wasn't clear until I saw this simple snippet. Thanks! This took me hours to fix!Semifinalist
U
1

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');
});
Umbilication answered 5/5, 2016 at 9:43 Comment(0)
D
0

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.

Doan answered 17/5, 2016 at 4:7 Comment(0)
T
0

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'
));
Tomfoolery answered 14/6, 2016 at 10:16 Comment(0)
S
0
// 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.

Simony answered 16/3, 2018 at 6:22 Comment(0)
D
0

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
Dachia answered 27/9, 2018 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.