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>

View file

@ -1 +0,0 @@
vendor/

View file

@ -1,21 +0,0 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
- hhvm-nightly
matrix:
fast_finish: true
allow_failures:
- php: 7.0
before_script:
- composer --prefer-source install
script:
- phpunit

View file

@ -0,0 +1,67 @@
# Contribute to Doctrine
Thank you for contributing to Doctrine!
Before we can merge your Pull-Request here are some guidelines that you need to follow.
These guidelines exist not to annoy you, but to keep the code base clean,
unified and future proof.
## We only accept PRs to "master"
Our branching strategy is "everything to master first", even
bugfixes and we then merge them into the stable branches. You should only
open pull requests against the master branch. Otherwise we cannot accept the PR.
There is one exception to the rule, when we merged a bug into some stable branches
we do occasionally accept pull requests that merge the same bug fix into earlier
branches.
## Coding Standard
We use [doctrine coding standard](https://github.com/doctrine/coding-standard) which is PSR-1 and PSR-2:
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
with some exceptions/differences:
* Keep the nesting of control structures per method as small as possible
* Align equals (=) signs
* Add spaces between assignment, control and return statements
* Prefer early exit over nesting conditions
* Add spaces around a negation if condition ``if ( ! $cond)``
* Add legal information at the beginning of each source file
* Add ``@author`` [phpDoc](https://www.phpdoc.org/docs/latest/references/phpdoc/tags/author.html) comment at DockBlock of class/interface/trait that you create.
## Unit-Tests
Please try to add a test for your pull-request.
* If you want to contribute new functionality add unit- or functional tests
depending on the scope of the feature.
You can run the unit-tests by calling ``vendor/bin/phpunit`` from the root of the project.
It will run all the project tests.
In order to do that, you will need a fresh copy of doctrine/collections, and you
will have to run a composer installation in the project:
```sh
git clone git@github.com:doctrine/collections.git
cd collections
curl -sS https://getcomposer.org/installer | php --
./composer.phar install
```
## Travis
We automatically run your pull request through [Travis CI](https://www.travis-ci.org)
against supported PHP versions. If you break the tests, we cannot merge your code,
so please make sure that your code is working before opening up a Pull-Request.
## Getting merged
Please allow us time to review your pull requests. We will give our best to review
everything as fast as possible, but cannot always live up to our own expectations.
Thank you very much again for your contribution!

View file

@ -1,6 +1,8 @@
# Doctrine Collections
[![Build Status](https://travis-ci.org/doctrine/collections.svg?branch=master)](https://travis-ci.org/doctrine/collections)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/collections/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/collections/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/doctrine/collections/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/collections/?branch=master)
Collections Abstraction library

View file

@ -13,17 +13,23 @@
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": ">=5.3.2"
"php": "^5.6 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
"phpunit/phpunit": "^5.7",
"doctrine/coding-standard": "~0.1@dev"
},
"autoload": {
"psr-0": { "Doctrine\\Common\\Collections\\": "lib/" }
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Tests\\": "tests/Doctrine/Tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
"dev-master": "1.3.x-dev"
}
}
}

View file

@ -26,6 +26,11 @@ use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
/**
* An ArrayCollection is a Collection implementation that wraps a regular PHP array.
*
* Warning: Using (un-)serialize() on a collection is not a supported use-case
* and may break when we change the internals in the future. If you need to
* serialize a collection use {@link toArray()} and reconstruct the collection
* manually.
*
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
@ -50,6 +55,21 @@ class ArrayCollection implements Collection, Selectable
$this->elements = $elements;
}
/**
* Creates a new instance from the specified elements.
*
* This method is provided for derived classes to specify how a new
* instance should be created when constructor semantics have changed.
*
* @param array $elements Elements.
*
* @return static
*/
protected function createFrom(array $elements)
{
return new static($elements);
}
/**
* {@inheritDoc}
*/
@ -254,9 +274,9 @@ class ArrayCollection implements Collection, Selectable
/**
* {@inheritDoc}
*/
public function add($value)
public function add($element)
{
$this->elements[] = $value;
$this->elements[] = $element;
return true;
}
@ -284,7 +304,7 @@ class ArrayCollection implements Collection, Selectable
*/
public function map(Closure $func)
{
return new static(array_map($func, $this->elements));
return $this->createFrom(array_map($func, $this->elements));
}
/**
@ -292,7 +312,7 @@ class ArrayCollection implements Collection, Selectable
*/
public function filter(Closure $p)
{
return new static(array_filter($this->elements, $p));
return $this->createFrom(array_filter($this->elements, $p));
}
/**
@ -324,7 +344,7 @@ class ArrayCollection implements Collection, Selectable
}
}
return array(new static($matches), new static($noMatches));
return array($this->createFrom($matches), $this->createFrom($noMatches));
}
/**
@ -368,8 +388,9 @@ class ArrayCollection implements Collection, Selectable
}
if ($orderings = $criteria->getOrderings()) {
$next = null;
foreach (array_reverse($orderings) as $field => $ordering) {
$next = ClosureExpressionVisitor::sortByField($field, $ordering == Criteria::DESC ? -1 : 1);
$next = ClosureExpressionVisitor::sortByField($field, $ordering == Criteria::DESC ? -1 : 1, $next);
}
uasort($filtered, $next);
@ -382,6 +403,6 @@ class ArrayCollection implements Collection, Selectable
$filtered = array_slice($filtered, (int)$offset, $length);
}
return new static($filtered);
return $this->createFrom($filtered);
}
}

View file

@ -69,6 +69,24 @@ class ClosureExpressionVisitor extends ExpressionVisitor
return $object[$field];
}
if (isset($object->$field)) {
return $object->$field;
}
// camelcase field name to support different variable naming conventions
$ccField = preg_replace_callback('/_(.?)/', function($matches) { return strtoupper($matches[1]); }, $field);
foreach ($accessors as $accessor) {
$accessor .= $ccField;
if ( ! method_exists($object, $accessor)) {
continue;
}
return $object->$accessor();
}
return $object->$field;
}
@ -155,6 +173,26 @@ class ClosureExpressionVisitor extends ExpressionVisitor
return false !== strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
};
case Comparison::MEMBER_OF:
return function ($object) use ($field, $value) {
$fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
if (!is_array($fieldValues)) {
$fieldValues = iterator_to_array($fieldValues);
}
return in_array($value, $fieldValues);
};
case Comparison::STARTS_WITH:
return function ($object) use ($field, $value) {
return 0 === strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
};
case Comparison::ENDS_WITH:
return function ($object) use ($field, $value) {
return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value));
};
default:
throw new \RuntimeException("Unknown comparison operator: " . $comparison->getOperator());
}

View file

@ -27,17 +27,19 @@ namespace Doctrine\Common\Collections\Expr;
*/
class Comparison implements Expression
{
const EQ = '=';
const NEQ = '<>';
const LT = '<';
const LTE = '<=';
const GT = '>';
const GTE = '>=';
const IS = '='; // no difference with EQ
const IN = 'IN';
const NIN = 'NIN';
const CONTAINS = 'CONTAINS';
const EQ = '=';
const NEQ = '<>';
const LT = '<';
const LTE = '<=';
const GT = '>';
const GTE = '>=';
const IS = '='; // no difference with EQ
const IN = 'IN';
const NIN = 'NIN';
const CONTAINS = 'CONTAINS';
const MEMBER_OF = 'MEMBER_OF';
const STARTS_WITH = 'STARTS_WITH';
const ENDS_WITH = 'ENDS_WITH';
/**
* @var string
*/

View file

@ -27,7 +27,7 @@ use Doctrine\Common\Collections\Expr\Value;
* Builder for Expressions in the {@link Selectable} interface.
*
* Important Notice for interoperable code: You have to use scalar
* values only for comparisons, otherwise the behavior of the comparision
* values only for comparisons, otherwise the behavior of the comparison
* may be different between implementations (Array vs ORM vs ODM).
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
@ -163,4 +163,38 @@ class ExpressionBuilder
{
return new Comparison($field, Comparison::CONTAINS, new Value($value));
}
/**
* @param string $field
* @param mixed $value
*
* @return Comparison
*/
public function memberOf ($field, $value)
{
return new Comparison($field, Comparison::MEMBER_OF, new Value($value));
}
/**
* @param string $field
* @param mixed $value
*
* @return Comparison
*/
public function startsWith($field, $value)
{
return new Comparison($field, Comparison::STARTS_WITH, new Value($value));
}
/**
* @param string $field
* @param mixed $value
*
* @return Comparison
*/
public function endsWith($field, $value)
{
return new Comparison($field, Comparison::ENDS_WITH, new Value($value));
}
}

View file

@ -1,31 +0,0 @@
<?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"
>
<testsuites>
<testsuite name="Doctrine Collections Test Suite">
<directory>./tests/Doctrine/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./lib/Doctrine/</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
</exclude>
</groups>
</phpunit>

View file

@ -1,10 +0,0 @@
build/
logs/
reports/
dist/
tests/Doctrine/Tests/Common/Proxy/generated/
vendor/
.idea
composer.lock
doctrine-common-*.tar
doctrine-common-*.tar.gz

View file

@ -1,3 +0,0 @@
[submodule "lib/vendor/doctrine-build-common"]
path = lib/vendor/doctrine-build-common
url = git://github.com/doctrine/doctrine-build-common.git

View file

@ -1,26 +0,0 @@
language: php
sudo: false
cache:
directory:
- $HOME/.composer/cache
php:
- 5.3.3
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
before_script:
- composer --prefer-source install
script:
- ./vendor/bin/phpunit
matrix:
allow_failures:
- 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

@ -1,3 +0,0 @@
# Version class and file
project.version_class = Doctrine\\Common\\Version
project.version_file = lib/Doctrine/Common/Version.php

View file

@ -1,101 +0,0 @@
<?xml version="1.0"?>
<project name="DoctrineCommon" default="build" basedir=".">
<property file="build.properties" />
<target name="php">
<exec executable="which" outputproperty="php_executable">
<arg value="php" />
</exec>
</target>
<target name="prepare">
<mkdir dir="build" />
</target>
<target name="build" depends="check-git-checkout-clean,prepare,php,composer">
<exec executable="${php_executable}">
<arg value="build/composer.phar" />
<arg value="archive" />
<arg value="--dir=build" />
</exec>
</target>
<target name="composer" depends="php,composer-check,composer-download">
<exec executable="${php_executable}">
<arg value="build/composer.phar" />
<arg value="install" />
</exec>
</target>
<target name="composer-check" depends="prepare">
<available file="build/composer.phar" property="composer.present"/>
</target>
<target name="composer-download" unless="composer.present">
<exec executable="wget">
<arg value="-Obuild/composer.phar" />
<arg value="http://getcomposer.org/composer.phar" />
</exec>
</target>
<target name="make-release" depends="check-git-checkout-clean,prepare,php">
<replace file="${project.version_file}" token="-DEV" value="" failOnNoReplacements="true" />
<exec executable="${php_executable}" outputproperty="doctrine.current_version" failonerror="true">
<arg value="-r" />
<arg value="require_once '${project.version_file}';echo ${project.version_class}::VERSION;" />
</exec>
<exec executable="${php_executable}" outputproperty="doctrine.next_version" failonerror="true">
<arg value="-r" />
<arg value="$parts = explode('.', str_ireplace(array('-DEV', '-ALPHA', '-BETA'), '', '${doctrine.current_version}'));
if (count($parts) != 3) {
throw new \InvalidArgumentException('Version is assumed in format x.y.z, ${doctrine.current_version} given');
}
$parts[2]++;
echo implode('.', $parts);
" />
</exec>
<git-commit file="${project.version_file}" message="Release ${doctrine.current_version}" />
<git-tag version="${doctrine.current_version}" />
<replace file="${project.version_file}" token="${doctrine.current_version}" value="${doctrine.next_version}-DEV" />
<git-commit file="${project.version_file}" message="Bump version to ${doctrine.next_version}" />
</target>
<target name="check-git-checkout-clean">
<exec executable="git" failonerror="true">
<arg value="diff-index" />
<arg value="--quiet" />
<arg value="HEAD" />
</exec>
</target>
<macrodef name="git-commit">
<attribute name="file" default="NOT SET"/>
<attribute name="message" default="NOT SET"/>
<sequential>
<exec executable="git">
<arg value="add" />
<arg value="@{file}" />
</exec>
<exec executable="git">
<arg value="commit" />
<arg value="-m" />
<arg value="@{message}" />
</exec>
</sequential>
</macrodef>
<macrodef name="git-tag">
<attribute name="version" default="NOT SET" />
<sequential>
<exec executable="git">
<arg value="tag" />
<arg value="-m" />
<arg value="v@{version}" />
<arg value="v@{version}" />
</exec>
</sequential>
</macrodef>
</project>

View file

@ -13,26 +13,24 @@
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": ">=5.3.2",
"php": "~5.6|~7.0",
"doctrine/inflector": "1.*",
"doctrine/cache": "1.*",
"doctrine/collections": "1.*",
"doctrine/lexer": "1.*",
"doctrine/annotations": "1.*"
},
"minimum-stability": "dev",
"require-dev": {
"phpunit/phpunit": "~3.7"
"phpunit/phpunit": "^5.4.6"
},
"autoload": {
"psr-0": { "Doctrine\\Common\\": "lib/" }
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.6.x-dev"
"dev-master": "2.7.x-dev"
}
},
"archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar"]
}
}

