From e1884c04fccc7abb825e13b5d13a482ddfba8428 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com> Date: Thu, 11 Jan 2024 18:07:45 +0700 Subject: [PATCH] Add mapping caching --- CHANGELOG.md | 1 + config/services.php | 9 +++ src/Mapping/CachingMappingFactory.php | 83 +++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/Mapping/CachingMappingFactory.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 07b53b3d..c84a66e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * use `ObjectCacheFactory` to generate `ObjectCache` instances * Update `MapperFactory` to reflect framework usage * Use property info caching in non-framework usage +* Add mapping caching ## 0.5.2 diff --git a/config/services.php b/config/services.php index 6cf92783..868606df 100644 --- a/config/services.php +++ b/config/services.php @@ -16,6 +16,7 @@ use Rekalogika\Mapper\MainTransformer; use Rekalogika\Mapper\Mapper; use Rekalogika\Mapper\MapperInterface; +use Rekalogika\Mapper\Mapping\CachingMappingFactory; use Rekalogika\Mapper\Mapping\MappingFactory; use Rekalogika\Mapper\Mapping\MappingFactoryInterface; use Rekalogika\Mapper\ObjectCache\ObjectCacheFactory; @@ -148,6 +149,14 @@ $services ->alias(MappingFactoryInterface::class, 'rekalogika.mapper.mapping_factory'); + $services + ->set('rekalogika.mapper.mapping_factory.caching', CachingMappingFactory::class) + ->decorate('rekalogika.mapper.mapping_factory') + ->args([ + service('rekalogika.mapper.mapping_factory.caching.inner'), + service('kernel') + ]); + # other services $services diff --git a/src/Mapping/CachingMappingFactory.php b/src/Mapping/CachingMappingFactory.php new file mode 100644 index 00000000..cda58822 --- /dev/null +++ b/src/Mapping/CachingMappingFactory.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Mapping; + +use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\VarExporter\VarExporter; + +final class CachingMappingFactory implements + MappingFactoryInterface, + CacheWarmerInterface +{ + private ?Mapping $innerMappingCache = null; + + public function __construct( + private MappingFactoryInterface $realMappingFactory, + private KernelInterface $kernel, + ) { + } + + private function getMappingFromInnerFactory(): Mapping + { + if ($this->innerMappingCache === null) { + $this->innerMappingCache = $this->realMappingFactory->getMapping(); + } + + return $this->innerMappingCache; + } + + private function warmUpAndGetMapping(): Mapping + { + $this->warmUp($this->kernel->getCacheDir(), $this->kernel->getBuildDir()); + + return $this->getMappingFromInnerFactory(); + } + + public function getMapping(): Mapping + { + if (!file_exists($this->getCacheFilePath())) { + return $this->warmUpAndGetMapping(); + } + + /** @psalm-suppress UnresolvableInclude */ + $result = require $this->getCacheFilePath(); + + if (!$result instanceof Mapping) { + unlink($this->getCacheFilePath()); + + return $this->warmUpAndGetMapping(); + } + + return $result; + } + + public function isOptional(): bool + { + return true; + } + + public function getCacheFilePath(): string + { + return $this->kernel->getBuildDir() . '/rekalogika_mapper_mapping.php'; + } + + public function warmUp(string $cacheDir, ?string $buildDir = null): array + { + $mapping = VarExporter::export($this->realMappingFactory->getMapping()); + file_put_contents($this->getCacheFilePath(), '