Skip to content

Commit 55814cc

Browse files
authored
Merge pull request #3 from IlicMiljan/refactor-caching-logic
[Breaking Change] Refactor Caching Logic
2 parents e11a354 + a198cde commit 55814cc

File tree

9 files changed

+278
-156
lines changed

9 files changed

+278
-156
lines changed

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,35 @@ $cipher = new AsymmetricEncryptionCipher($publicKey, $privateKey);
8787

8888
## Property Readers
8989

90-
SecureProps comes with two implementations of property readers: a runtime one and a decorator for caching.
90+
SecureProps provides two types of property readers to handle encrypted properties within your PHP objects efficiently: `RuntimeObjectPropertiesReader` and `CachingObjectPropertiesReader`.
9191

9292
### RuntimeObjectPropertiesReader
9393

94-
This reader inspects objects at runtime to find properties marked with the `#[Encrypted]` attribute. It uses PHP's reflection capabilities to perform its duties without requiring any caching mechanism.
94+
The `RuntimeObjectPropertiesReader` dynamically examines objects at runtime to identify properties decorated with the `#[Encrypted]` attribute. Utilizing PHP's reflection requires no additional setup for caching and offers straightforward inspection capabilities.
9595

9696
### CachingObjectPropertiesReader
9797

98-
This reader wraps another `ObjectPropertiesReader` implementation and caches the results to improve performance. It's particularly useful for applications that repeatedly process the same object types, reducing the overhead of reflection operations. The `PSR-6` caching standard provides a flexible framework for integrating various caching backends, offering developers the freedom to choose a solution that best fits their application's scaling and performance requirements.
98+
For enhanced performance, especially in applications that frequently deal with the same types of objects, the `CachingObjectPropertiesReader` caches property reading results. This approach reduces the computational overhead associated with reflection.
99+
100+
It integrates seamlessly with `PSR-6` compliant caching solutions, allowing for customizable performance optimization.
101+
102+
#### Quick Start Example
103+
104+
Combining `CachingObjectPropertiesReader` with `RuntimeObjectPropertiesReader` and a `PSR-6` compliant cache implementation:
105+
106+
```php
107+
// Initialize a PSR-6 cache pool
108+
$cache = new FilesystemAdapter(...);
109+
110+
// Configure the caching reader
111+
$reader = new CachingObjectPropertiesReader(
112+
new RuntimeObjectPropertiesReader(),
113+
new ItemPoolCompatibleCache($cache)
114+
);
115+
116+
// Set up the ObjectEncryptionService with the reader
117+
$encryptionService = new ObjectEncryptionService($cipher, $reader);
118+
```
99119

100120
## Contributing
101121

src/Cache/Cache.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace IlicMiljan\SecureProps\Cache;
4+
5+
use IlicMiljan\SecureProps\Cache\Exception\InvalidCacheKey;
6+
use Psr\Cache\CacheItemInterface;
7+
8+
interface Cache
9+
{
10+
/**
11+
* Fetches a value from the cache or computes it if not found.
12+
*
13+
* @template T
14+
*
15+
* @param string $key The cache key.
16+
* @param (callable(CacheItemInterface):T) $callable A callable that
17+
* computes the value if it's not found in the
18+
* cache.
19+
* @param int|null $ttl The time-to-live for the cache entry in seconds.
20+
*
21+
* @return T The cached or computed value.
22+
* @throws InvalidCacheKey When $key is not valid.
23+
*/
24+
public function get(string $key, callable $callable, ?int $ttl = null): mixed;
25+
}

src/Reader/Exception/InvalidCacheKey.php renamed to src/Cache/Exception/InvalidCacheKey.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace IlicMiljan\SecureProps\Reader\Exception;
3+
namespace IlicMiljan\SecureProps\Cache\Exception;
44

55
use LogicException;
66
use Throwable;

src/Cache/ItemPoolCompatibleCache.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace IlicMiljan\SecureProps\Cache;
4+
5+
use IlicMiljan\SecureProps\Cache\Exception\InvalidCacheKey;
6+
use Psr\Cache\CacheItemPoolInterface;
7+
use Psr\Cache\InvalidArgumentException;
8+
9+
class ItemPoolCompatibleCache implements Cache
10+
{
11+
private CacheItemPoolInterface $cachePool;
12+
13+
public function __construct(CacheItemPoolInterface $cachePool)
14+
{
15+
$this->cachePool = $cachePool;
16+
}
17+
18+
public function get(string $key, callable $callable, ?int $ttl = null): mixed
19+
{
20+
try {
21+
$cacheItem = $this->cachePool->getItem($key);
22+
} catch (InvalidArgumentException $e) {
23+
throw new InvalidCacheKey($key, $e);
24+
}
25+
26+
if (!$cacheItem->isHit()) {
27+
$cacheItem->set($callable($cacheItem));
28+
$cacheItem->expiresAfter($ttl);
29+
30+
$this->cachePool->save($cacheItem);
31+
}
32+
33+
return $cacheItem->get();
34+
}
35+
}

src/Reader/CachingObjectPropertiesReader.php

Lines changed: 20 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,44 @@
22

33
namespace IlicMiljan\SecureProps\Reader;
44

