-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce method to warm the cache up
This new method can be used for instance in a pipeline during the build and deployment of the application. The cache has to be registered first, otherwise the warmup will end up being useless. ```php $cache = new \CuyZ\Valinor\Cache\FileSystemCache('path/to/cache-dir'); $mapperBuilder = (new \CuyZ\Valinor\MapperBuilder())->withCache($cache); // During the build: $mapperBuilder->warmup(SomeClass::class, SomeOtherClass::class); // In the application: $mapper->mapper()->map(SomeClass::class, [/* … */]); ``` Co-authored-by: Romain Canon <[email protected]>
- Loading branch information
Showing
8 changed files
with
281 additions
and
4 deletions.
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
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,21 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CuyZ\Valinor\Cache\Exception; | ||
|
||
use CuyZ\Valinor\Type\Parser\Exception\InvalidType; | ||
use RuntimeException; | ||
|
||
/** @internal */ | ||
final class InvalidSignatureToWarmup extends RuntimeException | ||
{ | ||
public function __construct(string $signature, InvalidType $exception) | ||
{ | ||
parent::__construct( | ||
"Cannot warm up invalid signature `$signature`: {$exception->getMessage()}", | ||
1653330261, | ||
$exception | ||
); | ||
} | ||
} |
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,79 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CuyZ\Valinor\Cache\Warmup; | ||
|
||
use CuyZ\Valinor\Cache\Exception\InvalidSignatureToWarmup; | ||
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository; | ||
use CuyZ\Valinor\Type\CompositeType; | ||
use CuyZ\Valinor\Type\Parser\Exception\InvalidType; | ||
use CuyZ\Valinor\Type\Parser\TypeParser; | ||
use CuyZ\Valinor\Type\Type; | ||
use CuyZ\Valinor\Type\Types\ClassType; | ||
|
||
use function in_array; | ||
|
||
/** @internal */ | ||
final class RecursiveCacheWarmupService | ||
{ | ||
private TypeParser $parser; | ||
|
||
private ClassDefinitionRepository $classDefinitionRepository; | ||
|
||
/** @var list<class-string> */ | ||
private array $classesWarmedUp = []; | ||
|
||
public function __construct(TypeParser $parser, ClassDefinitionRepository $classDefinitionRepository) | ||
{ | ||
$this->parser = $parser; | ||
$this->classDefinitionRepository = $classDefinitionRepository; | ||
} | ||
|
||
public function warmup(string ...$signatures): void | ||
{ | ||
foreach ($signatures as $signature) { | ||
try { | ||
$this->warmupType($this->parser->parse($signature)); | ||
} catch (InvalidType $exception) { | ||
throw new InvalidSignatureToWarmup($signature, $exception); | ||
} | ||
} | ||
} | ||
|
||
private function warmupType(Type $type): void | ||
{ | ||
if ($type instanceof ClassType) { | ||
$this->warmupClassType($type); | ||
} | ||
|
||
if ($type instanceof CompositeType) { | ||
foreach ($type->traverse() as $subType) { | ||
$this->warmupType($subType); | ||
} | ||
} | ||
} | ||
|
||
private function warmupClassType(ClassType $type): void | ||
{ | ||
if (in_array($type->className(), $this->classesWarmedUp, true)) { | ||
return; | ||
} | ||
|
||
$this->classesWarmedUp[] = $type->className(); | ||
|
||
$classDefinition = $this->classDefinitionRepository->for($type); | ||
|
||
foreach ($classDefinition->properties() as $property) { | ||
$this->warmupType($property->type()); | ||
} | ||
|
||
foreach ($classDefinition->methods() as $method) { | ||
$this->warmupType($method->returnType()); | ||
|
||
foreach ($method->parameters() as $parameter) { | ||
$this->warmupType($parameter->type()); | ||
} | ||
} | ||
} | ||
} |
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
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
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
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
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,117 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CuyZ\Valinor\Tests\Integration\Cache; | ||
|
||
use CuyZ\Valinor\Cache\Exception\InvalidSignatureToWarmup; | ||
use CuyZ\Valinor\MapperBuilder; | ||
use CuyZ\Valinor\Tests\Fake\Cache\FakeCache; | ||
use CuyZ\Valinor\Tests\Integration\IntegrationTest; | ||
use DateTimeInterface; | ||
|
||
final class CacheWarmupTest extends IntegrationTest | ||
{ | ||
private FakeCache $cache; | ||
|
||
private MapperBuilder $mapper; | ||
|
||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
$this->cache = new FakeCache(); | ||
$this->mapper = (new MapperBuilder())->withCache($this->cache); | ||
} | ||
|
||
public function test_will_warmup_type_parser_cache(): void | ||
{ | ||
$this->mapper->warmup(ObjectToWarmup::class); | ||
$this->mapper->warmup(ObjectToWarmup::class, SomeObjectJ::class); | ||
|
||
self::assertSame(11, $this->cache->countEntries()); | ||
self::assertSame(11, $this->cache->timeSetWasCalled()); | ||
} | ||
|
||
public function test_warmup_invalid_signature_throws_exception(): void | ||
{ | ||
$this->expectException(InvalidSignatureToWarmup::class); | ||
$this->expectExceptionCode(1653330261); | ||
$this->expectExceptionMessage('Cannot warm up invalid signature `SomeInvalidClass`: Cannot parse unknown symbol `SomeInvalidClass`.'); | ||
|
||
$this->mapper->warmup('SomeInvalidClass'); | ||
} | ||
} | ||
|
||
final class ObjectToWarmup | ||
{ | ||
public string $string; | ||
|
||
public SomeObjectA $objectA; | ||
|
||
/** @var array<string> */ | ||
public array $arrayOfStrings; | ||
|
||
/** @var array<SomeObjectB> */ | ||
public array $arrayOfObjects; | ||
|
||
/** @var list<SomeObjectC> */ | ||
public array $listOfObjects; | ||
|
||
/** @var iterable<SomeObjectD> */ | ||
public iterable $iterableOfObjects; | ||
|
||
/** @var array{foo: string, object: SomeObjectE} */ | ||
public array $shapedArrayContainingObject; | ||
|
||
/** @var string|SomeObjectF */ | ||
public $unionContainingObject; // @PHP8.0 Native union | ||
|
||
/** @var SomeObjectG&DateTimeInterface */ | ||
public object $intersectionOfObjects; | ||
|
||
public static function someMethod(string $string, SomeObjectH $object): SomeObjectI | ||
{ | ||
return new SomeObjectI(); | ||
} | ||
} | ||
|
||
class SomeObjectA | ||
{ | ||
} | ||
|
||
class SomeObjectB | ||
{ | ||
} | ||
|
||
class SomeObjectC | ||
{ | ||
} | ||
|
||
class SomeObjectD | ||
{ | ||
} | ||
|
||
class SomeObjectE | ||
{ | ||
} | ||
|
||
class SomeObjectF | ||
{ | ||
} | ||
|
||
class SomeObjectG | ||
{ | ||
} | ||
|
||
class SomeObjectH | ||
{ | ||
} | ||
|
||
class SomeObjectI | ||
{ | ||
} | ||
|
||
class SomeObjectJ | ||
{ | ||
} |