HypervelHypervel
Hypervel
Documentation
GitHub
Hypervel
Documentation
GitHub
  • Documentation

    • Prologue

      • Contributing Guide
    • Getting Started

      • Introduction
      • Installation
      • Configuration
      • Directory Structure
      • Deployment
    • Architecture Concepts

      • Request Lifecycle
      • Service Container
      • Service Providers
      • Facades
    • The Basics

      • Routing
      • Middleware
      • CSRF Protection
      • Controllers
      • Requests
      • Responses
      • Views
      • Blade Templates
      • URL Generation
      • Session
      • Validation
      • Error Handling
      • Logging
    • Digging Deeper

      • Artisan Console
      • Broadcasting
      • Cache
      • Collections
      • Context
      • Coroutine
      • Contracts
      • Data Objects
      • Events
      • File Storage
      • Helpers
      • HTTP Client
      • Localization
      • Mail
      • Notifications
      • Package Development
      • Package Porting
      • Processes
      • Queues
      • Rate Limiting
      • Strings
      • Task Scheduling
    • Security

      • Authentication
      • Authorization
      • Encryption
      • Hashing
    • Database

      • Getting Started
      • Query Builder
      • Pagination
      • Migrations
      • Seeding
      • Redis
    • Eloquent ORM

      • Getting Started
      • Relationships
      • Collections
      • Mutators / Casts
      • API Resources
      • Serialization
      • Factories
    • Testing

      • Getting Started
      • HTTP Tests
      • Console Tests
      • Database
      • Mocking
      • Packages Toolkit
    • Packages

      • Sanctum
      • Permission
      • Prompts
      • Nested Set
      • Telescope

Hypervel Permission

  • Introduction
  • Installation
    • Publishing Assets
    • Running Migrations
  • Configuration
    • Models
    • Table Names
    • Column Names
    • Cache Configuration
  • Basic Usage
    • Adding Traits to Models
    • Creating Permissions and Roles
  • Working with Roles
    • Assigning Roles to Models
    • Checking Roles
    • Removing Roles
  • Working with Permissions
    • Assigning Permissions to Models
    • Checking Permissions
    • Forbidden Permissions
    • Revoking Permissions
    • Getting All Permissions
  • Using Enums
    • Backed Enums
    • Unit Enums
  • Middleware
    • Permission Middleware
    • Role Middleware
    • Using with Enums
  • Console Commands
    • Viewing Permissions and Roles
  • Advanced Usage
    • Custom Guards
    • Polymorphic Relationships
    • Working with the Permission Manager
    • Custom Models
  • Caching
    • Cache Strategy
    • Cache Invalidation
    • Manual Cache Management
  • Performance Considerations
    • Optimizing Queries
    • Eager Loading
    • Cache Warming
  • Common Patterns
    • Hierarchical Permissions
    • Resource-Based Permissions
    • Dynamic Permission Checking

Introduction

Modern web applications often need to control what users can and cannot do. Whether you're building a content management system where editors can publish articles but only admins can manage users, or an e-commerce platform where different staff members have access to different parts of the system, you'll need a robust way to manage permissions and user roles.

The Hypervel Permission package provides a flexible and powerful solution for implementing role-based access control (RBAC) in your applications. This package is ported from Spatie's Permission package but optimized for the Hypervel framework with advanced caching capabilities and support for modern PHP features. Instead of hardcoding permission checks throughout your codebase, you can define roles like "editor" or "admin", assign specific permissions to those roles, and then simply check if a user has the required role or permission. The package handles all the complex database queries and caching behind the scenes.

What makes this package particularly powerful is its flexibility - you can assign roles to users for broad access control, assign specific permissions for fine-grained control, or even use "forbidden permissions" to explicitly deny access to certain actions. All permission checks are optimized with intelligent caching, so you don't have to worry about performance even with complex permission hierarchies.

Installation

You can install the permission package via Composer:

composer require hypervel/permission

The package will automatically register its service provider.

Publishing Assets

Publish the migration and configuration files:

php artisan vendor:publish --provider="Hypervel\Permission\PermissionServiceProvider"

Or publish them separately:

# Publish config only
php artisan vendor:publish --provider="Hypervel\Permission\PermissionServiceProvider" --tag="permission-config"

# Publish migrations only
php artisan vendor:publish --provider="Hypervel\Permission\PermissionServiceProvider" --tag="permission-migrations"

Running Migrations

After publishing, run the migrations to create the necessary tables:

php artisan migrate

This will create the following tables:

  • roles - stores role information
  • permissions - stores permission information
  • role_has_permissions - pivot table for role-permission relationships
  • owner_has_permissions - polymorphic table for model-permission relationships
  • owner_has_roles - polymorphic table for model-role relationships

