中秋节快乐
This commit is contained in:
+559
@@ -0,0 +1,559 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
use Cache\Adapter\Common\Exception\CacheException;
|
||||
use Cache\Adapter\Common\Exception\CachePoolException;
|
||||
use Cache\Adapter\Common\Exception\InvalidArgumentException;
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
|
||||
/**
|
||||
* @author Aaron Scherer <aequasi@gmail.com>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
abstract class AbstractCachePool implements PhpCachePool, LoggerAwareInterface, CacheInterface
|
||||
{
|
||||
const SEPARATOR_TAG = '!';
|
||||
|
||||
/**
|
||||
* @type LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @type PhpCacheItem[] deferred
|
||||
*/
|
||||
protected $deferred = [];
|
||||
|
||||
/**
|
||||
* @param PhpCacheItem $item
|
||||
* @param int|null $ttl seconds from now
|
||||
*
|
||||
* @return bool true if saved
|
||||
*/
|
||||
abstract protected function storeItemInCache(PhpCacheItem $item, $ttl);
|
||||
|
||||
/**
|
||||
* Fetch an object from the cache implementation.
|
||||
*
|
||||
* If it is a cache miss, it MUST return [false, null, [], null]
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return array with [isHit, value, tags[], expirationTimestamp]
|
||||
*/
|
||||
abstract protected function fetchObjectFromCache($key);
|
||||
|
||||
/**
|
||||
* Clear all objects from cache.
|
||||
*
|
||||
* @return bool false if error
|
||||
*/
|
||||
abstract protected function clearAllObjectsFromCache();
|
||||
|
||||
/**
|
||||
* Remove one object from cache.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function clearOneObjectFromCache($key);
|
||||
|
||||
/**
|
||||
* Get an array with all the values in the list named $name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getList($name);
|
||||
|
||||
/**
|
||||
* Remove the list.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function removeList($name);
|
||||
|
||||
/**
|
||||
* Add a item key on a list named $name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $key
|
||||
*/
|
||||
abstract protected function appendListItem($name, $key);
|
||||
|
||||
/**
|
||||
* Remove an item from the list.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $key
|
||||
*/
|
||||
abstract protected function removeListItem($name, $key);
|
||||
|
||||
/**
|
||||
* Make sure to commit before we destruct.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItem($key)
|
||||
{
|
||||
$this->validateKey($key);
|
||||
if (isset($this->deferred[$key])) {
|
||||
/** @type CacheItem $item */
|
||||
$item = clone $this->deferred[$key];
|
||||
$item->moveTagsToPrevious();
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
$func = function () use ($key) {
|
||||
try {
|
||||
return $this->fetchObjectFromCache($key);
|
||||
} catch (\Exception $e) {
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
};
|
||||
|
||||
return new CacheItem($key, $func);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getItems(array $keys = [])
|
||||
{
|
||||
$items = [];
|
||||
foreach ($keys as $key) {
|
||||
$items[$key] = $this->getItem($key);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
try {
|
||||
return $this->getItem($key)->isHit();
|
||||
} catch (\Exception $e) {
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
// Clear the deferred items
|
||||
$this->deferred = [];
|
||||
|
||||
try {
|
||||
return $this->clearAllObjectsFromCache();
|
||||
} catch (\Exception $e) {
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
try {
|
||||
return $this->deleteItems([$key]);
|
||||
} catch (\Exception $e) {
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
$deleted = true;
|
||||
foreach ($keys as $key) {
|
||||
$this->validateKey($key);
|
||||
|
||||
// Delete form deferred
|
||||
unset($this->deferred[$key]);
|
||||
|
||||
// We have to commit here to be able to remove deferred hierarchy items
|
||||
$this->commit();
|
||||
$this->preRemoveItem($key);
|
||||
|
||||
if (!$this->clearOneObjectFromCache($key)) {
|
||||
$deleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(CacheItemInterface $item)
|
||||
{
|
||||
if (!$item instanceof PhpCacheItem) {
|
||||
$e = new InvalidArgumentException('Cache items are not transferable between pools. Item MUST implement PhpCacheItem.');
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->removeTagEntries($item);
|
||||
$this->saveTags($item);
|
||||
$timeToLive = null;
|
||||
if (null !== $timestamp = $item->getExpirationTimestamp()) {
|
||||
$timeToLive = $timestamp - time();
|
||||
|
||||
if ($timeToLive < 0) {
|
||||
return $this->deleteItem($item->getKey());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->storeItemInCache($item, $timeToLive);
|
||||
} catch (\Exception $e) {
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveDeferred(CacheItemInterface $item)
|
||||
{
|
||||
$this->deferred[$item->getKey()] = $item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$saved = true;
|
||||
foreach ($this->deferred as $item) {
|
||||
if (!$this->save($item)) {
|
||||
$saved = false;
|
||||
}
|
||||
}
|
||||
$this->deferred = [];
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function validateKey($key)
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
$e = new InvalidArgumentException(sprintf(
|
||||
'Cache key must be string, "%s" given',
|
||||
gettype($key)
|
||||
));
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
if (!isset($key[0])) {
|
||||
$e = new InvalidArgumentException('Cache key cannot be an empty string');
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
if (preg_match('|[\{\}\(\)/\\\@\:]|', $key)) {
|
||||
$e = new InvalidArgumentException(sprintf(
|
||||
'Invalid key: "%s". The key contains one or more characters reserved for future extension: {}()/\@:',
|
||||
$key
|
||||
));
|
||||
$this->handleException($e, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs with an arbitrary level if the logger exists.
|
||||
*
|
||||
* @param mixed $level
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
protected function log($level, $message, array $context = [])
|
||||
{
|
||||
if ($this->logger !== null) {
|
||||
$this->logger->log($level, $message, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log exception and rethrow it.
|
||||
*
|
||||
* @param \Exception $e
|
||||
* @param string $function
|
||||
*
|
||||
* @throws CachePoolException
|
||||
*/
|
||||
private function handleException(\Exception $e, $function)
|
||||
{
|
||||
$level = 'alert';
|
||||
if ($e instanceof InvalidArgumentException) {
|
||||
$level = 'warning';
|
||||
}
|
||||
|
||||
$this->log($level, $e->getMessage(), ['exception' => $e]);
|
||||
if (!$e instanceof CacheException) {
|
||||
$e = new CachePoolException(sprintf('Exception thrown when executing "%s". ', $function), 0, $e);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tags
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function invalidateTags(array $tags)
|
||||
{
|
||||
$itemIds = [];
|
||||
foreach ($tags as $tag) {
|
||||
$itemIds = array_merge($itemIds, $this->getList($this->getTagKey($tag)));
|
||||
}
|
||||
|
||||
// Remove all items with the tag
|
||||
$success = $this->deleteItems($itemIds);
|
||||
|
||||
if ($success) {
|
||||
// Remove the tag list
|
||||
foreach ($tags as $tag) {
|
||||
$this->removeList($this->getTagKey($tag));
|
||||
$l = $this->getList($this->getTagKey($tag));
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function invalidateTag($tag)
|
||||
{
|
||||
return $this->invalidateTags([$tag]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpCacheItem $item
|
||||
*/
|
||||
protected function saveTags(PhpCacheItem $item)
|
||||
{
|
||||
$tags = $item->getTags();
|
||||
foreach ($tags as $tag) {
|
||||
$this->appendListItem($this->getTagKey($tag), $item->getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the key form all tag lists. When an item with tags is removed
|
||||
* we MUST remove the tags. If we fail to remove the tags a new item with
|
||||
* the same key will automatically get the previous tags.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function preRemoveItem($key)
|
||||
{
|
||||
$item = $this->getItem($key);
|
||||
$this->removeTagEntries($item);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpCacheItem $item
|
||||
*/
|
||||
private function removeTagEntries(PhpCacheItem $item)
|
||||
{
|
||||
$tags = $item->getPreviousTags();
|
||||
foreach ($tags as $tag) {
|
||||
$this->removeListItem($this->getTagKey($tag), $item->getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTagKey($tag)
|
||||
{
|
||||
return 'tag'.self::SEPARATOR_TAG.$tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
$item = $this->getItem($key);
|
||||
if (!$item->isHit()) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $item->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($key, $value, $ttl = null)
|
||||
{
|
||||
$item = $this->getItem($key);
|
||||
$item->set($value);
|
||||
$item->expiresAfter($ttl);
|
||||
|
||||
return $this->save($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
return $this->deleteItem($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMultiple($keys, $default = null)
|
||||
{
|
||||
if (!is_array($keys)) {
|
||||
if (!$keys instanceof \Traversable) {
|
||||
throw new InvalidArgumentException('$keys is neither an array nor Traversable');
|
||||
}
|
||||
|
||||
// Since we need to throw an exception if *any* key is invalid, it doesn't
|
||||
// make sense to wrap iterators or something like that.
|
||||
$keys = iterator_to_array($keys, false);
|
||||
}
|
||||
|
||||
$items = $this->getItems($keys);
|
||||
|
||||
return $this->generateValues($default, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $default
|
||||
* @param $items
|
||||
*
|
||||
* @return \Generator
|
||||
*/
|
||||
private function generateValues($default, $items)
|
||||
{
|
||||
foreach ($items as $key => $item) {
|
||||
/** @type $item CacheItemInterface */
|
||||
if (!$item->isHit()) {
|
||||
yield $key => $default;
|
||||
} else {
|
||||
yield $key => $item->get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMultiple($values, $ttl = null)
|
||||
{
|
||||
if (!is_array($values)) {
|
||||
if (!$values instanceof \Traversable) {
|
||||
throw new InvalidArgumentException('$values is neither an array nor Traversable');
|
||||
}
|
||||
}
|
||||
|
||||
$keys = [];
|
||||
$arrayValues = [];
|
||||
foreach ($values as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
$key = (string) $key;
|
||||
}
|
||||
$this->validateKey($key);
|
||||
$keys[] = $key;
|
||||
$arrayValues[$key] = $value;
|
||||
}
|
||||
|
||||
$items = $this->getItems($keys);
|
||||
$itemSuccess = true;
|
||||
foreach ($items as $key => $item) {
|
||||
$item->set($arrayValues[$key]);
|
||||
|
||||
try {
|
||||
$item->expiresAfter($ttl);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$itemSuccess = $itemSuccess && $this->saveDeferred($item);
|
||||
}
|
||||
|
||||
return $itemSuccess && $this->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteMultiple($keys)
|
||||
{
|
||||
if (!is_array($keys)) {
|
||||
if (!$keys instanceof \Traversable) {
|
||||
throw new InvalidArgumentException('$keys is neither an array nor Traversable');
|
||||
}
|
||||
|
||||
// Since we need to throw an exception if *any* key is invalid, it doesn't
|
||||
// make sense to wrap iterators or something like that.
|
||||
$keys = iterator_to_array($keys, false);
|
||||
}
|
||||
|
||||
return $this->deleteItems($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($key)
|
||||
{
|
||||
return $this->hasItem($key);
|
||||
}
|
||||
}
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
use Cache\Adapter\Common\Exception\InvalidArgumentException;
|
||||
use Cache\TagInterop\TaggableCacheItemInterface;
|
||||
|
||||
/**
|
||||
* @author Aaron Scherer <aequasi@gmail.com>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class CacheItem implements PhpCacheItem
|
||||
{
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
private $prevTags = [];
|
||||
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
private $tags = [];
|
||||
|
||||
/**
|
||||
* @type \Closure
|
||||
*/
|
||||
private $callable;
|
||||
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
private $key;
|
||||
|
||||
/**
|
||||
* @type mixed
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* The expiration timestamp is the source of truth. This is the UTC timestamp
|
||||
* when the cache item expire. A value of zero means it never expires. A nullvalue
|
||||
* means that no expiration is set.
|
||||
*
|
||||
* @type int|null
|
||||
*/
|
||||
private $expirationTimestamp = null;
|
||||
|
||||
/**
|
||||
* @type bool
|
||||
*/
|
||||
private $hasValue = false;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param \Closure|bool $callable or boolean hasValue
|
||||
*/
|
||||
public function __construct($key, $callable = null, $value = null)
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
if ($callable === true) {
|
||||
$this->hasValue = true;
|
||||
$this->value = $value;
|
||||
} elseif ($callable !== false) {
|
||||
// This must be a callable or null
|
||||
$this->callable = $callable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->hasValue = true;
|
||||
$this->callable = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
if (!$this->isHit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isHit()
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
if (!$this->hasValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->expirationTimestamp !== null) {
|
||||
return $this->expirationTimestamp > time();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getExpirationTimestamp()
|
||||
{
|
||||
return $this->expirationTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function expiresAt($expiration)
|
||||
{
|
||||
if ($expiration instanceof \DateTimeInterface) {
|
||||
$this->expirationTimestamp = $expiration->getTimestamp();
|
||||
} elseif (is_int($expiration) || null === $expiration) {
|
||||
$this->expirationTimestamp = $expiration;
|
||||
} else {
|
||||
throw new InvalidArgumentException('Cache item ttl/expiresAt must be of type integer or \DateTimeInterface.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function expiresAfter($time)
|
||||
{
|
||||
if ($time === null) {
|
||||
$this->expirationTimestamp = null;
|
||||
} elseif ($time instanceof \DateInterval) {
|
||||
$date = new \DateTime();
|
||||
$date->add($time);
|
||||
$this->expirationTimestamp = $date->getTimestamp();
|
||||
} elseif (is_int($time)) {
|
||||
$this->expirationTimestamp = time() + $time;
|
||||
} else {
|
||||
throw new InvalidArgumentException('Cache item ttl/expiresAfter must be of type integer or \DateInterval.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPreviousTags()
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
return $this->prevTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setTags(array $tags)
|
||||
{
|
||||
$this->tags = [];
|
||||
$this->tag($tags);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tag to a cache item.
|
||||
*
|
||||
* @param string|string[] $tags A tag or array of tags
|
||||
*
|
||||
* @throws InvalidArgumentException When $tag is not valid.
|
||||
*
|
||||
* @return TaggableCacheItemInterface
|
||||
*/
|
||||
private function tag($tags)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
if (!is_array($tags)) {
|
||||
$tags = [$tags];
|
||||
}
|
||||
foreach ($tags as $tag) {
|
||||
if (!is_string($tag)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given', is_object($tag) ? get_class($tag) : gettype($tag)));
|
||||
}
|
||||
if (isset($this->tags[$tag])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($tag[0])) {
|
||||
throw new InvalidArgumentException('Cache tag length must be greater than zero');
|
||||
}
|
||||
if (isset($tag[strcspn($tag, '{}()/\@:')])) {
|
||||
throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:', $tag));
|
||||
}
|
||||
$this->tags[$tag] = $tag;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If callable is not null, execute it an populate this object with values.
|
||||
*/
|
||||
private function initialize()
|
||||
{
|
||||
if ($this->callable !== null) {
|
||||
// $func will be $adapter->fetchObjectFromCache();
|
||||
$func = $this->callable;
|
||||
$result = $func();
|
||||
$this->hasValue = $result[0];
|
||||
$this->value = $result[1];
|
||||
$this->prevTags = isset($result[2]) ? $result[2] : [];
|
||||
$this->expirationTimestamp = null;
|
||||
|
||||
if (isset($result[3]) && is_int($result[3])) {
|
||||
$this->expirationTimestamp = $result[3];
|
||||
}
|
||||
|
||||
$this->callable = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal This function should never be used and considered private.
|
||||
*
|
||||
* Move tags from $tags to $prevTags
|
||||
*/
|
||||
public function moveTagsToPrevious()
|
||||
{
|
||||
$this->prevTags = $this->tags;
|
||||
$this->tags = [];
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# Change Log
|
||||
|
||||
The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Added
|
||||
|
||||
* Support for PHP 8
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Added
|
||||
|
||||
- Support for storing binary data
|
||||
|
||||
### Fixed
|
||||
|
||||
- Issue with one character variables
|
||||
|
||||
### Changed
|
||||
|
||||
- Tests are now extending `PHPUnit\Framework\TestCase`
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* No changes since 0.4.0.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Added
|
||||
|
||||
* `AbstractCachePool` has 4 new abstract methods: `getList`, `removeList`, `appendListItem` and `removeListItem`.
|
||||
* `AbstractCachePool::invalidateTags` and `AbstractCachePool::invalidateTags`
|
||||
* Added interfaces for our items and pools `PhpCachePool` and `PhpCacheItem`
|
||||
* Trait to help adapters to support tags. `TagSupportWithArray`.
|
||||
|
||||
### Changed
|
||||
|
||||
* First parameter to `AbstractCachePool::storeItemInCache` must be a `PhpCacheItem`.
|
||||
* Return value from `AbstractCachePool::fetchObjectFromCache` must be a an array with 4 values. Added expiration timestamp.
|
||||
* `HasExpirationDateInterface` is replaced by `HasExpirationTimestampInterface`
|
||||
* We do not work with `\DateTime` internally anymore. We work with timestamps.
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Fixed
|
||||
|
||||
* Bugfix when you fetch data from the cache storage that was saved as "non-tagging item" but fetch as a tagging item.
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Added
|
||||
|
||||
* Cache pools do implement `LoggerAwareInterface`
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Changed
|
||||
|
||||
* The `AbstractCachePool` does not longer implement `TaggablePoolInterface`. However, the `CacheItem` does still implement `TaggableItemInterface`.
|
||||
* `CacheItem::getKeyFromTaggedKey` has been removed
|
||||
* The `CacheItem`'s second parameter is a callable that must return an array with 3 elements; [`hasValue`, `value`, `tags`].
|
||||
|
||||
## 0.2.0
|
||||
|
||||
* No changelog before this version
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common\Exception;
|
||||
|
||||
use Psr\Cache\CacheException as CacheExceptionInterface;
|
||||
|
||||
/**
|
||||
* A base exception. All exceptions in this organization will extend this exception.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
abstract class CacheException extends \RuntimeException implements CacheExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common\Exception;
|
||||
|
||||
/**
|
||||
* If an exception is caused by a pool or by the cache storage.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class CachePoolException extends CacheException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common\Exception;
|
||||
|
||||
use Psr\Cache\InvalidArgumentException as CacheInvalidArgumentException;
|
||||
use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInvalidArgumentException;
|
||||
|
||||
class InvalidArgumentException extends CacheException implements CacheInvalidArgumentException, SimpleCacheInvalidArgumentException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
/**
|
||||
* @author Aaron Scherer <aequasi@gmail.com>
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
interface HasExpirationTimestampInterface
|
||||
{
|
||||
/**
|
||||
* The timestamp when the object expires.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getExpirationTimestamp();
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
/**
|
||||
* This trait provides common routines for safely encoding binary and non-UTF8 data in
|
||||
* JSON. This is needed for components that use JSON natively (currently, the MongoDB
|
||||
* adapter and EncryptedCachePool).
|
||||
*
|
||||
* @author Stephen Clouse <stephen.clouse@noaa.gov>
|
||||
*/
|
||||
trait JsonBinaryArmoring
|
||||
{
|
||||
private static $ESCAPE_JSON_CHARACTERS = [
|
||||
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
|
||||
"\x08", "\x09", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F",
|
||||
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
|
||||
"\x18", "\x19", "\x1A", "\x1B", "\x1C", "\x1D", "\x1E", "\x1F",
|
||||
];
|
||||
|
||||
private static $ENCODED_JSON_CHARACTERS = [
|
||||
'\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007',
|
||||
'\u0008', '\u0009', '\u000A', '\u000B', '\u000C', '\u000D', '\u000E', '\u000F',
|
||||
'\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017',
|
||||
'\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', '\u001E', '\u001F',
|
||||
];
|
||||
|
||||
/**
|
||||
* Armor a value going into a JSON document.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function jsonArmor($value)
|
||||
{
|
||||
return str_replace(
|
||||
static::$ESCAPE_JSON_CHARACTERS,
|
||||
static::$ENCODED_JSON_CHARACTERS,
|
||||
utf8_encode($value)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* De-armor a value from a JSON document.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function jsonDeArmor($value)
|
||||
{
|
||||
return utf8_decode(str_replace(
|
||||
static::$ENCODED_JSON_CHARACTERS,
|
||||
static::$ESCAPE_JSON_CHARACTERS,
|
||||
$value
|
||||
));
|
||||
}
|
||||
}
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Aaron Scherer, Tobias Nyholm
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
use Cache\TagInterop\TaggableCacheItemInterface;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
interface PhpCacheItem extends HasExpirationTimestampInterface, TaggableCacheItemInterface
|
||||
{
|
||||
/**
|
||||
* Get the current tags. These are not the same tags as getPrevious tags. This
|
||||
* is the tags that has been added to the item after the item was fetched from
|
||||
* the cache storage.
|
||||
*
|
||||
* WARNING: This is generally not the function you want to use. Please see
|
||||
* `getPreviousTags`.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags();
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
use Cache\TagInterop\TaggableCacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
interface PhpCachePool extends TaggableCacheItemPoolInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return PhpCacheItem
|
||||
*/
|
||||
public function getItem($key);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return array|\Traversable|PhpCacheItem[]
|
||||
*/
|
||||
public function getItems(array $keys = []);
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Common PSR-6 Cache pool
|
||||
[](https://gitter.im/php-cache/cache?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://packagist.org/packages/cache/adapter-common)
|
||||
[](https://codecov.io/github/php-cache/adapter-common?branch=master)
|
||||
[](https://packagist.org/packages/cache/adapter-common)
|
||||
[](https://packagist.org/packages/cache/adapter-common)
|
||||
[](LICENSE)
|
||||
|
||||
This repository contains shared classes and interfaces used by the PHP Cache organisation. To read about
|
||||
features like tagging and hierarchy support please read the shared documentation at [www.php-cache.com](http://www.php-cache.com).
|
||||
|
||||
### Contribute
|
||||
|
||||
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/php-cache/cache) or
|
||||
report any issues you find on the [issue tracker](http://issues.php-cache.com).
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Common;
|
||||
|
||||
/**
|
||||
* This trait could be used by adapters that do not have a native support for lists.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
trait TagSupportWithArray
|
||||
{
|
||||
/**
|
||||
* Get a value from the storage.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function getDirectValue($name);
|
||||
|
||||
/**
|
||||
* Set a value to the storage.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
abstract public function setDirectValue($name, $value);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function appendListItem($name, $value)
|
||||
{
|
||||
$data = $this->getDirectValue($name);
|
||||
if (!is_array($data)) {
|
||||
$data = [];
|
||||
}
|
||||
$data[] = $value;
|
||||
$this->setDirectValue($name, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getList($name)
|
||||
{
|
||||
$data = $this->getDirectValue($name);
|
||||
if (!is_array($data)) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function removeList($name)
|
||||
{
|
||||
$this->setDirectValue($name, []);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function removeListItem($name, $key)
|
||||
{
|
||||
$data = $this->getList($name);
|
||||
foreach ($data as $i => $value) {
|
||||
if ($key === $value) {
|
||||
unset($data[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->setDirectValue($name, $data);
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "cache/adapter-common",
|
||||
"type": "library",
|
||||
"description": "Common classes for PSR-6 adapters",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"psr-6",
|
||||
"tag"
|
||||
],
|
||||
"homepage": "http://www.php-cache.com/en/latest/",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Aaron Scherer",
|
||||
"email": "aequasi@gmail.com",
|
||||
"homepage": "https://github.com/aequasi"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0 || ^8.0",
|
||||
"cache/tag-interop": "^1.0",
|
||||
"psr/cache": "^1.0",
|
||||
"psr/log": "^1.0",
|
||||
"psr/simple-cache": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"cache/integration-tests": "^0.16",
|
||||
"phpunit/phpunit": "^5.7.21"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cache\\Adapter\\Common\\": ""
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Cache\\Adapter\\Common\\Tests\\": "Tests/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
# Change Log
|
||||
|
||||
The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.
|
||||
|
||||
## UNRELEASED
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Added
|
||||
|
||||
* Support for PHP 8
|
||||
|
||||
### Changed
|
||||
|
||||
* Use `League\Flysystem\FilesystemInterface` instead of concrete `League\Flysystem\Filesystem` class
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* No changes since 0.4.0
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Added
|
||||
|
||||
* Support for the new `TaggableCacheItemPoolInterface`.
|
||||
* Support for PSR-16 SimpleCache
|
||||
|
||||
### Changed
|
||||
|
||||
* The behavior of `CacheItem::getTags()` has changed. It will not return the tags stored in the cache storage.
|
||||
|
||||
### Removed
|
||||
|
||||
* `CacheItem::getExpirationDate()`. Use `CacheItem::getExpirationTimestamp()`
|
||||
* `CacheItem::getTags()`. Use `CacheItem::getPreviousTags()`
|
||||
* `CacheItem::addTag()`. Use `CacheItem::setTags()`
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Fixed
|
||||
|
||||
* Race condition in `fetchObjectFromCache`.
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Changed
|
||||
|
||||
* Using `Filesystem::update` instead of `Filesystem::delete` and `Filesystem::write`.
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Added
|
||||
|
||||
* Add ability to change cache path in FilesystemCachePool
|
||||
|
||||
## 0.3.0
|
||||
|
||||
* No changelog before this version
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\Adapter\Filesystem;
|
||||
|
||||
use Cache\Adapter\Common\AbstractCachePool;
|
||||
use Cache\Adapter\Common\Exception\InvalidArgumentException;
|
||||
use Cache\Adapter\Common\PhpCacheItem;
|
||||
use League\Flysystem\FileExistsException;
|
||||
use League\Flysystem\FileNotFoundException;
|
||||
use League\Flysystem\FilesystemInterface;
|
||||
|
||||
/**
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
class FilesystemCachePool extends AbstractCachePool
|
||||
{
|
||||
/**
|
||||
* @type FilesystemInterface
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* The folder should not begin nor end with a slash. Example: path/to/cache.
|
||||
*
|
||||
* @type string
|
||||
*/
|
||||
private $folder;
|
||||
|
||||
/**
|
||||
* @param FilesystemInterface $filesystem
|
||||
* @param string $folder
|
||||
*/
|
||||
public function __construct(FilesystemInterface $filesystem, $folder = 'cache')
|
||||
{
|
||||
$this->folder = $folder;
|
||||
|
||||
$this->filesystem = $filesystem;
|
||||
$this->filesystem->createDir($this->folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
*/
|
||||
public function setFolder($folder)
|
||||
{
|
||||
$this->folder = $folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function fetchObjectFromCache($key)
|
||||
{
|
||||
$empty = [false, null, [], null];
|
||||
$file = $this->getFilePath($key);
|
||||
|
||||
try {
|
||||
$data = @unserialize($this->filesystem->read($file));
|
||||
if ($data === false) {
|
||||
return $empty;
|
||||
}
|
||||
} catch (FileNotFoundException $e) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
// Determine expirationTimestamp from data, remove items if expired
|
||||
$expirationTimestamp = $data[2] ?: null;
|
||||
if ($expirationTimestamp !== null && time() > $expirationTimestamp) {
|
||||
foreach ($data[1] as $tag) {
|
||||
$this->removeListItem($this->getTagKey($tag), $key);
|
||||
}
|
||||
$this->forceClear($key);
|
||||
|
||||
return $empty;
|
||||
}
|
||||
|
||||
return [true, $data[0], $data[1], $expirationTimestamp];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function clearAllObjectsFromCache()
|
||||
{
|
||||
$this->filesystem->deleteDir($this->folder);
|
||||
$this->filesystem->createDir($this->folder);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function clearOneObjectFromCache($key)
|
||||
{
|
||||
return $this->forceClear($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function storeItemInCache(PhpCacheItem $item, $ttl)
|
||||
{
|
||||
$data = serialize(
|
||||
[
|
||||
$item->get(),
|
||||
$item->getTags(),
|
||||
$item->getExpirationTimestamp(),
|
||||
]
|
||||
);
|
||||
|
||||
$file = $this->getFilePath($item->getKey());
|
||||
if ($this->filesystem->has($file)) {
|
||||
// Update file if it exists
|
||||
return $this->filesystem->update($file, $data);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->filesystem->write($file, $data);
|
||||
} catch (FileExistsException $e) {
|
||||
// To handle issues when/if race conditions occurs, we try to update here.
|
||||
return $this->filesystem->update($file, $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getFilePath($key)
|
||||
{
|
||||
if (!preg_match('|^[a-zA-Z0-9_\.! ]+$|', $key)) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid key "%s". Valid filenames must match [a-zA-Z0-9_\.! ].', $key));
|
||||
}
|
||||
|
||||
return sprintf('%s/%s', $this->folder, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getList($name)
|
||||
{
|
||||
$file = $this->getFilePath($name);
|
||||
|
||||
if (!$this->filesystem->has($file)) {
|
||||
$this->filesystem->write($file, serialize([]));
|
||||
}
|
||||
|
||||
return unserialize($this->filesystem->read($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function removeList($name)
|
||||
{
|
||||
$file = $this->getFilePath($name);
|
||||
$this->filesystem->delete($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function appendListItem($name, $key)
|
||||
{
|
||||
$list = $this->getList($name);
|
||||
$list[] = $key;
|
||||
|
||||
return $this->filesystem->update($this->getFilePath($name), serialize($list));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function removeListItem($name, $key)
|
||||
{
|
||||
$list = $this->getList($name);
|
||||
foreach ($list as $i => $item) {
|
||||
if ($item === $key) {
|
||||
unset($list[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->filesystem->update($this->getFilePath($name), serialize($list));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function forceClear($key)
|
||||
{
|
||||
try {
|
||||
return $this->filesystem->delete($this->getFilePath($key));
|
||||
} catch (FileNotFoundException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Aaron Scherer, Tobias Nyholm
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Filesystem PSR-6 Cache pool
|
||||
[](https://gitter.im/php-cache/cache?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://packagist.org/packages/cache/filesystem-adapter)
|
||||
[](https://codecov.io/github/php-cache/filesystem-adapter?branch=master)
|
||||
[](https://packagist.org/packages/cache/filesystem-adapter)
|
||||
[](https://packagist.org/packages/cache/filesystem-adapter)
|
||||
[](LICENSE)
|
||||
|
||||
This is a PSR-6 cache implementation using Filesystem. It is a part of the PHP Cache organisation. To read about
|
||||
features like tagging and hierarchy support please read the shared documentation at [www.php-cache.com](http://www.php-cache.com).
|
||||
|
||||
This implementation is using the excellent [Flysystem](http://flysystem.thephpleague.com/).
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
composer require cache/filesystem-adapter
|
||||
```
|
||||
|
||||
### Use
|
||||
|
||||
To create an instance of `FilesystemCachePool` you need to configure a `Filesystem` and its adapter.
|
||||
|
||||
```php
|
||||
use League\Flysystem\Adapter\Local;
|
||||
use League\Flysystem\Filesystem;
|
||||
use Cache\Adapter\Filesystem\FilesystemCachePool;
|
||||
|
||||
$filesystemAdapter = new Local(__DIR__.'/');
|
||||
$filesystem = new Filesystem($filesystemAdapter);
|
||||
|
||||
$pool = new FilesystemCachePool($filesystem);
|
||||
```
|
||||
|
||||
You can change the folder the cache pool will write to through the `setFolder` setter:
|
||||
|
||||
```php
|
||||
$pool = new FilesystemCachePool($filesystem);
|
||||
$pool->setFolder('path/to/cache');
|
||||
```
|
||||
|
||||
### Contribute
|
||||
|
||||
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/php-cache/cache) or
|
||||
report any issues you find on the [issue tracker](http://issues.php-cache.com).
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "cache/filesystem-adapter",
|
||||
"type": "library",
|
||||
"description": "A PSR-6 cache implementation using filesystem. This implementation supports tags",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"psr-6",
|
||||
"filesystem",
|
||||
"tag"
|
||||
],
|
||||
"homepage": "http://www.php-cache.com/en/latest/",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Aaron Scherer",
|
||||
"email": "aequasi@gmail.com",
|
||||
"homepage": "https://github.com/aequasi"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0 || ^8.0",
|
||||
"cache/adapter-common": "^1.0",
|
||||
"league/flysystem": "^1.0",
|
||||
"psr/cache": "^1.0",
|
||||
"psr/simple-cache": "^1.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/cache-implementation": "^1.0",
|
||||
"psr/simple-cache-implementation": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"cache/integration-tests": "^0.16",
|
||||
"phpunit/phpunit": "^5.7.21"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cache\\Adapter\\Filesystem\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
This is a READ ONLY repository.
|
||||
|
||||
Please make your pull request to https://github.com/php-cache/cache
|
||||
|
||||
Thank you for contributing.
|
||||
@@ -0,0 +1,2 @@
|
||||
composer.lock
|
||||
vendor
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
language: php
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 7.1
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- "$HOME/.composer/cache"
|
||||
|
||||
install:
|
||||
- composer update --prefer-dist --prefer-stable
|
||||
|
||||
script:
|
||||
- ./vendor/bin/phpunit --coverage-clover=coverage.xml
|
||||
|
||||
after_success:
|
||||
- pip install --user codecov && codecov
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
# Change Log
|
||||
|
||||
The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
* Support PHP 8.1
|
||||
* Support for psr/cache v2
|
||||
|
||||
## 1.0.1
|
||||
|
||||
* Support PHP 8
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* First release
|
||||
|
||||
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Aaron Scherer, Tobias Nyholm
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
# Tag support for PSR-6 Cache
|
||||
[](https://gitter.im/php-cache/cache?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://packagist.org/packages/cache/tag-interop)
|
||||
[](https://packagist.org/packages/cache/tag-interop)
|
||||
[](https://packagist.org/packages/cache/tag-interop)
|
||||
[](LICENSE)
|
||||
|
||||
This repository holds two interfaces for tagging. These interfaces will make their
|
||||
way into PHP Fig. Representatives from Symfony, PHP-cache and Drupal has worked
|
||||
together to agree on these interfaces.
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
composer require cache/tag-interop
|
||||
```
|
||||
|
||||
### Use
|
||||
|
||||
Read the [documentation on usage](http://www.php-cache.com/).
|
||||
|
||||
### Contribute
|
||||
|
||||
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/php-cache/cache) or
|
||||
report any issues you find on the [issue tracker](http://issues.php-cache.com).
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\TagInterop;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* An item that supports tags. This interface is a soon-to-be-PSR.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface TaggableCacheItemInterface extends CacheItemInterface
|
||||
{
|
||||
/**
|
||||
* Get all existing tags. These are the tags the item has when the item is
|
||||
* returned from the pool.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPreviousTags();
|
||||
|
||||
/**
|
||||
* Overwrite all tags with a new set of tags.
|
||||
*
|
||||
* @param string[] $tags An array of tags
|
||||
*
|
||||
* @throws InvalidArgumentException When a tag is not valid.
|
||||
*
|
||||
* @return TaggableCacheItemInterface
|
||||
*/
|
||||
public function setTags(array $tags);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of php-cache organization.
|
||||
*
|
||||
* (c) 2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Cache\TagInterop;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Interface for invalidating cached items using tags. This interface is a soon-to-be-PSR.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface TaggableCacheItemPoolInterface extends CacheItemPoolInterface
|
||||
{
|
||||
/**
|
||||
* Invalidates cached items using a tag.
|
||||
*
|
||||
* @param string $tag The tag to invalidate
|
||||
*
|
||||
* @throws InvalidArgumentException When $tags is not valid
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function invalidateTag($tag);
|
||||
|
||||
/**
|
||||
* Invalidates cached items using tags.
|
||||
*
|
||||
* @param string[] $tags An array of tags to invalidate
|
||||
*
|
||||
* @throws InvalidArgumentException When $tags is not valid
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function invalidateTags(array $tags);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return TaggableCacheItemInterface
|
||||
*/
|
||||
public function getItem($key);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return array|\Traversable|TaggableCacheItemInterface[]
|
||||
*/
|
||||
public function getItems(array $keys = []);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "cache/tag-interop",
|
||||
"description": "Framework interoperable interfaces for tags",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"psr6",
|
||||
"tag",
|
||||
"psr"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas Grekas ",
|
||||
"email": "p@tchwork.com",
|
||||
"homepage": "https://github.com/nicolas-grekas"
|
||||
}
|
||||
],
|
||||
"homepage": "https://www.php-cache.com/en/latest/",
|
||||
"require": {
|
||||
"php": "^5.5 || ^7.0 || ^8.0",
|
||||
"psr/cache": "^1.0 || ^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cache\\TagInterop\\": ""
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user