Update core 8.3.0

This commit is contained in:
Rob Davies 2017-04-13 15:53:35 +01:00
parent da7a7918f8
commit cd7a898e66
6144 changed files with 132297 additions and 87747 deletions

View file

@ -1,11 +1,17 @@
language: php
sudo: false
cache:
directories:
- vendor
- $HOME/.composer/cache
php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
- 5.5
- 5.6
- 7.0
- hhvm
services:
- riak
@ -14,13 +20,14 @@ services:
- redis-server
before_install:
- sh -c "if [ $TRAVIS_PHP_VERSION != 'hhvm' ]; then pecl install riak-beta; fi"
- sh -c "if [[ $TRAVIS_PHP_VERSION != 'hhvm' && `php-config --vernum` -ge 50500 ]] ; then pecl config-set preferred_state beta; printf "yes\n" | pecl install apcu ; else echo 'extension="apc.so"' >> ./tests/travis/php.ini ;fi"
- composer self-update
- sh -c "if [ $TRAVIS_PHP_VERSION != 'hhvm' ]; then phpenv config-add ./tests/travis/php.ini; fi"
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' ]] ; then pecl channel-update pecl.php.net; fi;
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' && $TRAVIS_PHP_VERSION != '7.0' ]]; then pecl install riak-beta; fi;
- if [[ $TRAVIS_PHP_VERSION =~ 5.[56] ]] ; then echo yes | pecl install apcu-4.0.10; fi;
- if [[ $TRAVIS_PHP_VERSION = 7.* ]] ; then pecl config-set preferred_state beta; echo yes | pecl install apcu; fi;
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' ]]; then phpenv config-add ./tests/travis/php.ini; fi;
install:
- composer --prefer-source --dev install
- travis_retry composer install
script:
- ./vendor/bin/phpunit -c ./tests/travis/phpunit.travis.xml -v
@ -29,5 +36,7 @@ after_script:
- php vendor/bin/coveralls -v
matrix:
allow_failures:
- php: hhvm
fast_finish: true
allow_failures:
- php: hhvm
- php: 7.0

View file

@ -1,4 +1,4 @@
Copyright (c) 2006-2012 Doctrine Project
Copyright (c) 2006-2015 Doctrine Project
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

View file

@ -13,10 +13,10 @@
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": ">=5.3.2"
"php": "~5.5|~7.0"
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"phpunit/phpunit": "~4.8|~5.0",
"satooshi/php-coveralls": "~0.6",
"predis/predis": "~1.0"
},
@ -24,11 +24,14 @@
"doctrine/common": ">2.2,<2.4"
},
"autoload": {
"psr-0": { "Doctrine\\Common\\Cache\\": "lib/" }
"psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" }
},
"autoload-dev": {
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine/Tests" }
},
"extra": {
"branch-alias": {
"dev-master": "1.5.x-dev"
"dev-master": "1.6.x-dev"
}
}
}

View file

