VOOZH about

URL: https://deepwiki.com/hypervel/permission/6-advanced-features

⇱ Advanced Features | hypervel/permission | DeepWiki


Loading...
Menu

Advanced Features

This page documents the advanced capabilities of the Hypervel Permission package, including the sophisticated caching architecture, exception handling strategy, and administrative console commands. These features optimize performance, provide clear error communication, and enable system introspection.

For basic permission and role checking functionality, see Core Permission System. For HTTP request protection, see HTTP Middleware Integration. For configuration options that control these features, see Configuration Reference.

Caching System

The package implements a two-tier caching architecture to minimize database queries while maintaining flexibility. The system caches both global role-permission mappings and owner-specific assignments.

Cache Architecture


Sources: src/PermissionManager.php1-224

Cache Configuration

The PermissionManager initializes its caching system during construction using configuration values:

Configuration PathPurposeDefault
permission.cache.storeCache driver to use'default'
permission.cache.expiration_secondsCache TTL in secondsConfigured value
permission.cache.keys.rolesKey for global roles cacheConfigured string
permission.cache.keys.owner_rolesPrefix for owner roles cacheConfigured prefix
permission.cache.keys.owner_permissionsPrefix for owner permissions cacheConfigured prefix

The initialization occurs in src/PermissionManager.php79-86:

protected function initializeCache(): void
{
 $this->cache = $this->getCacheStoreFromConfig();
 $this->cacheTtl = $this->getConfig('cache.expiration_seconds');
 $this->allRolesPermissionsCacheKey = $this->getConfig('cache.keys.roles');
 $this->ownerRolesCacheKeyPrefix = $this->getConfig('cache.keys.owner_roles');
 $this->ownerPermissionsCacheKeyPrefix = $this->getConfig('cache.keys.owner_permissions');
}

Sources: src/PermissionManager.php79-86 src/PermissionManager.php31-39

Cache Store Resolution

The system supports multiple cache backends through the CacheManager. Store resolution follows this logic in src/PermissionManager.php102-119:

  1. If cache.store is 'default', use the framework's default cache store
  2. If the specified store exists in cache.stores configuration, use that store
  3. If the specified store does not exist, fallback to 'array' (ephemeral, in-memory cache)

Sources: src/PermissionManager.php102-119

Tier 1: Global Roles Cache

The global cache stores all roles with their associated permissions in a single cache entry. This cache is accessed via getAllRolesWithPermissions() in src/PermissionManager.php140-156:


The cached structure maps role IDs to arrays containing both the role data and its permissions:

[
 role_id => [
 'role' => [...role attributes...],
 'permissions' => [...permission objects...]
 ]
]

Sources: src/PermissionManager.php140-156

Tier 2: Owner-Specific Caches

Owner-specific caches store individual owner's direct role and permission assignments. These are separate cache entries per owner, generated using the owner's polymorphic type and ID.

Cache Key Generation

The PermissionManager generates owner-specific cache keys in src/PermissionManager.php124-135:

public function getOwnerRolesCacheKey(string $ownerType, int|string $ownerId): string
{
 return "{$this->ownerRolesCacheKeyPrefix}:{$ownerType}:{$ownerId}";
}

public function getOwnerPermissionsCacheKey(string $ownerType, int|string $ownerId): string
{
 return "{$this->ownerPermissionsCacheKeyPrefix}:{$ownerType}:{$ownerId}";
}

For example, if an owner of type App\Models\User with ID 123 has:

  • Roles cache key: owner_roles:App\Models\User:123
  • Permissions cache key: owner_permissions:App\Models\User:123

Sources: src/PermissionManager.php124-135

Storing Owner Data

Owner-specific data is cached via src/PermissionManager.php161-180:

MethodPurposeParameters
cacheOwnerRoles()Cache owner's direct role assignments$ownerType, $ownerId, $roles array
cacheOwnerPermissions()Cache owner's direct permission assignments$ownerType, $ownerId, $permissions array

Both methods use put() to store data with the configured TTL.

