2023-03-11 12:04:29 +03:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Zend Framework (http://framework.zend.com/)
|
|
|
|
*
|
|
|
|
* @link http://github.com/zendframework/zf2 for the canonical source repository
|
2023-04-01 09:03:34 +03:00
|
|
|
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
2023-03-11 12:04:29 +03:00
|
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Zend\Cache\Storage\Adapter;
|
|
|
|
|
|
|
|
use ArrayObject;
|
|
|
|
use SplObjectStorage;
|
|
|
|
use stdClass;
|
|
|
|
use Traversable;
|
|
|
|
use Zend\Cache\Exception;
|
|
|
|
use Zend\Cache\Storage\Capabilities;
|
|
|
|
use Zend\Cache\Storage\Event;
|
|
|
|
use Zend\Cache\Storage\ExceptionEvent;
|
|
|
|
use Zend\Cache\Storage\Plugin;
|
|
|
|
use Zend\Cache\Storage\PostEvent;
|
|
|
|
use Zend\Cache\Storage\StorageInterface;
|
|
|
|
use Zend\EventManager\EventManager;
|
|
|
|
use Zend\EventManager\EventManagerInterface;
|
|
|
|
use Zend\EventManager\EventsCapableInterface;
|
|
|
|
|
|
|
|
abstract class AbstractAdapter implements StorageInterface, EventsCapableInterface
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* The used EventManager if any
|
|
|
|
*
|
|
|
|
* @var null|EventManagerInterface
|
|
|
|
*/
|
|
|
|
protected $events = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handles of this adapter
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $eventHandles = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The plugin registry
|
|
|
|
*
|
|
|
|
* @var SplObjectStorage Registered plugins
|
|
|
|
*/
|
|
|
|
protected $pluginRegistry;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Capabilities of this adapter
|
|
|
|
*
|
|
|
|
* @var null|Capabilities
|
|
|
|
*/
|
|
|
|
protected $capabilities = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Marker to change capabilities
|
|
|
|
*
|
|
|
|
* @var null|object
|
|
|
|
*/
|
|
|
|
protected $capabilityMarker;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* options
|
|
|
|
*
|
|
|
|
* @var mixed
|
|
|
|
*/
|
|
|
|
protected $options;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* @param null|array|Traversable|AdapterOptions $options
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
public function __construct($options = null)
|
|
|
|
{
|
|
|
|
if ($options) {
|
|
|
|
$this->setOptions($options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*
|
|
|
|
* detach all registered plugins to free
|
|
|
|
* event handles of event manager
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
foreach ($this->getPluginRegistry() as $plugin) {
|
|
|
|
$this->removePlugin($plugin);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->eventHandles) {
|
|
|
|
$events = $this->getEventManager();
|
|
|
|
foreach ($this->eventHandles as $handle) {
|
|
|
|
$events->detach($handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* configuration */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set options.
|
|
|
|
*
|
|
|
|
* @param array|Traversable|AdapterOptions $options
|
|
|
|
* @return AbstractAdapter
|
|
|
|
* @see getOptions()
|
|
|
|
*/
|
|
|
|
public function setOptions($options)
|
|
|
|
{
|
|
|
|
if ($this->options !== $options) {
|
|
|
|
if (!$options instanceof AdapterOptions) {
|
|
|
|
$options = new AdapterOptions($options);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->options) {
|
|
|
|
$this->options->setAdapter(null);
|
|
|
|
}
|
|
|
|
$options->setAdapter($this);
|
|
|
|
$this->options = $options;
|
|
|
|
|
|
|
|
$event = new Event('option', $this, new ArrayObject($options->toArray()));
|
|
|
|
$this->getEventManager()->trigger($event);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get options.
|
|
|
|
*
|
|
|
|
* @return AdapterOptions
|
|
|
|
* @see setOptions()
|
|
|
|
*/
|
|
|
|
public function getOptions()
|
|
|
|
{
|
|
|
|
if (!$this->options) {
|
|
|
|
$this->setOptions(new AdapterOptions());
|
|
|
|
}
|
|
|
|
return $this->options;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable/Disable caching.
|
|
|
|
*
|
|
|
|
* Alias of setWritable and setReadable.
|
|
|
|
*
|
|
|
|
* @see setWritable()
|
|
|
|
* @see setReadable()
|
|
|
|
* @param bool $flag
|
|
|
|
* @return AbstractAdapter
|
|
|
|
*/
|
|
|
|
public function setCaching($flag)
|
|
|
|
{
|
|
|
|
$flag = (bool) $flag;
|
|
|
|
$options = $this->getOptions();
|
|
|
|
$options->setWritable($flag);
|
|
|
|
$options->setReadable($flag);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get caching enabled.
|
|
|
|
*
|
|
|
|
* Alias of getWritable and getReadable.
|
|
|
|
*
|
|
|
|
* @see getWritable()
|
|
|
|
* @see getReadable()
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function getCaching()
|
|
|
|
{
|
|
|
|
$options = $this->getOptions();
|
|
|
|
return ($options->getWritable() && $options->getReadable());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Event/Plugin handling */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the event manager
|
|
|
|
*
|
|
|
|
* @return EventManagerInterface
|
|
|
|
*/
|
|
|
|
public function getEventManager()
|
|
|
|
{
|
|
|
|
if ($this->events === null) {
|
|
|
|
$this->events = new EventManager(array(__CLASS__, get_class($this)));
|
|
|
|
}
|
|
|
|
return $this->events;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Trigger a pre event and return the event response collection
|
|
|
|
*
|
|
|
|
* @param string $eventName
|
|
|
|
* @param ArrayObject $args
|
|
|
|
* @return \Zend\EventManager\ResponseCollection All handler return values
|
|
|
|
*/
|
|
|
|
protected function triggerPre($eventName, ArrayObject $args)
|
|
|
|
{
|
|
|
|
return $this->getEventManager()->trigger(new Event($eventName . '.pre', $this, $args));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Triggers the PostEvent and return the result value.
|
|
|
|
*
|
|
|
|
* @param string $eventName
|
|
|
|
* @param ArrayObject $args
|
|
|
|
* @param mixed $result
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
protected function triggerPost($eventName, ArrayObject $args, & $result)
|
|
|
|
{
|
|
|
|
$postEvent = new PostEvent($eventName . '.post', $this, $args, $result);
|
|
|
|
$eventRs = $this->getEventManager()->trigger($postEvent);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
return $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $postEvent->getResult();
|
2023-03-11 12:04:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Trigger an exception event
|
|
|
|
*
|
|
|
|
* If the ExceptionEvent has the flag "throwException" enabled throw the
|
|
|
|
* exception after trigger else return the result.
|
|
|
|
*
|
|
|
|
* @param string $eventName
|
|
|
|
* @param ArrayObject $args
|
|
|
|
* @param mixed $result
|
|
|
|
* @param \Exception $exception
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
protected function triggerException($eventName, ArrayObject $args, & $result, \Exception $exception)
|
|
|
|
{
|
|
|
|
$exceptionEvent = new ExceptionEvent($eventName . '.exception', $this, $args, $result, $exception);
|
|
|
|
$eventRs = $this->getEventManager()->trigger($exceptionEvent);
|
|
|
|
|
|
|
|
if ($exceptionEvent->getThrowException()) {
|
|
|
|
throw $exceptionEvent->getException();
|
|
|
|
}
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
return $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $exceptionEvent->getResult();
|
2023-03-11 12:04:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a plugin is registered
|
|
|
|
*
|
|
|
|
* @param Plugin\PluginInterface $plugin
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function hasPlugin(Plugin\PluginInterface $plugin)
|
|
|
|
{
|
|
|
|
$registry = $this->getPluginRegistry();
|
|
|
|
return $registry->contains($plugin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register a plugin
|
|
|
|
*
|
|
|
|
* @param Plugin\PluginInterface $plugin
|
|
|
|
* @param int $priority
|
|
|
|
* @return AbstractAdapter Fluent interface
|
|
|
|
* @throws Exception\LogicException
|
|
|
|
*/
|
|
|
|
public function addPlugin(Plugin\PluginInterface $plugin, $priority = 1)
|
|
|
|
{
|
|
|
|
$registry = $this->getPluginRegistry();
|
|
|
|
if ($registry->contains($plugin)) {
|
|
|
|
throw new Exception\LogicException(sprintf(
|
|
|
|
'Plugin of type "%s" already registered',
|
|
|
|
get_class($plugin)
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
$plugin->attach($this->getEventManager(), $priority);
|
|
|
|
$registry->attach($plugin);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregister an already registered plugin
|
|
|
|
*
|
|
|
|
* @param Plugin\PluginInterface $plugin
|
|
|
|
* @return AbstractAdapter Fluent interface
|
|
|
|
* @throws Exception\LogicException
|
|
|
|
*/
|
|
|
|
public function removePlugin(Plugin\PluginInterface $plugin)
|
|
|
|
{
|
|
|
|
$registry = $this->getPluginRegistry();
|
|
|
|
if ($registry->contains($plugin)) {
|
|
|
|
$plugin->detach($this->getEventManager());
|
|
|
|
$registry->detach($plugin);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return registry of plugins
|
|
|
|
*
|
|
|
|
* @return SplObjectStorage
|
|
|
|
*/
|
|
|
|
public function getPluginRegistry()
|
|
|
|
{
|
|
|
|
if (!$this->pluginRegistry instanceof SplObjectStorage) {
|
|
|
|
$this->pluginRegistry = new SplObjectStorage();
|
|
|
|
}
|
|
|
|
return $this->pluginRegistry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reading */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param bool $success
|
|
|
|
* @param mixed $casToken
|
|
|
|
* @return mixed Data on success, null on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers getItem.pre(PreEvent)
|
|
|
|
* @triggers getItem.post(PostEvent)
|
|
|
|
* @triggers getItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function getItem($key, & $success = null, & $casToken = null)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getReadable()) {
|
|
|
|
$success = false;
|
2023-04-01 09:03:34 +03:00
|
|
|
return;
|
2023-03-11 12:04:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
|
|
|
|
$argn = func_num_args();
|
|
|
|
$args = array(
|
|
|
|
'key' => & $key,
|
|
|
|
);
|
|
|
|
if ($argn > 1) {
|
|
|
|
$args['success'] = & $success;
|
|
|
|
}
|
|
|
|
if ($argn > 2) {
|
|
|
|
$args['casToken'] = & $casToken;
|
|
|
|
}
|
|
|
|
$args = new ArrayObject($args);
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
if ($eventRs->stopped()) {
|
|
|
|
$result = $eventRs->last();
|
|
|
|
} elseif ($args->offsetExists('success') && $args->offsetExists('casToken')) {
|
2023-03-11 12:04:29 +03:00
|
|
|
$result = $this->internalGetItem($args['key'], $args['success'], $args['casToken']);
|
|
|
|
} elseif ($args->offsetExists('success')) {
|
|
|
|
$result = $this->internalGetItem($args['key'], $args['success']);
|
|
|
|
} else {
|
|
|
|
$result = $this->internalGetItem($args['key']);
|
|
|
|
}
|
2023-04-01 09:03:34 +03:00
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = null;
|
|
|
|
$success = false;
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to get an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param bool $success
|
|
|
|
* @param mixed $casToken
|
|
|
|
* @return mixed Data on success, null on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
abstract protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keys
|
|
|
|
* @return array Associative array of keys and values
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers getItems.pre(PreEvent)
|
|
|
|
* @triggers getItems.post(PostEvent)
|
|
|
|
* @triggers getItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function getItems(array $keys)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getReadable()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeys($keys);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keys' => & $keys,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalGetItems($args['keys']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array();
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to get multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeys
|
|
|
|
* @return array Associative array of keys and values
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalGetItems(array & $normalizedKeys)
|
|
|
|
{
|
|
|
|
$success = null;
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeys as $normalizedKey) {
|
|
|
|
$value = $this->internalGetItem($normalizedKey, $success);
|
|
|
|
if ($success) {
|
|
|
|
$result[$normalizedKey] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test if an item exists.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers hasItem.pre(PreEvent)
|
|
|
|
* @triggers hasItem.post(PostEvent)
|
|
|
|
* @triggers hasItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function hasItem($key)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getReadable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalHasItem($args['key']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to test if an item exists.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalHasItem(& $normalizedKey)
|
|
|
|
{
|
|
|
|
$success = null;
|
|
|
|
$this->internalGetItem($normalizedKey, $success);
|
|
|
|
return $success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keys
|
|
|
|
* @return array Array of found keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers hasItems.pre(PreEvent)
|
|
|
|
* @triggers hasItems.post(PostEvent)
|
|
|
|
* @triggers hasItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function hasItems(array $keys)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getReadable()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeys($keys);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keys' => & $keys,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalHasItems($args['keys']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array();
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to test multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeys
|
|
|
|
* @return array Array of found keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalHasItems(array & $normalizedKeys)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeys as $normalizedKey) {
|
|
|
|
if ($this->internalHasItem($normalizedKey)) {
|
|
|
|
$result[] = $normalizedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get metadata of an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @return array|bool Metadata on success, false on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers getMetadata.pre(PreEvent)
|
|
|
|
* @triggers getMetadata.post(PostEvent)
|
|
|
|
* @triggers getMetadata.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function getMetadata($key)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getReadable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalGetMetadata($args['key']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to get metadata of an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @return array|bool Metadata on success, false on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalGetMetadata(& $normalizedKey)
|
|
|
|
{
|
|
|
|
if (!$this->internalHasItem($normalizedKey)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get multiple metadata
|
|
|
|
*
|
|
|
|
* @param array $keys
|
|
|
|
* @return array Associative array of keys and metadata
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers getMetadatas.pre(PreEvent)
|
|
|
|
* @triggers getMetadatas.post(PostEvent)
|
|
|
|
* @triggers getMetadatas.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function getMetadatas(array $keys)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getReadable()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeys($keys);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keys' => & $keys,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalGetMetadatas($args['keys']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array();
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to get multiple metadata
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeys
|
|
|
|
* @return array Associative array of keys and metadata
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalGetMetadatas(array & $normalizedKeys)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeys as $normalizedKey) {
|
|
|
|
$metadata = $this->internalGetMetadata($normalizedKey);
|
|
|
|
if ($metadata !== false) {
|
|
|
|
$result[$normalizedKey] = $metadata;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* writing */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Store an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers setItem.pre(PreEvent)
|
|
|
|
* @triggers setItem.post(PostEvent)
|
|
|
|
* @triggers setItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function setItem($key, $value)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
'value' => & $value,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalSetItem($args['key'], $args['value']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to store an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
abstract protected function internalSetItem(& $normalizedKey, & $value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Store multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keyValuePairs
|
|
|
|
* @return array Array of not stored keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers setItems.pre(PreEvent)
|
|
|
|
* @triggers setItems.post(PostEvent)
|
|
|
|
* @triggers setItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function setItems(array $keyValuePairs)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return array_keys($keyValuePairs);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeyValuePairs($keyValuePairs);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keyValuePairs' => & $keyValuePairs,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalSetItems($args['keyValuePairs']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array_keys($keyValuePairs);
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to store multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeyValuePairs
|
|
|
|
* @return array Array of not stored keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalSetItems(array & $normalizedKeyValuePairs)
|
|
|
|
{
|
|
|
|
$failedKeys = array();
|
|
|
|
foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
|
|
|
|
if (!$this->internalSetItem($normalizedKey, $value)) {
|
|
|
|
$failedKeys[] = $normalizedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $failedKeys;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers addItem.pre(PreEvent)
|
|
|
|
* @triggers addItem.post(PostEvent)
|
|
|
|
* @triggers addItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function addItem($key, $value)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
'value' => & $value,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalAddItem($args['key'], $args['value']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to add an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalAddItem(& $normalizedKey, & $value)
|
|
|
|
{
|
|
|
|
if ($this->internalHasItem($normalizedKey)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return $this->internalSetItem($normalizedKey, $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keyValuePairs
|
|
|
|
* @return array Array of not stored keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers addItems.pre(PreEvent)
|
|
|
|
* @triggers addItems.post(PostEvent)
|
|
|
|
* @triggers addItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function addItems(array $keyValuePairs)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return array_keys($keyValuePairs);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeyValuePairs($keyValuePairs);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keyValuePairs' => & $keyValuePairs,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalAddItems($args['keyValuePairs']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array_keys($keyValuePairs);
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to add multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeyValuePairs
|
|
|
|
* @return array Array of not stored keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalAddItems(array & $normalizedKeyValuePairs)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
|
|
|
|
if (!$this->internalAddItem($normalizedKey, $value)) {
|
|
|
|
$result[] = $normalizedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replace an existing item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers replaceItem.pre(PreEvent)
|
|
|
|
* @triggers replaceItem.post(PostEvent)
|
|
|
|
* @triggers replaceItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function replaceItem($key, $value)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
'value' => & $value,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalReplaceItem($args['key'], $args['value']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to replace an existing item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalReplaceItem(& $normalizedKey, & $value)
|
|
|
|
{
|
|
|
|
if (!$this->internalhasItem($normalizedKey)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->internalSetItem($normalizedKey, $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replace multiple existing items.
|
|
|
|
*
|
|
|
|
* @param array $keyValuePairs
|
|
|
|
* @return array Array of not stored keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers replaceItems.pre(PreEvent)
|
|
|
|
* @triggers replaceItems.post(PostEvent)
|
|
|
|
* @triggers replaceItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function replaceItems(array $keyValuePairs)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return array_keys($keyValuePairs);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeyValuePairs($keyValuePairs);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keyValuePairs' => & $keyValuePairs,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalReplaceItems($args['keyValuePairs']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array_keys($keyValuePairs);
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to replace multiple existing items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeyValuePairs
|
|
|
|
* @return array Array of not stored keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalReplaceItems(array & $normalizedKeyValuePairs)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
|
|
|
|
if (!$this->internalReplaceItem($normalizedKey, $value)) {
|
|
|
|
$result[] = $normalizedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set an item only if token matches
|
|
|
|
*
|
|
|
|
* It uses the token received from getItem() to check if the item has
|
|
|
|
* changed before overwriting it.
|
|
|
|
*
|
|
|
|
* @param mixed $token
|
|
|
|
* @param string $key
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
* @see getItem()
|
|
|
|
* @see setItem()
|
|
|
|
*/
|
|
|
|
public function checkAndSetItem($token, $key, $value)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'token' => & $token,
|
|
|
|
'key' => & $key,
|
|
|
|
'value' => & $value,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalCheckAndSetItem($args['token'], $args['key'], $args['value']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to set an item only if token matches
|
|
|
|
*
|
|
|
|
* @param mixed $token
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param mixed $value
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
* @see getItem()
|
|
|
|
* @see setItem()
|
|
|
|
*/
|
|
|
|
protected function internalCheckAndSetItem(& $token, & $normalizedKey, & $value)
|
|
|
|
{
|
|
|
|
$oldValue = $this->internalGetItem($normalizedKey);
|
|
|
|
if ($oldValue !== $token) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->internalSetItem($normalizedKey, $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset lifetime of an item
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers touchItem.pre(PreEvent)
|
|
|
|
* @triggers touchItem.post(PostEvent)
|
|
|
|
* @triggers touchItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function touchItem($key)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalTouchItem($args['key']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to reset lifetime of an item
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalTouchItem(& $normalizedKey)
|
|
|
|
{
|
|
|
|
$success = null;
|
|
|
|
$value = $this->internalGetItem($normalizedKey, $success);
|
|
|
|
if (!$success) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->internalReplaceItem($normalizedKey, $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset lifetime of multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keys
|
|
|
|
* @return array Array of not updated keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers touchItems.pre(PreEvent)
|
|
|
|
* @triggers touchItems.post(PostEvent)
|
|
|
|
* @triggers touchItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function touchItems(array $keys)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return $keys;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeys($keys);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keys' => & $keys,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalTouchItems($args['keys']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $keys, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to reset lifetime of multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeys
|
|
|
|
* @return array Array of not updated keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalTouchItems(array & $normalizedKeys)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeys as $normalizedKey) {
|
|
|
|
if (!$this->internalTouchItem($normalizedKey)) {
|
|
|
|
$result[] = $normalizedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers removeItem.pre(PreEvent)
|
|
|
|
* @triggers removeItem.post(PostEvent)
|
|
|
|
* @triggers removeItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function removeItem($key)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalRemoveItem($args['key']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to remove an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @return bool
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
abstract protected function internalRemoveItem(& $normalizedKey);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keys
|
|
|
|
* @return array Array of not removed keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers removeItems.pre(PreEvent)
|
|
|
|
* @triggers removeItems.post(PostEvent)
|
|
|
|
* @triggers removeItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function removeItems(array $keys)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return $keys;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeys($keys);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keys' => & $keys,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalRemoveItems($args['keys']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $keys, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to remove multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeys
|
|
|
|
* @return array Array of not removed keys
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalRemoveItems(array & $normalizedKeys)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeys as $normalizedKey) {
|
|
|
|
if (!$this->internalRemoveItem($normalizedKey)) {
|
|
|
|
$result[] = $normalizedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increment an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param int $value
|
|
|
|
* @return int|bool The new value on success, false on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers incrementItem.pre(PreEvent)
|
|
|
|
* @triggers incrementItem.post(PostEvent)
|
|
|
|
* @triggers incrementItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function incrementItem($key, $value)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
'value' => & $value,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalIncrementItem($args['key'], $args['value']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to increment an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param int $value
|
|
|
|
* @return int|bool The new value on success, false on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalIncrementItem(& $normalizedKey, & $value)
|
|
|
|
{
|
|
|
|
$success = null;
|
|
|
|
$value = (int) $value;
|
|
|
|
$get = (int) $this->internalGetItem($normalizedKey, $success);
|
|
|
|
$newValue = $get + $value;
|
|
|
|
|
|
|
|
if ($success) {
|
|
|
|
$this->internalReplaceItem($normalizedKey, $newValue);
|
|
|
|
} else {
|
|
|
|
$this->internalAddItem($normalizedKey, $newValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $newValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increment multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keyValuePairs
|
|
|
|
* @return array Associative array of keys and new values
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers incrementItems.pre(PreEvent)
|
|
|
|
* @triggers incrementItems.post(PostEvent)
|
|
|
|
* @triggers incrementItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function incrementItems(array $keyValuePairs)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeyValuePairs($keyValuePairs);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keyValuePairs' => & $keyValuePairs,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalIncrementItems($args['keyValuePairs']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array();
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to increment multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeyValuePairs
|
|
|
|
* @return array Associative array of keys and new values
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalIncrementItems(array & $normalizedKeyValuePairs)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
|
|
|
|
$newValue = $this->internalIncrementItem($normalizedKey, $value);
|
|
|
|
if ($newValue !== false) {
|
|
|
|
$result[$normalizedKey] = $newValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrement an item.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param int $value
|
|
|
|
* @return int|bool The new value on success, false on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers decrementItem.pre(PreEvent)
|
|
|
|
* @triggers decrementItem.post(PostEvent)
|
|
|
|
* @triggers decrementItem.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function decrementItem($key, $value)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'key' => & $key,
|
|
|
|
'value' => & $value,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalDecrementItem($args['key'], $args['value']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to decrement an item.
|
|
|
|
*
|
|
|
|
* @param string $normalizedKey
|
|
|
|
* @param int $value
|
|
|
|
* @return int|bool The new value on success, false on failure
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalDecrementItem(& $normalizedKey, & $value)
|
|
|
|
{
|
|
|
|
$success = null;
|
|
|
|
$value = (int) $value;
|
|
|
|
$get = (int) $this->internalGetItem($normalizedKey, $success);
|
|
|
|
$newValue = $get - $value;
|
|
|
|
|
|
|
|
if ($success) {
|
|
|
|
$this->internalReplaceItem($normalizedKey, $newValue);
|
|
|
|
} else {
|
|
|
|
$this->internalAddItem($normalizedKey, $newValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $newValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrement multiple items.
|
|
|
|
*
|
|
|
|
* @param array $keyValuePairs
|
|
|
|
* @return array Associative array of keys and new values
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*
|
|
|
|
* @triggers incrementItems.pre(PreEvent)
|
|
|
|
* @triggers incrementItems.post(PostEvent)
|
|
|
|
* @triggers incrementItems.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function decrementItems(array $keyValuePairs)
|
|
|
|
{
|
|
|
|
if (!$this->getOptions()->getWritable()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->normalizeKeyValuePairs($keyValuePairs);
|
|
|
|
$args = new ArrayObject(array(
|
|
|
|
'keyValuePairs' => & $keyValuePairs,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalDecrementItems($args['keyValuePairs']);
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = array();
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to decrement multiple items.
|
|
|
|
*
|
|
|
|
* @param array $normalizedKeyValuePairs
|
|
|
|
* @return array Associative array of keys and new values
|
|
|
|
* @throws Exception\ExceptionInterface
|
|
|
|
*/
|
|
|
|
protected function internalDecrementItems(array & $normalizedKeyValuePairs)
|
|
|
|
{
|
|
|
|
$result = array();
|
|
|
|
foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
|
|
|
|
$newValue = $this->decrementItem($normalizedKey, $value);
|
|
|
|
if ($newValue !== false) {
|
|
|
|
$result[$normalizedKey] = $newValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* status */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get capabilities of this adapter
|
|
|
|
*
|
|
|
|
* @return Capabilities
|
|
|
|
* @triggers getCapabilities.pre(PreEvent)
|
|
|
|
* @triggers getCapabilities.post(PostEvent)
|
|
|
|
* @triggers getCapabilities.exception(ExceptionEvent)
|
|
|
|
*/
|
|
|
|
public function getCapabilities()
|
|
|
|
{
|
|
|
|
$args = new ArrayObject();
|
|
|
|
|
|
|
|
try {
|
|
|
|
$eventRs = $this->triggerPre(__FUNCTION__, $args);
|
|
|
|
|
2023-04-01 09:03:34 +03:00
|
|
|
$result = $eventRs->stopped()
|
|
|
|
? $eventRs->last()
|
|
|
|
: $this->internalGetCapabilities();
|
|
|
|
|
2023-03-11 12:04:29 +03:00
|
|
|
return $this->triggerPost(__FUNCTION__, $args, $result);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$result = false;
|
|
|
|
return $this->triggerException(__FUNCTION__, $args, $result, $e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal method to get capabilities of this adapter
|
|
|
|
*
|
|
|
|
* @return Capabilities
|
|
|
|
*/
|
|
|
|
protected function internalGetCapabilities()
|
|
|
|
{
|
|
|
|
if ($this->capabilities === null) {
|
|
|
|
$this->capabilityMarker = new stdClass();
|
|
|
|
$this->capabilities = new Capabilities($this, $this->capabilityMarker);
|
|
|
|
}
|
|
|
|
return $this->capabilities;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* internal */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validates and normalizes a key
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @return void
|
|
|
|
* @throws Exception\InvalidArgumentException On an invalid key
|
|
|
|
*/
|
|
|
|
protected function normalizeKey(& $key)
|
|
|
|
{
|
|
|
|
$key = (string) $key;
|
|
|
|
|
|
|
|
if ($key === '') {
|
|
|
|
throw new Exception\InvalidArgumentException(
|
|
|
|
"An empty key isn't allowed"
|
|
|
|
);
|
|
|
|
} elseif (($p = $this->getOptions()->getKeyPattern()) && !preg_match($p, $key)) {
|
|
|
|
throw new Exception\InvalidArgumentException(
|
|
|
|
"The key '{$key}' doesn't match against pattern '{$p}'"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validates and normalizes multiple keys
|
|
|
|
*
|
|
|
|
* @param array $keys
|
|
|
|
* @return void
|
|
|
|
* @throws Exception\InvalidArgumentException On an invalid key
|
|
|
|
*/
|
|
|
|
protected function normalizeKeys(array & $keys)
|
|
|
|
{
|
|
|
|
if (!$keys) {
|
|
|
|
throw new Exception\InvalidArgumentException(
|
|
|
|
"An empty list of keys isn't allowed"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
array_walk($keys, array($this, 'normalizeKey'));
|
|
|
|
$keys = array_values(array_unique($keys));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validates and normalizes an array of key-value pairs
|
|
|
|
*
|
|
|
|
* @param array $keyValuePairs
|
|
|
|
* @return void
|
|
|
|
* @throws Exception\InvalidArgumentException On an invalid key
|
|
|
|
*/
|
|
|
|
protected function normalizeKeyValuePairs(array & $keyValuePairs)
|
|
|
|
{
|
|
|
|
$normalizedKeyValuePairs = array();
|
|
|
|
foreach ($keyValuePairs as $key => $value) {
|
|
|
|
$this->normalizeKey($key);
|
|
|
|
$normalizedKeyValuePairs[$key] = $value;
|
|
|
|
}
|
|
|
|
$keyValuePairs = $normalizedKeyValuePairs;
|
|
|
|
}
|
|
|
|
}
|