diff --git a/README.md b/README.md index c847fa4..8e994d8 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,12 @@ For details on how to use the MLC Service and Factory directly. [MultiLevelCacheService and MultiLevelCacheFactory Documentation](documentation/mlc-service-and-factory.md) +# FAQ + +We now have an FAQ with the most common questions on how to do things. + +[Look Here for all FAQ goodness](documentation/faq.md) + ## License MIT diff --git a/documentation/faq.md b/documentation/faq.md new file mode 100644 index 0000000..26a2ed4 --- /dev/null +++ b/documentation/faq.md @@ -0,0 +1,11 @@ +# FAQ + +## I want to: + +- [Create a simple Cached Version of a service i have](faq/01_simple_example.md) +- [Only use the [Redis/In-Memory] cache and not the others](faq/02_configure_the_mlc.md) +- [Have an additional interface on my Cached Service](faq/03_additional_interface.md) + +## That's nice but: +- [What if the DTO i return changes, doesn't this cause problems?](faq/but_01_data_version.md) +- [What if my method uses internal properties the MLC doesn't know about?](faq/but_02_additional_cache_key_getter.md) \ No newline at end of file diff --git a/documentation/faq/01_simple_example.md b/documentation/faq/01_simple_example.md new file mode 100644 index 0000000..1eec5df --- /dev/null +++ b/documentation/faq/01_simple_example.md @@ -0,0 +1,93 @@ +# Simple example of a cached service: + +Given you have the following Service that you want a cached Version of. + +```php +stringToReturn; + } + + public function setStringToReturn(string $string): void + { + $this->stringToReturn = $string; + } + +} +``` + +This would cause the MLC to cache the first response and then ignore all changes to `$this->stringToReturn`. That's not good. + +Let's fix this by setting the `additionalCacheKeyGetter` property of `MlcCacheableService`. + +```php +stringToReturn; + } + + public function setStringToReturn(string $string): void + { + $this->stringToReturn = $string; + } + + public function getAdditionalCacheKeys(): array + { + return [ + 'importantString' => $this->stringToReturn, + ]; + } + +} +``` + +Now the MLC is aware that there is more to your Service function than the method attributes and everything should work as expected. + +Additional Bonus Fact: + +You can return any serializable data through the getter. As long as PHPs `serialize()` can handle it, the MLC is fine with it. \ No newline at end of file diff --git a/src/CopycatConfig.php b/src/CopycatConfig.php index fbb11e8..ffe1177 100644 --- a/src/CopycatConfig.php +++ b/src/CopycatConfig.php @@ -4,6 +4,7 @@ namespace Tbessenreither\MultiLevelCache; +use Tbessenreither\Copycat\Dto\EnvVar; use Tbessenreither\Copycat\Enum\CopyTargetEnum; use Tbessenreither\Copycat\Enum\EnvTargetEnum; use Tbessenreither\Copycat\Interface\CopycatConfigInterface; @@ -33,17 +34,37 @@ public static function run(CopycatInterface $copycat): void $copycat->envAdd( target: EnvTargetEnum::DOT_EXAMPLE, entries: [ - 'REDIS_DSN' => 'redis://redis:6379', - 'MLC_DISABLE_READ' => 'FLAG_ACTIVE', - 'MLC_COLLECT_ENHANCED_DATA' => false, + new EnvVar( + name: 'REDIS_DSN', + value: 'redis://redis:6379', + description: 'The DSN for the Redis server used by the Multi-Level Cache Bundle.', + ), + new EnvVar( + name: 'MLC_DISABLE_READ', + isFlag: true, + description: 'When present, the Multi-Level-Cache will not perform cache reads and always call the source, but it will still perform cache writes. This can be useful for testing or debugging purposes.', + ), + new EnvVar( + name: 'MLC_COLLECT_ENHANCED_DATA', + value: true, + description: 'When true the profiler will collect extra data for statistics and debugging. This will take more time and memory, so it should only be enabled in development environments.', + ), ], overwrite: true, ); $copycat->envAdd( target: EnvTargetEnum::DOT_LOCAL, entries: [ - 'REDIS_DSN' => 'redis://redis:6379', - 'MLC_COLLECT_ENHANCED_DATA' => false, + new EnvVar( + name: 'REDIS_DSN', + value: 'redis://redis:6379', + description: 'The DSN for the Redis server used by the Multi-Level Cache Bundle.', + ), + new EnvVar( + name: 'MLC_COLLECT_ENHANCED_DATA', + value: true, + description: 'When true the profiler will collect extra data for statistics and debugging. This will take more time and memory, so it should only be enabled in development environments.', + ), ], overwrite: false, ); diff --git a/src/Service/MultiLevelCacheService.php b/src/Service/MultiLevelCacheService.php index 50c96c7..7a34f1e 100644 --- a/src/Service/MultiLevelCacheService.php +++ b/src/Service/MultiLevelCacheService.php @@ -511,10 +511,10 @@ private function cacheReadDisabled(): bool return $this->cacheReadDisabled; } - private function cloneBulkMethodCallObjectWithNewIdentifier(MethodCallObject $methodCallObject, string|int $newIdentifier): MethodCallObject + private function cloneBulkMethodCallObjectWithNewIdentifier(MethodCallObject $methodCallObject, string|int|float $newIdentifier): MethodCallObject { - if (is_int($newIdentifier)) { - $newIdentifier = (string) $newIdentifier; + if (!is_string($newIdentifier)) { + $newIdentifier = (string)$newIdentifier; } $arguments = $methodCallObject->getArguments(); diff --git a/tests/CachedServiceGenerator/Service/TestSrc/TestServiceA.php b/tests/CachedServiceGenerator/Service/TestSrc/TestServiceA.php index 6bb5c04..46cbe86 100644 --- a/tests/CachedServiceGenerator/Service/TestSrc/TestServiceA.php +++ b/tests/CachedServiceGenerator/Service/TestSrc/TestServiceA.php @@ -66,6 +66,23 @@ public static function bulkTestFunctionWithIntIdentifier(array $keys) return $values; } + public static function bulkTestFunctionWithFloatIdentifier(array $keys) + { + self::$sourceWasCalled = true; + self::$entriesRequestedFromSource = $keys; + $values = []; + $i = 1; + foreach ($keys as $key) { + $values[] = [ + 'key' => (float) $i + 0.5, + 'value' => 'value for ' . $key, + ]; + $i++; + } + + return $values; + } + public static function bulkTestFunctionWithWrongResponse(array $keys) { $response = []; diff --git a/tests/Dto/DataCollectorIssueDtoTest.php b/tests/Dto/DataCollectorIssueDtoTest.php index 29218f1..5be0631 100644 --- a/tests/Dto/DataCollectorIssueDtoTest.php +++ b/tests/Dto/DataCollectorIssueDtoTest.php @@ -15,7 +15,7 @@ #[CoversClass(DataCollectorIssueDto::class)] #[UsesClass(WarningEnum::class)] #[UsesClass(DataCollectorIssueOccurrenceDto::class)] - +#[UsesClass(InfoEnum::class)] class DataCollectorIssueDtoTest extends TestCase { public function testGettersAndSetters(): void diff --git a/tests/Service/MultiLevelCacheServiceTest.php b/tests/Service/MultiLevelCacheServiceTest.php index 1bd9c19..c8982c2 100644 --- a/tests/Service/MultiLevelCacheServiceTest.php +++ b/tests/Service/MultiLevelCacheServiceTest.php @@ -534,6 +534,52 @@ class: TestServiceA::class, $this->assertEquals($expectedResults, $results, 'The results from the getBulk callable should match the expected results'); } + public function testGetBulkWithFloatIdentifier(): void + { + $keys = ['key1', 'key2', 'key3']; + $expectedResults = []; + $i = 1; + foreach ($keys as $key) { + $id = $i; + $expectedResults[] = [ + 'key' => (float) $id + 0.5, + 'value' => 'value for ' . $key, + ]; + $i++; + } + TestServiceA::resetStatic(); + $methodCallObject = new MethodCallObject( + class: TestServiceA::class, + method: 'bulkTestFunctionWithFloatIdentifier', + arguments: [$keys], + ); + + + $service = new MultiLevelCacheService( + caches: [new InMemoryCacheService(5)], + writeL0OnSet: true, + stopwatch: null, + cacheDataCollector: null, + ttlRandomnessSeconds: 0, + ); + + $results = $service->getBulk( + methodCallObject: $methodCallObject, + mlcCacheableMethodAttribute: new MlcCacheableMethod( + ttlSeconds: 5, + bulkConfig: new BulkConfig( + identifierSelector: 'key', + listType: BulkListTypeEnum::ARRAY_NUMERIC, + ), + ), + ); + + $this->assertTrue(TestServiceA::$sourceWasCalled, 'The source callable should have been called since bulk is not configured'); + $this->assertEquals($keys, TestServiceA::$entriesRequestedFromSource, 'The keys requested from the source should match the original keys'); + + $this->assertEquals($expectedResults, $results, 'The results from the getBulk callable should match the expected results'); + } + public function testGetBulkMisconfigured(): void { $keys = ['key1', 'key2', 'key3']; @@ -743,6 +789,18 @@ public function testConstructorHelperSetupDataCollector(): void $this->assertIsArray($statisticsObject->getConfigData(), 'The config data in the statistics object should be an array'); } + public function testExceptionTransparencyRuntimeException(): void + { + $this->expectException(RuntimeException::class); + $service = new MultiLevelCacheService( + caches: [new InMemoryCacheService(5)], + ); + + $service->get('testkey', function () { + throw new RuntimeException('Test exception'); + }, 300); + } + private function fixYieldedConfiguration(array &$configuration) { $caches = [];