Sources: src/PermissionManager.php161-180

Retrieving Owner Data

Owner-specific data is retrieved via src/PermissionManager.php185-202:

MethodReturnsCache Miss Behavior
getOwnerCachedRoles()?array of rolesReturns null
getOwnerCachedPermissions()?array of permissionsReturns null

These methods use get() which returns null on cache miss, allowing the calling code to load from database when needed.

Sources: src/PermissionManager.php185-202

Cache Invalidation


The package provides two cache invalidation methods in src/PermissionManager.php207-223:

clearAllRolesPermissionsCache()

Invalidates the global roles-permissions cache. Call this when:

  • A role is created, updated, or deleted
  • Permissions are attached to or detached from a role
  • The is_forbidden flag is changed on a role-permission relationship

clearOwnerCache(string $ownerType, int|string $ownerId)

Invalidates both role and permission caches for a specific owner. Call this when:

  • Roles are assigned to or removed from an owner
  • Permissions are granted to or revoked from an owner
  • The is_forbidden flag is changed on owner relationships

Note: Cache invalidation must be triggered manually by the application. The package does not automatically invalidate caches when models change.

Sources: src/PermissionManager.php207-223

Performance Implications

ScenarioCache BehaviorDatabase Queries
First permission checkCache miss on both tiers2-3 queries (roles, owner roles, owner permissions)
Subsequent checks (same owner)Cache hit on both tiers0 queries
Different owner (same request)Cache hit on Tier 1, miss on Tier 21-2 queries (owner-specific data)
After cache expirationCache missFull reload from database

The two-tier architecture optimizes for the common case where:

  1. Role-permission mappings change infrequently
  2. Individual owner checks occur frequently
  3. Multiple owners are checked in a single request

Sources: src/PermissionManager.php140-156 src/PermissionManager.php185-202

Exception Handling

The package defines three exception types, all extending Hypervel\HttpMessage\Exceptions\HttpException. These exceptions communicate authorization failures with appropriate HTTP status codes.

Exception Hierarchy


Sources: src/Exceptions/PermissionException.php1-27 src/Exceptions/RoleException.php1-27

PermissionException

Defined in src/Exceptions/PermissionException.php10-27 this exception signals that a permission check failed.

Constructor Signature

public function __construct(
 int $statusCode,
 string $message = '',
 int $code = 0,
 ?Throwable $previous = null,
 protected array $headers = [],
 protected array $permissions = []
)

Properties and Methods

MemberTypePurpose
$statusCodeintHTTP status code (typically 403)
$messagestringHuman-readable error message
$permissionsarrayList of permission names that were required
permissions()arrayAccessor method for the required permissions

Usage Context

Thrown by PermissionMiddleware when:

  • User lacks one or more required permissions (status 403)
  • The authenticated user exists but does not have hasAnyPermissions() method (status 500)

The $permissions array contains the names of permissions that were required, enabling detailed error responses.

Sources: src/Exceptions/PermissionException.php1-27

RoleException

Defined in src/Exceptions/RoleException.php10-27 this exception signals that a role check failed.

Constructor Signature

public function __construct(
 int $statusCode,
 string $message = '',
 int $code = 0,
 ?Throwable $previous = null,
 protected array $headers = [],
 protected array $roles = []
)

Properties and Methods

MemberTypePurpose
$statusCodeintHTTP status code (typically 403)
$messagestringHuman-readable error message
$rolesarrayList of role names that were required
roles()arrayAccessor method for the required roles

Usage Context

Thrown by RoleMiddleware when:

  • User lacks one or more required roles (status 403)
  • The authenticated user exists but does not have hasAnyRoles() method (status 500)

The $roles array contains the names of roles that were required, enabling detailed error responses.

Sources: src/Exceptions/RoleException.php1-27

UnauthorizedException

While not defined in the provided files, this exception is referenced in the system architecture diagrams. It is thrown when:

  • No authenticated user is present (status 401)
  • Configuration errors occur (status 500)