View file

@ -0,0 +1,11 @@
{
"source": {
"directories": [
"lib\/Doctrine"
]
},
"timeout": 10,
"logs": {
"text": "reports/humbuglog.txt"
}
}

View file

@ -153,7 +153,7 @@ class ClassLoader
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
spl_autoload_register([$this, 'loadClass']);
}
/**
@ -163,7 +163,7 @@ class ClassLoader
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
spl_autoload_unregister([$this, 'loadClass']);
}
/**
@ -275,6 +275,6 @@ class ClassLoader
{
return class_exists($type, $autoload)
|| interface_exists($type, $autoload)
|| (function_exists('trait_exists') && trait_exists($type, $autoload));
|| trait_exists($type, $autoload);
}
}

View file

@ -38,7 +38,7 @@ class EventManager
*
* @var array
*/
private $_listeners = array();
private $_listeners = [];
/**
* Dispatches an event to all registered listeners.

View file

@ -141,7 +141,7 @@ abstract class AbstractManagerRegistry implements ManagerRegistry
*/
public function getConnections()
{
$connections = array();
$connections = [];
foreach ($this->connections as $name => $id) {
$connections[$name] = $this->getService($id);
}
@ -195,8 +195,13 @@ abstract class AbstractManagerRegistry implements ManagerRegistry
}
$proxyClass = new \ReflectionClass($class);
if ($proxyClass->implementsInterface($this->proxyInterfaceName)) {
$class = $proxyClass->getParentClass()->getName();
if (! $parentClass = $proxyClass->getParentClass()) {
return null;
}
$class = $parentClass->getName();
}
foreach ($this->managers as $id) {
@ -221,7 +226,7 @@ abstract class AbstractManagerRegistry implements ManagerRegistry
*/
public function getManagers()
{
$dms = array();
$dms = [];
foreach ($this->managers as $name => $id) {
$dms[$name] = $this->getService($id);
}
@ -253,5 +258,7 @@ abstract class AbstractManagerRegistry implements ManagerRegistry
// force the creation of a new document manager
// if the current one is closed
$this->resetService($this->managers[$name]);
return $this->getManager($name);
}
}