Configuration

The package configuration file config/permission.php allows you to customize various aspects:

Models

You can specify custom models for roles and permissions:

'models' => [
    'role' => \App\Models\Role::class,
    'permission' => \App\Models\Permission::class,
],

Table Names

Customize table names to match your database schema:

'table_names' => [
    'roles' => 'roles',
    'permissions' => 'permissions',
    'role_has_permissions' => 'role_has_permissions',
    'owner_has_permissions' => 'owner_has_permissions',
    'owner_has_roles' => 'owner_has_roles',
],

Column Names

Customize column names used in relationships:

'column_names' => [
    'role_pivot_key' => 'role_id',
    'permission_pivot_key' => 'permission_id',
    'owner_morph_key' => 'owner_id',
    'owner_name' => 'owner',
],

Cache Configuration

Configure caching behavior for optimal performance:

'cache' => [
    'expiration_seconds' => 86400, // 24 hours
    'keys' => [
        'roles' => 'hypervel.permission.cache.roles',
        'owner_roles' => 'hypervel.permission.cache.owner.roles',
        'owner_permissions' => 'hypervel.permission.cache.owner.permissions',
    ],
    'store' => env('PERMISSION_CACHE_STORE', 'default'),
],

Basic Usage

Adding Traits to Models

To use permissions and roles with your models, add the appropriate traits:

For Users (or any model that should have roles and permissions):

namespace App\Models;

use Hypervel\Database\Eloquent\Model;
use Hypervel\Permission\Traits\HasRole;

class User extends Model
{
    use HasRole; // This also includes HasPermission trait

    // Your model code...
}

For Custom Permission Model:

namespace App\Models;

use Hypervel\Permission\Models\Permission as BasePermission;

class Permission extends BasePermission
{
    // Add custom methods or properties
}

For Custom Role Model:

namespace App\Models;

use Hypervel\Permission\Models\Role as BaseRole;

class Role extends BaseRole
{
    // Add custom methods or properties
}

Creating Permissions and Roles

Creating Permissions

use Hypervel\Permission\Models\Permission;

// Create permissions
$permission = Permission::create(['name' => 'edit articles', 'guard_name' => 'web']);
$permission = Permission::create(['name' => 'delete articles', 'guard_name' => 'web']);
$permission = Permission::create(['name' => 'publish articles', 'guard_name' => 'web']);

Creating Roles

use Hypervel\Permission\Models\Role;

// Create roles
$role = Role::create(['name' => 'writer', 'guard_name' => 'web']);
$role = Role::create(['name' => 'editor', 'guard_name' => 'web']);
$role = Role::create(['name' => 'admin', 'guard_name' => 'web']);

Assigning Permissions to Roles

// Assign permissions to roles
$role = Role::findByName('writer');
$role->givePermissionTo('edit articles');

// Assign multiple permissions
$role->givePermissionTo(['edit articles', 'delete articles']);

// Sync permissions (replaces all existing permissions)
$role->syncPermissions(['edit articles', 'publish articles']);

Working with Roles

Assigning Roles to Models

// Assign a role to a user
$user->assignRole('writer');

// Assign multiple roles
$user->assignRole(['writer', 'editor']);

// You can also use IDs
$user->assignRole(1);

// Sync roles (replaces all existing roles)
$user->syncRoles(['writer', 'editor']);

Checking Roles

// Check if user has a specific role
if ($user->hasRole('writer')) {
    // User has writer role
}

// Check if user has any of the specified roles
if ($user->hasAnyRoles(['writer', 'editor'])) {
    // User has at least one of these roles
}

// Check if user has all specified roles
if ($user->hasAllRoles(['writer', 'editor'])) {
    // User has both roles
}

// Get specific roles that match
$matchingRoles = $user->onlyRoles(['writer', 'admin']);

Removing Roles

// Remove a role
$user->removeRole('writer');

// Remove multiple roles
$user->removeRole(['writer', 'editor']);

Working with Permissions

Assigning Permissions to Models

// Give permission directly to user
$user->givePermissionTo('edit articles');

// Give multiple permissions
$user->givePermissionTo(['edit articles', 'delete articles']);

// Sync permissions (replaces all existing permissions)
$user->syncPermissions(['edit articles', 'publish articles']);

Checking Permissions

// Check if user has a specific permission
if ($user->hasPermission('edit articles')) {
    // User has permission (either direct or via role)
}

// Check direct permissions only
if ($user->hasDirectPermission('edit articles')) {
    // User has direct permission (not via role)
}

// Check if user has permission via roles
if ($user->hasPermissionViaRoles('edit articles')) {
    // User has permission through assigned roles
}

