- <?php
- /**
- * Zend Framework (http://framework.zend.com/)
- *
- * @link http://github.com/zendframework/zf2 for the canonical source repository
- * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
-
- namespace Zend\Cache\Storage;
-
- use ArrayObject;
- use stdClass;
- use Zend\Cache\Exception;
- use Zend\EventManager\EventsCapableInterface;
-
- class Capabilities
- {
- /**
- * The storage instance
- *
- * @var StorageInterface
- */
- protected $storage;
-
- /**
- * A marker to set/change capabilities
- *
- * @var stdClass
- */
- protected $marker;
-
- /**
- * Base capabilities
- *
- * @var null|Capabilities
- */
- protected $baseCapabilities;
-
- /**
- * Expire read
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|bool
- */
- protected $expiredRead;
-
- /**
- * Max. key length
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|int
- */
- protected $maxKeyLength;
-
- /**
- * Min. TTL (0 means items never expire)
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|int
- */
- protected $minTtl;
-
- /**
- * Max. TTL (0 means infinite)
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|int
- */
- protected $maxTtl;
-
- /**
- * Namespace is prefix
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|bool
- */
- protected $namespaceIsPrefix;
-
- /**
- * Namespace separator
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|string
- */
- protected $namespaceSeparator;
-
- /**
- * Static ttl
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|bool
- */
- protected $staticTtl;
-
- /**
- * Supported datatypes
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|array
- */
- protected $supportedDatatypes;
-
- /**
- * Supported metdata
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|array
- */
- protected $supportedMetadata;
-
- /**
- * TTL precision
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|int
- */
- protected $ttlPrecision;
-
- /**
- * Use request time
- *
- * If it's NULL the capability isn't set and the getter
- * returns the base capability or the default value.
- *
- * @var null|bool
- */
- protected $useRequestTime;
-
- /**
- * Constructor
- *
- * @param StorageInterface $storage
- * @param stdClass $marker
- * @param array $capabilities
- * @param null|Capabilities $baseCapabilities
- */
- public function __construct(
- StorageInterface $storage,
- stdClass $marker,
- array $capabilities = array(),
- Capabilities $baseCapabilities = null
- ) {
- $this->storage = $storage;
- $this->marker = $marker;
- $this->baseCapabilities = $baseCapabilities;
-
- foreach ($capabilities as $name => $value) {
- $this->setCapability($marker, $name, $value);
- }
- }
-
- /**
- * Get the storage adapter
- *
- * @return StorageInterface
- */
- public function getAdapter()
- {
- return $this->storage;
- }
-
- /**
- * Get supported datatypes
- *
- * @return array
- */
- public function getSupportedDatatypes()
- {
- return $this->getCapability('supportedDatatypes', array(
- 'NULL' => false,
- 'boolean' => false,
- 'integer' => false,
- 'double' => false,
- 'string' => true,
- 'array' => false,
- 'object' => false,
- 'resource' => false,
- ));
- }
-
- /**
- * Set supported datatypes
- *
- * @param stdClass $marker
- * @param array $datatypes
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setSupportedDatatypes(stdClass $marker, array $datatypes)
- {
- $allTypes = array(
- 'array',
- 'boolean',
- 'double',
- 'integer',
- 'NULL',
- 'object',
- 'resource',
- 'string',
- );
-
- // check/normalize datatype values
- foreach ($datatypes as $type => &$toType) {
- if (!in_array($type, $allTypes)) {
- throw new Exception\InvalidArgumentException("Unknown datatype '{$type}'");
- }
-
- if (is_string($toType)) {
- $toType = strtolower($toType);
- if (!in_array($toType, $allTypes)) {
- throw new Exception\InvalidArgumentException("Unknown datatype '{$toType}'");
- }
- } else {
- $toType = (bool) $toType;
- }
- }
-
- // add missing datatypes as not supported
- $missingTypes = array_diff($allTypes, array_keys($datatypes));
- foreach ($missingTypes as $type) {
- $datatypes[$type] = false;
- }
-
- return $this->setCapability($marker, 'supportedDatatypes', $datatypes);
- }
-
- /**
- * Get supported metadata
- *
- * @return array
- */
- public function getSupportedMetadata()
- {
- return $this->getCapability('supportedMetadata', array());
- }
-
- /**
- * Set supported metadata
- *
- * @param stdClass $marker
- * @param string[] $metadata
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setSupportedMetadata(stdClass $marker, array $metadata)
- {
- foreach ($metadata as $name) {
- if (!is_string($name)) {
- throw new Exception\InvalidArgumentException('$metadata must be an array of strings');
- }
- }
- return $this->setCapability($marker, 'supportedMetadata', $metadata);
- }
-
- /**
- * Get minimum supported time-to-live
- *
- * @return int 0 means items never expire
- */
- public function getMinTtl()
- {
- return $this->getCapability('minTtl', 0);
- }
-
- /**
- * Set minimum supported time-to-live
- *
- * @param stdClass $marker
- * @param int $minTtl
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setMinTtl(stdClass $marker, $minTtl)
- {
- $minTtl = (int) $minTtl;
- if ($minTtl < 0) {
- throw new Exception\InvalidArgumentException('$minTtl must be greater or equal 0');
- }
- return $this->setCapability($marker, 'minTtl', $minTtl);
- }
-
- /**
- * Get maximum supported time-to-live
- *
- * @return int 0 means infinite
- */
- public function getMaxTtl()
- {
- return $this->getCapability('maxTtl', 0);
- }
-
- /**
- * Set maximum supported time-to-live
- *
- * @param stdClass $marker
- * @param int $maxTtl
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setMaxTtl(stdClass $marker, $maxTtl)
- {
- $maxTtl = (int) $maxTtl;
- if ($maxTtl < 0) {
- throw new Exception\InvalidArgumentException('$maxTtl must be greater or equal 0');
- }
- return $this->setCapability($marker, 'maxTtl', $maxTtl);
- }
-
- /**
- * Is the time-to-live handled static (on write)
- * or dynamic (on read)
- *
- * @return bool
- */
- public function getStaticTtl()
- {
- return $this->getCapability('staticTtl', false);
- }
-
- /**
- * Set if the time-to-live handled static (on write) or dynamic (on read)
- *
- * @param stdClass $marker
- * @param bool $flag
- * @return Capabilities Fluent interface
- */
- public function setStaticTtl(stdClass $marker, $flag)
- {
- return $this->setCapability($marker, 'staticTtl', (bool) $flag);
- }
-
- /**
- * Get time-to-live precision
- *
- * @return float
- */
- public function getTtlPrecision()
- {
- return $this->getCapability('ttlPrecision', 1);
- }
-
- /**
- * Set time-to-live precision
- *
- * @param stdClass $marker
- * @param float $ttlPrecision
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setTtlPrecision(stdClass $marker, $ttlPrecision)
- {
- $ttlPrecision = (float) $ttlPrecision;
- if ($ttlPrecision <= 0) {
- throw new Exception\InvalidArgumentException('$ttlPrecision must be greater than 0');
- }
- return $this->setCapability($marker, 'ttlPrecision', $ttlPrecision);
- }
-
- /**
- * Get use request time
- *
- * @return bool
- */
- public function getUseRequestTime()
- {
- return $this->getCapability('useRequestTime', false);
- }
-
- /**
- * Set use request time
- *
- * @param stdClass $marker
- * @param bool $flag
- * @return Capabilities Fluent interface
- */
- public function setUseRequestTime(stdClass $marker, $flag)
- {
- return $this->setCapability($marker, 'useRequestTime', (bool) $flag);
- }
-
- /**
- * Get if expired items are readable
- *
- * @return bool
- */
- public function getExpiredRead()
- {
- return $this->getCapability('expiredRead', false);
- }
-
- /**
- * Set if expired items are readable
- *
- * @param stdClass $marker
- * @param bool $flag
- * @return Capabilities Fluent interface
- */
- public function setExpiredRead(stdClass $marker, $flag)
- {
- return $this->setCapability($marker, 'expiredRead', (bool) $flag);
- }
-
- /**
- * Get maximum key lenth
- *
- * @return int -1 means unknown, 0 means infinite
- */
- public function getMaxKeyLength()
- {
- return $this->getCapability('maxKeyLength', -1);
- }
-
- /**
- * Set maximum key length
- *
- * @param stdClass $marker
- * @param int $maxKeyLength
- * @throws Exception\InvalidArgumentException
- * @return Capabilities Fluent interface
- */
- public function setMaxKeyLength(stdClass $marker, $maxKeyLength)
- {
- $maxKeyLength = (int) $maxKeyLength;
- if ($maxKeyLength < -1) {
- throw new Exception\InvalidArgumentException('$maxKeyLength must be greater or equal than -1');
- }
- return $this->setCapability($marker, 'maxKeyLength', $maxKeyLength);
- }
-
- /**
- * Get if namespace support is implemented as prefix
- *
- * @return bool
- */
- public function getNamespaceIsPrefix()
- {
- return $this->getCapability('namespaceIsPrefix', true);
- }
-
- /**
- * Set if namespace support is implemented as prefix
- *
- * @param stdClass $marker
- * @param bool $flag
- * @return Capabilities Fluent interface
- */
- public function setNamespaceIsPrefix(stdClass $marker, $flag)
- {
- return $this->setCapability($marker, 'namespaceIsPrefix', (bool) $flag);
- }
-
- /**
- * Get namespace separator if namespace is implemented as prefix
- *
- * @return string
- */
- public function getNamespaceSeparator()
- {
- return $this->getCapability('namespaceSeparator', '');
- }
-
- /**
- * Set the namespace separator if namespace is implemented as prefix
- *
- * @param stdClass $marker
- * @param string $separator
- * @return Capabilities Fluent interface
- */
- public function setNamespaceSeparator(stdClass $marker, $separator)
- {
- return $this->setCapability($marker, 'namespaceSeparator', (string) $separator);
- }
-
- /**
- * Get a capability
- *
- * @param string $property
- * @param mixed $default
- * @return mixed
- */
- protected function getCapability($property, $default = null)
- {
- if ($this->$property !== null) {
- return $this->$property;
- } elseif ($this->baseCapabilities) {
- $getMethod = 'get' . $property;
- return $this->baseCapabilities->$getMethod();
- }
- return $default;
- }
-
- /**
- * Change a capability
- *
- * @param stdClass $marker
- * @param string $property
- * @param mixed $value
- * @return Capabilities Fluent interface
- * @throws Exception\InvalidArgumentException
- */
- protected function setCapability(stdClass $marker, $property, $value)
- {
- if ($this->marker !== $marker) {
- throw new Exception\InvalidArgumentException('Invalid marker');
- }
-
- if ($this->$property !== $value) {
- $this->$property = $value;
-
- // trigger event
- if ($this->storage instanceof EventsCapableInterface) {
- $this->storage->getEventManager()->trigger('capability', $this->storage, new ArrayObject(array(
- $property => $value
- )));
- }
- }
-
- return $this;
- }
- }