-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added cache implementation for queries
- Loading branch information
Showing
13 changed files
with
316 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
...hitectureBundle/Bridge/Nette/DI/definitions/architecture_bundle/infrastructure.cache.neon
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
services: | ||
infrastructure.cache: | ||
autowired: SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\CacheInterface | ||
type: SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\CacheInterface | ||
factory: @extension.infrastructure.cache.nette | ||
|
||
infrastructure.cache.nette: | ||
autowired: no | ||
factory: SixtyEightPublishers\ArchitectureBundle\Infrastructure\NetteCache\NetteCache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/ArchitectureBundle/Bridge/Symfony/Messenger/Middleware/QueryCacheMiddleware.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Bridge\Symfony\Messenger\Middleware; | ||
|
||
use Psr\Log\LoggerInterface; | ||
use SixtyEightPublishers\ArchitectureBundle\Bridge\Symfony\Messenger\Stamp\RefreshCacheStamp; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\CacheInterface; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\UnableToReadCacheException; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\UnableToWriteCacheException; | ||
use SixtyEightPublishers\ArchitectureBundle\ReadModel\Query\CachableQueryInterface; | ||
use Symfony\Component\Messenger\Envelope; | ||
use Symfony\Component\Messenger\Middleware\MiddlewareInterface; | ||
use Symfony\Component\Messenger\Middleware\StackInterface; | ||
|
||
final class QueryCacheMiddleware implements MiddlewareInterface | ||
{ | ||
public function __construct( | ||
private readonly CacheInterface $cache, | ||
private readonly ?LoggerInterface $logger = null, | ||
) {} | ||
|
||
public function handle(Envelope $envelope, StackInterface $stack): Envelope | ||
{ | ||
$message = $envelope->getMessage(); | ||
|
||
if (!($message instanceof CachableQueryInterface)) { | ||
return $stack->next()->handle( | ||
envelope: $envelope, | ||
stack: $stack, | ||
); | ||
} | ||
|
||
$refreshCache = $envelope->last(RefreshCacheStamp::class) !== null; | ||
$cacheMetadata = $message->createCacheMetadata(); | ||
|
||
try { | ||
$item = !$refreshCache ? $this->cache->getItem( | ||
key: $cacheMetadata->key, | ||
) : null; | ||
} catch (UnableToReadCacheException $e) { | ||
if (null === $this->logger) { | ||
throw $e; | ||
} | ||
|
||
$this->logger->error( | ||
message: $e->getMessage(), | ||
context: [ | ||
'exception' => $e, | ||
], | ||
); | ||
|
||
$item = null; | ||
} | ||
|
||
if (null !== $item) { | ||
return $item; | ||
} | ||
|
||
$item = $stack->next()->handle( | ||
envelope: $envelope, | ||
stack: $stack, | ||
); | ||
|
||
try { | ||
$this->cache->saveItem( | ||
metadata: $cacheMetadata, | ||
item: $item, | ||
); | ||
} catch (UnableToWriteCacheException $e) { | ||
if (null === $this->logger) { | ||
throw $e; | ||
} | ||
|
||
$this->logger->error( | ||
message: $e->getMessage(), | ||
context: [ | ||
'exception' => $e, | ||
], | ||
); | ||
} | ||
|
||
return $item; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/ArchitectureBundle/Bridge/Symfony/Messenger/Stamp/RefreshCacheStamp.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Bridge\Symfony\Messenger\Stamp; | ||
|
||
use Symfony\Component\Messenger\Stamp\StampInterface; | ||
|
||
final class RefreshCacheStamp implements StampInterface | ||
{ | ||
} |
30 changes: 30 additions & 0 deletions
30
src/ArchitectureBundle/Infrastructure/Cache/CacheInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache; | ||
|
||
interface CacheInterface | ||
{ | ||
/** | ||
* @throws UnableToReadCacheException | ||
*/ | ||
public function getItem(string $key): mixed; | ||
|
||
/** | ||
* @throws UnableToWriteCacheException | ||
*/ | ||
public function saveItem(CacheMetadata $metadata, mixed $item): void; | ||
|
||
/** | ||
* @throws UnableToDeleteCacheException | ||
*/ | ||
public function deleteItem(string $key): void; | ||
|
||
/** | ||
* @param array<int, string>|null $tags | ||
* | ||
* @throws UnableToDeleteCacheException | ||
*/ | ||
public function clean(?array $tags = null): void; | ||
} |
19 changes: 19 additions & 0 deletions
19
src/ArchitectureBundle/Infrastructure/Cache/CacheMetadata.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache; | ||
|
||
use DateTimeImmutable; | ||
|
||
final class CacheMetadata | ||
{ | ||
/** | ||
* @param array<int, string> $tags | ||
*/ | ||
public function __construct( | ||
public readonly string $key, | ||
public readonly int|DateTimeImmutable|null $expiration, | ||
public readonly array $tags = [], | ||
) {} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/ArchitectureBundle/Infrastructure/Cache/UnableToDeleteCacheException.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache; | ||
|
||
use RuntimeException; | ||
|
||
final class UnableToDeleteCacheException extends RuntimeException | ||
{ | ||
} |
11 changes: 11 additions & 0 deletions
11
src/ArchitectureBundle/Infrastructure/Cache/UnableToReadCacheException.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache; | ||
|
||
use RuntimeException; | ||
|
||
final class UnableToReadCacheException extends RuntimeException | ||
{ | ||
} |
11 changes: 11 additions & 0 deletions
11
src/ArchitectureBundle/Infrastructure/Cache/UnableToWriteCacheException.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache; | ||
|
||
use RuntimeException; | ||
|
||
final class UnableToWriteCacheException extends RuntimeException | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
src/ArchitectureBundle/Infrastructure/NetteCache/NetteCache.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\Infrastructure\NetteCache; | ||
|
||
use DateTimeImmutable; | ||
use Nette\Caching\Cache; | ||
use Nette\Caching\Storage; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\CacheInterface; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\CacheMetadata; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\UnableToDeleteCacheException; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\UnableToReadCacheException; | ||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\UnableToWriteCacheException; | ||
use Throwable; | ||
use function count; | ||
use function is_int; | ||
|
||
final class NetteCache implements CacheInterface | ||
{ | ||
private readonly Cache $cache; | ||
|
||
public function __construct( | ||
Storage $storage, | ||
) { | ||
$this->cache = new Cache( | ||
storage: $storage, | ||
namespace: self::class, | ||
); | ||
} | ||
|
||
public function getItem(string $key): mixed | ||
{ | ||
try { | ||
return $this->cache->load( | ||
key: $key, | ||
); | ||
} catch (Throwable $e) { | ||
throw new UnableToReadCacheException( | ||
message: $e->getMessage(), | ||
code: $e->getCode(), | ||
previous: $e, | ||
); | ||
} | ||
} | ||
|
||
public function saveItem(CacheMetadata $metadata, mixed $item): void | ||
{ | ||
$dependencies = []; | ||
|
||
if ($metadata->expiration instanceof DateTimeImmutable) { | ||
$dependencies[Cache::Expire] = $metadata->expiration->format('U.u'); | ||
} elseif (is_int($metadata->expiration)) { | ||
$dependencies[Cache::Expire] = $metadata->expiration + time(); | ||
} | ||
|
||
if (0 < count($metadata->tags)) { | ||
$dependencies[Cache::Tags] = $metadata->tags; | ||
} | ||
|
||
try { | ||
$this->cache->save( | ||
key: $metadata->key, | ||
data: $item, | ||
dependencies: $dependencies, | ||
); | ||
} catch (Throwable $e) { | ||
throw new UnableToWriteCacheException( | ||
message: $e->getMessage(), | ||
code: $e->getCode(), | ||
previous: $e, | ||
); | ||
} | ||
} | ||
|
||
public function deleteItem(string $key): void | ||
{ | ||
try { | ||
$this->cache->remove( | ||
key: $key, | ||
); | ||
} catch (Throwable $e) { | ||
throw new UnableToDeleteCacheException( | ||
message: $e->getMessage(), | ||
code: $e->getCode(), | ||
previous: $e, | ||
); | ||
} | ||
} | ||
|
||
public function clean(?array $tags = null): void | ||
{ | ||
$conditions = null !== $tags | ||
? [ | ||
Cache::Tags => $tags, | ||
] | ||
: [ | ||
Cache::All => true, | ||
]; | ||
|
||
try { | ||
$this->cache->clean( | ||
conditions: $conditions, | ||
); | ||
} catch (Throwable $e) { | ||
throw new UnableToDeleteCacheException( | ||
message: $e->getMessage(), | ||
code: $e->getCode(), | ||
previous: $e, | ||
); | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/ArchitectureBundle/ReadModel/Query/CachableQueryInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\ArchitectureBundle\ReadModel\Query; | ||
|
||
use SixtyEightPublishers\ArchitectureBundle\Infrastructure\Cache\CacheMetadata; | ||
|
||
interface CachableQueryInterface extends QueryInterface | ||
{ | ||
public function createCacheMetadata(): CacheMetadata; | ||
} |