// Check if user has any of the specified permissions
if ($user->hasAnyPermissions(['edit articles', 'delete articles'])) {
    // User has at least one permission
}

// Check if user has all specified permissions
if ($user->hasAllPermissions(['edit articles', 'delete articles'])) {
    // User has all permissions
}

Forbidden Permissions

The package supports forbidden permissions that explicitly deny access:

// Give forbidden permission (denies access)
$user->giveForbiddenTo('delete articles');

// Check if user has forbidden permission
if ($user->hasForbiddenPermission('delete articles')) {
    // Access is explicitly denied
}

// Forbidden permissions override allowed permissions
$user->givePermissionTo('delete articles');
$user->giveForbiddenTo('delete articles');
// hasPermission('delete articles') will return false

Revoking Permissions

// Revoke permission
$user->revokePermissionTo('edit articles');

// Revoke multiple permissions
$user->revokePermissionTo(['edit articles', 'delete articles']);

Getting All Permissions

// Get all permissions (direct + via roles, excluding forbidden)
$permissions = $user->getAllPermissions();

// Get permissions via roles only
$rolePermissions = $user->getPermissionsViaRoles();

Using Enums

The package supports PHP 8.1+ enums for type-safe permission and role management:

Backed Enums

enum Permission: string
{
    case EDIT_ARTICLES = 'edit articles';
    case DELETE_ARTICLES = 'delete articles';
    case PUBLISH_ARTICLES = 'publish articles';
}

enum Role: string
{
    case WRITER = 'writer';
    case EDITOR = 'editor';
    case ADMIN = 'admin';
}

// Usage with enums
$user->assignRole(Role::WRITER);
$user->givePermissionTo(Permission::EDIT_ARTICLES);

if ($user->hasPermission(Permission::EDIT_ARTICLES)) {
    // User can edit articles
}

Unit Enums

enum SimplePermission
{
    case EDIT_ARTICLES;
    case DELETE_ARTICLES;
    case PUBLISH_ARTICLES;
}

// The enum name will be used as the permission name
$user->givePermissionTo(SimplePermission::EDIT_ARTICLES);

Middleware

The package provides middleware for protecting routes based on roles and permissions.

Permission Middleware

use Hypervel\Permission\Middlewares\PermissionMiddleware;

// In your route definitions
$router->get('/admin', [AdminController::class, 'index'], [
    'middleware' => [PermissionMiddleware::using('view admin')],
]);

// Multiple permissions (user needs ANY of them)
$router->get('/posts/edit', [PostController::class, 'edit'], [
    'middleware' => [PermissionMiddleware::using('edit articles', 'edit all')],
]);

Role Middleware

use Hypervel\Permission\Middlewares\RoleMiddleware;

// In your route definitions
$router->get('/admin', [AdminController::class, 'index'], [
    'middleware' => [RoleMiddleware::using('admin')],
]);

// Multiple roles (user needs ANY of them)
$router->get('/editor', [EditorController::class, 'index'], [
    'middleware' => [RoleMiddleware::using('editor', 'admin')],
]);

Using with Enums

$router->get('/admin', [AdminController::class, 'index'], [
    'middleware' => [PermissionMiddleware::using(Permission::VIEW_ADMIN)],
]);

$router->get('/editor', [EditorController::class, 'index'], [
    'middleware' => [RoleMiddleware::using(Role::EDITOR, Role::ADMIN)],
]);

Console Commands

Viewing Permissions and Roles

Use the built-in command to view the permission matrix:

# Show all permissions and roles
php artisan permission:show

# Show for specific guard
php artisan permission:show web

# Use different table style
php artisan permission:show web compact

Advanced Usage

Custom Guards

The package supports multiple guards:

// Create permissions for different guards
Permission::create(['name' => 'view admin', 'guard_name' => 'web']);
Permission::create(['name' => 'api access', 'guard_name' => 'api']);

// Roles with different guards
Role::create(['name' => 'admin', 'guard_name' => 'web']);
Role::create(['name' => 'api-user', 'guard_name' => 'api']);

Polymorphic Relationships

The package uses polymorphic relationships, so any model can have roles and permissions:

class Team extends Model
{
    use HasRole;
}

$team = Team::find(1);
$team->assignRole('project-manager');
$team->givePermissionTo('manage projects');

Working with the Permission Manager

The PermissionManager class provides advanced functionality:

use Hypervel\Permission\PermissionManager;

$manager = app(PermissionManager::class);

// Get role and permission classes
$roleClass = $manager->getRoleClass();
$permissionClass = $manager->getPermissionClass();

// Cache management
$manager->clearAllRolesPermissionsCache();
$manager->clearOwnerCache(User::class, $userId);

