Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Request Errors not accessible in blade (Laravel 5.2)

It had been many months since I'm using laravel but never faced such problem.

I have made a simple Request class to validate the the update user request which works fine if validation rules are followed. If validation rule fails we should come back to the previous page and display all errors in html.

According to me I have written everything correctly as I used to write in other applications but the $errors seems to be inaccessible in blade

Following are my required code snippets to debug:

routes.php

Route::group(['middleware' => ['web']], function () {
    Route::get('/users/{id}/edit', 'UserController@edit');
    Route::post('/users/{id}/edit', 'UserController@update');
});

UserController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Requests\UserUpdateRequest;
use App\Models\User;
use App\Models\Role;
use App\Models\Post;

class UserController extends Controller
{    
    public function edit($id)
    {
        try {
            $user = User::find($id);
            $roles = Role::all();
            return view('users.edit', compact(['user', 'roles']));
        }catch(Exception $e) {
            return view('errors.500', compact(['e']));
        }
    }

    public function update($id, UserUpdateRequest $request)
    {
        dd($request);
    }
}

UserUpdateRequest.php

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class UserUpdateRequest extends Request
{
    /**
     * 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 [
            'name'      =>  'required|string|min:4',
            'email'     =>  'required|email',
            'role'      =>  'required|numeric',
            'password'  =>  'required',
        ];
    }
}

edit.blade.php

@extends('master')

@section('title') Edit Users @stop

@section('content')
<div class="row">
    <div class="col-sm-12">
        <h2>Edit User</h2>
    </div>
</div>
<div class="alert alert-warning alert-dismissible" role="alert">
  @foreach($errors->all() as $error)
  {{ $error }}
  @endforeach
</div>
<form action="{{ url('/users/'.$user->id.'/edit') }}" method="post">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <div class="col-sm-6">
        <div class="form-group">
            <label>Name</label>
            <input type="text" name="name" value="{{ $user->name }}" class="form-control" placeholder="Name">
        </div>
    </div>
    <div class="col-sm-6">
        <div class="form-group">
            <label>Email Address</label>
            <input type="text" name="email" value="{{ $user->email }}" class="form-control" placeholder="Email Address">
        </div>
    </div>
    <div class="col-sm-6">
        <div class="form-group">
            <label>Role</label>
            <select name="role" class="form-control">
            @foreach($roles as $role)
            @if($role->id == $user->role)
            <option value="{{ $role->id }}" selected>{{ $role->name }}</option>
            @else
            <option value="{{ $role->id }}">{{ $role->name }}</option>
            @endif
            @endforeach
            </select>
        </div>
    </div>
    <div class="col-sm-6">
        <div class="form-group">
            <label>Password</label>
            <input type="password" name="password" class="form-control" placeholder="New Password">
        </div>
    </div>
    <div class="col-sm-12">
        <div class="form-group">
            <input type="submit" class="btn btn-info btn-block" value="Update">
        </div>
    </div>
</form>
@stop

The HTML response on browser is blank. I also tried <?php dd($errors); ?> which displayed the following

Edit User

ViewErrorBag {#168 ▼
  #bags: []
}

More info here

like image 837
Cybersupernova Avatar asked Apr 11 '16 20:04

Cybersupernova


2 Answers

@VipindasKS is right with his assumption. Since Laravel Version 5.2.28 the web middleware is included in all routes via the RouteServiceProviders's method:

protected function mapWebRoutes(Router $router)
{
    $router->group([
        'namespace' => $this->namespace, 'middleware' => 'web',
    ], function ($router) {
        require app_path('Http/routes.php');
    });
}

Since that version Laravel's default routes.php file only contains:

Route::get('/', function () {
    return view('welcome');
});

So if you upgrade from a previous version, that has a routes.php file like this:

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

Your application will just work fine, because with an composer update you won't touch your RouteServiceProvider (It does not add the mapWebRoutes() method). So the 'web' middleware is only added to the routes within the 'web' group'.

However if you are pulling a fresh installation of Laravel ( currently 5.2.29 ) and have a routes.php with

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

The web middleware stack will be added twice to the routes. You can check this via:

php artisan route:list

Which will show that the 'web' middleware is added twice:

| POST      | users/{id}/edit          |                  | App\Http\Controllers\UserController@update      | web,web    |

This breaks the Session's flash variables as they are normally only intended to last only during one session lifecycle.

So the solution is:

Don't use the 'web' middleware group in the routes.php file if you pulled a fresh instance of laravel.

like image 58
shock_gone_wild Avatar answered Oct 25 '22 01:10

shock_gone_wild


You may want to use withErrors redirect, in case validation fails

    if ($validator->fails()) {
        return redirect()
            ->route('route.here')
            ->withErrors($validator)
            ->withInput();
    }

Also, please check

  \Illuminate\View\Middleware\ShareErrorsFromSession::class,

is there in 'web' middleware in app/Http/Kernel.php

so your kernel.php should look something like:

/**
 * The application's route middleware groups.
 *
 * @var array
 */
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',
    ],
];

If that too doesn't work, you can move the

  \Illuminate\View\Middleware\ShareErrorsFromSession::class,

to the global middleware. (just to try. I won't suggest)

** Make sure sessions work. To have errors returned or to flash messages to the browser, you need to have a session running.

From 5.2, sessions only start if you specify that the route should use the 'web' middleware (which is already done by you in the routes.php).

And, From 5.2.28, web middleware is automatically included in all routes, you can see this in the RouteServiceProvider. so, we don't want to specify a 'web' middleware to the routes.php or in controller unless we have a custom middleware. But, not sure this caused the problem.

like image 42
VipindasKS Avatar answered Oct 25 '22 01:10

VipindasKS