Now, if you try to click Add Role, you will get an error Undefined variable $errors
That variable comes from the default Validation mechanism, exactly as the Laravel documentation says.
packages/laraveldaily/laravel-permission-editor/resources/views/roles/create.blade.php:
// ... <div class="sm:max-w-md px-6 py-4"> @if ($errors->any()) <div class="text-red-500 text-sm mb-4"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form action="{{ route('permission-editor.roles.store') }}" method="POST"> @csrf <div> // ...
So if Laravel docs say that validation error should come automatically, why is it not defined as a variable?
Because that automation comes from the Laravel middleware called "web".
It is automatically enabled in the Laravel project app/Providers/RouteServiceProvider.php
when registering routes/web.php
, but in our package, we haven't specifically enabled it.
Let's fix this by adding it to the Route::group()
.
packages/laraveldaily/laravel-permission-editor/src/PermissionEditorServiceProvider.php:
class PermissionEditorServiceProvider extends ServiceProvider{ public function boot() { Route::prefix('permission-editor') ->as('permission-editor.') ->middleware('web') // <- THIS ->group(function () { $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); }); }}
Now if we reload the browser for the Create Role form...
It works!
Now, while we're discussing the subject of Middleware, it may be beneficial to know not only how to assign the existing Laravel middleware, but also to create your custom one.
For example, let's add a check that Spatie Permission DB tables are created, if we don't find them in the database, it means the package is not configured and we need to throw an exception with the error message.
Like for some other classes, I prefer to run the Artisan command to generate the class outside the package, and then copy the generated file into the package, changing the namespaces.
php artisan make:middleware SpatiePermissionMiddleware
Then, after copying that file and changing namespaces, we have this:
packages/laraveldaily/laravel-permission-editor/src/Http/Middleware/SpatiePermissionMiddleware.php:
namespace Laraveldaily\LaravelPermissionEditor\Http\Middleware; use Closure;use Illuminate\Support\Facades\Schema; class SpatiePermissionMiddleware{ public function handle($request, Closure $next) { if (!Schema::hasTable('roles') || !Schema::hasTable('permissions')) { throw new \Exception('Spatie Laravel Permission package is not configured: missing roles/permissions DB tables'); } return $next($request); }}
Notice that we place that file into src/Http/Middleware
, exactly as we would do in app/Http/Middleware
outside the package.
Now, we need to assign this middleware to our Routes:
packages/laraveldaily/laravel-permission-editor/src/PermissionEditorServiceProvider.php:
use Illuminate\Routing\Router;use Laraveldaily\LaravelPermissionEditor\Http\Middleware\SpatiePermissionMiddleware; class PermissionEditorServiceProvider extends ServiceProvider{ public function boot() { Route::prefix('permission-editor') ->as('permission-editor.') ->middleware(['web', 'spatie-permission']) ->group(function () { $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); }); $router = $this->app->make(Router::class); $router->aliasMiddleware('spatie-permission', SpatiePermissionMiddleware::class); }}
As you can see, the syntax is a bit different than registering the Middleware in a typical app/Http/Kernel.php
outside the package, but it's doing the same thing: assigning the name of spatie-permission
to our Middleware class.
Now, if we don't have the roles
DB table for some reason, we will see this:
Great, we've protected our package from being misconfigured.
Of course, you may add more Middleware classes to secure your routes, like auth
and others.
Speaking of which... Let's make the Middlewares configurable?