-
Notifications
You must be signed in to change notification settings - Fork 53
Provide a PSR-16 decorator for zend-cache storage adapters #152
Provide a PSR-16 decorator for zend-cache storage adapters #152
Conversation
2bffdda
to
e0bf3eb
Compare
@weierophinney Can we also add this on composer.json? "provide": {
"psr/cache-implementation": "1.0",
"psr/simple-cache-implementation": "1.0"
} |
@thomasvargiu Done! |
e2d3875
to
936568b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only had a quick scan but looks good!
The thing that made the PSR-6 adapter such a pain was handling the different limitations of the underlying storage and the different values they can store.
I’m wondering if it would be better to serialise everything up front to avoid those.
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function set($key, $value, $ttl = null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops darn mobile interface are my comment: the spec forbids some character (like @) in the key. These should be caught early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, okay - I'll review the spec and add some checks here and in setMultiple()
then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a validation method that does the following:
- Checks for any characters reserved by the PSR-16 specification, raising an exception if any are detected.
- Checks the key length; anything over 64 characters results in an exception.
Both set()
and setMultiple()
now call this before doing any other logic.
d4253b0
to
7a2a9bb
Compare
I just turned to that section of the specification, and it looks like it may be identical to PSR-6. As such, I'm going to implement the logic found in the PSR-6 adapter with regards to:
The only other consideration is what to do about adapters that do not support per-item TTL, as this is a soft requirement of PSR-16 (see: requirements on The options I see are:
Considering the idea behind PSR-16 was to make caching simple and to prevent raising exceptions for common operations, I think the second approach likely would be more in the spirit of PSR-16 support, so I'm going to proceed in that direction. |
src/Psr/SimpleCacheDecorator.php
Outdated
$options->setTtl($ttl); | ||
|
||
try { | ||
$result = $this->storage->setItem($key, $value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a negative or zero TTL is provided, the item MUST be deleted from the cache if it exists, as it is expired already.
Should it be checked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch; I'll address this when working on the TTL items I listed above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you wanted to add a %s inside the braces with an implode of self::INVALID_KEY_CHARS?
src/Psr/SimpleCacheDecorator.php
Outdated
throw static::translateException($e); | ||
} | ||
|
||
$options->setTtl($previousTtl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better if we put this into a finally block to ensure that even after catching an exception, the ttl is being restored?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
src/Psr/SimpleCacheDecorator.php
Outdated
$regex = sprintf('/[%s]/', preg_quote(self::INVALID_KEY_CHARS, '/')); | ||
if (preg_match($regex, $key)) { | ||
throw new SimpleCacheInvalidArgumentException(sprintf( | ||
'Invalid key "%s" provided; cannot contain any of ()', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you wanted to add a %s inside the braces with an implode of self::INVALID_KEY_CHARS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch - thanks!
@weierophinney Did you consider to test it using php-cache/integration-tests like PSR-6 tests? |
I'll look into it today. I'm not sure if this will be terribly feasible, as we'd need an actual adapter (not a mock one) to easily use those. It may make more sense to wait to do those until we split the adapters into their own repos. |
32ff796
to
d22f9e0
Compare
Regarding this statement:
I've added an integration test for the APC adapter, and discovered a number of things already. One thing interesting: the integration tests are sometimes covering behavior not explicitly detailed in the spec. As examples: they test for generator/iterable arguments to the various As such, I think we definitely need some integration tests in play, as they're helping me refine the adapter. I'll get these in place today. |
@weierophinney good, and I agree with you. I think should be better to have an integration test for every adapter like in PSR-6 tests. Then we can decide what to do when some adapter fail. |
d22f9e0
to
e09b369
Compare
Initial tests are now in place for APC and APCu adapters; APCu was running fine locally at this point, which is promising! I also found a bug in the integration tests and reported it: php-cache/integration-tests#92 I'll hammer through the tests for the remaining adapters this afternoon; they should be fairly straight-forward, as I can use the setup logic from the PSR-6 integration tests. |
e09b369
to
688a7a2
Compare
This patch builds on both the approach made in zendframework#126 as well as a comment to that patch made by @marc-mabe (zendframework#126 (comment)) in order to provide a decorator for zend-cache storage adapters that fulfills the PSR-16 `SimpleCacheInterface`. Usage is as follows: ```php // $adapter is an instance of StorageInterface $cache = new SimpleCacheDecorator($adapter); ``` From there, you can then use `$cache` anywhere you would normally use a PSR-16 instance.
All completed specs are now published on the website.
PSR-16 reserves the keys `{}()@/\\`, and does not allow their usage in cache keys.
Per PSR-16, key lengths up to 64 characters are supported, but no more than that.
Extracts it to a trait so that it can be re-used with the SimpleCacheDecorator. Defines two methods: - `memoizeSerializationCapabilities()` detects serialization capabilities, and sets the properties `$serializeValues` and `$serializedFalse` if serialization is required. - the abstract function `unserialize()`, as both adapters will require this functionality, but how it is implemented will differ as they have different needs. The `CacheItemPoolAdapter` constructor was altered to call `memoizeSerializationCapabilities()` instead of the original `shouldSerialize()` (which has been removed).
688a7a2
to
7d9031c
Compare
e4a5945
to
2d4a69c
Compare
Looks like the bulk of integration test issues are when using setMultiple() with adapters that require serialization; essentially every single one that requires serialization had |
None of the setMultiple* tests appear to work; they each produce `unserialize()` errors.
2d4a69c
to
8c39032
Compare
If the adapter requires serialization, we need to call `set()` for each ktem in the `$values` array. I'm still unclear why this is the case, but every single adapter that requires serialization was failing in the exact same way, with an `unserialize()` error when retrieving a value set via a `setMultiple()` operation. Making this change allows them to pass.
So, this is interesting: evidently the logic in individual adapter The workaround I found was to detect if the adapter requires serialization, and, if so, have it call |
This ensures that even after an exception, the adapter options are reset; particularly important when in async environments!
Also edits and re-organizes all entries for 2.8.0 to have slighly more semantic sense.
Okay, all feedback incorporated, and no changes at this time that affect tests, which were green on last run! Going to merge to develop, and will release 2.8.0 next Monday. Please test, and provide feedback if you run into issues! |
Hi @weierophinney, Thanks for starting working at it!
|
@marc-mabe Thanks for the feedback! I've opened #155 to address your second point; however, the approach I took was to use I'll start addressing the other three points in the next few days. I'm going to open tickets for each so that others can more easily find the information. |
This patch serves as an alternative to #126, based on a comment by @marc-mabe to that patch.
The patch adds a new class,
Zend\Cache\Psr\SimpleCacheDecorator
, which accepts a zend-cache storage instance to its constructor, and then proxies to it via the methods that implement the PSR-16CacheInterface
. The approach is simpler than that in #126 as it does not require testing against every adapter; we can test the decorator against a mock of theStorageInterface
, validating its behavior. The tests provided also ensure that any exceptions thrown by the underlying storage operations are re-cast to PSR-16 implementations.This approach may miss a few details; each of @marc-mabe, @kynx, and @boesing raised a few issues in #126 that I am uncertain if this approach covers. I'd love feedback before I merge this.
TODO
set()
andsetMultiple()
remove the item(s) from the cache (instead of storing).set()
andsetMultiple()
return boolean false for non-null,>0
TTL values.