View file

@ -53,7 +53,7 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
/**
* @var ClassMetadata[]
*/
private $loadedMetadata = array();
private $loadedMetadata = [];
/**
* @var bool
@ -110,7 +110,7 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
}
$driver = $this->getDriver();
$metadata = array();
$metadata = [];
foreach ($driver->getAllClassNames() as $className) {
$metadata[] = $this->getMetadataFor($className);
}
@ -208,7 +208,7 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
try {
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) !== false) {
if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) instanceof ClassMetadata) {
$this->loadedMetadata[$realClassName] = $cached;
$this->wakeupReflection($cached, $this->getReflectionService());
@ -277,7 +277,7 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
protected function getParentClasses($name)
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
$parentClasses = [];
foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
if ( ! $this->getDriver()->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
@ -306,7 +306,7 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
$this->initialize();
}
$loaded = array();
$loaded = [];
$parentClasses = $this->getParentClasses($name);
$parentClasses[] = $name;
@ -314,7 +314,7 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
// Move down the hierarchy of parent classes, starting from the topmost class
$parent = null;
$rootEntityFound = false;
$visited = array();
$visited = [];
$reflService = $this->getReflectionService();
foreach ($parentClasses as $className) {
if (isset($this->loadedMetadata[$className])) {

View file

@ -45,14 +45,14 @@ abstract class AnnotationDriver implements MappingDriver
*
* @var array
*/
protected $paths = array();
protected $paths = [];
/**
* The paths excluded from path where to look for mapping files.
*
* @var array
*/
protected $excludePaths = array();
protected $excludePaths = [];
/**
* The file extension of mapping documents.
@ -73,7 +73,7 @@ abstract class AnnotationDriver implements MappingDriver
*
* @var array
*/
protected $entityAnnotationClasses = array();
protected $entityAnnotationClasses = [];
/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
@ -200,8 +200,8 @@ abstract class AnnotationDriver implements MappingDriver
throw MappingException::pathRequired();
}
$classes = array();
$includedFiles = array();
$classes = [];
$includedFiles = [];
foreach ($this->paths as $path) {
if ( ! is_dir($path)) {

View file

@ -37,7 +37,7 @@ class DefaultFileLocator implements FileLocator
*
* @var array
*/
protected $paths = array();
protected $paths = [];
/**
* The file extension of mapping documents.
@ -125,7 +125,7 @@ class DefaultFileLocator implements FileLocator
*/
public function getAllClassNames($globalBasename)
{
$classes = array();
$classes = [];
if ($this->paths) {
foreach ($this->paths as $path) {

View file

@ -117,6 +117,8 @@ abstract class FileDriver implements MappingDriver
throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->locator->getFileExtension());
}
$this->classCache[$className] = $result[$className];
return $result[$className];
}
@ -145,11 +147,14 @@ abstract class FileDriver implements MappingDriver
$this->initialize();
}
$classNames = (array)$this->locator->getAllClassNames($this->globalBasename);
if ($this->classCache) {
$classNames = array_merge(array_keys($this->classCache), $classNames);
if (! $this->classCache) {
return (array) $this->locator->getAllClassNames($this->globalBasename);
}
return $classNames;
return array_merge(
array_keys($this->classCache),
(array) $this->locator->getAllClassNames($this->globalBasename)
);
}
/**
@ -175,7 +180,7 @@ abstract class FileDriver implements MappingDriver
*/
protected function initialize()
{
$this->classCache = array();
$this->classCache = [];
if (null !== $this->globalBasename) {
foreach ($this->locator->getPaths() as $path) {
$file = $path.'/'.$this->globalBasename.$this->locator->getFileExtension();

View file

@ -39,12 +39,12 @@ class MappingDriverChain implements MappingDriver
*
* @var MappingDriver|null
*/
private $defaultDriver = null;
private $defaultDriver;
/**
* @var array
*/
private $drivers = array();
private $drivers = [];
/**
* Gets the default driver.
@ -117,8 +117,8 @@ class MappingDriverChain implements MappingDriver
*/
public function getAllClassNames()
{
$classNames = array();
$driverClasses = array();
$classNames = [];
$driverClasses = [];
/* @var $driver MappingDriver */
foreach ($this->drivers AS $namespace => $driver) {

View file

@ -44,8 +44,7 @@ class PHPDriver extends FileDriver
*/
public function __construct($locator, $fileExtension = null)
{
$fileExtension = ".php";
parent::__construct($locator, $fileExtension);
parent::__construct($locator, '.php');
}
/**
@ -54,6 +53,7 @@ class PHPDriver extends FileDriver
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
$this->metadata = $metadata;
$this->loadMappingFile($this->locator->findMappingFile($className));
}
@ -65,6 +65,6 @@ class PHPDriver extends FileDriver
$metadata = $this->metadata;
include $file;
return array($metadata->getName() => $metadata);
return [$metadata->getName() => $metadata];
}
}

View file

@ -40,7 +40,7 @@ class StaticPHPDriver implements MappingDriver
*
* @var array
*/
private $paths = array();
private $paths = [];
/**
* Map of all class names.
@ -93,8 +93,8 @@ class StaticPHPDriver implements MappingDriver
throw MappingException::pathRequired();
}
$classes = array();
$includedFiles = array();
$classes = [];
$includedFiles = [];
foreach ($this->paths as $path) {
if (!is_dir($path)) {

View file

@ -37,14 +37,14 @@ class SymfonyFileLocator implements FileLocator
*
* @var array
*/
protected $paths = array();
protected $paths = [];
/**
* A map of mapping directory path to namespace prefix used to expand class shortnames.
*
* @var array
*/
protected $prefixes = array();
protected $prefixes = [];
/**
* File extension that is searched for.
@ -153,7 +153,9 @@ class SymfonyFileLocator implements FileLocator
}
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', $this->nsSeparator).$this->fileExtension;
return is_file($filename);
if (is_file($filename)) {
return true;
}
}
return false;
@ -164,7 +166,7 @@ class SymfonyFileLocator implements FileLocator
*/
public function getAllClassNames($globalBasename = null)
{
$classes = array();
$classes = [];
if ($this->paths) {
foreach ((array) $this->paths as $path) {
@ -194,7 +196,7 @@ class SymfonyFileLocator implements FileLocator
'\\'
);
$classes[] = $this->prefixes[$path] . $nsSuffix . '\\' .str_replace($this->nsSeparator, '\\', $fileName);
$classes[] = $this->prefixes[$path] . str_replace(DIRECTORY_SEPARATOR, '\\', $nsSuffix) . '\\' .str_replace($this->nsSeparator, '\\', $fileName);
} else {
$classes[] = str_replace($this->nsSeparator, '\\', $fileName);
}
@ -230,8 +232,6 @@ class SymfonyFileLocator implements FileLocator
if (is_file($filename)) {
return $filename;
}
throw MappingException::mappingFileNotFound($className, $filename);
}
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->fileExtension);

View file

@ -31,7 +31,7 @@ class StaticReflectionService implements ReflectionService
*/
public function getParentClasses($class)
{
return array();
return [];
}
/**

View file

@ -34,7 +34,7 @@ interface ObjectRepository
*
* @param mixed $id The identifier.
*
* @return object The object.
* @return object|null The object.
*/
public function find($id);
@ -68,7 +68,7 @@ interface ObjectRepository
*
* @param array $criteria The criteria.
*
* @return object The object.
* @return object|null The object.
*/
public function findOneBy(array $criteria);

View file

@ -198,7 +198,7 @@ abstract class PersistentObject implements ObjectManagerAware
throw new \InvalidArgumentException("Expected persistent object of type '".$targetClass."'");
}
if (!($this->$field instanceof Collection)) {
$this->$field = new ArrayCollection($this->$field ?: array());
$this->$field = new ArrayCollection($this->$field ?: []);
}
$this->$field->add($args[0]);
$this->completeOwningSide($field, $targetClass, $args[0]);

View file

@ -87,7 +87,7 @@ abstract class AbstractProxyFactory
/**
* @var \Doctrine\Common\Proxy\ProxyDefinition[]
*/
private $definitions = array();
private $definitions = [];
/**
* @param \Doctrine\Common\Proxy\ProxyGenerator $proxyGenerator

View file

@ -49,9 +49,13 @@ class Autoloader
throw InvalidArgumentException::notProxyClass($className, $proxyNamespace);
}
$className = str_replace('\\', '', substr($className, strlen($proxyNamespace) + 1));
// remove proxy namespace from class name
$classNameRelativeToProxyNamespace = substr($className, strlen($proxyNamespace));
return $proxyDir . DIRECTORY_SEPARATOR . $className . '.php';
// remove namespace separators from remaining class name
$fileName = str_replace('\\', '', $classNameRelativeToProxyNamespace);
return $proxyDir . DIRECTORY_SEPARATOR . $fileName . '.php';
}
/**

View file

@ -41,15 +41,19 @@ class UnexpectedValueException extends BaseUnexpectedValueException implements P
}
/**
* @param string $className
* @param string $methodName
* @param string $parameterName
* @param \Exception $previous
* @param string $className
* @param string $methodName
* @param string $parameterName
* @param \Exception|null $previous
*
* @return self
*/
public static function invalidParameterTypeHint($className, $methodName, $parameterName, \Exception $previous)
{
public static function invalidParameterTypeHint(
$className,
$methodName,
$parameterName,
\Exception $previous = null
) {
return new self(
sprintf(
'The type hint of parameter "%s" in method "%s" in class "%s" is invalid.',
@ -61,4 +65,24 @@ class UnexpectedValueException extends BaseUnexpectedValueException implements P
$previous
);
}
/**
* @param $className
* @param $methodName
* @param \Exception|null $previous
*
* @return self
*/
public static function invalidReturnTypeHint($className, $methodName, \Exception $previous = null)
{
return new self(
sprintf(
'The return type of method "%s" in class "%s" is invalid.',
$methodName,
$className
),
0,
$previous
);
}
}

View file

@ -37,7 +37,7 @@ class ProxyGenerator
* Used to match very simple id methods that don't need
* to be decorated since the identifier is known.
*/
const PATTERN_MATCH_ID_METHOD = '((public\s+)?(function\s+%s\s*\(\)\s*)\s*{\s*return\s*\$this->%s;\s*})i';
const PATTERN_MATCH_ID_METHOD = '((public\s+)?(function\s+%s\s*\(\)\s*)\s*(?::\s*\??\s*\\\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*\s*)?{\s*return\s*\$this->%s;\s*})i';
/**
* The namespace that contains all proxy classes.
@ -58,10 +58,10 @@ class ProxyGenerator
*
* @var string[]|callable[]
*/
protected $placeholders = array(
'baseProxyInterface' => 'Doctrine\Common\Proxy\Proxy',
protected $placeholders = [
'baseProxyInterface' => Proxy::class,
'additionalProperties' => '',
);
];
/**
* Template used as a blueprint to generate proxies.
@ -106,7 +106,7 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
*
* @see \Doctrine\Common\Persistence\Proxy::__getLazyProperties
*/
public static $lazyPropertiesDefaults = array(<lazyPropertiesDefaults>);
public static $lazyPropertiesDefaults = [<lazyPropertiesDefaults>];
<additionalProperties>
@ -129,7 +129,7 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
*/
public function __load()
{
$this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', array());
$this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', []);
}
/**
@ -263,12 +263,12 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
preg_match_all('(<([a-zA-Z]+)>)', $this->proxyClassTemplate, $placeholderMatches);
$placeholderMatches = array_combine($placeholderMatches[0], $placeholderMatches[1]);
$placeholders = array();
$placeholders = [];
foreach ($placeholderMatches as $placeholder => $name) {
$placeholders[$placeholder] = isset($this->placeholders[$name])
? $this->placeholders[$name]
: array($this, 'generate' . $name);
: [$this, 'generate' . $name];
}
foreach ($placeholders as & $placeholder) {
@ -302,7 +302,7 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
$tmpFileName = $fileName . '.' . uniqid('', true);
file_put_contents($tmpFileName, $proxyCode);
chmod($tmpFileName, 0664);
@chmod($tmpFileName, 0664);
rename($tmpFileName, $fileName);
}
@ -358,7 +358,7 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
private function generateLazyPropertiesDefaults(ClassMetadata $class)
{
$lazyPublicProperties = $this->getLazyLoadedPublicProperties($class);
$values = array();
$values = [];
foreach ($lazyPublicProperties as $key => $value) {
$values[] = var_export($key, true) . ' => ' . var_export($value, true);
@ -385,7 +385,7 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
{
EOT;
$toUnset = array();
$toUnset = [];
foreach ($this->getLazyLoadedPublicProperties($class) as $lazyPublicProperty => $unused) {
$toUnset[] = '$this->' . $lazyPublicProperty;
@ -443,7 +443,7 @@ EOT;
if ( ! empty($lazyPublicProperties)) {
$magicGet .= <<<'EOT'
if (array_key_exists($name, $this->__getLazyProperties())) {
$this->__initializer__ && $this->__initializer__->__invoke($this, '__get', array($name));
$this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]);
return $this->$name;
}
@ -454,7 +454,7 @@ EOT;
if ($hasParentGet) {
$magicGet .= <<<'EOT'
$this->__initializer__ && $this->__initializer__->__invoke($this, '__get', array($name));
$this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]);
return parent::__get($name);
@ -502,7 +502,7 @@ EOT;
if ( ! empty($lazyPublicProperties)) {
$magicSet .= <<<'EOT'
if (array_key_exists($name, $this->__getLazyProperties())) {
$this->__initializer__ && $this->__initializer__->__invoke($this, '__set', array($name, $value));
$this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]);
$this->$name = $value;
@ -515,7 +515,7 @@ EOT;
if ($hasParentSet) {
$magicSet .= <<<'EOT'
$this->__initializer__ && $this->__initializer__->__invoke($this, '__set', array($name, $value));
$this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]);
return parent::__set($name, $value);
EOT;
@ -559,7 +559,7 @@ EOT;
if ( ! empty($lazyPublicProperties)) {
$magicIsset .= <<<'EOT'
if (array_key_exists($name, $this->__getLazyProperties())) {
$this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', array($name));
$this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]);
return isset($this->$name);
}
@ -570,7 +570,7 @@ EOT;
if ($hasParentIsset) {
$magicIsset .= <<<'EOT'
$this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', array($name));
$this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]);
return parent::__isset($name);
@ -605,7 +605,7 @@ EOT;
if ($hasParentSleep) {
return $sleepImpl . <<<'EOT'
$properties = array_merge(array('__isInitialized__'), parent::__sleep());
$properties = array_merge(['__isInitialized__'], parent::__sleep());
if ($this->__isInitialized__) {
$properties = array_diff($properties, array_keys($this->__getLazyProperties()));
@ -616,7 +616,7 @@ EOT;
EOT;
}
$allProperties = array('__isInitialized__');
$allProperties = ['__isInitialized__'];
/* @var $prop \ReflectionProperty */
foreach ($class->getReflectionClass()->getProperties() as $prop) {
@ -645,10 +645,10 @@ EOT;
return $sleepImpl . <<<EOT
if (\$this->__isInitialized__) {
return array($allProperties);
return [$allProperties];
}
return array($protectedProperties);
return [$protectedProperties];
}
EOT;
}
@ -662,7 +662,7 @@ EOT;
*/
private function generateWakeupImpl(ClassMetadata $class)
{
$unsetPublicProperties = array();
$unsetPublicProperties = [];
$hasWakeup = $class->getReflectionClass()->hasMethod('__wakeup');
foreach (array_keys($this->getLazyLoadedPublicProperties($class)) as $lazyPublicProperty) {
@ -727,7 +727,7 @@ EOT;
*/
public function __clone()
{
\$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', array());
\$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', []);
$callParentClone }
EOT;
}
@ -742,16 +742,16 @@ EOT;
private function generateMethods(ClassMetadata $class)
{
$methods = '';
$methodNames = array();
$methodNames = [];
$reflectionMethods = $class->getReflectionClass()->getMethods(\ReflectionMethod::IS_PUBLIC);
$skippedMethods = array(
$skippedMethods = [
'__sleep' => true,
'__clone' => true,
'__wakeup' => true,
'__get' => true,
'__set' => true,
'__isset' => true,
);
];
foreach ($reflectionMethods as $method) {
$name = $method->getName();
@ -778,15 +778,18 @@ EOT;
}
$methods .= $name . '(' . $this->buildParametersString($class, $method, $method->getParameters()) . ')';
$methods .= $this->getMethodReturnType($method);
$methods .= "\n" . ' {' . "\n";
if ($this->isShortIdentifierGetter($method, $class)) {
$identifier = lcfirst(substr($name, 3));
$fieldType = $class->getTypeOfField($identifier);
$cast = in_array($fieldType, array('integer', 'smallint')) ? '(int) ' : '';
$cast = in_array($fieldType, ['integer', 'smallint']) ? '(int) ' : '';
$methods .= ' if ($this->__isInitialized__ === false) {' . "\n";
$methods .= ' return ' . $cast . ' parent::' . $method->getName() . "();\n";
$methods .= ' ';
$methods .= $this->shouldProxiedMethodReturn($method) ? 'return ' : '';
$methods .= $cast . ' parent::' . $method->getName() . "();\n";
$methods .= ' }' . "\n\n";
}
@ -795,8 +798,10 @@ EOT;
$methods .= "\n \$this->__initializer__ "
. "&& \$this->__initializer__->__invoke(\$this, " . var_export($name, true)
. ", array(" . $invokeParamsString . "));"
. "\n\n return parent::" . $name . '(' . $callParamsString . ');'
. ", [" . $invokeParamsString . "]);"
. "\n\n "
. ($this->shouldProxiedMethodReturn($method) ? 'return ' : '')
. "parent::" . $name . '(' . $callParamsString . ');'
. "\n" . ' }' . "\n";
}
@ -872,7 +877,7 @@ EOT;
private function getLazyLoadedPublicProperties(ClassMetadata $class)
{
$defaultProperties = $class->getReflectionClass()->getDefaultProperties();
$properties = array();
$properties = [];
foreach ($class->getReflectionClass()->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
$name = $property->getName();
@ -894,7 +899,7 @@ EOT;
*/
private function buildParametersString(ClassMetadata $class, \ReflectionMethod $method, array $parameters)
{
$parameterDefinitions = array();
$parameterDefinitions = [];
/* @var $param \ReflectionParameter */
foreach ($parameters as $param) {
@ -908,10 +913,8 @@ EOT;
$parameterDefinition .= '&';
}
if (method_exists($param, 'isVariadic')) {
if ($param->isVariadic()) {
$parameterDefinition .= '...';
}
if (method_exists($param, 'isVariadic') && $param->isVariadic()) {
$parameterDefinition .= '...';
}
$parameters[] = '$' . $param->getName();
@ -936,13 +939,20 @@ EOT;
*/
private function getParameterType(ClassMetadata $class, \ReflectionMethod $method, \ReflectionParameter $parameter)
{
if (method_exists($parameter, 'hasType')) {
if ( ! $parameter->hasType()) {
return '';
}
// We need to pick the type hint class too
return $this->formatType($parameter->getType(), $parameter->getDeclaringFunction(), $parameter);
}
// For PHP 5.x, we need to pick the type hint in the old way (to be removed for PHP 7.0+)
if ($parameter->isArray()) {
return 'array';
}
if (method_exists($parameter, 'isCallable') && $parameter->isCallable()) {
if ($parameter->isCallable()) {
return 'callable';
}
@ -990,10 +1000,8 @@ EOT;
function (\ReflectionParameter $parameter) {
$name = '';
if (method_exists($parameter, 'isVariadic')) {
if ($parameter->isVariadic()) {
$name .= '...';
}
if (method_exists($parameter, 'isVariadic') && $parameter->isVariadic()) {
$name .= '...';
}
$name .= '$' . $parameter->getName();
@ -1003,4 +1011,83 @@ EOT;
$parameters
);
}
/**
* @Param \ReflectionMethod $method
*
* @return string
*/
private function getMethodReturnType(\ReflectionMethod $method)
{
if ( ! method_exists($method, 'hasReturnType') || ! $method->hasReturnType()) {
return '';
}
return ': ' . $this->formatType($method->getReturnType(), $method);
}
/**
* @param \ReflectionMethod $method
*
* @return bool
*/
private function shouldProxiedMethodReturn(\ReflectionMethod $method)
{
if ( ! method_exists($method, 'hasReturnType') || ! $method->hasReturnType()) {
return true;
}
return 'void' !== strtolower($this->formatType($method->getReturnType(), $method));
}
/**
* @param \ReflectionType $type
* @param \ReflectionMethod $method
* @param \ReflectionParameter|null $parameter
*
* @return string
*/
private function formatType(
\ReflectionType $type,
\ReflectionMethod $method,
\ReflectionParameter $parameter = null
) {
$name = method_exists($type, 'getName') ? $type->getName() : (string) $type;
$nameLower = strtolower($name);
if ('self' === $nameLower) {
$name = $method->getDeclaringClass()->getName();
}
if ('parent' === $nameLower) {
$name = $method->getDeclaringClass()->getParentClass()->getName();
}
if ( ! $type->isBuiltin() && ! class_exists($name) && ! interface_exists($name)) {
if (null !== $parameter) {
throw UnexpectedValueException::invalidParameterTypeHint(
$method->getDeclaringClass()->getName(),
$method->getName(),
$parameter->getName()
);
}
throw UnexpectedValueException::invalidReturnTypeHint(
$method->getDeclaringClass()->getName(),
$method->getName()
);
}
if ( ! $type->isBuiltin()) {
$name = '\\' . $name;
}
if ($type->allowsNull()
&& (null === $parameter || ! $parameter->isDefaultValueAvailable() || null !== $parameter->getDefaultValue())
) {
$name = '?' . $name;
}
return $name;
}
}

View file

@ -402,7 +402,7 @@ class StaticReflectionClass extends ReflectionClass
/**
* {@inheritDoc}
*/
public function newInstanceArgs(array $args = array())
public function newInstanceArgs(array $args = [])
{
throw new ReflectionException('Method not implemented');
}

View file

@ -69,18 +69,18 @@ class StaticReflectionParser implements ReflectionProviderInterface
*
* @var array
*/
protected $useStatements = array();
protected $useStatements = [];
/**
* The docComment of the class.
*
* @var string
*/
protected $docComment = array(
protected $docComment = [
'class' => '',
'property' => array(),
'method' => array()
);
'property' => [],
'method' => []
];
/**
* The name of the class this class extends, if any.

View file

@ -91,7 +91,7 @@ class StaticReflectionProperty extends ReflectionProperty
/**
* {@inheritDoc}
*/
public static function export ($class, $name, $return = false)
public static function export($class, $name, $return = false)
{
throw new ReflectionException('Method not implemented');
}
@ -155,7 +155,7 @@ class StaticReflectionProperty extends ReflectionProperty
/**
* {@inheritDoc}
*/
public function setAccessible ($accessible)
public function setAccessible($accessible)
{
throw new ReflectionException('Method not implemented');
}
@ -163,7 +163,7 @@ class StaticReflectionProperty extends ReflectionProperty
/**
* {@inheritDoc}
*/
public function setValue ($object, $value = null)
public function setValue($object, $value = null)
{
throw new ReflectionException('Method not implemented');
}

View file

@ -19,6 +19,7 @@
namespace Doctrine\Common\Util;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Persistence\Proxy;
/**
@ -64,7 +65,7 @@ final class Debug
ini_set('xdebug.var_display_max_depth', $maxDepth);
}
$var = self::export($var, $maxDepth++);
$var = self::export($var, $maxDepth);
ob_start();
var_dump($var);
@ -76,11 +77,11 @@ final class Debug
$dumpText = ($stripTags ? strip_tags(html_entity_decode($dump)) : $dump);
ini_set('html_errors', $html);
if ($echo) {
echo $dumpText;
}
return $dumpText;
}
@ -95,51 +96,90 @@ final class Debug
$return = null;
$isObj = is_object($var);
if ($isObj && in_array('Doctrine\Common\Collections\Collection', class_implements($var))) {
if ($var instanceof Collection) {
$var = $var->toArray();
}
if ($maxDepth) {
if (is_array($var)) {
$return = array();
foreach ($var as $k => $v) {
$return[$k] = self::export($v, $maxDepth - 1);
}
} else if ($isObj) {
$return = new \stdclass();
if ($var instanceof \DateTime) {
$return->__CLASS__ = "DateTime";
$return->date = $var->format('c');
$return->timezone = $var->getTimeZone()->getName();
} else {
$reflClass = ClassUtils::newReflectionObject($var);
$return->__CLASS__ = ClassUtils::getClass($var);
if ($var instanceof Proxy) {
$return->__IS_PROXY__ = true;
$return->__PROXY_INITIALIZED__ = $var->__isInitialized();
}
if ($var instanceof \ArrayObject || $var instanceof \ArrayIterator) {
$return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1);
}
foreach ($reflClass->getProperties() as $reflProperty) {
$name = $reflProperty->getName();
$reflProperty->setAccessible(true);
$return->$name = self::export($reflProperty->getValue($var), $maxDepth - 1);
}
}
} else {
$return = $var;
}
} else {
$return = is_object($var) ? get_class($var)
if (! $maxDepth) {
return is_object($var) ? get_class($var)
: (is_array($var) ? 'Array(' . count($var) . ')' : $var);
}
if (is_array($var)) {
$return = [];
foreach ($var as $k => $v) {
$return[$k] = self::export($v, $maxDepth - 1);
}
return $return;
}
if (! $isObj) {
return $var;
}
$return = new \stdclass();
if ($var instanceof \DateTimeInterface) {
$return->__CLASS__ = get_class($var);
$return->date = $var->format('c');
$return->timezone = $var->getTimezone()->getName();
return $return;
}
$return->__CLASS__ = ClassUtils::getClass($var);
if ($var instanceof Proxy) {
$return->__IS_PROXY__ = true;
$return->__PROXY_INITIALIZED__ = $var->__isInitialized();
}
if ($var instanceof \ArrayObject || $var instanceof \ArrayIterator) {
$return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1);
}
return self::fillReturnWithClassAttributes($var, $return, $maxDepth);
}
/**
* Fill the $return variable with class attributes
*
* @param object $var
* @param stdClass $return
* @param int $maxDepth
*
* @return mixed
*/
private static function fillReturnWithClassAttributes($var, \stdClass $return, $maxDepth)
{
$reflClass = ClassUtils::newReflectionObject($var);
$parsedAttributes = array();
do {
$currentClassName = $reflClass->getName();
foreach ($reflClass->getProperties() as $reflProperty) {
$attributeKey = $reflProperty->isPrivate() ? $currentClassName . '#' : '';
$attributeKey .= $reflProperty->getName();
if (isset($parsedAttributes[$attributeKey])) {
continue;
}
$parsedAttributes[$attributeKey] = true;
$name =
$reflProperty->getName()
. ($return->__CLASS__ !== $currentClassName || $reflProperty->isPrivate() ? ':' . $currentClassName : '')
. ($reflProperty->isPrivate() ? ':private' : '')
. ($reflProperty->isProtected() ? ':protected' : '')
;
$reflProperty->setAccessible(true);
$return->$name = self::export($reflProperty->getValue($var), $maxDepth - 1);
}
} while ($reflClass = $reflClass->getParentClass());
return $return;
}

View file

@ -34,7 +34,7 @@ class Version
/**
* Current Doctrine Version.
*/
const VERSION = '2.6.0-DEV';
const VERSION = '2.7.0-DEV';
/**
* Compares a Doctrine version with the current one.

View file

@ -1,25 +0,0 @@
<?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"
>
<testsuites>
<testsuite name="Doctrine Common Test Suite">
<directory>./tests/Doctrine/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./lib/Doctrine/</directory>
</whitelist>
</filter>
</phpunit>

View file

@ -1,11 +1,21 @@
language: php
sudo: false
cache:
directory:
- $HOME/.composer/cache
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
install:
- composer --prefer-source install
- composer install -n
script:
- phpunit

View file

@ -1,4 +1,4 @@
Copyright (c) 2006-2013 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

@ -23,7 +23,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
}
}

View file

@ -56,11 +56,12 @@ class Inflector
'/(p)erson$/i' => '\1eople',
'/(m)an$/i' => '\1en',
'/(c)hild$/i' => '\1hildren',
'/(buffal|tomat)o$/i' => '\1\2oes',
'/(f)oot$/i' => '\1eet',
'/(buffal|her|potat|tomat|volcan)o$/i' => '\1\2oes',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
'/us$/i' => 'uses',
'/(alias)$/i' => '\1es',
'/(ax|cris|test)is$/i' => '\1es',
'/(analys|ax|cris|test|thes)is$/i' => '\1es',
'/s$/' => 's',
'/^$/' => '',
'/$/' => 's',
@ -70,27 +71,42 @@ class Inflector
),
'irregular' => array(
'atlas' => 'atlases',
'axe' => 'axes',
'beef' => 'beefs',
'brother' => 'brothers',
'cafe' => 'cafes',
'chateau' => 'chateaux',
'child' => 'children',
'cookie' => 'cookies',
'corpus' => 'corpuses',
'cow' => 'cows',
'criteria' => 'criterion',
'criterion' => 'criteria',
'curriculum' => 'curricula',
'demo' => 'demos',
'domino' => 'dominoes',
'echo' => 'echoes',
'foot' => 'feet',
'fungus' => 'fungi',
'ganglion' => 'ganglions',
'genie' => 'genies',
'genus' => 'genera',
'graffito' => 'graffiti',
'hippopotamus' => 'hippopotami',
'hoof' => 'hoofs',
'human' => 'humans',
'iris' => 'irises',
'leaf' => 'leaves',
'loaf' => 'loaves',
'man' => 'men',
'medium' => 'media',
'memorandum' => 'memoranda',
'money' => 'monies',
'mongoose' => 'mongooses',
'motto' => 'mottoes',
'move' => 'moves',
'mythos' => 'mythoi',
'niche' => 'niches',
'nucleus' => 'nuclei',
'numen' => 'numina',
'occiput' => 'occiputs',
'octopus' => 'octopuses',
@ -98,11 +114,19 @@ class Inflector
'ox' => 'oxen',
'penis' => 'penises',
'person' => 'people',
'plateau' => 'plateaux',
'runner-up' => 'runners-up',
'sex' => 'sexes',
'soliloquy' => 'soliloquies',
'son-in-law' => 'sons-in-law',
'syllabus' => 'syllabi',
'testis' => 'testes',
'thief' => 'thieves',
'tooth' => 'teeth',
'tornado' => 'tornadoes',
'trilby' => 'trilbys',
'turf' => 'turfs',
'volcano' => 'volcanoes',
)
);
@ -120,9 +144,10 @@ class Inflector
'/(vert|ind)ices$/i' => '\1ex',
'/^(ox)en/i' => '\1',
'/(alias)(es)*$/i' => '\1',
'/(buffal|her|potat|tomat|volcan)oes$/i' => '\1o',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
'/([ftw]ax)es/i' => '\1',
'/(cris|ax|test)es$/i' => '\1is',
'/(analys|ax|cris|test|thes)es$/i' => '\1is',
'/(shoe|slave)s$/i' => '\1',
'/(o)es$/i' => '\1',
'/ouses$/' => 'ouse',
@ -143,6 +168,7 @@ class Inflector
'/(p)eople$/i' => '\1\2erson',
'/(m)en$/i' => '\1an',
'/(c)hildren$/i' => '\1\2hild',
'/(f)eet$/i' => '\1oot',
'/(n)ews$/i' => '\1\2ews',
'/eaus$/' => 'eau',
'/^(.*us)$/' => '\\1',
@ -159,10 +185,15 @@ class Inflector
'.*ss',
),
'irregular' => array(
'criterion' => 'criteria',
'curves' => 'curve',
'foes' => 'foe',
'waves' => 'wave',
'criteria' => 'criterion',
'curves' => 'curve',
'emphases' => 'emphasis',
'foes' => 'foe',
'hoaxes' => 'hoax',
'media' => 'medium',
'neuroses' => 'neurosis',
'waves' => 'wave',
'oases' => 'oasis',
)
);
@ -236,6 +267,42 @@ class Inflector
return lcfirst(self::classify($word));
}
/**
* Uppercases words with configurable delimeters between words.
*
* Takes a string and capitalizes all of the words, like PHP's built-in
* ucwords function. This extends that behavior, however, by allowing the
* word delimeters to be configured, rather than only separating on
* whitespace.
*
* Here is an example:
* <code>
* <?php
* $string = 'top-o-the-morning to all_of_you!';
* echo \Doctrine\Common\Inflector\Inflector::ucwords($string);
* // Top-O-The-Morning To All_of_you!
*
* echo \Doctrine\Common\Inflector\Inflector::ucwords($string, '-_ ');
* // Top-O-The-Morning To All_Of_You!
* ?>
* </code>
*
* @param string $string The string to operate on.
* @param string $delimiters A list of word separators.
*
* @return string The string with all delimeter-separated words capitalized.
*/
public static function ucwords($string, $delimiters = " \n\t\r\0\x0B-")
{
return preg_replace_callback(
'/[^' . preg_quote($delimiters, '/') . ']+/',
function($matches) {
return ucfirst($matches[0]);
},
$string
);
}
/**
* Clears Inflectors inflected value caches, and resets the inflection
* rules to the initial values.