@ -22,13 +22,14 @@ namespace Doctrine\Common\Cache;
/**
* APC cache provider.
*
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author David Abdemoulaie <dave@hobodave.com>
* @link www.doctrine-project.org
* @deprecated since version 1.6, use ApcuCache instead
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author David Abdemoulaie <dave@hobodave.com>
*/
class ApcCache extends CacheProvider
{
@ -53,7 +54,7 @@ class ApcCache extends CacheProvider
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return (bool) apc_store($id, $data, (int) $lifeTime);
return apc_store($id, $data, $lifeTime);
}
/**
@ -61,7 +62,8 @@ class ApcCache extends CacheProvider
*/
protected function doDelete($id)
{
return apc_delete($id);
// apc_delete returns false if the id does not exist
return apc_delete($id) || ! apc_exists($id);
}
/**
@ -77,7 +79,17 @@ class ApcCache extends CacheProvider
*/
protected function doFetchMultiple(array $keys)
{
return apc_fetch($keys);
return apc_fetch($keys) ?: [];
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$result = apc_store($keysAndValues, null, $lifetime);
return empty($result);
}
/**

View file

@ -0,0 +1,106 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common\Cache;
/**
* APCu cache provider.
*
* @link www.doctrine-project.org
* @since 1.6
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ApcuCache extends CacheProvider
{
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return apcu_fetch($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return apcu_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return apcu_store($id, $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
// apcu_delete returns false if the id does not exist
return apcu_delete($id) || ! apcu_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return apcu_clear_cache();
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
return apcu_fetch($keys) ?: [];
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$result = apcu_store($keysAndValues, null, $lifetime);
return empty($result);
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$info = apcu_cache_info(true);
$sma = apcu_sma_info();
return array(
Cache::STATS_HITS => $info['num_hits'],
Cache::STATS_MISSES => $info['num_misses'],
Cache::STATS_UPTIME => $info['start_time'],
Cache::STATS_MEMORY_USAGE => $info['mem_size'],
Cache::STATS_MEMORY_AVAILABLE => $sma['avail_mem'],
);
}
}

View file

@ -33,16 +33,47 @@ namespace Doctrine\Common\Cache;
class ArrayCache extends CacheProvider
{
/**
* @var array $data
* @var array[] $data each element being a tuple of [$data, $expiration], where the expiration is int|bool
*/
private $data = array();
private $data = [];
/**
* @var int
*/
private $hitsCount = 0;
/**
* @var int
*/
private $missesCount = 0;
/**
* @var int
*/
private $upTime;
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->upTime = time();
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->doContains($id) ? $this->data[$id] : false;
if (! $this->doContains($id)) {
$this->missesCount += 1;
return false;
}
$this->hitsCount += 1;
return $this->data[$id][0];
}
/**
@ -50,8 +81,19 @@ class ArrayCache extends CacheProvider
*/
protected function doContains($id)
{
// isset() is required for performance optimizations, to avoid unnecessary function calls to array_key_exists.
return isset($this->data[$id]) || array_key_exists($id, $this->data);
if (! isset($this->data[$id])) {
return false;
}
$expiration = $this->data[$id][1];
if ($expiration && $expiration < time()) {
$this->doDelete($id);
return false;
}
return true;
}
/**
@ -59,7 +101,7 @@ class ArrayCache extends CacheProvider
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$this->data[$id] = $data;
$this->data[$id] = [$data, $lifeTime ? time() + $lifeTime : false];
return true;
}
@ -79,7 +121,7 @@ class ArrayCache extends CacheProvider
*/
protected function doFlush()
{
$this->data = array();
$this->data = [];
return true;
}
@ -89,6 +131,12 @@ class ArrayCache extends CacheProvider
*/
protected function doGetStats()
{
return null;
return [
Cache::STATS_HITS => $this->hitsCount,
Cache::STATS_MISSES => $this->missesCount,
Cache::STATS_UPTIME => $this->upTime,
Cache::STATS_MEMORY_USAGE => null,
Cache::STATS_MEMORY_AVAILABLE => null,
];
}
}

View file

@ -59,19 +59,22 @@ interface Cache
*
* @param string $id The cache id of the entry to check for.
*
* @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise.
* @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise.
*/
public function contains($id);
/**
* Puts data into the cache.
*
* If a cache entry with the given id already exists, its data will be replaced.
*
* @param string $id The cache id.
* @param mixed $data The cache entry/data.
* @param int $lifeTime The cache lifetime.
* If != 0, sets a specific lifetime for this cache entry (0 => infinite lifeTime).
* @param int $lifeTime The lifetime in number of seconds for this cache entry.
* If zero (the default), the entry never expires (although it may be deleted from the cache
* to make place for other entries).
*
* @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise.
* @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
*/
public function save($id, $data, $lifeTime = 0);
@ -80,7 +83,8 @@ interface Cache
*
* @param string $id The cache id.
*
* @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise.
* @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
* Deleting a non-existing entry is considered successful.
*/
public function delete($id);