5-
use IlicMiljan\SecureProps\Reader\Exception\InvalidCacheKey;
6-
use IlicMiljan\SecureProps\Reader\Exception\InvalidCacheValueDataType;
5+
use IlicMiljan\SecureProps\Cache\Cache;
6+
use IlicMiljan\SecureProps\Cache\Exception\InvalidCacheKey;
77
use IlicMiljan\SecureProps\Reader\Exception\ObjectPropertyNotFound;
88
use Psr\Cache\CacheItemInterface;
9-
use Psr\Cache\CacheItemPoolInterface;
10-
use Psr\Cache\InvalidArgumentException;
119
use ReflectionException;
12-
use ReflectionObject;
1310
use ReflectionProperty;
1411

1512
class CachingObjectPropertiesReader implements ObjectPropertiesReader
1613
{
14+
private const CACHE_TTL_DEFAULT = null;
15+
1716
public function __construct(
1817
private ObjectPropertiesReader $objectPropertiesReader,
19-
private CacheItemPoolInterface $cache
18+
private Cache $cache,
19+
private ?int $cacheTtl = self::CACHE_TTL_DEFAULT
2020
) {
2121
}
2222

2323
/**
2424
* @throws InvalidCacheKey
25-
* @throws InvalidCacheValueDataType
2625
* @throws ObjectPropertyNotFound
2726
*/
2827
public function getPropertiesWithAttribute(object $object, string $attributeClass): array
2928
{
30-
$cachedProperties = $this->getCacheItem($this->getCacheKey($object, $attributeClass));
31-
32-
if ($cachedProperties->isHit()) {
33-
$this->ensureCacheItemValueIsArray($cachedProperties);
34-
35-
/** @var string[] $cachedPropertiesValue */
36-
$cachedPropertiesValue = $cachedProperties->get();
37-
38-
return $this->loadRuntimeReflectionProperties($object, $cachedPropertiesValue);
39-
}
40-
41-
$propertiesWithAttribute = $this->objectPropertiesReader->getPropertiesWithAttribute(
42-
$object,
43-
$attributeClass
44-
);
45-
46-
$this->updateCache(
47-
$cachedProperties,
48-
$this->getCacheablePropertiesArray($propertiesWithAttribute)
29+
$propertyArray = $this->cache->get(
30+
$this->getCacheKey($object, $attributeClass),
31+
function (CacheItemInterface $cacheItem) use ($object, $attributeClass) {
32+
$propertiesWithAttribute = $this->objectPropertiesReader->getPropertiesWithAttribute(
33+
$object,
34+
$attributeClass
35+
);
36+
37+
return $this->getCacheablePropertiesArray($propertiesWithAttribute);
38+
},
39+
$this->cacheTtl
4940
);
5041

51-
return $propertiesWithAttribute;
42+
return $this->loadRuntimeReflectionProperties($object, $propertyArray);
5243
}
5344

5445
private function getCacheKey(object $object, string $attributeClass): string
@@ -66,32 +57,15 @@ private function getCacheKey(object $object, string $attributeClass): string
6657
*/
6758
private function loadRuntimeReflectionProperties(object $object, array $propertyNames): array
6859
{
69-
$reflection = new ReflectionObject($object);
70-
7160
try {
72-
return array_map(function ($propertyName) use ($reflection) {
73-
return $reflection->getProperty($propertyName);
61+
return array_map(function ($propertyName) use ($object) {
62+
return new ReflectionProperty($object, $propertyName);
7463
}, $propertyNames);
7564
} catch (ReflectionException $e) {
7665
throw new ObjectPropertyNotFound($object::class, $e);
7766
}
7867
}
7968

80-
/**
81-
* @param string $cacheKey
82-
* @return CacheItemInterface
83-
*
84-
* @throws InvalidCacheKey
85-
*/
86-
private function getCacheItem(string $cacheKey): CacheItemInterface
87-
{
88-
try {
89-
return $this->cache->getItem($cacheKey);
90-
} catch (InvalidArgumentException $e) {
91-
throw new InvalidCacheKey($cacheKey, $e);
92-
}
93-
}
94-
9569
/**
9670
* @param ReflectionProperty[] $properties
9771
* @return string[]
@@ -102,29 +76,4 @@ private function getCacheablePropertiesArray(array $properties): array
10276
return $property->getName();
10377
}, $properties);
10478
}
105-
106-
/**
107-
* @param CacheItemInterface $cacheItem
108-
* @return void
109-
*
110-
* @throws InvalidCacheValueDataType
111-
*/
112-
private function ensureCacheItemValueIsArray(CacheItemInterface $cacheItem): void
113-
{
114-
$cachedValue = $cacheItem->get();
115-
116-
if (is_array($cachedValue)) {
117-
return;
118-
}
119-
120-
throw new InvalidCacheValueDataType(gettype($cachedValue), 'array');
121-
}
122-
123-
private function updateCache(CacheItemInterface $cacheItem, mixed $data): void
124-
{
125-
$cacheItem->set($data);
126-
$cacheItem->expiresAfter(3600);
127-
128-
$this->cache->save($cacheItem);
129-
}
13079
}

src/Reader/Exception/InvalidCacheValueDataType.php

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)