GAC includes a built-in caching system to improve performance by reducing database queries. The caching layer supports multiple adapters, configurable TTL (Time To Live), and granular purging strategies.
All cache adapters must implement the CacheAdapterInterface:
// CacheAdapterInterface.phpinterface CacheAdapterInterface { /** * Get cached value * @return mixed Value or NULL if not found/expired */ public function get(string $key): mixed; /** * Save value to cache * @return bool Success status */ public function save(string $key, mixed $data, ?int $ttl = 60): bool; /** * Delete specific cache entry * @return bool Success status */ public function delete(string $key): bool; /** * Delete entries matching pattern (glob-style) * @return int Number of deleted entries */ public function deleteMatching(string $pattern): int; /** * Clear all cache entries * @return bool Success status */ public function clean(): bool;}
gac_p_1_12345 - Permissions for user 12345gac_r_1_12345 - Restrictions for user 12345gac_p_2_789 - Permissions for client 789gac_r_2_789 - Restrictions for client 789gac_r_global - Global restrictions
// Get permissions with cache (GAC.php:139-156)public function getPermissions(bool $fromCache = true) : Permissions { $type = 'permissions'; if (empty($this->entityType) || empty($this->entityId)) { throw new \Exception('Entity type and ID must be set before loading data.'); } $permissions = null; if ($fromCache) { // Try to load from cache first $permissions = $this->getFromCache($type); } if (!is_array($permissions)) { // Cache miss - load from database $permissions = $this->getPermissionsFromDB(); // Save to cache for next time $this->saveToCache($type, $permissions); } return new Permissions($permissions);}
// Get restrictions with cache (GAC.php:165-191)public function getRestrictions(bool $fromCache = true) : Restrictions { if (empty($this->entityType) || empty($this->entityId)) { throw new \Exception('Entity type and ID must be set before loading data.'); } // Try cache for both global and personal $restrictionsP = null; $restrictionsG = null; if ($fromCache) { $restrictionsG = $this->getFromCache('restrictions_global'); $restrictionsP = $this->getFromCache('restrictions'); } // Load from database if cache miss if (!is_array($restrictionsG)) { $restrictionsG = $this->getRestrictionsFromDB(true); $this->saveToCache('restrictions_global', $restrictionsG); } if (!is_array($restrictionsP)) { $restrictionsP = $this->getRestrictionsFromDB(false); $this->saveToCache('restrictions', $restrictionsP); } // Merge global and personal restrictions $restrictions = array_merge_recursive($restrictionsG, $restrictionsP); return new Restrictions($restrictions);}
Global restrictions are cached separately and shared across all entities, reducing redundant database queries.
// Purge cache for specific users$gac->purgePermissionsBy('user', [12345, 67890]);$gac->purgeRestrictionsBy('user', [12345, 67890]);// When to use:// - User permissions/restrictions changed// - User roles were modified
// Purge all entities with specific role(s)$gac->purgePermissionsBy('role', [101, 102]);// When to use:// - Role permissions changed// - Role was assigned/removed from entities// - Bulk updates affecting role members
// Purge specific client(s)$gac->purgeRestrictionsBy('client', [789]);// When to use:// - Client restrictions changed// - Client configuration updated
// Purge all cached permissions$gac->purgePermissionsBy('global');// When to use:// - System-wide permission changes// - Module structure changed// - After major updates
The deleteMatching() method supports glob patterns:
// Delete matching (CacheAdapter.php:100-114)public function deleteMatching(string $pattern) : int { if (empty($this->cacheDir) || empty($pattern)) { return 0; } $deletedCount = 0; $files = glob($this->cacheDir . DIRECTORY_SEPARATOR . $pattern); foreach ($files as $file) { if (is_file($file) && unlink($file)) { $deletedCount++; } } return $deletedCount;}
Pattern Examples:
// Delete all permissions cache$adapter->deleteMatching('gac_p_*');// Delete all cache for user entity type$adapter->deleteMatching('gac_*_1_*');// Delete everything$adapter->deleteMatching('gac_*');