View file

@ -29,7 +29,7 @@ namespace Doctrine\Common\Cache;
* @author Roman Borschel <roman@code-factory.org>
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiGetCache
abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiGetCache, MultiPutCache
{
const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]';
@ -83,6 +83,10 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
*/
public function fetchMultiple(array $keys)
{
if (empty($keys)) {
return array();
}
// note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys
$namespacedKeys = array_combine($keys, array_map(array($this, 'getNamespacedId'), $keys));
$items = $this->doFetchMultiple($namespacedKeys);
@ -91,7 +95,7 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
// no internal array function supports this sort of mapping: needs to be iterative
// this filters and combines keys in one pass
foreach ($namespacedKeys as $requestedKey => $namespacedKey) {
if (isset($items[$namespacedKey])) {
if (isset($items[$namespacedKey]) || array_key_exists($namespacedKey, $items)) {
$foundItems[$requestedKey] = $items[$namespacedKey];
}
}
@ -99,6 +103,19 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
return $foundItems;
}
/**
* {@inheritdoc}
*/
public function saveMultiple(array $keysAndValues, $lifetime = 0)
{
$namespacedKeysAndValues = array();
foreach ($keysAndValues as $key => $value) {
$namespacedKeysAndValues[$this->getNamespacedId($key)] = $value;
}
return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime);
}
/**
* {@inheritdoc}
*/
@ -147,9 +164,13 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
$namespaceCacheKey = $this->getNamespaceCacheKey();
$namespaceVersion = $this->getNamespaceVersion() + 1;
$this->namespaceVersion = $namespaceVersion;
if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
$this->namespaceVersion = $namespaceVersion;
return $this->doSave($namespaceCacheKey, $namespaceVersion);
return true;
}
return false;
}
/**
@ -188,15 +209,7 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
}
$namespaceCacheKey = $this->getNamespaceCacheKey();
$namespaceVersion = $this->doFetch($namespaceCacheKey);
if (false === $namespaceVersion) {
$namespaceVersion = 1;
$this->doSave($namespaceCacheKey, $namespaceVersion);
}
$this->namespaceVersion = $namespaceVersion;
$this->namespaceVersion = $this->doFetch($namespaceCacheKey) ?: 1;
return $this->namespaceVersion;
}
@ -211,8 +224,8 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
{
$returnValues = array();
foreach ($keys as $index => $key) {
if (false !== ($item = $this->doFetch($key))) {
foreach ($keys as $key) {
if (false !== ($item = $this->doFetch($key)) || $this->doContains($key)) {
$returnValues[$key] = $item;
}
}
@ -225,7 +238,7 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
*
* @param string $id The id of the cache entry to fetch.
*
* @return mixed|boolean The cached data or FALSE, if no cache entry exists for the given id.
* @return mixed|false The cached data or FALSE, if no cache entry exists for the given id.
*/
abstract protected function doFetch($id);
@ -234,10 +247,32 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
*
* @param string $id The cache id of the entry to check for.
*
* @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise.
* @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise.
*/
abstract protected function doContains($id);
/**
* Default implementation of doSaveMultiple. Each driver that supports multi-put should override it.
*
* @param array $keysAndValues Array of keys and values to save in cache
* @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these
* cache entries (0 => infinite lifeTime).
*
* @return bool TRUE if the operation was successful, FALSE if it wasn't.
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$success = true;
foreach ($keysAndValues as $key => $value) {
if (!$this->doSave($key, $value, $lifetime)) {
$success = false;
}
}
return $success;
}
/**
* Puts data into the cache.
*
@ -246,7 +281,7 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
* @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this
* cache entry (0 => infinite lifeTime).
*
* @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise.
* @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
*/
abstract protected function doSave($id, $data, $lifeTime = 0);
@ -255,14 +290,14 @@ abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, M
*
* @param string $id The cache id.
*
* @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise.
* @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
*/
abstract protected function doDelete($id);
/**
* Flushes all cache entries.
*
* @return boolean TRUE if the cache entries were successfully flushed, FALSE otherwise.
* @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
*/
abstract protected function doFlush();