// Get cached data
$allRolesWithPermissions = $manager->getAllRolesWithPermissions();
$cachedRoles = $manager->getOwnerCachedRoles(User::class, $userId);
$cachedPermissions = $manager->getOwnerCachedPermissions(User::class, $userId);

Custom Models

If you want to extend the base models:

// Custom Permission Model
class CustomPermission extends \Hypervel\Permission\Models\Permission
{
    protected array $fillable = ['name', 'guard_name', 'description'];

    public function getDescriptionAttribute($value)
    {
        return ucfirst($value);
    }
}

// Custom Role Model
class CustomRole extends \Hypervel\Permission\Models\Role
{
    protected array $fillable = ['name', 'guard_name', 'description'];

    public function users()
    {
        return $this->morphedByMany(User::class, 'owner', 'owner_has_roles');
    }
}

// Update config
'models' => [
    'permission' => CustomPermission::class,
    'role' => CustomRole::class,
],

Caching

The package includes sophisticated caching to ensure high performance:

Cache Strategy

  • All Roles with Permissions: Cached globally to avoid N+1 queries when checking role-based permissions
  • Owner Roles: Individual user/model roles are cached separately
  • Owner Permissions: Individual user/model permissions are cached separately

Cache Invalidation

Cache is automatically cleared when:

  • Roles or permissions are assigned/revoked
  • Role permissions are modified
  • Models with roles/permissions are updated

Manual Cache Management

use Hypervel\Permission\PermissionManager;

$manager = app(PermissionManager::class);

// Clear all caches
$manager->clearAllRolesPermissionsCache();

// Clear specific owner cache
$manager->clearOwnerCache(User::class, $user->id);

// Get cache store
$cache = $manager->getCache();

Performance Considerations

Optimizing Queries

The package is designed to minimize database queries through caching:

// This loads and caches all roles with their permissions in one query
$allRolesWithPermissions = $manager->getAllRolesWithPermissions();

// Subsequent permission checks use cached data
$user->hasPermissionViaRoles('edit articles'); // No additional queries

Eager Loading

When working with multiple models, consider eager loading:

// Load users with their roles and permissions
$users = User::with(['roles.permissions', 'permissions'])->get();

// Now permission checks won't trigger additional queries
foreach ($users as $user) {
    if ($user->hasPermission('edit articles')) {
        // Process user
    }
}

Cache Warming

For high-traffic applications, warm the cache on deployment:

use Hypervel\Permission\PermissionManager;

// In a deployment script or command
$manager = app(PermissionManager::class);
$manager->getAllRolesWithPermissions(); // Warms the cache

Common Patterns

Hierarchical Permissions

// Create a hierarchy using role inheritance
$admin = Role::create(['name' => 'admin', 'guard_name' => 'web']);
$editor = Role::create(['name' => 'editor', 'guard_name' => 'web']);
$writer = Role::create(['name' => 'writer', 'guard_name' => 'web']);

// Assign cumulative permissions
$writer->givePermissionTo(['create articles', 'edit own articles']);
$editor->givePermissionTo(['create articles', 'edit own articles', 'edit all articles', 'publish articles']);

// Users get permissions through role assignment
$user->assignRole('editor'); // Gets all editor permissions

Resource-Based Permissions

// Create permissions for specific resources
Permission::create(['name' => 'view articles', 'guard_name' => 'web']);
Permission::create(['name' => 'create articles', 'guard_name' => 'web']);
Permission::create(['name' => 'edit articles', 'guard_name' => 'web']);
Permission::create(['name' => 'delete articles', 'guard_name' => 'web']);

Permission::create(['name' => 'view users', 'guard_name' => 'web']);
Permission::create(['name' => 'create users', 'guard_name' => 'web']);
Permission::create(['name' => 'edit users', 'guard_name' => 'web']);
Permission::create(['name' => 'delete users', 'guard_name' => 'web']);

Dynamic Permission Checking

class ArticleController extends Controller
{
    public function show(Article $article)
    {
        // Check if user can view this specific article
        if (!$this->canView($article)) {
            throw new UnauthorizedException('Cannot view this article');
        }

        return view('articles.show', compact('article'));
    }

    private function canView(Article $article): bool
    {
        $user = auth()->user();

        // Admin can view all
        if ($user->hasRole('admin')) {
            return true;
        }

        // Users can view published articles
        if ($article->is_published && $user->hasPermission('view articles')) {
            return true;
        }

        // Authors can view their own articles
        if ($article->author_id === $user->id && $user->hasPermission('view own articles')) {
            return true;
        }

        return false;
    }
}
Edit this page
Last Updated:
Contributors: Albert Chen
Prev
Sanctum
Next
Prompts