Source code
What is Laravel-permission?
Not every user needs to have an access to all the data in the database. Let’s take the example of a college website. The access to the data and permissions allowed to a teacher will be different from that of a student. Why? Because their roles and responsibilities are different.
Laravel-permission allows you to do the same with your database. It lets you manage users’ roles and permissions in your database. Let’s see how you can do the same step-by-step.
Prefer watching a video instead? No worries! Just follow along with the video below.
Step 1. Install Laravel project
To keep things simple, I am going to show you how to install Laravel using composer provided that you already have WAMP or XAMPP installation and Composer on your computer.
Copy composer create-project laravel/laravel laravel-permission-demo
cd laravel-permission-demo
Once the application is started after you run the above-mentioned command, you have to start Laravel’s local development server. For that, use Artisan CLI’s serve command.
Now you have to create a new database in PhpMyAdmin and add the database details in the root directory .env file. We are going to use MySQL.
Copy DB_CONNECTION= mysql
DB_HOST= mysql
DB_PORT= 3306
DB_DATABASE= laravel_permission_demo
DB_USERNAME= root
DB_PASSWORD= password
Step 2. Install Breeze
What is Breeze?
Whenever you go to any website, you will often see login and signup forms which also reset and confirm passwords, and verify your email. Lararvel Breeze helps you do exactly this with your website in a simple way.
Now, if you want to assign permissions to your users, you need to have a proper login system. So here is how you can install Breeze and publish the authentication views, routes, controllers, and other resources.
Copy composer require laravel / breeze --dev
php artisan breeze:install
Now it’s time to compile the frontend assets of your application. For a new terminal, run: -
Copy npm install
npm run dev
For database migration: -
Once your migration users and tables are created in your database, you can see the following.
Now you can check your application’s login and register URLs
For login
Copy http://127.0.0.1:8000/login
For register
Copy http://127.0.0.1:8000/register
Step 3. Install Laravel-permission package
Why do we use Laravel permission?
Not everybody needs to get access to everything in your database. Otherwise, you may be running the risk of jeopardizing your invaluable data. Thus, Laravel permissions give you the power to limit access to data as per the roles of the user. So next we will cover how to install the Laravel-permission package.
I would recommend you to first go and check the prerequisites page for user models. Please also check that you don’t have a file named config/permission.php
because this package will publish a file with that name. If you have one, then rename it.
Run this command.
Copy composer require spatie/laravel-permission
You can even manually add the service provider in your config/app.php
file. However, it is optional.
Copy 'providers' => [
// ...
Spatie \ Permission \ PermissionServiceProvider :: class ,
] ;
Now publish the migration and the config/permission.php
config file using: -
Copy php artisan vendor:publish --provider= "Spatie\Permission\PermissionServiceProvider"
Here I want to point out a couple of things: -
If you want to use teams feature, updates your config/permission.php
file and set 'teams' => true
. If you want to use a custom foreign key for teams, you should also change teamforeignkey
. I also recommend you to check the advanced section of docs on UUID steps if your are using UUIDs.
Clear your config cache as it is a bad practice to do config-caching while developing. For clearing caching configurations locally, use these commands: -
Copy php artisan optimize:clear
# or
php artisan config:clear
Once the config and migration have been published and configured, create the tables for this package by running: -
Add all the required traits to your user model. You can refer to the Basic Usage section of the docs to know how to get started using the feature of this package.
Add this line user.php
Copy use Spatie\Permission\Traits\HasRoles;
After that user HasRoles in class.
Copy - use HasApiTokens, HasFactory, Notifiable;
+ use HasApiTokens, HasFactory, Notifiable , HasRoles;
Step 4: Create permission, roles, and screens
What is a role?
The role is the authority we assign to someone for access to the data. The higher someone’s role is, the more permissions he will get. Usually, we assign roles as per the rank of the user. For example - executives may get the role of super admin to do anything he wants. Here is how you can create permissions, roles, and screens.
First, we will create a database seeder for the super admin user.
Copy php artisan make:seeder BasicPermissionSeeder
Use spatie classes in seeder file.
Copy use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;
Now, replace this code in database\seeder\BasicPermissionSeeder.php
Copy <? php
namespace Database \ Seeders ;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate \ Database \ Seeder ;
use Spatie \ Permission \ Models \ Permission ;
use Spatie \ Permission \ Models \ Role ;
use Spatie \ Permission \ PermissionRegistrar ;
class BasicPermissionSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run ()
{
// Reset cached roles and permissions
app () [ PermissionRegistrar ::class ] -> forgetCachedPermissions () ;
// create permissions
$permissions = [
'permission list' ,
'permission create' ,
'permission edit' ,
'permission delete' ,
'role list' ,
'role create' ,
'role edit' ,
'role delete' ,
'user list' ,
'user create' ,
'user edit' ,
'user delete'
];
foreach ($permissions as $permission) {
Permission :: create ( [ 'name' => $permission] ) ;
}
// create roles and assign existing permissions
$role1 = Role :: create ( [ 'name' => 'writer' ] ) ;
$role1 -> givePermissionTo ( 'permission list' ) ;
$role1 -> givePermissionTo ( 'role list' ) ;
$role1 -> givePermissionTo ( 'user list' ) ;
$role2 = Role :: create ( [ 'name' => 'admin' ] ) ;
foreach ($permissions as $permission) {
$role2 -> givePermissionTo ( $permission ) ;
}
$role3 = Role :: create ( [ 'name' => 'super-admin' ] ) ;
// gets all permissions via Gate::before rule; see AuthServiceProvider
// create demo users
$user = \ App \ Models \ User :: factory () -> create ( [
'name' => 'Super Admin' ,
'email' => 'superadmin@example.com' ,
] ) ;
$user -> assignRole ( $role3 ) ;
$user = \ App \ Models \ User :: factory () -> create ( [
'name' => 'Admin User' ,
'email' => 'admin@example.com' ,
] ) ;
$user -> assignRole ( $role2 ) ;
$user = \ App \ Models \ User :: factory () -> create ( [
'name' => 'Example User' ,
'email' => 'test@example.com' ,
] ) ;
$user -> assignRole ( $role1 ) ;
}
}
So, just to recap, till now we have created a super admin user, a test user, and an admin user and assigned to each one of them permissions as per role 1, role 2, and role 3 respectively.
Next, you have to run the database seed command to insert data into the database.
Copy php artisan db:seed --class= BasicPermissionSeeder
Grant Super-Admin access
Gate has allowed all the permissions to the super-admin. We are using Laravel’s default password for the super-admin, which is “password”.
Add below a Gate::before
checking in your AuthServiceProvider
boot function.
Copy use Illuminate\Support\Facades\Gate;
Copy // Implicitly grant "Super-Admin" role all permission checks using can ()
Gate::before(function ($user, $ability) {
if ($user- > hasRole( env( 'APP_SUPER_ADMIN' , 'super-admin' ))) {
return true ;
}
});
Add permission check
Now all the users have full access to the application as we have not added permission to check Laravel’s default can
function.
Copy $user- > can( 'permission create' );
In Blade directives:
Copy @can('permission create')
...
@endcan
Next, we are going to implement CRUD (screen) for the permission and roles.
Step 5: Permission management CRUD
Follow these steps to create permission CRUD for our Laravel Admin panel.
For the permission
Step 1: Create a model
We are going to start by creating a model for permission CRUD. You can create your model using the make:model
Artisan command. It will create a Permission.php
file in app/Models
folder.
We can also create the models and controllers manually.
Copy php artisan make:model Permission
Next is to extend our permission model with Spatie\\Permission\\Models\\Permission
and update the model with the below code.
app/Models/Permission.php
Copy <? php
namespace App \ Models ;
use Spatie \ Permission \ Models \ Permission as OriginalPermission;
class Permission extends OriginalPermission
{
protected $fillable = [
'name' ,
'guard_name' ,
'updated_at' ,
'created_at'
];
}
Step 2: Create a controller
The make:controller
Artisan command is used to create the controllers.
Copy php artisan make:controller Admin / PermissionController -- model = Permission -- resource
The --resource
option is used to quickly create a controller to handle create, read, update, and delete (“CRUD”) operations.
Step 3: Add routes
Extend controllers in web.php file.
Copy use App\\Http\\Controllers\\Admin\\PermissionController;
Add resource route in web.php. We are using auth middleware and Admin namespace.
Copy Route::prefix('admin')- > namespace('App\\Http\\Controllers\\Admin')- > middleware([ 'auth' ])- > group(function() {
Route : :resource( 'permission' , PermissionController::class );
});
Step 4: Add a link to the navigation
So, we have completed the creation of CRUD for permission. Now add the permission link below the Navigation Links on navigation.blade.php.
resources/views/layouts/navigation.blade.php
Copy <!-- Navigation Links -->
< div class = "hidden space-x-8 sm:-my-px sm:ml-10 sm:flex" >
< x-nav-link :href = "route('dashboard')"
:active = "request()->routeIs('dashboard')" >
{{ __('Dashboard') }}
</ x-nav-link >
< x-nav-link :href = "route('permission.index')"
:active = "request()->routeIs('permission.index')" >
{{ __('Permission') }}
</ x-nav-link >
</ div >
For mobile navigation
Copy <!-- Responsive Navigation Menu -->
< div :class = "{'block': open, 'hidden': ! open}" class = "hidden sm:hidden" >
< div class = "pt-2 pb-3 space-y-1" >
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')"> {{ __('Dashboard') }}
</ x-responsive-nav-link >
< x-responsive-nav-link :href = "route('permission.index')" :active = "request()->routeIs('permission.index')" >
{{ __('Permission') }}
</ x-responsive-nav-link >
</ div >
Step 5: Index page with action links
Update index function with permission paginating.
app/Http/Controllers/Admin/PermissionController.php
Copy function __construct ()
{
$this -> middleware ( 'can:permission list' , [ 'only' => [ 'index' , 'show' ]] ) ;
$this -> middleware ( 'can:permission create' , [ 'only' => [ 'create' , 'store' ]] ) ;
$this -> middleware ( 'can:permission edit' , [ 'only' => [ 'edit' , 'update' ]] ) ;
$this -> middleware ( 'can:permission delete' , [ 'only' => [ 'destroy' ]] ) ;
}
public function index ()
{
$permissions = Permission :: latest () -> paginate ( 5 ) ;
return view ( 'admin.permission.index' , compact ( 'permissions' )) -> with ( 'i' , ( request () -> input ( 'page' , 1 ) - 1 ) * 5 ) ;
}
Create the index.blade.php
view file inside the admin/permission
folder.
resources/views/admin/permission/index.blade.php
Copy < x-app-layout >
< x-slot name = "header" >
< h2 class = "font-semibold text-xl text-gray-800 leading-tight" >
{{ __('Permissions') }}
</ h2 >
</ x-slot >
< div class = "py-12" >
< div class = "max-w-7xl mx-auto sm:px-6 lg:px-8" >
< div class = "bg-white overflow-hidden shadow-sm sm:rounded-lg" >
< div class = "p-6 bg-white border-b border-gray-200" >
< div class = "flex flex-col mt-8" >
@can('permission create')
< div class = "d-print-none with-border mb-8" >
< a href = "{{ route('permission.create') }}"
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">{{
__( 'Add Permission' ) }}</a>
</ div >
@endcan
< div class = "py-2" >
@if(session()->has('message'))
< div class = "mb-8 text-green-400 font-bold" >
{{ session()->get('message') }}
</ div >
@endif
< div class = "min-w-full border-b border-gray-200 shadow" >
< table class = "border-collapse table-auto w-full text-sm" >
< thead >
< tr >
< th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
{{ __( 'Name' ) }}
</th>
@canany(['permission edit', 'permission delete'])
< th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
{{ __( 'Actions' ) }}
</th>
@endcanany
</ tr >
</ thead >
< tbody class = "bg-white dark:bg-slate-800" >
@foreach($permissions as $permission)
< tr >
< td
class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">
<div class = "text-sm text-gray-900" >
< a href = "{{route('permission.show', $permission->id)}}"
class = "no-underline hover:underline text-cyan-600 dark:text-cyan-400" >{{ $permission->name
}}</ a >
</ div >
</ td >
@canany(['permission edit', 'permission delete'])
< td
class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">
<form action = "{{ route('permission.destroy', $permission->id) }}" method = "POST" >
< a href = "{{route('permission.edit', $permission->id)}}"
class = "px-4 py-2 text-white mr-4 bg-blue-600" >
{{ __('Edit') }}
</ a >
@csrf
@method('DELETE')
< button class = "px-4 py-2 text-white bg-red-600" >
{{ __('Delete') }}
</ button >
</ form >
</ td >
@endcanany
</ tr >
@endforeach
</ tbody >
</ table >
</ div >
< div class = "py-8" >
{{ $permissions->links() }}
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ x-app-layout >
This page has create, read, and update links. We have also added a delete button with the form. Update the destroy function with the below code: -
app/Http/Controllers/Admin/PermissionController.php
Copy public function destroy(Permission $permission)
{
$permission-> delete ();
return redirect () - > route (' permission . index ') - > with (' message ','P ermission deleted successfully ');
}
Step 6: Create operation
Update the create
function with the below code and create create.blade.php
view file.
app/Http/Controllers/Admin/PermissionController.php
Copy public function create ()
{
return view ( 'admin.permission.create' );
}
resources/views/admin/permission/create.blade.php
Copy < x-app-layout >
< x-slot name = "header" >
< h2 class = "font-semibold text-xl text-gray-800 leading-tight" >
{{ __('Permissions') }}
</ h2 >
</ x-slot >
< div class = "py-12" >
< div class = "max-w-7xl mx-auto sm:px-6 lg:px-8" >
< div class = "bg-white overflow-hidden shadow-sm sm:rounded-lg" >
< div class = "px-6 flex justify-between items-center" >
< h2
class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">
{{ __( 'Create permission' ) }}</h2>
< a href = "{{route('permission.index')}}" class = "px-4 py-2 text-white mr-4 bg-blue-600" >{{ __('Back to all
permission') }}</ a >
@if ($errors->any())
< ul class = "mt-3 list-none list-inside text-sm text-red-400" >
@foreach ($errors->all() as $error)
< li >{{ $error }}</ li >
@endforeach
</ ul >
@endif
</ div >
< div class = "w-full px-6 py-4 bg-white overflow-hidden" >
< form method = "POST" action = "{{ route('permission.store') }}" >
@csrf
< div class = "py-2" >
< label for = "name"
class = "block font-medium text-sm text-gray-700{{$errors->has('name') ? ' text-red-400' : ''}}" >{{
__('Name') }}</ label >
< input id = "name"
class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('name') ? ' border-red-400' : ''}}"
type = "text" name = "name" value = "{{ old('name') }}" />
</ div >
< div class = "flex justify-end mt-4" >
< button type = 'submit'
class='inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __( 'Create' ) }}
</button>
</ div >
</ form >
</ div >
</ div >
</ div >
</ div >
</ x-app-layout >
Navigate the http://127.0.0.1:8000/admin/permission/create
URL in the browser.
The submit action will call the store
function. So copy the below code to the store
function
app/Http/Controllers/Admin/PermissionController.php
Copy public function store ( Request $request)
{
$request->validate(['name' => 'required|string|max:255|unique:'.config('permission.table_names.permissions', 'permissions').',name',]);
Permission :: create ( [ 'name' => $request -> name , 'guard_name' => 'web' ] ) ;
return redirect () -> route ( 'permission.index' ) -> with ( 'message' , 'Permission created successfully.' ) ;
}
The $request->validate
is used to validate the create form.
Step 7: Update operation
We will use two functions used for the update. The edit
function for form display and update
function to save the form.
app/Http/Controllers/Admin/PermissionController.php
Copy public function edit ( Permission $permission)
{
return view ( 'admin.permission.edit' , compact ( 'permission' )) ;
}
public function update ( Request $request , Permission $permission)
{
$request->validate(['name' => 'required|string|max:255|unique:'.config('permission.table_names.permissions', 'permissions').',name,'.$permission->id,]);
$permission -> update ( [ 'name' => $request -> name , 'guard_name' => 'web' ] ) ;
return redirect () -> route ( 'permission.index' ) -> with ( 'message' , 'Permission updated successfully.' ) ;
}
resources/views/admin/permission/edit.blade.php
Step 8: View operation
This is the final step for our permission CRUD. The show
function is used for the view operation.
app/Http/Controllers/Admin/PermissionController.php
Copy public function show ( Permission $permission)
{
return view ( 'admin.permission.show' , compact ( 'permission' )) ;
}
resources/views/admin/permission/show.blade.php
Copy < x-app-layout >
< x-slot name = "header" >
< h2 class = "font-semibold text-xl text-gray-800 leading-tight" >
{{ __('Permissions') }}
</ h2 >
</ x-slot >
< div class = "py-12" >
< div class = "max-w-7xl mx-auto sm:px-6 lg:px-8" >
< div class = "bg-white overflow-hidden shadow-sm sm:rounded-lg" >
< div class = "px-6 flex justify-between items-center" >
<h2 class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">{{ __('View permission') }}</h2>
<a href="{{route('permission.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all permission') }}</a>
@if ($errors->any())
< ul class = "mt-3 list-none list-inside text-sm text-red-400" >
@foreach ($errors->all() as $error)
< li >{{ $error }}</ li >
@endforeach
</ ul >
@endif
</ div >
< div class = "w-full px-6 py-4" >
< div class = "min-w-full border-b border-gray-200 shadow" >
< table class = "table-fixed w-full text-sm" >
< tbody class = "bg-white dark:bg-slate-800" >
< tr >
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Name') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$permission->name}}</td>
</ tr >
< tr >
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Created') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$permission->created_at}}</td>
</ tr >
</ tbody >
</ table >
</ div >
</ div >
</ div >
</ div >
</ div >
</ x-app-layout >
We have successfully created our first Laravel CRUD. This permission CRUD is open for all authenticated users. So for the next part, we need to add permission-based access restriction to our permission CRUD.
For the Roles and User
Step 1: Create Model
Copy php artisan make:model Role
app/Models/Role.php
Copy <? php
namespace App \\ Models ;
use Spatie \\ Permission \\ Models \\ Role as OriginalRole;
class Role extends OriginalRole
{
protected $fillable = [
'name' ,
'guard_name' ,
'updated_at' ,
'created_at'
];
}
Step 2: Create a controller
Copy php artisan make:controller Admin / RoleController -- model = Role -- resource
php artisan make:controller Admin / UserController -- model = User -- resource
Step 3: Add Routes
We have added two routes: -
Copy Route::prefix('admin')- > namespace('App\\Http\\Controllers\\Admin')- > middleware([ 'auth' ])- > group(function() {
Route : :resource( 'permission' , PermissionController::class );
Route : :resource( 'role' , RoleController::class );
Route : :resource( 'user' , UserController::class );
});
Step 4: Add a link to the navigation
Copy <!-- Navigation Links -->
< div class = "hidden space-x-8 sm:-my-px sm:ml-10 sm:flex" >
< x-nav-link :href = "route('dashboard')"
:active = "request()->routeIs('dashboard')" >
{{ __('Dashboard') }}
</ x-nav-link >
< x-nav-link :href = "route('permission.index')"
:active = "request()->routeIs('permission.index')" >
{{ __('Permission') }}
</ x-nav-link >
< x-nav-link :href = "route('role.index')"
:active = "request()->routeIs('role.index')" >{{ __('Roles') }}
</ x-nav-link >
< x-nav-link :href = "route('user.index')"
:active = "request()->routeIs('user.index')" >{{ __('Users') }}
</ x-nav-link >
</ div >
For mobile navigation
Copy <!-- Responsive Navigation Menu -->
< div :class = "{'block': open, 'hidden': ! open}" class = "hidden sm:hidden" >
< div class = "pt-2 pb-3 space-y-1" >
< x-responsive-nav-link :href = "route('dashboard')" :active = "request()->routeIs('dashboard')" >
{{ __('Dashboard') }}
</ x-responsive-nav-link >
< x-responsive-nav-link :href = "route('permission.index')" :active = "request()->routeIs('permission.index')" >
{{ __('Permission') }}
</ x-responsive-nav-link >
< x-responsive-nav-link :href = "route('role.index')" :active = "request()->routeIs('role.index')" >
{{ __('Roles') }}
</ x-responsive-nav-link >
< x-responsive-nav-link :href = "route('user.index')" :active = "request()->routeIs('user.index')" >
{{ __('Users') }}
</ x-responsive-nav-link >
</ div >
Step 5: Index page with action links
Update index function with permission paginating.
app/Http/Controllers/Admin/RoleController.php
Copy function __construct ()
{
$this -> middleware ( 'can:role list' , [ 'only' => [ 'index' , 'show' ]] ) ;
$this -> middleware ( 'can:role create' , [ 'only' => [ 'create' , 'store' ]] ) ;
$this -> middleware ( 'can:role edit' , [ 'only' => [ 'edit' , 'update' ]] ) ;
$this -> middleware ( 'can:role delete' , [ 'only' => [ 'destroy' ]] ) ;
}
public function index ()
{
$roles = ( new Role ) -> newQuery () ;
if ( request () -> has ( 'search' ) ) {
$roles -> where ( 'name' , 'Like' , '%' . request () -> input ( 'search' ) . '%' ) ;
}
if ( request () -> query ( 'sort' ) ) {
$attribute = request () -> query ( 'sort' ) ;
$sort_order = 'ASC' ;
if ( strncmp ( $attribute , '-' , 1 ) === 0 ) {
$sort_order = 'DESC' ;
$attribute = substr ( $attribute , 1 ) ;
}
$roles -> orderBy ( $attribute , $sort_order ) ;
} else {
$roles -> latest () ;
}
$roles = $roles -> paginate ( 5 ) ;
return view ( 'admin.role.index' , compact ( 'roles' ))
-> with ( 'i' , ( request () -> input ( 'page' , 1 ) - 1 ) * 5 ) ;
}
Create the index.blade.php
view file inside the admin/role
folder.
resources/views/admin/role/index.blade.php
Copy < x-app-layout >
< x-slot name = "header" >
< h2 class = "font-semibold text-xl text-gray-800 leading-tight" >
{{ __('Roles') }}
</ h2 >
</ x-slot >
< div class = "py-12" >
< div class = "max-w-7xl mx-auto sm:px-6 lg:px-8" >
< div class = "bg-white overflow-hidden shadow-sm sm:rounded-lg" >
< div class = "p-6 bg-white border-b border-gray-200" >
< div class = "flex flex-col mt-8" >
@can('role create')
< div class = "d-print-none with-border mb-8" >
< a href = "{{ route('role.create') }}"
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">{{
__( 'Add Role' ) }}</a>
</ div >
@endcan
< div class = "py-2" >
@if(session()->has('message'))
< div class = "mb-8 text-green-400 font-bold" >
{{ session()->get('message') }}
</ div >
@endif
< div class = "min-w-full border-b border-gray-200 shadow" >
< form method = "GET" action = "{{ route('role.index') }}" >
< div class = "py-2 flex" >
< div class = "overflow-hidden flex pl-4" >
< input type = "search" name = "search" value = "{{ request()->input('search') }}"
class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
placeholder = "Search" >
< button type = 'submit'
class='ml-4 inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __( 'Search' ) }}
</button>
</ div >
</ div >
</ form >
< table class = "border-collapse table-auto w-full text-sm" >
< thead >
< tr >
< th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
</th>
@canany(['role edit', 'role delete'])
< th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
{{ __( 'Actions' ) }}
</th>
@endcanany
</ tr >
</ thead >
< tbody class = "bg-white dark:bg-slate-800" >
@foreach($roles as $role)
< tr >
< td
class = "border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400" >
< div class = "text-sm text-gray-900" >
< a href = "{{route('role.show', $role->id)}}"
class = "no-underline hover:underline text-cyan-600 dark:text-cyan-400" >{{ $role->name }}</ a >
</ div >
</ td >
@canany(['role edit', 'role delete'])
< td
class = "border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400" >
< form action = "{{ route('role.destroy', $role->id) }}" method = "POST" >
@can('role edit')
< a href = "{{route('role.edit', $role->id)}}" class = "px-4 py-2 text-white mr-4 bg-blue-600" >
{{ __('Edit') }}
</ a >
@endcan
@can('role delete')
@csrf
@method('DELETE')
< button class = "px-4 py-2 text-white bg-red-600" >
{{ __('Delete') }}
</ button >
@endcan
</ form >
</ td >
@endcanany
</ tr >
@endforeach
</ tbody >
</ table >
</ div >
< div class = "py-8" >
{{ $roles->appends(request()->query())->links() }}
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ x-app-layout >
Don’t forget the run the npm run dev
to rebuild the CSS.
This page has create, read, and update links. We have also added a delete button with the form. Update the destroy function with the below code.
app/Http/Controllers/Admin/RoleController.php
Copy public function destroy(Role $role)
{
$role-> delete ();
return redirect () - > route (' role . index ')
- > with (' message ','R ole deleted successfully ');
}
2 . User
Create the index.blade.php, create.blade.php, edit.blade.php
, and show.blade.php
files inside the admin/user
folder.
resources/views/admin/user/index.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Users') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
<div class="flex flex-col mt-8">
@can('user create')
<div class="d-print-none with-border mb-8">
<a href="{{ route('user.create') }}"
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">{{
__('Add User') }}</a>
</div>
@endcan
<div class="py-2">
@if(session()->has('message'))
<div class="mb-8 text-green-400 font-bold">
{{ session()->get('message') }}
</div>
@endif
<div class="min-w-full border-b border-gray-200 shadow">
<form method="GET" action="{{ route('user.index') }}">
<div class="py-2 flex">
<div class="overflow-hidden flex pl-4">
<input type="search" name="search" value="{{ request()->input('search') }}"
class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
placeholder="Search">
<button type='submit'
class='ml-4 inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __('Search') }}
</button>
</div>
</div>
</form>
<table class="border-collapse table-auto w-full text-sm">
<thead>
<tr>
<th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
{{ __('Name')}}
</th>
<th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
{{ __('Email')}}
</th>
@canany(['user edit', 'user delete'])
<th
class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light text-left">
{{ __('Actions') }}
</th>
@endcanany
</tr>
</thead>
<tbody class="bg-white dark:bg-slate-800">
@foreach($users as $user)
<tr>
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">
<div class="text-sm text-gray-900">
<a href="{{route('user.show', $user->id)}}"
class="no-underline hover:underline text-cyan-600 dark:text-cyan-400">{{ $user->name }}</a>
</div>
</td>
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">
<div class="text-sm text-gray-900">
{{ $user->email }}
</div>
</td>
@canany(['user edit', 'user delete'])
<td
class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">
<form action="{{ route('user.destroy', $user->id) }}" method="POST">
@can('user edit')
<a href="{{route('user.edit', $user->id)}}" class="px-4 py-2 text-white mr-4 bg-blue-600">
{{ __('Edit') }}
</a>
@endcan
@can('user delete')
@csrf
@method('DELETE')
<button class="px-4 py-2 text-white bg-red-600">
{{ __('Delete') }}
</button>
@endcan
</form>
</td>
@endcanany
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="py-8">
{{ $users->appends(request()->query())->links() }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
app/Http/Controllers/Admin/UserController.php
Copy function __construct()
{
$this->middleware('can:user list', ['only' => ['index','show']]);
$this->middleware('can:user create', ['only' => ['create','store']]);
$this->middleware('can:user edit', ['only' => ['edit','update']]);
$this->middleware('can:user delete', ['only' => ['destroy']]);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$users = (new User)->newQuery();
if (request()->has('search')) {
$users->where('name', 'Like', '%' . request()->input('search') . '%');
}
if (request()->query('sort')) {
$attribute = request()->query('sort');
$sort_order = 'ASC';
if (strncmp($attribute, '-', 1) === 0) {
$sort_order = 'DESC';
$attribute = substr($attribute, 1);
}
$users->orderBy($attribute, $sort_order);
} else {
$users->latest();
}
$users = $users->paginate(5);
return view('admin.user.index',compact('users'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
public function destroy(User $user)
{
$user->delete();
return redirect()->route('user.index')
->with('message','User deleted successfully');
}
Step 6: Create operation
Update the create
function with the below code and create create.blade.php
view file. The Permission::all()
is used to list the permission on create page.
app/Http/Controllers/Admin/RoleController.php
Copy public function create()
{
$permissions = Permission::all();
return view('admin.role.create', compact('permissions'));
}
resources/views/admin/role/create.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Roles') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="px-6 flex justify-between items-center">
<h2
class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">
{{ __('Create role') }}</h2>
<a href="{{route('role.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all role')
}}</a>
@if ($errors->any())
<ul class="mt-3 list-none list-inside text-sm text-red-400">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
</div>
<div class="w-full px-6 py-4 bg-white overflow-hidden">
<form method="POST" action="{{ route('role.store') }}">
@csrf
<div class="py-2">
<label for="name"
class="block font-medium text-sm text-gray-700{{$errors->has('name') ? ' text-red-400' : ''}}">{{
__('Name') }}</label>
<input id="name"
class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('name') ? ' border-red-400' : ''}}"
type="text" name="name" value="{{ old('name') }}" />
</div>
<div class="py-2">
<h3
class="inline-block text-xl sm:text-2xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">
Permissions</h3>
<div class="grid grid-cols-4 gap-4">
@forelse ($permissions as $permission)
<div class="col-span-4 sm:col-span-2 md:col-span-1">
<label class="form-check-label">
<input type="checkbox" name="permissions[]" value="{{ $permission->name }}"
class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
{{ $permission->name }}
</label>
</div>
@empty
----
@endforelse
</div>
</div>
<div class="flex justify-end mt-4">
<button type='submit'
class='inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __('Create') }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
Navigate the http://127.0.0.1:8000/admin/role/create
URL in the browser.
The submit action will call the store
function. So copy the below code in the store
function.
app/Http/Controllers/Admin/RoleController.php
Copy public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255|unique:'.config('permission.table_names.roles', 'roles').',name',
]);
$role = Role::create($request->all());
if(! empty($request->permissions)) {
$role->givePermissionTo($request->permissions);
}
return redirect()->route('role.index')
->with('message','Role created successfully.');
}
2 . User
Users, in this case, are anyone who asks for permission to your database. They are usually the people in your organization.
app/Http/Controllers/Admin/UserController.php
Extend model in user controller
Copy use App\Models\Role;
use App\Models\Permission;
use Spatie\Permission\Models\Role as OriginalRole;
use Spatie\Permission\Models\Permission as OriginalPermission;
Copy public function create()
{
$roles = Role::all();
return view('admin.user.create', compact('roles'));
}
public function store(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
if(! empty($request->roles)) {
$user->assignRole($request->roles);
}
return redirect()->route('user.index')->with('message','User created successfully.');
}
resources/views/admin/user/create.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Users') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="px-6 flex justify-between items-center">
<h2 class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">{{ __('Create user') }}</h2>
<a href="{{route('user.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all users') }}</a>
@if ($errors->any())
<ul class="mt-3 list-none list-inside text-sm text-red-400">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
</div>
<div class="w-full px-6 py-4 bg-white overflow-hidden">
<form method="POST" action="{{ route('user.store') }}">
@csrf
<div class="py-2">
<label for="name" class="block font-medium text-sm text-gray-700{{$errors->has('name') ? ' text-red-400' : ''}}">{{ __('Name') }}</label>
<input id="name" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('name') ? ' border-red-400' : ''}}" type="text" name="name" value="{{ old('name') }}" />
</div>
<div class="py-2">
<label for="email" class="block font-medium text-sm text-gray-700{{$errors->has('email') ? ' text-red-400' : ''}}">{{ __('Email') }}</label>
<input id="email" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('email') ? ' border-red-400' : ''}}" type="email" name="email" value="{{ old('email') }}" />
</div>
<div class="py-2">
<label for="password" class="block font-medium text-sm text-gray-700{{$errors->has('password') ? ' text-red-400' : ''}}">{{ __('Password') }}</label>
<input id="password" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('password') ? ' border-red-400' : ''}}" type="password" name="password" />
</div>
<div class="py-2">
<label for="password_confirmation" class="block font-medium text-sm text-gray-700{{$errors->has('password') ? ' text-red-400' : ''}}">{{ __('Password Confirmation') }}</label>
<input id="password_confirmation" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('password') ? ' border-red-400' : ''}}" type="password" name="password_confirmation" />
</div>
<div class="py-2">
<h3 class="inline-block text-xl sm:text-2xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">Roles</h3>
<div class="grid grid-cols-4 gap-4">
@forelse ($roles as $role)
<div class="col-span-4 sm:col-span-2 md:col-span-1">
<label class="form-check-label">
<input type="checkbox" name="roles[]" value="{{ $role->name }}" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
{{ $role->name }}
</label>
</div>
@empty
----
@endforelse
</div>
</div>
<div class="flex justify-end mt-4">
<button type='submit' class='inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __('Create') }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
Step 7: Update operation
We will use two functions used for the update. The edit
function for form display and update
function to save the form.
app/Http/Controllers/Admin/RoleController.php
Export spatie role and permission class
Copy use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
Copy public function edit(Role $role)
{
$permissions = Permission::all();
$roleHasPermissions = array_column(json_decode($role->permissions, true), 'id');
return view('admin.role.edit',compact('role', 'permissions', 'roleHasPermissions'));
}
public function update(Request $request, Role $role)
{
$request->validate([
'name' => 'required|string|max:255|unique:'.config('permission.table_names.roles', 'roles').',name,'.$role->id,
]);
$role->update(['name' => $request->name , 'guard_name'=> 'web' ]);
$permissions = $request->permissions ?? [];
$role->syncPermissions($permissions);
return redirect()->route('role.index')
->with('message','Role updated successfully.');
}
resources/views/admin/role/edit.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Roles') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="px-6 flex justify-between items-center">
<h2 class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">{{ __('Update role') }}</h2>
<a href="{{route('role.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all role') }}</a>
@if ($errors->any())
<ul class="mt-3 list-none list-inside text-sm text-red-400">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
</div>
<div class="w-full px-6 py-4 bg-white overflow-hidden">
<form method="POST" action="{{ route('role.update', $role->id) }}">
@csrf
@method('PUT')
<div class="py-2">
<label for="name" class="block font-medium text-sm text-gray-700{{$errors->has('name') ? ' text-red-400' : ''}}">{{ __('Name') }}</label>
<input id="name" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('name') ? ' border-red-400' : ''}}" type="text" name="name" value="{{ old('name', $role->name) }}" />
</div>
@unless ($role->name == env('APP_SUPER_ADMIN', 'super-admin'))
<div class="py-2">
<h3 class="inline-block text-xl sm:text-2xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">Permissions</h3>
<div class="grid grid-cols-4 gap-4">
@forelse ($permissions as $permission)
<div class="col-span-4 sm:col-span-2 md:col-span-1">
<label class="form-check-label">
<input type="checkbox" name="permissions[]" value="{{ $permission->name }}" {{ in_array($permission->id, $roleHasPermissions) ? 'checked' : '' }} class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
{{ $permission->name }}
</label>
</div>
@empty
----
@endforelse
</div>
</div>
@endunless
<div class="flex justify-end mt-4">
<button type='submit' class='inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __('Update') }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
You need to make sure that the users of your database get the right set of permissions so that the security of your data remains strong.
resources/views/admin/user/edit.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Users') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="px-6 flex justify-between items-center">
<h2 class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">{{ __('Update user') }}</h2>
<a href="{{route('user.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all users') }}</a>
@if ($errors->any())
<ul class="mt-3 list-none list-inside text-sm text-red-400">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
</div>
<div class="w-full px-6 py-4 bg-white overflow-hidden">
<form method="POST" action="{{ route('user.update', $user->id) }}">
@csrf
@method('PUT')
<div class="py-2">
<label for="name" class="block font-medium text-sm text-gray-700{{$errors->has('name') ? ' text-red-400' : ''}}">{{ __('Name') }}</label>
<input id="name" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('name') ? ' border-red-400' : ''}}" type="text" name="name" value="{{ old('name', $user->name) }}" />
</div>
<div class="py-2">
<label for="email" class="block font-medium text-sm text-gray-700{{$errors->has('email') ? ' text-red-400' : ''}}">{{ __('Email') }}</label>
<input id="email" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('email') ? ' border-red-400' : ''}}" type="email" name="email" value="{{ old('email', $user->email) }}" />
</div>
<div class="py-2">
<label for="password" class="block font-medium text-sm text-gray-700{{$errors->has('password') ? ' text-red-400' : ''}}">{{ __('Password') }}</label>
<input id="password" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('password') ? ' border-red-400' : ''}}" type="password" name="password" />
</div>
<div class="py-2">
<label for="password_confirmation" class="block font-medium text-sm text-gray-700{{$errors->has('password') ? ' text-red-400' : ''}}">{{ __('Password Confirmation') }}</label>
<input id="password_confirmation" class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 block mt-1 w-full{{$errors->has('password') ? ' border-red-400' : ''}}" type="password" name="password_confirmation" />
</div>
<div class="py-2">
<h3 class="inline-block text-xl sm:text-2xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">Roles</h3>
<div class="grid grid-cols-4 gap-4">
@forelse ($roles as $role)
<div class="col-span-4 sm:col-span-2 md:col-span-1">
<label class="form-check-label">
<input type="checkbox" name="roles[]" value="{{ $role->name }}" {{ in_array($role->id, $userHasRoles) ? 'checked' : '' }} class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
{{ $role->name }}
</label>
</div>
@empty
----
@endforelse
</div>
</div>
<div class="flex justify-end mt-4">
<button type='submit' class='inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring ring-gray-300 disabled:opacity-25 transition ease-in-out duration-150'>
{{ __('Update') }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
app/Http/Controllers/Admin/UserController.php
Copy public function edit(User $user)
{
$roles = Role::all();
$userHasRoles = array_column(json_decode($user->roles, true), 'id');
return view('admin.user.edit', compact('user', 'roles', 'userHasRoles'));
}
public function update(Request $request, User $user)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,'.$user->id],
'password' => ['nullable','confirmed', Rules\\Password::defaults()],
]);
$user->update([
'name' => $request->name,
'email' => $request->email,
]);
if($request->password){
$user->update([
'password' => Hash::make($request->password),
]);
}
$roles = $request->roles ?? [];
$user->syncRoles($roles);
return redirect()->route('user.index')->with('message','User updated successfully.');
}
8. View operation
Here, with this operation, we will be viewing the roles of the users to whom you have granted the permissions.
app/Http/Controllers/Admin/RoleController.php
Copy public function show(Role $role)
{
$permissions = Permission::all();
$roleHasPermissions = array_column(json_decode($role->permissions, true), 'id');
return view('admin.role.show', compact('role', 'permissions', 'roleHasPermissions'));
}
resources/views/admin/role/show.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Roles') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="px-6 flex justify-between items-center">
<h2 class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">{{ __('View role') }}</h2>
<a href="{{route('role.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all role') }}</a>
@if ($errors->any())
<ul class="mt-3 list-none list-inside text-sm text-red-400">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
</div>
<div class="w-full px-6 py-4">
<div class="min-w-full border-b border-gray-200 shadow">
<table class="table-fixed w-full text-sm">
<tbody class="bg-white dark:bg-slate-800">
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Name') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$role->name}}</td>
</tr>
<tr>
@unless ($role->name == env('APP_SUPER_ADMIN', 'super-admin'))
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Permissions') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">
<div class="py-2">
<div class="grid grid-cols-4 gap-4">
@forelse ($permissions as $permission)
<div class="col-span-4 sm:col-span-2 md:col-span-2">
<label class="form-check-label">
<input type="checkbox" name="permissions[]" value="{{ $permission->name }}" {{ in_array($permission->id, $roleHasPermissions) ? 'checked' : '' }} disabled="disabled" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
{{ $permission->name }}
</label>
</div>
@empty
----
@endforelse
</div>
</div>
</td>
</tr>
@endunless
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Created') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$role->created_at}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
Here is how you can view users of your database along with their other details such as their assigned permissions.
app/Http/Controllers/Admin/UserController.php
Copy public function show(User $user)
{
$roles = Role::all();
$userHasRoles = array_column(json_decode($user->roles, true), 'id');
return view('admin.user.show', compact('user', 'roles', 'userHasRoles'));
}
resources/views/admin/user/show.blade.php
Copy <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Users') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="px-6 flex justify-between items-center">
<h2 class="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200 py-4 block sm:inline-block flex">{{ __('View user') }}</h2>
<a href="{{route('user.index')}}" class="px-4 py-2 text-white mr-4 bg-blue-600">{{ __('Back to all users') }}</a>
@if ($errors->any())
<ul class="mt-3 list-none list-inside text-sm text-red-400">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
</div>
<div class="w-full px-6 py-4">
<div class="min-w-full border-b border-gray-200 shadow">
<table class="table-fixed w-full text-sm">
<tbody class="bg-white dark:bg-slate-800">
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Name') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$user->name}}</td>
</tr>
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Email') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$user->email}}</td>
</tr>
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Roles') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">
<div class="py-2">
<div class="grid grid-cols-4 gap-4">
@forelse ($roles as $role)
<div class="col-span-4 sm:col-span-2 md:col-span-2">
<label class="form-check-label">
<input type="checkbox" name="roles[]" value="{{ $role->name }}" {{ in_array($role->id, $userHasRoles) ? 'checked' : '' }} disabled="disabled" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
{{ $role->name }}
</label>
</div>
@empty
----
@endforelse
</div>
</div>
</td>
</tr>
<tr>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 pl-8 text-slate-500 dark:text-slate-400">{{ __('Created') }}</td>
<td class="border-b border-slate-100 dark:border-slate-700 p-4 text-slate-500 dark:text-slate-400">{{$user->created_at}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
Add link in the dropdown
Copy <x-slot name="content">
<!-- Authentication -->
<x-dropdown-link :href="route('admin.profile.info')" :active="request()->routeIs('admin.account.info')">
{{ __('My Account') }}
</x-dropdown-link>
Add function in user controller
app/Http/Controllers/Admin/UserController.php
Copy public function profileInformation() {
$user = Auth::user();
return view('admin.user.profile',compact('user'));
}
public function profileInformationStore(Request $request)
{
$request->validateWithBag('account', [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,'.\Auth::user()->id],
]);
$user = \Auth::user()->update($request->except(['_token']));
if ($user) {
$message = "Account updated successfully.";
} else {
$message = "Error while saving. Please try again.";
}
return redirect()->route('admin.profile.info')->with('account_message', $message);
}
public function changePasswordStore(Request $request)
{
$validator = \Validator::make($request->all(), [
'old_password' => ['required'],
'new_password' => ['required', Rules\Password::defaults()],
'confirm_password' => ['required', 'same:new_password', Rules\Password::defaults()],
]);
$validator->after(function ($validator) use ($request) {
if ($validator->failed()) return;
if (! Hash::check($request->input('old_password'), \Auth::user()->password)) {
$validator->errors()->add(
'old_password', 'Old password is incorrect.'
);
}
});
$validator->validateWithBag('password');
$user = \Auth::user()->update([
'password' => Hash::make($request->input('new_password')),
]);
if ($user) {
$message = "Password updated successfully.";
} else {
$message = "Error while saving. Please try again.";
}
return redirect()->route('admin.profile.info')->with('password_message', $message);
}
If you are wondering about the source of this code and want to have a look, then here is the link.
Github Link - Laravel Permission Demo
If you are wondering about the source of this code and want to have a look, then here is the link.
https://permission-demo.acquaintsoft.com/
Here is the demo link. Have a look to see it all in even more detail.
Conclusion
Assigning permissions to users is necessary for sake of the security of your data. If you have followed along with the above-mentioned steps, I know that you also would have been able to create permissions and assign roles easily.