View file

@ -34,7 +34,7 @@ interface ClearableCache
/**
* Deletes all cache entries in the current cache namespace.
*
* @return boolean TRUE if the cache entries were successfully deleted, FALSE otherwise.
* @return bool TRUE if the cache entries were successfully deleted, FALSE otherwise.
*/
public function deleteAll();
}

View file

@ -24,6 +24,7 @@ namespace Doctrine\Common\Cache;
*
* @since 2.3
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @author Tobias Schultze <http://tobion.de>
*/
abstract class FileCache extends CacheProvider
{
@ -42,22 +43,24 @@ abstract class FileCache extends CacheProvider
private $extension;
/**
* @var string[] regular expressions for replacing disallowed characters in file name
* @var int
*/
private $disallowedCharacterPatterns = array(
'/\-/', // replaced to disambiguate original `-` and `-` derived from replacements
'/[^a-zA-Z0-9\-_\[\]]/' // also excludes non-ascii chars (not supported, depending on FS)
);
/**
* @var string[] replacements for disallowed file characters
*/
private $replacementCharacters = array('__', '-');
private $umask;
/**
* @var int
*/
private $umask;
private $directoryStringLength;
/**
* @var int
*/
private $extensionStringLength;
/**
* @var bool
*/
private $isRunningOnWindows;
/**
* Constructor.
@ -95,6 +98,10 @@ abstract class FileCache extends CacheProvider
// YES, this needs to be *after* createPathIfNeeded()
$this->directory = realpath($directory);
$this->extension = (string) $extension;
$this->directoryStringLength = strlen($this->directory);
$this->extensionStringLength = strlen($this->extension);
$this->isRunningOnWindows = defined('PHP_WINDOWS_VERSION_BUILD');
}
/**
@ -110,7 +117,7 @@ abstract class FileCache extends CacheProvider
/**
* Gets the cache file extension.
*
* @return string|null
* @return string
*/
public function getExtension()
{
@ -124,11 +131,29 @@ abstract class FileCache extends CacheProvider
*/
protected function getFilename($id)
{
$hash = hash('sha256', $id);
// This ensures that the filename is unique and that there are no invalid chars in it.
if (
'' === $id
|| ((strlen($id) * 2 + $this->extensionStringLength) > 255)
|| ($this->isRunningOnWindows && ($this->directoryStringLength + 4 + strlen($id) * 2 + $this->extensionStringLength) > 258)
) {
// Most filesystems have a limit of 255 chars for each path component. On Windows the the whole path is limited
// to 260 chars (including terminating null char). Using long UNC ("\\?\" prefix) does not work with the PHP API.
// And there is a bug in PHP (https://bugs.php.net/bug.php?id=70943) with path lengths of 259.
// So if the id in hex representation would surpass the limit, we use the hash instead. The prefix prevents
// collisions between the hash and bin2hex.
$filename = '_' . $hash;
} else {
$filename = bin2hex($id);
}
return $this->directory
. DIRECTORY_SEPARATOR
. implode(str_split(hash('sha256', $id), 2), DIRECTORY_SEPARATOR)
. substr($hash, 0, 2)
. DIRECTORY_SEPARATOR
. preg_replace($this->disallowedCharacterPatterns, $this->replacementCharacters, $id)
. $filename
. $this->extension;
}
@ -137,7 +162,9 @@ abstract class FileCache extends CacheProvider
*/
protected function doDelete($id)
{
return @unlink($this->getFilename($id));
$filename = $this->getFilename($id);
return @unlink($filename) || ! file_exists($filename);
}
/**
@ -146,7 +173,16 @@ abstract class FileCache extends CacheProvider
protected function doFlush()
{
foreach ($this->getIterator() as $name => $file) {
@unlink($name);
if ($file->isDir()) {
// Remove the intermediate directories which have been created to balance the tree. It only takes effect
// if the directory is empty. If several caches share the same directory but with different file extensions,
// the other ones are not removed.
@rmdir($name);
} elseif ($this->isFilenameEndingWithExtension($name)) {
// If an extension is set, only remove files which end with the given extension.
// If no extension is set, we have no other choice than removing everything.
@unlink($name);
}
}
return true;
@ -158,8 +194,10 @@ abstract class FileCache extends CacheProvider
protected function doGetStats()
{
$usage = 0;
foreach ($this->getIterator() as $file) {
$usage += $file->getSize();
foreach ($this->getIterator() as $name => $file) {
if (! $file->isDir() && $this->isFilenameEndingWithExtension($name)) {
$usage += $file->getSize();
}
}
$free = disk_free_space($this->directory);
@ -229,9 +267,20 @@ abstract class FileCache extends CacheProvider
*/
private function getIterator()
{
return new \RegexIterator(
new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory)),
'/^.+' . preg_quote($this->extension, '/') . '$/i'
return new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
}
/**
* @param string $name The filename
*
* @return bool
*/
private function isFilenameEndingWithExtension($name)
{
return '' === $this->extension
|| strrpos($name, $this->extension) === (strlen($name) - $this->extensionStringLength);
}
}

