Skip to content

Commit c2b8d31

Browse files
deemonicclaude
andauthored
feat: add custom cache driver configuration (#34)
* feat: add custom cache driver configuration Add the ability to specify a custom cache driver for Blasp via config or environment variable. This is useful for environments like Laravel Vapor where DynamoDB has size limits that can be exceeded when caching profanity expressions. - Add `cache_driver` config option with `BLASP_CACHE_DRIVER` env support - Refactor ConfigurationLoader to use configurable cache store - Add tests for cache driver configuration - Update README with cache driver documentation Based on PR #25 by @dimzeta - adapted for Blasp v3.0 architecture. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: use explicit null check in getCache() Address CodeRabbit nitpick - use `!== null` instead of truthy check to make intent clearer and handle edge case of empty string config. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8352bea commit c2b8d31

File tree

5 files changed

+188
-10
lines changed

5 files changed

+188
-10
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,26 @@ php artisan blasp:clear
266266

267267
This command will clear all cached Blasp expressions and configurations.
268268

269+
### Cache Driver Configuration
270+
271+
By default, Blasp uses Laravel's default cache driver. You can specify a different cache driver for Blasp by setting the `cache_driver` option in your configuration:
272+
273+
```php
274+
// config/blasp.php
275+
return [
276+
'cache_driver' => env('BLASP_CACHE_DRIVER'),
277+
// ...
278+
];
279+
```
280+
281+
Or set it via environment variable:
282+
283+
```env
284+
BLASP_CACHE_DRIVER=redis
285+
```
286+
287+
This is particularly useful in environments like **Laravel Vapor** where the default cache driver (DynamoDB) has size limits that can be exceeded when caching large profanity expression sets. By configuring a different cache driver (such as Redis), you can avoid these limitations.
288+
269289
## ⚡ Performance
270290

271291
Blasp v3.0 includes significant performance optimizations:

config/config.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@
2323
*/
2424
'mask_character' => '*',
2525

26+
/*
27+
|--------------------------------------------------------------------------
28+
| Cache Driver
29+
|--------------------------------------------------------------------------
30+
|
31+
| Specify the cache driver to use for storing profanity expressions.
32+
| If not specified, the default Laravel cache driver will be used.
33+
| This is useful for environments like Laravel Vapor where DynamoDB
34+
| has size limits that can be exceeded by cached profanity expressions.
35+
|
36+
| Supported: Any cache driver configured in your Laravel application
37+
| Example: "redis", "file", "array", "database", etc.
38+
|
39+
*/
40+
'cache_driver' => env('BLASP_CACHE_DRIVER'),
2641

2742
/*
2843
|--------------------------------------------------------------------------

src/Config/ConfigurationLoader.php

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ class ConfigurationLoader
2222
{
2323
private const CACHE_TTL = 86400; // 24 hours
2424

25+
/**
26+
* Get the cache store instance with the configured driver.
27+
*
28+
* @return \Illuminate\Contracts\Cache\Repository
29+
*/
30+
private static function getCache(): \Illuminate\Contracts\Cache\Repository
31+
{
32+
$driver = config('blasp.cache_driver');
33+
34+
return $driver !== null ? Cache::store($driver) : Cache::store();
35+
}
36+
2537
public function __construct(
2638
private ?ExpressionGeneratorInterface $expressionGenerator = null
2739
) {
@@ -249,7 +261,7 @@ public function loadLanguage(string $language): ?array
249261
private function loadFromCacheOrGenerate(DetectionConfigInterface $config): DetectionConfigInterface
250262
{
251263
$cacheKey = $config->getCacheKey();
252-
$cached = Cache::get($cacheKey);
264+
$cached = self::getCache()->get($cacheKey);
253265

254266
if ($cached) {
255267
return $this->loadFromCache($cached);
@@ -312,12 +324,12 @@ private function cacheConfiguration(DetectionConfigInterface $config, string $ca
312324
'false_positives' => $config->getFalsePositivesForLanguage($language)
313325
];
314326
}
315-
327+
316328
$configToCache['language_data'] = $languageData;
317329
$configToCache['default_language'] = $config->getCurrentLanguage();
318330
}
319331

320-
Cache::put($cacheKey, $configToCache, self::CACHE_TTL);
332+
self::getCache()->put($cacheKey, $configToCache, self::CACHE_TTL);
321333
$this->trackCacheKey($cacheKey);
322334
}
323335

@@ -329,11 +341,12 @@ private function cacheConfiguration(DetectionConfigInterface $config, string $ca
329341
*/
330342
private function trackCacheKey(string $cacheKey): void
331343
{
332-
$keys = Cache::get('blasp_cache_keys', []);
333-
344+
$cache = self::getCache();
345+
$keys = $cache->get('blasp_cache_keys', []);
346+
334347
if (!in_array($cacheKey, $keys)) {
335348
$keys[] = $cacheKey;
336-
Cache::put('blasp_cache_keys', $keys, self::CACHE_TTL);
349+
$cache->put('blasp_cache_keys', $keys, self::CACHE_TTL);
337350
}
338351
}
339352

@@ -344,11 +357,13 @@ private function trackCacheKey(string $cacheKey): void
344357
*/
345358
public static function clearCache(): void
346359
{
347-
$keys = Cache::get('blasp_cache_keys', []);
360+
$cache = self::getCache();
361+
$keys = $cache->get('blasp_cache_keys', []);
362+
348363
foreach ($keys as $key) {
349-
Cache::forget($key);
364+
$cache->forget($key);
350365
}
351-
352-
Cache::forget('blasp_cache_keys');
366+
367+
$cache->forget('blasp_cache_keys');
353368
}
354369
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
namespace Blaspsoft\Blasp\Tests;
4+
5+
use Blaspsoft\Blasp\Config\ConfigurationLoader;
6+
use Blaspsoft\Blasp\Contracts\ExpressionGeneratorInterface;
7+
use Illuminate\Support\Facades\Cache;
8+
use Illuminate\Support\Facades\Config;
9+
10+
class CacheDriverConfigurationTest extends TestCase
11+
{
12+
private ConfigurationLoader $loader;
13+
private ExpressionGeneratorInterface $mockExpressionGenerator;
14+
15+
public function setUp(): void
16+
{
17+
parent::setUp();
18+
19+
$this->mockExpressionGenerator = $this->createMock(ExpressionGeneratorInterface::class);
20+
$this->mockExpressionGenerator->method('generateExpressions')->willReturn([]);
21+
22+
$this->loader = new ConfigurationLoader($this->mockExpressionGenerator);
23+
24+
// Clear cache before each test
25+
Cache::flush();
26+
}
27+
28+
public function test_default_cache_driver_is_used_when_not_configured(): void
29+
{
30+
Config::set('blasp.cache_driver', null);
31+
32+
$config = $this->loader->load(['test'], ['false_positive']);
33+
34+
$this->assertNotNull($config);
35+
$this->assertTrue(Cache::has('blasp_cache_keys'));
36+
}
37+
38+
public function test_custom_cache_driver_is_used_when_configured(): void
39+
{
40+
// Use the array driver as a test cache store
41+
Config::set('blasp.cache_driver', 'array');
42+
43+
$config = $this->loader->load(['custom_test'], ['custom_false']);
44+
45+
$this->assertNotNull($config);
46+
// Verify caching worked with the custom driver
47+
$keys = Cache::store('array')->get('blasp_cache_keys', []);
48+
$this->assertNotEmpty($keys);
49+
}
50+
51+
public function test_cache_clear_uses_configured_driver(): void
52+
{
53+
Config::set('blasp.cache_driver', 'array');
54+
55+
// Load and cache a configuration
56+
$this->loader->load(['test'], ['false_positive']);
57+
58+
// Verify something is cached
59+
$keys = Cache::store('array')->get('blasp_cache_keys', []);
60+
$this->assertNotEmpty($keys);
61+
62+
// Clear cache
63+
ConfigurationLoader::clearCache();
64+
65+
// Verify cache is cleared
66+
$keys = Cache::store('array')->get('blasp_cache_keys', []);
67+
$this->assertEmpty($keys);
68+
}
69+
70+
public function test_configuration_is_cached_with_custom_driver(): void
71+
{
72+
Config::set('blasp.cache_driver', 'array');
73+
74+
// Load configuration first time
75+
$config1 = $this->loader->load(['test_prof'], ['test_false']);
76+
77+
// Create a new loader
78+
$mockGenerator2 = $this->createMock(ExpressionGeneratorInterface::class);
79+
$mockGenerator2->method('generateExpressions')->willReturn(['different' => 'result']);
80+
$loader2 = new ConfigurationLoader($mockGenerator2);
81+
82+
// Load configuration second time - should come from cache
83+
$config2 = $loader2->load(['test_prof'], ['test_false']);
84+
85+
// Both configs should have the same data (from cache)
86+
$this->assertEquals($config1->getProfanities(), $config2->getProfanities());
87+
$this->assertEquals($config1->getFalsePositives(), $config2->getFalsePositives());
88+
}
89+
90+
public function test_cache_keys_are_tracked_with_custom_driver(): void
91+
{
92+
Config::set('blasp.cache_driver', 'array');
93+
94+
// Load multiple configurations
95+
$this->loader->load(['prof1'], ['false1']);
96+
$this->loader->load(['prof2'], ['false2']);
97+
98+
// Verify cache keys are tracked in the custom driver
99+
$cacheKeys = Cache::store('array')->get('blasp_cache_keys', []);
100+
$this->assertGreaterThan(0, count($cacheKeys));
101+
102+
// All tracked keys should exist in the custom cache store
103+
foreach ($cacheKeys as $key) {
104+
$this->assertTrue(
105+
Cache::store('array')->has($key),
106+
"Cache key {$key} should exist in array store"
107+
);
108+
}
109+
}
110+
111+
public function test_switching_cache_driver_clears_from_correct_store(): void
112+
{
113+
// First, cache with array driver
114+
Config::set('blasp.cache_driver', 'array');
115+
$this->loader->load(['test1'], ['false1']);
116+
117+
$arrayKeys = Cache::store('array')->get('blasp_cache_keys', []);
118+
$this->assertNotEmpty($arrayKeys);
119+
120+
// Clear cache (should clear from array store)
121+
ConfigurationLoader::clearCache();
122+
123+
// Verify array store is cleared
124+
$arrayKeys = Cache::store('array')->get('blasp_cache_keys', []);
125+
$this->assertEmpty($arrayKeys);
126+
}
127+
}

tests/TestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ protected function setUp(): void
2626
Config::set('blasp.languages', config('blasp.languages', []));
2727
Config::set('blasp.substitutions', config('blasp.substitutions', []));
2828
Config::set('blasp.mask_character', '*'); // Default mask character
29+
Config::set('blasp.cache_driver', config('blasp.cache_driver'));
2930
}
3031
}

0 commit comments

Comments
 (0)