For middleware throwing behavior, see Permission Middleware and Role Middleware.

Exception Flow


Sources: src/Exceptions/PermissionException.php1-27 src/Exceptions/RoleException.php1-27

Error Response Information

Both PermissionException and RoleException carry the specific permissions or roles that were required. This enables custom exception handlers to:

  1. Log detailed authorization failure information
  2. Return informative error messages to clients
  3. Implement retry logic or alternative authorization flows
  4. Audit authorization failures

Example usage in an exception handler:


Sources: src/Exceptions/PermissionException.php23-26 src/Exceptions/RoleException.php23-26

Console Commands

The package provides the permission:show command for visualizing the permission structure. This administrative tool displays a matrix of roles, permissions, and their relationships.

ShowCommand

Defined in src/Console/ShowCommand.php11-68 the ShowCommand class generates tabular displays of the permission system state.

Command Signature

permission:show {guard?} {style?}
ArgumentRequiredDescriptionDefault
guardNoFilter by guard nameAll guards
styleNoTable display style'default'

Sources: src/Console/ShowCommand.php13-15

Command Execution Flow


Sources: src/Console/ShowCommand.php19-67

Model Class Resolution

The command loads model classes from configuration in src/Console/ShowCommand.php21-22:

$permissionClass = new (config('permission.models.permission'))();
$roleClass = new (config('permission.models.role'))();

This allows the command to work with custom model classes if configured.

Sources: src/Console/ShowCommand.php21-22

Guard Filtering

The command supports filtering by guard in src/Console/ShowCommand.php25-30:

  • If no guard is specified, all unique guard_name values are collected from both permissions and roles tables
  • If a guard is specified, only that guard is processed
  • Each guard is displayed with its own table

Sources: src/Console/ShowCommand.php25-30

Data Loading

For each guard, the command loads data in src/Console/ShowCommand.php34-45:

  1. Roles with permissions: Role::where('guard_name', $guard)->with('permissions')->orderBy('name')->get()
  2. All permissions: Permission::whereGuardName($guard)->orderBy('name')->pluck('name', 'id')

The roles are mapped to a structure containing their permission IDs for quick lookup.

Sources: src/Console/ShowCommand.php34-45

Matrix Generation

The permission matrix is built in src/Console/ShowCommand.php47-51:

$body = $permissions->map(
 fn ($permission, $id) => $roles->map(
 fn (array $role_data) => $role_data['permissions']->contains($id) ? ' ✔' : ' ·'
 )->prepend($permission)
);

For each permission:

  • Iterate through each role
  • If the role has the permission, display
  • Otherwise, display ·
  • Prepend the permission name to the row

Sources: src/Console/ShowCommand.php47-51

Table Display

The table is rendered in src/Console/ShowCommand.php53-65 with:

Column Headers

Role names are processed to remove trailing underscores and numbers:

$roles->keys()->map(function ($val) {
 $name = explode('_', $val);
 array_pop($name);
 return implode('_', $name);
})

An empty TableCell is prepended for the permission name column.

Display Styles

The $style argument supports Symfony Console table styles:

StyleDescription
defaultStandard bordered table
borderlessNo borders
compactMinimal spacing
boxBox-drawing characters

Sources: src/Console/ShowCommand.php53-65

Example Output

When executed, the command produces output similar to:

Guard: web

 --------- ----------- ------------ ----------
 admin moderator user 
 --------- ----------- ------------ ----------
 edit ✔ ✔ · 
 delete ✔ · · 
 view ✔ ✔ ✔ 
 create ✔ ✔ · 
 --------- ----------- ------------ ----------

Each row represents a permission, each column represents a role, and checkmarks indicate granted permissions.

Sources: src/Console/ShowCommand.php1-68

Use Cases

The permission:show command is useful for:

  1. Auditing: Verify permission assignments match security policies
  2. Debugging: Identify why a user has or lacks specific permissions
  3. Documentation: Generate visual representation of authorization structure
  4. Testing: Validate permission setup in different environments

Sources: src/Console/ShowCommand.php17