This site uses tracking cookies used for marketing and statistics. Privacy Policy
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.
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.
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.
php artisan serve
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.
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel_permission_demo
DB_USERNAME=root
DB_PASSWORD=password
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.
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: -
npm install
npm run dev
For database migration: -
php artisan migrate
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
http://127.0.0.1:8000/login
For register
http://127.0.0.1:8000/register
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.
composer require spatie/laravel-permission
You can even manually add the service provider in your config/app.php
file. However, it is optional.
'providers' => [
// ...
Spatie\Permission\PermissionServiceProvider::class,
];
Now publish the migration and the config/permission.php
config file using: -
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: -
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: -
php artisan migrate
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.
App\Models\User.php
Add this line user.php
use Spatie\Permission\Traits\HasRoles;
After that user HasRoles in class.
- use HasApiTokens, HasFactory, Notifiable;
+ use HasApiTokens, HasFactory, Notifiable , HasRoles;
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.
php artisan make:seeder BasicPermissionSeeder
Use spatie classes in seeder file.
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;
Now, replace this code in database\seeder\BasicPermissionSeeder.php
<?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.
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.
use Illuminate\Support\Facades\Gate;
// 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.
$user->can('permission create');
In Blade directives:
@can('permission create')
...
@endcan
Next, we are going to implement CRUD (screen) for the permission and roles.
Follow these steps to create permission CRUD for our Laravel Admin panel.
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.
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
<?php
namespace App\Models;
use Spatie\Permission\Models\Permission as OriginalPermission;
class Permission extends OriginalPermission
{
protected $fillable = [
'name',
'guard_name',
'updated_at',
'created_at'
];
}
The make:controller
Artisan command is used to create the controllers.
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.
Extend controllers in web.php file.
use App\\Http\\Controllers\\Admin\\PermissionController;
Add resource route in web.php. We are using auth middleware and Admin namespace.
Route::prefix('admin')->namespace('App\\Http\\Controllers\\Admin')->middleware(['auth'])->group(function() {
Route::resource('permission', PermissionController::class);
});
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
<!-- 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
<!-- 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>
Update index function with permission paginating.
app/Http/Controllers/Admin/PermissionController.php
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
<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
public function destroy(Permission $permission)
{
$permission->delete();
return redirect()->route('permission.index')->with('message','Permission deleted successfully');
}
Update the create
function with the below code and create create.blade.php
view file.
app/Http/Controllers/Admin/PermissionController.php
public function create()
{
return view('admin.permission.create');
}
resources/views/admin/permission/create.blade.php
<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
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.
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
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
This is the final step for our permission CRUD. The show
function is used for the view operation.
app/Http/Controllers/Admin/PermissionController.php
public function show(Permission $permission)
{
return view('admin.permission.show',compact('permission'));
}
resources/views/admin/permission/show.blade.php
<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.
php artisan make:model Role
app/Models/Role.php
<?php
namespace App\\Models;
use Spatie\\Permission\\Models\\Role as OriginalRole;
class Role extends OriginalRole
{
protected $fillable = [
'name',
'guard_name',
'updated_at',
'created_at'
];
}
php artisan make:controller Admin/RoleController --model=Role --resource
php artisan make:controller Admin/UserController --model=User --resource
We have added two routes: -
role
user
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);
});
<!-- 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
<!-- 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>
Roles
Update index function with permission paginating.
app/Http/Controllers/Admin/RoleController.php
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
<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
public function destroy(Role $role)
{
$role->delete();
return redirect()->route('role.index')
->with('message','Role 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
<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
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');
}
Role
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
public function create()
{
$permissions = Permission::all();
return view('admin.role.create', compact('permissions'));
}
resources/views/admin/role/create.blade.php
<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
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
use App\Models\Role;
use App\Models\Permission;
use Spatie\Permission\Models\Role as OriginalRole;
use Spatie\Permission\Models\Permission as OriginalPermission;
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
<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>
Role
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
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
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
<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>
User
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
<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
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.');
}
Role
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
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
<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>
User
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
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
<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
<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
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.
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.
I love to make a difference. Thus, I started Acquaint Softtech with the vision of making developers easily accessible and affordable to all. Me and my beloved team have been fulfilling this vision for over 15 years now and will continue to get even bigger and better.
Uncover the pitfalls of blind brand loyalty and the benefits of prioritizing quality. Find out how to evaluate products beyond brand names for better choices.
Finding the best Flutter app development company to develop your hybrid app for Android and iOS? End your search here with a team that fits your need.
Develop a next-generation website using Statamic that is tailored to suit the custom needs of your business.