8
8
use Psr \Log \LoggerInterface ;
9
9
use Symfony \Component \Cache \Adapter \AbstractAdapter ;
10
10
use Symfony \Component \Cache \Adapter \FilesystemAdapter ;
11
+ use Symfony \Component \Cache \Adapter \MemcachedAdapter ;
11
12
use Symfony \Component \Cache \PruneableInterface ;
12
13
13
14
/**
@@ -243,7 +244,7 @@ private function saveRemediations(array $decisions): bool
243
244
}
244
245
}
245
246
246
- return $ this ->adapter -> commit ();
247
+ return $ this ->commit ();
247
248
}
248
249
249
250
private function removeRemediations (array $ decisions ): bool
@@ -268,7 +269,7 @@ private function removeRemediations(array $decisions): bool
268
269
}
269
270
}
270
271
271
- return $ this ->adapter -> commit ();
272
+ return $ this ->commit ();
272
273
}
273
274
274
275
/**
@@ -291,17 +292,22 @@ private function saveRemediationsForIp(array $decisions, string $ip): string
291
292
$ remediation = $ this ->formatRemediationFromDecision (null );
292
293
$ remediationResult = $ this ->addRemediationToCacheItem ($ ip , $ remediation [0 ], $ remediation [1 ], $ remediation [2 ]);
293
294
}
294
- $ this ->adapter -> commit ();
295
+ $ this ->commit ();
295
296
296
297
return $ remediationResult ;
297
298
}
298
299
299
300
public function clear (): bool
300
301
{
301
- $ cleared = $ this ->adapter ->clear ();
302
+ $ this ->setCustomErrorHandler ();
303
+ try {
304
+ $ cleared = $ this ->adapter ->clear ();
305
+ } finally {
306
+ $ this ->unsetCustomErrorHandler ();
307
+ }
302
308
$ this ->warmedUp = false ;
303
309
$ this ->defferUpdateCacheConfig (['warmed_up ' => $ this ->warmedUp ]);
304
- $ this ->adapter -> commit ();
310
+ $ this ->commit ();
305
311
$ this ->logger ->info ('' , ['type ' => 'CACHE_CLEARED ' ]);
306
312
307
313
return $ cleared ;
@@ -328,7 +334,7 @@ public function warmUp(): int
328
334
if ($ newDecisions ) {
329
335
$ this ->warmedUp = $ this ->saveRemediations ($ newDecisions );
330
336
$ this ->defferUpdateCacheConfig (['warmed_up ' => $ this ->warmedUp ]);
331
- $ this ->adapter -> commit ();
337
+ $ this ->commit ();
332
338
if (!$ this ->warmedUp ) {
333
339
throw new BouncerException ('Unable to warm the cache up ' );
334
340
}
@@ -338,7 +344,7 @@ public function warmUp(): int
338
344
// Store the fact that the cache has been warmed up.
339
345
$ this ->defferUpdateCacheConfig (['warmed_up ' => true ]);
340
346
341
- $ this ->adapter -> commit ();
347
+ $ this ->commit ();
342
348
$ this ->logger ->info ('' , ['type ' => 'CACHE_WARMED_UP ' , 'added_decisions ' => $ nbNew ]);
343
349
344
350
return $ nbNew ;
@@ -447,6 +453,9 @@ public function get(string $ip): string
447
453
return $ remediation ;
448
454
}
449
455
456
+ /**
457
+ * Prune the cache (only when using PHP File System cache).
458
+ */
450
459
public function prune (): bool
451
460
{
452
461
if ($ this ->adapter instanceof PruneableInterface) {
@@ -458,4 +467,59 @@ public function prune(): bool
458
467
459
468
throw new BouncerException ('Cache Adapter ' .\get_class ($ this ->adapter ).' is not prunable. ' );
460
469
}
470
+
471
+ /**
472
+ * When Memcached connection fail, it throw an unhandled warning.
473
+ * To catch this warning as a clean execption we have to temporarily change the error handler.
474
+ */
475
+ private function setCustomErrorHandler (): void
476
+ {
477
+ if ($ this ->adapter instanceof MemcachedAdapter) {
478
+ set_error_handler (function () {
479
+ throw new BouncerException ('Error when connecting to Memcached. Please fix the Memcached DSN or select another cache technology. ' );
480
+ });
481
+ }
482
+ }
483
+
484
+ /**
485
+ * When the selected cache adapter is MemcachedAdapter, revert to the previous error handler.
486
+ * */
487
+ private function unsetCustomErrorHandler (): void
488
+ {
489
+ if ($ this ->adapter instanceof MemcachedAdapter) {
490
+ restore_error_handler ();
491
+ }
492
+ }
493
+
494
+ /**
495
+ * Wrap the cacheAdapter to catch warnings.
496
+ *
497
+ * @throws BouncerException if the connection was not successful
498
+ * */
499
+ private function commit (): bool
500
+ {
501
+ $ this ->setCustomErrorHandler ();
502
+ try {
503
+ $ result = $ this ->adapter ->commit ();
504
+ } finally {
505
+ $ this ->unsetCustomErrorHandler ();
506
+ }
507
+
508
+ return $ result ;
509
+ }
510
+
511
+ /**
512
+ * Test the connection to the cache system (Redis or Memcached).
513
+ *
514
+ * @throws BouncerException if the connection was not successful
515
+ * */
516
+ public function testConnection (): void
517
+ {
518
+ $ this ->setCustomErrorHandler ();
519
+ try {
520
+ $ this ->adapter ->getItem (' ' );
521
+ } finally {
522
+ $ this ->unsetCustomErrorHandler ();
523
+ }
524
+ }
461
525
}
0 commit comments