View file

@ -53,7 +53,7 @@ class FilesystemCache extends FileCache
$resource = fopen($filename, "r");
if (false !== ($line = fgets($resource))) {
$lifetime = (integer) $line;
$lifetime = (int) $line;
}
if ($lifetime !== 0 && $lifetime < time()) {
@ -86,7 +86,7 @@ class FilesystemCache extends FileCache
$resource = fopen($filename, "r");
if (false !== ($line = fgets($resource))) {
$lifetime = (integer) $line;
$lifetime = (int) $line;
}
fclose($resource);

View file

@ -31,7 +31,7 @@ interface FlushableCache
/**
* Flushes all cache entries, globally.
*
* @return boolean TRUE if the cache entries were successfully flushed, FALSE otherwise.
* @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
*/
public function flushAll();
}

View file

@ -97,7 +97,8 @@ class MemcacheCache extends CacheProvider
*/
protected function doDelete($id)
{
return $this->memcache->delete($id);
// Memcache::delete() returns false if entry does not exist
return $this->memcache->delete($id) || ! $this->doContains($id);
}
/**

View file

@ -74,7 +74,19 @@ class MemcachedCache extends CacheProvider
*/
protected function doFetchMultiple(array $keys)
{
return $this->memcached->getMulti($keys);
return $this->memcached->getMulti($keys) ?: [];
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
if ($lifetime > 30 * 24 * 3600) {
$lifetime = time() + $lifetime;
}
return $this->memcached->setMulti($keysAndValues, $lifetime);
}
/**
@ -82,7 +94,8 @@ class MemcachedCache extends CacheProvider
*/
protected function doContains($id)
{
return (false !== $this->memcached->get($id));
return false !== $this->memcached->get($id)
|| $this->memcached->getResultCode() !== Memcached::RES_NOTFOUND;
}
/**
@ -101,7 +114,8 @@ class MemcachedCache extends CacheProvider
*/
protected function doDelete($id)
{
return $this->memcached->delete($id);
return $this->memcached->delete($id)
|| $this->memcached->getResultCode() === Memcached::RES_NOTFOUND;
}
/**

View file

@ -21,6 +21,7 @@ namespace Doctrine\Common\Cache;
use MongoBinData;
use MongoCollection;
use MongoCursorException;
use MongoDate;
/**
@ -41,7 +42,7 @@ class MongoDBCache extends CacheProvider
* cache entry should expire.
*
* With MongoDB 2.2+, entries can be automatically deleted by MongoDB by
* indexing this field wit the "expireAfterSeconds" option equal to zero.
* indexing this field with the "expireAfterSeconds" option equal to zero.
* This will direct MongoDB to regularly query for and delete any entries
* whose date is older than the current time. Entries without a date value
* in this field will be ignored.
@ -119,14 +120,18 @@ class MongoDBCache extends CacheProvider
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$result = $this->collection->update(
array('_id' => $id),
array('$set' => array(
self::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
self::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
)),
array('upsert' => true, 'multiple' => false)
);
try {
$result = $this->collection->update(
array('_id' => $id),
array('$set' => array(
self::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
self::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
)),
array('upsert' => true, 'multiple' => false)
);
} catch (MongoCursorException $e) {
return false;
}
return isset($result['ok']) ? $result['ok'] == 1 : true;
}
@ -138,7 +143,7 @@ class MongoDBCache extends CacheProvider
{
$result = $this->collection->remove(array('_id' => $id));
return isset($result['n']) ? $result['n'] == 1 : true;
return isset($result['ok']) ? $result['ok'] == 1 : true;
}
/**
@ -170,8 +175,8 @@ class MongoDBCache extends CacheProvider
return array(
Cache::STATS_HITS => null,
Cache::STATS_MISSES => null,
Cache::STATS_UPTIME => (isset($serverStatus['uptime']) ? (integer) $serverStatus['uptime'] : null),
Cache::STATS_MEMORY_USAGE => (isset($collStats['size']) ? (integer) $collStats['size'] : null),
Cache::STATS_UPTIME => (isset($serverStatus['uptime']) ? (int) $serverStatus['uptime'] : null),
Cache::STATS_MEMORY_USAGE => (isset($collStats['size']) ? (int) $collStats['size'] : null),
Cache::STATS_MEMORY_AVAILABLE => null,
);
}
@ -180,7 +185,8 @@ class MongoDBCache extends CacheProvider
* Check if the document is expired.
*
* @param array $document
* @return boolean
*
* @return bool
*/
private function isExpired(array $document)
{

View file

@ -0,0 +1,41 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common\Cache;
/**
* Interface for cache drivers that allows to put many items at once.
*
* @link www.doctrine-project.org
* @since 1.6
* @author Daniel Gorgan <danut007ro@gmail.com>
*/
interface MultiPutCache
{
/**
* Returns a boolean value indicating if the operation succeeded.
*
* @param array $keysAndValues Array of keys and values to save in cache
* @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these
* cache entries (0 => infinite lifeTime).
*
* @return bool TRUE if the operation was successful, FALSE if it wasn't.
*/
function saveMultiple(array $keysAndValues, $lifetime = 0);
}

View file

@ -2,7 +2,7 @@
namespace Doctrine\Common\Cache;
use Predis\Client;
use Predis\ClientInterface;
/**
* Predis cache provider.
@ -12,16 +12,16 @@ use Predis\Client;
class PredisCache extends CacheProvider
{
/**
* @var Client
* @var ClientInterface
*/
private $client;
/**
* @param Client $client
* @param ClientInterface $client
*
* @return void
*/
public function __construct(Client $client)
public function __construct(ClientInterface $client)
{
$this->client = $client;
}
@ -46,14 +46,43 @@ class PredisCache extends CacheProvider
{
$fetchedItems = call_user_func_array(array($this->client, 'mget'), $keys);
return array_filter(array_combine($keys, array_map('unserialize', $fetchedItems)));
return array_map('unserialize', array_filter(array_combine($keys, $fetchedItems)));
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
if ($lifetime) {
$success = true;
// Keys have lifetime, use SETEX for each of them
foreach ($keysAndValues as $key => $value) {
$response = $this->client->setex($key, $lifetime, serialize($value));
if ((string) $response != 'OK') {
$success = false;
}
}
return $success;
}
// No lifetime, use MSET
$response = $this->client->mset(array_map(function ($value) {
return serialize($value);
}, $keysAndValues));
return (string) $response == 'OK';
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return $this->client->exists($id);
return (bool) $this->client->exists($id);
}
/**
@ -76,7 +105,7 @@ class PredisCache extends CacheProvider
*/
protected function doDelete($id)
{
return $this->client->del($id) > 0;
return $this->client->del($id) >= 0;
}
/**

View file

@ -71,7 +71,40 @@ class RedisCache extends CacheProvider
*/
protected function doFetchMultiple(array $keys)
{
return array_filter(array_combine($keys, $this->redis->mget($keys)));
$fetchedItems = array_combine($keys, $this->redis->mget($keys));
// Redis mget returns false for keys that do not exist. So we need to filter those out unless it's the real data.
$foundItems = array();
foreach ($fetchedItems as $key => $value) {
if (false !== $value || $this->redis->exists($key)) {
$foundItems[$key] = $value;
}
}
return $foundItems;
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
if ($lifetime) {
$success = true;
// Keys have lifetime, use SETEX for each of them
foreach ($keysAndValues as $key => $value) {
if (!$this->redis->setex($key, $lifetime, $value)) {
$success = false;
}
}
return $success;
}
// No lifetime, use MSET
return (bool) $this->redis->mset($keysAndValues);
}
/**
@ -99,7 +132,7 @@ class RedisCache extends CacheProvider
*/
protected function doDelete($id)
{
return $this->redis->delete($id) > 0;
return $this->redis->delete($id) >= 0;
}
/**
@ -137,6 +170,11 @@ class RedisCache extends CacheProvider
if (defined('HHVM_VERSION')) {
return Redis::SERIALIZER_PHP;
}
return defined('Redis::SERIALIZER_IGBINARY') ? Redis::SERIALIZER_IGBINARY : Redis::SERIALIZER_PHP;
if (defined('Redis::SERIALIZER_IGBINARY') && extension_loaded('igbinary')) {
return Redis::SERIALIZER_IGBINARY;
}
return Redis::SERIALIZER_PHP;
}
}

View file

@ -202,7 +202,7 @@ class RiakCache extends CacheProvider
*
* @param \Riak\Object $object
*
* @return boolean
* @return bool
*/
private function isExpired(Object $object)
{

View file

@ -98,7 +98,7 @@ class SQLite3Cache extends CacheProvider
*/
protected function doContains($id)
{
return (boolean) $this->findById($id, false);
return null !== $this->findById($id, false);
}
/**
@ -157,7 +157,7 @@ class SQLite3Cache extends CacheProvider
* Find a single row by ID.
*
* @param mixed $id
* @param boolean $includeData
* @param bool $includeData
*
* @return array|null
*/
@ -208,7 +208,8 @@ class SQLite3Cache extends CacheProvider
* Check if the item is expired.
*
* @param array $item
* @return boolean
*
* @return bool
*/
private function isExpired(array $item)
{

View file

@ -21,5 +21,5 @@ namespace Doctrine\Common\Cache;
class Version
{
const VERSION = '1.4.0-DEV';
const VERSION = '1.6.1-DEV';
}

View file

@ -53,7 +53,7 @@ class WinCacheCache extends CacheProvider
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return (bool) wincache_ucache_set($id, $data, (int) $lifeTime);
return wincache_ucache_set($id, $data, $lifeTime);
}
/**
@ -72,6 +72,24 @@ class WinCacheCache extends CacheProvider
return wincache_ucache_clear();
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
return wincache_ucache_get($keys);
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$result = wincache_ucache_set($keysAndValues, null, $lifetime);
return empty($result);
}
/**
* {@inheritdoc}
*/

View file

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./tests/Doctrine/Tests/TestInit.php"
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Doctrine Cache Test Suite">
<directory>./tests/Doctrine/</directory>