fix(cache): resolve all cached brands before deleting collection key in BrandCache reset (F-2026-0002)

This commit is contained in:
Jérémy Munsch 2026-08-26 09:45:49 +02:00
parent fc268f0c7f
commit 1a93c74815
Signed by: forge-joniko
GPG key ID: D7EFE2F5CB6CC0E4
2 changed files with 11 additions and 5 deletions

View file

@ -9,6 +9,7 @@ use Domain\Models\ValueObjects\Brand\ArcadiaId;
use Domain\Models\ValueObjects\Brand\BrandCode;
use Domain\Models\ValueObjects\Brand\BrandId;
use Domain\Models\ValueObjects\Brand\BrandName;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
use Ramsey\Uuid\Uuid;
@ -20,7 +21,7 @@ final readonly class BrandCache
public function __construct(
private CacheInterface $cacheStore,
private \Psr\Log\LoggerInterface $logger,
private LoggerInterface $logger,
) {
}
@ -30,6 +31,7 @@ final readonly class BrandCache
return $this->fromCacheData($this->cacheStore->get($this->idKey($id)));
} catch (\Throwable $e) {
$this->logger->warning('BrandCache::getById failed', ['exception' => $e->getMessage()]);
return null;
}
}
@ -40,6 +42,7 @@ final readonly class BrandCache
return $this->fromCacheData($this->cacheStore->get($this->codeKey($code)));
} catch (\Throwable $e) {
$this->logger->warning('BrandCache::getByCode failed', ['exception' => $e->getMessage()]);
return null;
}
}
@ -50,6 +53,7 @@ final readonly class BrandCache
return $this->fromCacheData($this->cacheStore->get($this->arcadiaKey($arcadiaId)));
} catch (\Throwable $e) {
$this->logger->warning('BrandCache::getByArcadiaId failed', ['exception' => $e->getMessage()]);
return null;
}
}
@ -81,6 +85,7 @@ final readonly class BrandCache
return $brands;
} catch (\Throwable $e) {
$this->logger->warning('BrandCache::getAll failed', ['exception' => $e->getMessage()]);
return null;
}
}
@ -127,9 +132,10 @@ final readonly class BrandCache
public function reset(): void
{
try {
$all = $this->getAll();
$this->cacheStore->delete(self::KEY_ALL);
$all = $this->getAll();
if ($all !== null) {
foreach ($all as $brand) {
$this->cacheStore->delete($this->idKey($brand->id()));

View file

@ -46,7 +46,7 @@
"domain": "conventions",
"severity": "medium",
"confidence": "confirmed",
"status": "open",
"status": "fixed",
"summary": "BrandCache::reset() deletes KEY_ALL before calling getAll(), which causes getAll() to immediately return null and leaves individual brand cache entries intact.",
"why_it_matters": "When BrandCreated or BrandRenamed domain events fire, BrandCache::reset() fails to invalidate individual brand cache entries (brand:id:*, brand:code:*, brand:arcadia:*), serving stale brand data for up to 24 hours.",
"evidence": [
@ -64,8 +64,8 @@
],
"symbol": "Infra\\Cache\\BrandCache::reset",
"recommendation": "Retrieve $all = $this->getAll() before deleting self::KEY_ALL so individual brand keys can be successfully resolved and deleted.",
"remediation": "In BrandCache::reset(), move $all = $this->getAll() to the beginning of the method before $this->cacheStore->delete(self::KEY_ALL).",
"verification_notes": "Confirmed in BrandCache.php: lines 130-134 clearly show self::KEY_ALL being deleted prior to getAll() invocation.",
"remediation": "In BrandCache::reset(), moved $all = $this->getAll() before $this->cacheStore->delete(self::KEY_ALL).",
"verification_notes": "Fixed in BrandCache.php and verified with BrandCacheTest.",
"metadata": {
"priority": "p1",
"subsystem": "CFG"