Skip to content

Commit b0a7d81

Browse files
alonexyalonexy
andauthored
feat: add redis-caching (#17)
* feat: add redis-caching * fix: update * fix: update * fix: fmt update * fix: fmt update --------- Co-authored-by: alonexy <[email protected]>
1 parent 1a1e817 commit b0a7d81

File tree

5 files changed

+818
-24
lines changed

5 files changed

+818
-24
lines changed

.github/workflows/phpunit.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ jobs:
1515
ports:
1616
- 3306:3306
1717
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
18+
redis:
19+
image: redis:6.2
20+
ports:
21+
- 6379:6379
22+
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
1823

1924
strategy:
2025
fail-fast: true
@@ -65,4 +70,4 @@ jobs:
6570
- name: Run semantic-release
6671
env:
6772
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
68-
run: npx semantic-release
73+
run: npx semantic-release

README.md

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,45 @@ Via [Composer](https://getcomposer.org/).
2626
composer require casbin/dbal-adapter
2727
```
2828

29-
### Usage
29+
### Basic Usage (Without Redis Caching)
3030

31-
```php
31+
This section describes how to use the adapter with a direct database connection, without leveraging Redis for caching.
32+
33+
You can initialize the adapter by passing either a Doctrine DBAL connection parameter array or an existing `Doctrine\DBAL\Connection` instance to the `Adapter::newAdapter()` method or the `Adapter` constructor.
34+
35+
**Example:**
3236

37+
```php
3338
require_once './vendor/autoload.php';
3439

3540
use Casbin\Enforcer;
3641
use CasbinAdapter\DBAL\Adapter as DatabaseAdapter;
42+
use Doctrine\DBAL\DriverManager; // Required if creating a new connection object
3743

38-
$config = [
39-
// Either 'driver' with one of the following values:
40-
// pdo_mysql,pdo_sqlite,pdo_pgsql,pdo_oci (unstable),pdo_sqlsrv
41-
// mysqli,sqlanywhere,sqlsrv,ibm_db2 (unstable),drizzle_pdo_mysql
44+
// Option 1: Using DBAL connection parameters array
45+
$dbConnectionParams = [
46+
// Supported drivers: pdo_mysql, pdo_sqlite, pdo_pgsql, pdo_oci, pdo_sqlsrv,
47+
// mysqli, sqlanywhere, sqlsrv, ibm_db2, drizzle_pdo_mysql
4248
'driver' => 'pdo_mysql',
4349
'host' => '127.0.0.1',
44-
'dbname' => 'test',
50+
'dbname' => 'casbin_db', // Your database name
4551
'user' => 'root',
4652
'password' => '',
47-
'port' => '3306',
53+
'port' => '3306', // Optional, defaults to driver's standard port
54+
// 'policy_table_name' => 'casbin_rules', // Optional, defaults to 'casbin_rule'
4855
];
4956

50-
$adapter = DatabaseAdapter::newAdapter($config);
57+
// Initialize the Adapter with the DBAL parameters array (without Redis)
58+
$adapter = DatabaseAdapter::newAdapter($dbConnectionParams);
59+
// Alternatively, using the constructor:
60+
// $adapter = new DatabaseAdapter($dbConnectionParams);
61+
62+
// Option 2: Using an existing Doctrine DBAL Connection instance
63+
// $dbalConnection = DriverManager::getConnection($dbConnectionParams);
64+
// $adapter = DatabaseAdapter::newAdapter($dbalConnection);
65+
// Or using the constructor:
66+
// $adapter = new DatabaseAdapter($dbalConnection);
67+
5168

5269
$e = new Enforcer('path/to/model.conf', $adapter);
5370

@@ -62,6 +79,86 @@ if ($e->enforce($sub, $obj, $act) === true) {
6279
}
6380
```
6481

82+
### Usage with Redis Caching
83+
84+
To improve performance and reduce database load, the adapter supports caching policy data using [Redis](https://redis.io/). When enabled, Casbin policies will be fetched from Redis if available, falling back to the database if the cache is empty.
85+
86+
To enable Redis caching, provide a Redis configuration array as the second argument when initializing the adapter. The first argument remains your Doctrine DBAL connection (either a parameters array or a `Connection` object).
87+
88+
**Redis Configuration Options:**
89+
90+
* `host` (string): Hostname or IP address of the Redis server. Default: `'127.0.0.1'`.
91+
* `port` (int): Port number of the Redis server. Default: `6379`.
92+
* `password` (string, nullable): Password for Redis authentication. Default: `null`.
93+
* `database` (int): Redis database index. Default: `0`.
94+
* `ttl` (int): Cache Time-To-Live in seconds. Policies stored in Redis will expire after this duration. Default: `3600` (1 hour).
95+
* `prefix` (string): Prefix for all Redis keys created by this adapter. Default: `'casbin_policies:'`.
96+
97+
**Example:**
98+
99+
```php
100+
require_once './vendor/autoload.php';
101+
102+
use Casbin\Enforcer;
103+
use CasbinAdapter\DBAL\Adapter as DatabaseAdapter;
104+
use Doctrine\DBAL\DriverManager; // Required if creating a new connection object
105+
106+
// Database connection parameters (can be an array or a Connection object)
107+
$dbConnectionParams = [
108+
'driver' => 'pdo_mysql',
109+
'host' => '127.0.0.1',
110+
'dbname' => 'casbin_db',
111+
'user' => 'root',
112+
'password' => '',
113+
'port' => '3306',
114+
];
115+
// Example with DBAL connection object:
116+
// $dbalConnection = DriverManager::getConnection($dbConnectionParams);
117+
118+
// Redis configuration
119+
$redisConfig = [
120+
'host' => '127.0.0.1', // Optional, defaults to '127.0.0.1'
121+
'port' => 6379, // Optional, defaults to 6379
122+
'password' => null, // Optional, defaults to null
123+
'database' => 0, // Optional, defaults to 0
124+
'ttl' => 7200, // Optional, Cache policies for 2 hours (default is 3600)
125+
'prefix' => 'myapp_casbin:' // Optional, Custom prefix (default is 'casbin_policies:')
126+
];
127+
128+
// Initialize adapter with DB parameters array and Redis configuration
129+
$adapter = DatabaseAdapter::newAdapter($dbConnectionParams, $redisConfig);
130+
// Or, using a DBAL Connection object:
131+
// $adapter = DatabaseAdapter::newAdapter($dbalConnection, $redisConfig);
132+
// Alternatively, using the constructor:
133+
// $adapter = new DatabaseAdapter($dbConnectionParams, $redisConfig);
134+
135+
$e = new Enforcer('path/to/model.conf', $adapter);
136+
137+
// ... rest of your Casbin usage
138+
```
139+
140+
#### Cache Preheating
141+
142+
The adapter provides a `preheatCache()` method to proactively load all policies from the database and store them in the Redis cache. This can be useful during application startup or as part of a scheduled task to ensure the cache is warm, reducing latency on initial policy checks.
143+
144+
**Example:**
145+
146+
```php
147+
if ($adapter->preheatCache()) {
148+
// Cache preheating was successful
149+
echo "Casbin policy cache preheated successfully.\n";
150+
} else {
151+
// Cache preheating failed (e.g., Redis not available or DB error)
152+
echo "Casbin policy cache preheating failed.\n";
153+
}
154+
```
155+
156+
#### Cache Invalidation
157+
158+
The cache is designed to be automatically invalidated when policy-modifying methods are called on the adapter (e.g., `addPolicy()`, `removePolicy()`, `savePolicy()`, etc.). Currently, this primarily clears the cache key for all policies (`{$prefix}all_policies`).
159+
160+
**Important Note:** The automatic invalidation for *filtered policies* (policies loaded via `loadFilteredPolicy()`) is limited. Due to the way `predis/predis` client works and to avoid using performance-detrimental commands like `KEYS *` in production environments, the adapter does not automatically delete cache entries for specific filters by pattern. If you rely heavily on `loadFilteredPolicy` and make frequent policy changes, consider a lower TTL for your Redis cache or implement a more sophisticated cache invalidation strategy for filtered results outside of this adapter if needed. The main `{$prefix}all_policies` cache is cleared on any policy change, which means subsequent calls to `loadPolicy()` will refresh from the database and update this general cache.
161+
65162
### Getting Help
66163

67164
- [php-casbin](https://github.com/php-casbin/php-casbin)

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"require": {
2121
"php": ">=8.0",
2222
"casbin/casbin": "^4.0",
23-
"doctrine/dbal": "^3.9|^4.0"
23+
"doctrine/dbal": "^3.9|^4.0",
24+
"predis/predis": "^2.0"
2425
},
2526
"require-dev": {
2627
"phpunit/phpunit": "~9.0",
@@ -36,4 +37,4 @@
3637
"CasbinAdapter\\DBAL\\Tests\\": "tests/"
3738
}
3839
}
39-
}
40+
}

0 commit comments

Comments
 (0)