diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000000..81c67dbe04
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ mysql
+ true
+ com.mysql.jdbc.Driver
+ jdbc:mysql://localhost:3306/pydio
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/cmd.php b/core/src/cmd.php
index ead4363aed..78205d49d2 100644
--- a/core/src/cmd.php
+++ b/core/src/cmd.php
@@ -33,13 +33,9 @@
//set_error_handler(array("AJXP_XMLWriter", "catchError"), E_ALL & ~E_NOTICE );
//set_exception_handler(array("AJXP_XMLWriter", "catchException"));
-$pServ = AJXP_PluginsService::getInstance();
ConfService::init();
-$confPlugin = ConfService::getInstance()->confPluginSoftLoad($pServ);
-$pServ->loadPluginsRegistry(AJXP_INSTALL_PATH."/plugins", $confPlugin);
ConfService::start();
-
$confStorageDriver = ConfService::getConfStorageImpl();
require_once($confStorageDriver->getUserClassFileName());
//session_name("AjaXplorer");
diff --git a/core/src/core/classes/class.AJXP_PluginsService.php b/core/src/core/classes/class.AJXP_PluginsService.php
index 9d0b73f918..2d600e4f6a 100644
--- a/core/src/core/classes/class.AJXP_PluginsService.php
+++ b/core/src/core/classes/class.AJXP_PluginsService.php
@@ -40,10 +40,25 @@ class AJXP_PluginsService
* @var AbstractConfDriver
*/
private $confStorage;
+ private $cacheStorage;
private $mixinsDoc;
private $mixinsXPath;
+ /**
+ * @return bool
+ */
+ private function loadRegistryFromCacheService() {
+
+ $res = $this->cacheStorage->fetch("plugins_registry");
+
+ if (!$res) return false;
+
+ $this->registry = $res;
+
+ return true;
+ }
+
/**
* @return bool
*/
@@ -59,14 +74,22 @@ private function loadRegistryFromCache(){
}
require_once($fileName);
}
- $kvCache = ConfService::getInstance()->getKeyValueCache();
- $test = $kvCache->fetch("plugins_registry");
+ $test=FALSE;
+
+ //$test = CacheService::fetch("plugins_registry");
+
if($test !== FALSE) {
- $this->registry = $test;
+ AJXP_Logger::debug(__CLASS__, __FUNCTION__, 'Loaded from cache');
+
+ $this->registry=$test;
+
}else{
+ AJXP_Logger::debug(__CLASS__, __FUNCTION__, 'Saving registry');
$res = AJXP_Utils::loadSerialFile(AJXP_PLUGINS_CACHE_FILE);
- $this->registry = $res;
- $kvCache->save("plugins_registry", $res);
+
+ //CacheService::save("plugins_registry", $res);
+
+ $this->registry=$res;
}
// Refresh streamWrapperPlugins
foreach ($this->registry as $plugs) {
@@ -76,6 +99,8 @@ private function loadRegistryFromCache(){
}
}
}
+
+
return true;
}else{
return false;
@@ -92,13 +117,18 @@ private function loadRegistryFromCache(){
* @param AbstractConfDriver $confStorage
* @param bool $rewriteCache Force a cache rewriting
*/
- public function loadPluginsRegistry($pluginFolder, $confStorage, $rewriteCache = false)
+ public function loadPluginsRegistry($pluginFolder, $confStorage, $cacheStorage, $rewriteCache = false)
{
if(!$rewriteCache){
if(!empty($this->registry)){
return;
}
+ $this->cacheStorage = $cacheStorage;
+ if($this->loadRegistryFromCacheService()) {
+ return;
+ }
if($this->loadRegistryFromCache()){
+ CacheService::save("plugins_registry", $this->registry);
return;
}
}
@@ -138,6 +168,7 @@ public function loadPluginsRegistry($pluginFolder, $confStorage, $rewriteCache =
@unlink(AJXP_PLUGINS_QUERIES_CACHE);
}
}
+ $this->cacheStorage->save("plugins_registry", $this->registry);
}
/**
@@ -210,28 +241,32 @@ public static function clearPluginsCache(){
* @param array $pluginOptions
* @return AJXP_Plugin
*/
- public function softLoad($pluginId, $pluginOptions)
+ public function softLoad($pluginId, $pluginOptions, $skipCache = false)
{
- if(empty($this->registry)){
- $this->loadRegistryFromCache();
- }
- // Try to get from cache
- list($type, $name) = explode(".", $pluginId);
- if(!empty($this->registry) && isSet($this->registry[$type][$name])) {
- /**
- * @var AJXP_Plugin $plugin
- */
- $plugin = $this->registry[$type][$name];
- $plugin->init($pluginOptions);
- return clone $plugin;
- }
+ if (!$skipCache)
+ {
+ if(empty($this->registry)){
+ $this->loadRegistryFromCache();
+ }
+ // Try to get from cache
+ list($type, $name) = explode(".", $pluginId);
+ if(!empty($this->registry) && isSet($this->registry[$type][$name])) {
+ /**
+ * @var AJXP_Plugin $plugin
+ */
+ $plugin = $this->registry[$type][$name];
+ $plugin->init($pluginOptions);
+ return clone $plugin;
+ }
+ }
$plugin = new AJXP_Plugin($pluginId, AJXP_INSTALL_PATH."/".AJXP_PLUGINS_FOLDER."/".$pluginId);
$plugin->loadManifest();
$plugin = $this->instanciatePluginClass($plugin);
$plugin->loadConfigs(array()); // Load default
$plugin->init($pluginOptions);
+
return $plugin;
}
@@ -245,6 +280,7 @@ private function instanciatePluginClass($plugin)
{
$definition = $plugin->getClassFile();
if(!$definition) return $plugin;
+
$filename = AJXP_INSTALL_PATH."/".$definition["filename"];
$className = $definition["classname"];
if (is_file($filename)) {
diff --git a/core/src/core/classes/class.AuthService.php b/core/src/core/classes/class.AuthService.php
index 158e16c7d9..edf12b99d4 100644
--- a/core/src/core/classes/class.AuthService.php
+++ b/core/src/core/classes/class.AuthService.php
@@ -1147,7 +1147,7 @@ public static function getRole($roleId, $createIfNotExists = false)
public static function updateRole($roleObject, $userObject = null)
{
ConfService::getConfStorageImpl()->updateRole($roleObject, $userObject);
- ConfService::getInstance()->getKeyValueCache()->deleteAll();
+ CacheService::deleteAll();
}
/**
* Delete a role by its id
@@ -1158,7 +1158,7 @@ public static function updateRole($roleObject, $userObject = null)
public static function deleteRole($roleId)
{
ConfService::getConfStorageImpl()->deleteRole($roleId);
- ConfService::getInstance()->getKeyValueCache()->deleteAll();
+ CacheService::deleteAll();
}
public static function filterPluginParameters($pluginId, $params, $repoId = null)
diff --git a/core/src/core/classes/class.CacheService.php b/core/src/core/classes/class.CacheService.php
new file mode 100644
index 0000000000..b3e8454123
--- /dev/null
+++ b/core/src/core/classes/class.CacheService.php
@@ -0,0 +1,88 @@
+
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see .
+ *
+ * The latest code can be found at .
+ */
+defined('AJXP_EXEC') or die( 'Access not allowed');
+
+/**
+ * Static access to the caching mechanism. Encapsulates the cacheDriver implementation
+ * @package Pydio
+ * @subpackage Core
+ */
+class CacheService
+{
+
+ public static function contains($id) {
+ //var_dump('Cotnains' . $id);
+ $cacheDriver = ConfService::getCacheDriverImpl();
+
+ if ($cacheDriver) {
+ return $cacheDriver->contains($id);
+ }
+
+ return false;
+ }
+
+ public static function save($id, $object, $timelimit = 0 ) {
+ $cacheDriver = ConfService::getCacheDriverImpl();
+
+ if ($cacheDriver) {
+ return $cacheDriver->save($id, $object, $timelimit = 0);
+ } else {
+ AJXP_Logger::debug(__CLASS__,__FUNCTION__,'error '.$cacheDriver);
+ }
+
+ return false;
+ }
+
+ public static function fetch($id) {
+ //var_dump('Fetch' . $id);
+ $cacheDriver = ConfService::getCacheDriverImpl();
+
+ return false;
+ if ($cacheDriver) {
+ $data = $cacheDriver->fetch($id);
+ return $data;
+ }
+
+ return false;
+ }
+
+ public static function delete($id) {
+ //var_dump('Delete' . $id);
+ $cacheDriver = ConfService::getCacheDriverImpl();
+
+ if ($cacheDriver) {
+ return $cacheDriver->delete($id);
+ }
+
+ return false;
+ }
+
+ public static function deleteAll() {
+ //var_dump('Delete ALL' . $id);
+ $cacheDriver = ConfService::getCacheDriverImpl();
+
+ if ($cacheDriver) {
+ return $cacheDriver->deleteAll();
+ }
+
+ return false;
+ }
+}
diff --git a/core/src/core/classes/class.ConfService.php b/core/src/core/classes/class.ConfService.php
index 3e5b33a1d2..cc6aa206fe 100644
--- a/core/src/core/classes/class.ConfService.php
+++ b/core/src/core/classes/class.ConfService.php
@@ -30,31 +30,41 @@ class ConfService
private static $instance;
public static $useSession = true;
+ private $booter;
+ private $confPlugin;
+ private $cachePlugin;
private $errors = array();
private $configs = array();
private $contextRepositoryId;
private $contextCharset;
- /**
- * @var AJXP_KeyValueCache
- */
- private $keyValueCache;
-
/**
* @param AJXP_PluginsService $ajxpPluginService
* @return AbstractConfDriver
*/
- public function confPluginSoftLoad($ajxpPluginService)
+ public function confPluginSoftLoad()
{
- $booter = $ajxpPluginService->softLoad("boot.conf", array());
- $coreConfigs = $booter->loadPluginConfig("core", "conf");
- $corePlug = $ajxpPluginService->softLoad("core.conf", array());
+ $coreConfigs = $this->booter->loadPluginConfig("core", "conf");
+ $corePlug = AJXP_PluginsService::getInstance()->softLoad("core.conf", array());
$corePlug->loadConfigs($coreConfigs);
return $corePlug->getConfImpl();
}
+ /**
+ * @param AJXP_PluginsService $ajxpPluginService
+ * @return AbstractCacheDriver
+ */
+ public function cachePluginSoftLoad()
+ {
+
+ $coreConfigs = $this->booter->loadPluginConfig("core", "cache");
+ $corePlug = AJXP_PluginsService::getInstance()->softLoad("core.cache", array());
+ $corePlug->loadConfigs($coreConfigs);
+ return $corePlug->getCacheImpl();
+ }
+
/**
* @return AbstractConfDriver
*/
@@ -77,6 +87,7 @@ public static function init()
$inst = self::getInstance();
$inst->initInst();
}
+
/**
* Load the boostrap_* files and their configs
* @return void
@@ -94,7 +105,6 @@ public function initInst()
$this->configs["JS_DEBUG"] = AJXP_CLIENT_DEBUG;
$this->configs["SERVER_DEBUG"] = AJXP_SERVER_DEBUG;
-
if (is_file(AJXP_CONF_PATH."/bootstrap_repositories.php")) {
$REPOSITORIES = array();
include(AJXP_CONF_PATH."/bootstrap_repositories.php");
@@ -102,7 +112,25 @@ public function initInst()
} else {
$this->configs["DEFAULT_REPOSITORIES"] = array();
}
+
+ // Launching bootloader (no cache)
+ $this->booter = AJXP_PluginsService::getInstance()->softLoad("boot.conf", array(), true);
+
+ // Soft Load (order is important - cache before conf)
+ $this->cachePlugin = $this->cachePluginSoftLoad();
+
+ //AJXP_PluginsService::getInstance()->setPluginUniqueActiveForType("cache", self::getConfStorageImpl()->getName());
+
+ $this->confPlugin = $this->confPluginSoftLoad();
+
+ // Loading the registry
+ try {
+ AJXP_PluginsService::getInstance()->loadPluginsRegistry(AJXP_INSTALL_PATH."/plugins", $this->confPlugin, $this->cachePlugin);
+ } catch (Exception $e) {
+ die("Severe error while loading plugins registry : ".$e->getMessage());
+ }
}
+
/**
* Start the singleton
* @static
@@ -161,17 +189,10 @@ public function getContextRepositoryId(){
return self::$useSession ? $_SESSION["REPO_ID"] : $this->contextRepositoryId;
}
- public function getKeyValueCache(){
- if(!isSet($this->keyValueCache)){
- $this->keyValueCache = new AJXP_KeyValueCache();
- }
- return $this->keyValueCache;
- }
-
public static function clearAllCaches(){
AJXP_PluginsService::clearPluginsCache();
self::clearMessagesCache();
- self::getInstance()->getKeyValueCache()->deleteAll();
+ CacheService::deleteAll();
if(function_exists('opcache_reset')){
opcache_reset();
}
@@ -194,6 +215,7 @@ public static function instanciatePluginFromGlobalParams($globalsArray, $interfa
if (isSet($globalsArray["instance_name"])) {
$pName = $globalsArray["instance_name"];
unset($globalsArray["instance_name"]);
+
$plugin = AJXP_PluginsService::getInstance()->softLoad($pName, $globalsArray);
$plugin->performChecks();
}
@@ -209,6 +231,7 @@ public static function instanciatePluginFromGlobalParams($globalsArray, $interfa
return $plugin;
}
+
/**
* Check if the STDIN constant is defined
* @static
@@ -255,15 +278,21 @@ public static function backgroundActionsSupported()
* @var AbstractAuthDriver
*/
private static $tmpAuthStorageImpl;
+ /**
+ * @var AbstractCacheDriver
+ */
+ private static $tmpCacheStorageImpl;
/**
* @param $confStorage AbstractConfDriver
* @param $authStorage AbstractAuthDriver
+ * @paran $cacheStorage AbstractCacheDriver
*/
- public static function setTmpStorageImplementations($confStorage, $authStorage)
+ public static function setTmpStorageImplementations($confStorage, $authStorage, $cacheStorage)
{
self::$tmpConfStorageImpl = $confStorage;
self::$tmpAuthStorageImpl = $authStorage;
+ self::$tmpCacheStorageImpl = $cacheStorage;
}
/**
@@ -288,12 +317,25 @@ public static function getAuthDriverImpl()
return AJXP_PluginsService::getInstance()->getPluginById("core.auth")->getAuthImpl();
}
+ /**
+ * Get auth driver implementation
+ *
+ * @return AbstractAuthDriver
+ */
+ public static function getCacheDriverImpl()
+ {
+ if(isSet(self::$tmpCacheStorageImpl)) return self::$tmpCacheStorageImpl;
+ $inst = AJXP_PluginsService::getInstance();
+ $plug = $inst->getPluginById("core.cache");
+ $cache = $plug->getCacheImpl();
+ return $cache;
+ }
+
public static function getFilteredXMLRegistry($extendedVersion = true, $clone = false, $useCache = false){
if($useCache){
- $kvCache = ConfService::getInstance()->getKeyValueCache();
$cacheKey = self::getRegistryCacheKey($extendedVersion);
- $cachedXml = $kvCache->fetch($cacheKey);
+ $cachedXml = CacheService::fetch($cacheKey);
if($cachedXml !== false){
$registry = new DOMDocument("1.0", "utf-8");
$registry->loadXML($cachedXml);
@@ -542,7 +584,7 @@ public function invalidateLoadedRepositories()
{
if(isSet($_SESSION["REPOSITORIES"])) unset($_SESSION["REPOSITORIES"]);
$this->configs["REPOSITORIES"] = null;
- $this->getKeyValueCache()->deleteAll();
+ CacheService::deleteAll();
}
private function cacheRepository($repoId, $repository){
@@ -1007,20 +1049,20 @@ public function getRepositoryByIdInst($repoId)
if (iSset($this->configs["REPOSITORY"]) && $this->configs["REPOSITORY"]->getId()."" == $repoId) {
return $this->configs["REPOSITORY"];
}
- $test = $this->getKeyValueCache()->fetch("repository:".$repoId);
+ $test = CacheService::fetch("repository:".$repoId);
if($test !== false){
return $test;
}
$test = $this->getConfStorageImpl()->getRepositoryById($repoId);
if($test != null) {
- $this->getKeyValueCache()->save("repository:".$repoId, $test);
+ CacheService::save("repository:".$repoId, $test);
return $test;
}
// Finally try to search in default repositories
if (isSet($this->configs["DEFAULT_REPOSITORIES"]) && isSet($this->configs["DEFAULT_REPOSITORIES"][$repoId])) {
$repo = self::createRepositoryFromArray($repoId, $this->configs["DEFAULT_REPOSITORIES"][$repoId]);
$repo->setWriteable(false);
- $this->keyValueCache->save("repository:".$repoId, $repo);
+ CacheService::save("repository:".$repoId, $repo);
return $repo;
}
return null;
diff --git a/core/src/data/.htaccess b/core/src/data/.htaccess
deleted file mode 100644
index 2859d7f432..0000000000
--- a/core/src/data/.htaccess
+++ /dev/null
@@ -1,2 +0,0 @@
-Order Deny,Allow
-Deny from all
\ No newline at end of file
diff --git a/core/src/data/cache/.htaccess b/core/src/data/cache/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/cache/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/cache/index.html b/core/src/data/cache/index.html
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/core/src/data/files/.htaccess b/core/src/data/files/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/files/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/logs/.htaccess b/core/src/data/logs/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/logs/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/logs/index.html b/core/src/data/logs/index.html
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/core/src/data/personal/.htaccess b/core/src/data/personal/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/personal/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/plugins/.htaccess b/core/src/data/plugins/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/plugins/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/plugins/auth.serial/.htaccess b/core/src/data/plugins/auth.serial/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/plugins/auth.serial/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/plugins/conf.serial/.htaccess b/core/src/data/plugins/conf.serial/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/plugins/conf.serial/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/data/public/index.html b/core/src/data/public/index.html
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/core/src/data/tmp/.htaccess b/core/src/data/tmp/.htaccess
deleted file mode 100644
index 3418e55a68..0000000000
--- a/core/src/data/tmp/.htaccess
+++ /dev/null
@@ -1 +0,0 @@
-deny from all
\ No newline at end of file
diff --git a/core/src/index.php b/core/src/index.php
index 35f64de4ce..ec5ee0467d 100644
--- a/core/src/index.php
+++ b/core/src/index.php
@@ -47,14 +47,7 @@
set_exception_handler(array("AJXP_XMLWriter", "catchException"));
}
-$pServ = AJXP_PluginsService::getInstance();
ConfService::init();
-$confPlugin = ConfService::getInstance()->confPluginSoftLoad($pServ);
-try {
- $pServ->loadPluginsRegistry(AJXP_INSTALL_PATH."/plugins", $confPlugin);
-} catch (Exception $e) {
- die("Severe error while loading plugins registry : ".$e->getMessage());
-}
ConfService::start();
$confStorageDriver = ConfService::getConfStorageImpl();
diff --git a/core/src/plugins/boot.conf/class.BootConfLoader.php b/core/src/plugins/boot.conf/class.BootConfLoader.php
index 7698b78cf1..76e582e819 100644
--- a/core/src/plugins/boot.conf/class.BootConfLoader.php
+++ b/core/src/plugins/boot.conf/class.BootConfLoader.php
@@ -149,11 +149,11 @@ public function applyInstallerForm($action, $httpVars, $fileVars)
$data = array();
AJXP_Utils::parseStandardFormParameters($httpVars, $data, null, "");
- list($newConfigPlugin, $newAuthPlugin) = $this->createBootstrapConf($data);
+ list($newConfigPlugin, $newAuthPlugin, $newCachePlugin) = $this->createBootstrapConf($data);
$this->feedPluginsOptions($newConfigPlugin, $data);
- ConfService::setTmpStorageImplementations($newConfigPlugin, $newAuthPlugin);
+ ConfService::setTmpStorageImplementations($newConfigPlugin, $newAuthPlugin, $newCachePlugin);
$this->createUsers($data);
$this->setAdditionalData($data);
@@ -247,11 +247,13 @@ public function feedPluginsOptions($confDriver, $data, $optionsLinks = null){
public function createBootstrapConf($data){
// Create a custom bootstrap.json file
- $coreConf = array(); $coreAuth = array();
+ $coreConf = array(); $coreAuth = array(); $coreCache = array();
$this->_loadPluginConfig("core.conf", $coreConf);
$this->_loadPluginConfig("core.auth", $coreAuth);
+ $this->_loadPluginConfig("core.cache", $coreCache);
if(!isSet($coreConf["UNIQUE_INSTANCE_CONFIG"])) $coreConf["UNIQUE_INSTANCE_CONFIG"] = array();
if(!isSet($coreAuth["MASTER_INSTANCE_CONFIG"])) $coreAuth["MASTER_INSTANCE_CONFIG"] = array();
+ if(!isSet($coreCache["UNIQUE_INSTANCE_CONFIG"])) $coreCache["UNIQUE_INSTANCE_CONFIG"] = array();
$coreConf["AJXP_CLI_SECRET_KEY"] = AJXP_Utils::generateRandomString(24, true);
// REWRITE BOOTSTRAP.JSON
@@ -272,6 +274,9 @@ public function createBootstrapConf($data){
"group_switch_value"=> "auth.sql",
"SQL_DRIVER" => array("core_driver" => "core", "group_switch_value" => "core")
));
+ $coreCache["UNIQUE_INSTANCE_CONFIG"] = array_merge($coreCache["UNIQUE_INSTANCE_CONFIG"], array(
+ "instance_name"=> "cache.apc"
+ ));
// DETECT REQUIRED SQL TABLES AND INSTALL THEM
$registry = AJXP_PluginsService::getInstance()->getDetectedPlugins();
@@ -290,7 +295,7 @@ public function createBootstrapConf($data){
copy($oldBoot, $oldBoot.".bak");
unlink($oldBoot);
}
- $newBootstrap = array("core.conf" => $coreConf, "core.auth" => $coreAuth);
+ $newBootstrap = array("core.conf" => $coreConf, "core.auth" => $coreAuth, "core.cache" => $coreCache);
AJXP_Utils::saveSerialFile($oldBoot, $newBootstrap, true, false, "json", true);
@@ -300,6 +305,7 @@ public function createBootstrapConf($data){
$newConfigPlugin = ConfService::instanciatePluginFromGlobalParams($coreConf["UNIQUE_INSTANCE_CONFIG"], "AbstractConfDriver");
$newAuthPlugin = ConfService::instanciatePluginFromGlobalParams($coreAuth["MASTER_INSTANCE_CONFIG"], "AbstractAuthDriver");
+ $newCachePlugin = ConfService::instanciatePluginFromGlobalParans($coreCache["UNIQUE_INSTANCE_CONFIG"], "AbstractCacheDriver");
$sqlPlugs = array(
"core.notifications/UNIQUE_FEED_INSTANCE" => "feed.sql",
@@ -457,6 +463,11 @@ public function _loadPluginConfig($pluginId, &$options)
$options = $this->authLegacyToBootConf($internal["AUTH_DRIVER"]);
return;
+ } else if ($pluginId == "core.cache" && isSet($internal["CACHE_DRIVER"])) {
+ $options['UNIQUE_INSTANCE_CONFIG'] = array(
+ "instance_name" => "cache.".$internal["CACHE_DRIVER"]["NAME"]
+ );
+ return;
}
$jsonPath = $this->getPluginWorkDir(false)."/bootstrap.json";
$jsonData = AJXP_Utils::loadSerialFile($jsonPath, false, "json");
@@ -499,8 +510,8 @@ public function _savePluginConfig($pluginId, $options)
$jsonData = AJXP_Utils::loadSerialFile($jsonPath, false, "json");
if(!is_array($jsonData)) $jsonData = array();
$jsonData[$pluginId] = $options;
- if ($pluginId == "core.conf" || $pluginId == "core.auth") {
- $testKey = ($pluginId == "core.conf" ? "UNIQUE_INSTANCE_CONFIG" : "MASTER_INSTANCE_CONFIG" );
+ if ($pluginId == "core.conf" || $pluginId == "core.auth" || $pluginId == "core.cache") {
+ $testKey = ($pluginId == "core.conf" || $pluginId == "core.cache" ? "UNIQUE_INSTANCE_CONFIG" : "MASTER_INSTANCE_CONFIG" );
$current = array();
$this->_loadPluginConfig($pluginId, $current);
if (isSet($current[$testKey]["instance_name"]) && $current[$testKey]["instance_name"] != $options[$testKey]["instance_name"]) {
diff --git a/core/src/plugins/cache.doctrine/class.doctrineCacheDriver.php b/core/src/plugins/cache.doctrine/class.doctrineCacheDriver.php
new file mode 100644
index 0000000000..d3101ff3e2
--- /dev/null
+++ b/core/src/plugins/cache.doctrine/class.doctrineCacheDriver.php
@@ -0,0 +1,126 @@
+
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see .
+ *
+ * The latest code can be found at .
+ */
+
+defined('AJXP_EXEC') or die( 'Access not allowed');
+
+use \Doctrine\Common\Cache;
+
+/**
+ * Standard Memcache driver
+ * @package AjaXplorer_Plugins
+ * @subpackage Log
+ */
+class doctrineCacheDriver extends AbstractCacheDriver
+{
+ /**
+ * Close file handle on objects destructor.
+ */
+ public function __destruct()
+ {
+ }
+
+ /**
+ * If the plugin is cloned, make sure to renew the $fileHandle
+ */
+ public function __clone() {
+ }
+
+ /**
+ * Initialise the cache driver based on config
+ *
+ * @param Array $options array of options specific to the cache driver.
+ * @access public
+ * @return null
+ */
+ public function init($options)
+ {
+ parent::init($options);
+
+
+ $this->cacheDriver = null;
+ $this->options = $this->getFilteredOption("DRIVER");
+
+
+ switch ($this->options['driver']) {
+ case "apc":
+ $this->_apc_init();
+ break;
+ case "memcache":
+ $this->_memcache_init();
+ break;
+ case "memcached":
+ $this->_memcached_init();
+ break;
+ case "redis":
+ $this->_redis_init();
+ break;
+ case "xcache":
+ $this->_xcache_init();
+ break;
+ default:
+ break;
+ }
+ }
+
+ public function _apc_init() {
+ $this->cacheDriver = new Cache\ApcCache();
+ }
+
+ public function _memcache_init() {
+ $this->memcache = new Memcache();
+ @$running = $this->memcache->connect($this->options['MEMCACHE_HOSTNAME'], $this->options['MEMCACHE_PORT']);
+
+ if (! $running) return;
+
+ $this->cacheDriver = new Cache\MemcacheCache();
+ $this->cacheDriver->setMemcache($this->memcache);
+ }
+
+ public function _memcached_init() {
+ $this->memcached = new Memcache();
+ @$running = $this->memcached->connect($this->options['MEMCACHED_HOSTNAME'], $this->options['MEMCACHED_PORT']);
+
+ if (! $running) return;
+
+ $this->cacheDriver = new Cache\MemcachedCache();
+ $this->cacheDriver->setMemcached($this->memcached);
+ }
+
+ public function _redis_init() {
+ $this->redis = new Redis();
+ @$running = $this->redis->connect($this->options['REDIS_HOSTNAME'], $this->options['REDIS_PORT']);
+
+ if (! $running) return;
+
+ $this->cacheDriver = new \Doctrine\Common\Cache\RedisCache();
+ $this->cacheDriver->setRedis($this->redis);
+ }
+
+ public function _xcache_init() {
+ $this->cacheDriver = new Cache\XcacheCache();
+ }
+
+ public function getCacheDriver() {
+ return $this->cacheDriver;
+ }
+
+
+}
diff --git a/core/src/plugins/cache.doctrine/manifest.xml b/core/src/plugins/cache.doctrine/manifest.xml
new file mode 100644
index 0000000000..69ee24da39
--- /dev/null
+++ b/core/src/plugins/cache.doctrine/manifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/plugins/cache.doctrine/plugin_doc.html b/core/src/plugins/cache.doctrine/plugin_doc.html
new file mode 100644
index 0000000000..a317319056
--- /dev/null
+++ b/core/src/plugins/cache.doctrine/plugin_doc.html
@@ -0,0 +1 @@
+
The cache store uses Doctrine as a bridge to the main cache drivers
diff --git a/core/src/plugins/core.ajaxplorer/i18n/en.php b/core/src/plugins/core.ajaxplorer/i18n/en.php
index e67605e663..445a5f4c83 100644
--- a/core/src/plugins/core.ajaxplorer/i18n/en.php
+++ b/core/src/plugins/core.ajaxplorer/i18n/en.php
@@ -620,6 +620,8 @@
"plugtype.desc.boot" => "Unique plugin for loading the framework",
"plugtype.title.conf" => "Configuration Storage",
"plugtype.desc.conf" => "How configuration data are stored in the backend",
+"plugtype.title.cache" => "Cache server",
+"plugtype.desc.cache" => "Unique plugin to set up the cache server used by the application",
"plugtype.title.feed" => "Events Feed Storage",
"plugtype.desc.feed" => "Implementations for storing data events (only SQL yet)",
"plugtype.title.log" => "Loggers",
diff --git a/core/src/plugins/core.cache/class.AbstractCacheDriver.php b/core/src/plugins/core.cache/class.AbstractCacheDriver.php
new file mode 100644
index 0000000000..3053b328e9
--- /dev/null
+++ b/core/src/plugins/core.cache/class.AbstractCacheDriver.php
@@ -0,0 +1,147 @@
+, mosen
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see .
+ *
+ * The latest code can be found at .
+ */
+defined('AJXP_EXEC') or die( 'Access not allowed');
+
+require __DIR__ . "/doctrine/vendor/autoload.php";
+
+use Doctrine\Common\Cache;
+
+/**
+ * @package AjaXplorer_Plugins
+ * @subpackage Core
+ * @class AbstractCacheDriver
+ * @author ghecquet
+ * @abstract
+ * Abstraction of the caching system
+ * The cache will be implemented by the plugin which extends this class.
+ */
+abstract class AbstractCacheDriver extends AJXP_Plugin
+{
+ /**
+ * Driver type
+ *
+ * @var String type of driver
+ */
+ public $driverType = "cache";
+
+ public function init($options)
+ {
+ parent::init($options);
+ }
+
+ abstract public function getCacheDriver();
+
+ /**
+ * Fetches an entry from the cache.
+ *
+ * @param string $id The id of the cache entry to fetch.
+ *
+ * @return mixed The cached data or FALSE, if no cache entry exists for the given id.
+ */
+ public function fetch($id){
+ $cacheDriver = $this->getCacheDriver();
+
+ if (isset($cacheDriver) && $cacheDriver->contains($id)) {
+ AJXP_Logger::debug(__CLASS__,__FUNCTION__,'Fetching '.$id);
+ $result = $cacheDriver->fetch($id);
+ return $result;
+ }
+
+ return false;
+ }
+
+ /**
+ * Tests if an entry exists in the 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.
+ */
+ public function contains($id){
+ $cacheDriver = $this->getCacheDriver();
+
+ if (! isset($cacheDriver)) {
+ return false;
+ }
+
+ $result = $cacheDriver->contains($id);
+
+ return $result;
+ }
+
+ /**
+ * Puts data into the cache.
+ *
+ * @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).
+ *
+ * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise.
+ */
+ public function save($id, $data, $lifeTime = 0){
+ $cacheDriver = $this->getCacheDriver();
+
+ if (! isset($cacheDriver)) {
+ return false;
+ }
+
+ $result = $cacheDriver->save($id, $data, $lifeTime);
+
+ return $result;
+ }
+
+ /**
+ * Deletes an entry from the cache
+ *
+ * @param string $id The id of the cache entry to fetch.
+ *
+ * @return boolean TRUE if the entry was successfully deleted, FALSE otherwise.
+ */
+ public function delete($id){
+ $cacheDriver = $this->getCacheDriver();
+
+ if (isset($cacheDriver) && $cacheDriver->contains($id)) {
+ $result = $cacheDriver->delete($id);
+ return $result;
+ }
+
+ return false;
+ }
+
+ /**
+ * Deletes ALL entries from the cache
+ *
+ * @param string $id The id of the cache entry to fetch.
+ *
+ * @return boolean TRUE if the entries were successfully deleted, FALSE otherwise.
+ */
+ public function deleteAll(){
+ $cacheDriver = $this->getCacheDriver();
+
+ if (isset($cacheDriver)) {
+ $result = $cacheDriver->deleteAll($id);
+ return $result;
+ }
+
+ return false;
+ }
+}
diff --git a/core/src/plugins/core.cache/class.CoreCacheLoader.php b/core/src/plugins/core.cache/class.CoreCacheLoader.php
new file mode 100644
index 0000000000..3735c8b61a
--- /dev/null
+++ b/core/src/plugins/core.cache/class.CoreCacheLoader.php
@@ -0,0 +1,52 @@
+
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see .
+ *
+ * The latest code can be found at .
+ */
+defined('AJXP_EXEC') or die( 'Access not allowed');
+
+/**
+ * @package AjaXplorer_Plugins
+ * @subpackage Core
+ * @static
+ * Provides access to the cache via the Doctrine interface
+ */
+class CoreCacheLoader extends AJXP_Plugin
+{
+ /**
+ * @var AbstractCachegDriver
+ */
+ protected static $cacheInstance;
+
+ public function getCacheImpl()
+ {
+ if (!isSet(self::$cacheInstance) || (isset($this->pluginConf["UNIQUE_INSTANCE_CONFIG"]["instance_name"]) && self::$cacheInstance->getId() != $this->pluginConf["UNIQUE_INSTANCE_CONFIG"]["instance_name"])) {
+ if (isset($this->pluginConf["UNIQUE_INSTANCE_CONFIG"])) {
+ AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Instantiating ");
+ $this->pluginInstance = ConfService::instanciatePluginFromGlobalParams($this->pluginConf["UNIQUE_INSTANCE_CONFIG"], "AbstractCacheDriver");
+
+ if ($this->pluginInstance != false) {
+ AJXP_PluginsService::getInstance()->setPluginUniqueActiveForType("cache", $this->pluginInstance->getName(), $this->pluginInstance);
+ }
+ }
+ }
+
+ self::$cacheInstance = $this->pluginInstance;
+ return self::$cacheInstance;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/composer.json b/core/src/plugins/core.cache/doctrine/composer.json
new file mode 100644
index 0000000000..51c774b4fc
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "doctrine/cache": "*"
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/composer.lock b/core/src/plugins/core.cache/doctrine/composer.lock
new file mode 100644
index 0000000000..06dbb3121d
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/composer.lock
@@ -0,0 +1,89 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "3553070087b04043fc500ca92019f393",
+ "content-hash": "5ddea3bb5fa64282cbba71f90a4e9254",
+ "packages": [
+ {
+ "name": "doctrine/cache",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/cache.git",
+ "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
+ "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~5.5|~7.0"
+ },
+ "conflict": {
+ "doctrine/common": ">2.2,<2.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8|~5.0",
+ "predis/predis": "~1.0",
+ "satooshi/php-coveralls": "~0.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "Caching library offering an object-oriented API for many cache backends",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "cache",
+ "caching"
+ ],
+ "time": "2015-12-31 16:37:02"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": []
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/autoload.php b/core/src/plugins/core.cache/doctrine/vendor/autoload.php
new file mode 100644
index 0000000000..df8d2aa5c5
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/autoload.php
@@ -0,0 +1,7 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @see http://www.php-fig.org/psr/psr-0/
+ * @see http://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ // PSR-4
+ private $prefixLengthsPsr4 = array();
+ private $prefixDirsPsr4 = array();
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ private $prefixesPsr0 = array();
+ private $fallbackDirsPsr0 = array();
+
+ private $useIncludePath = false;
+ private $classMap = array();
+
+ private $classMapAuthoritative = false;
+
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
+ }
+
+ return array();
+ }
+
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 base directories
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return bool|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
+ if ('\\' == $class[0]) {
+ $class = substr($class, 1);
+ }
+
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative) {
+ return false;
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if ($file === null && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if ($file === null) {
+ // Remember that this class does not exist.
+ return $this->classMap[$class] = false;
+ }
+
+ return $file;
+ }
+
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/composer/LICENSE b/core/src/plugins/core.cache/doctrine/vendor/composer/LICENSE
new file mode 100644
index 0000000000..c8d57af8b2
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) 2015 Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/core/src/plugins/core.cache/doctrine/vendor/composer/autoload_classmap.php b/core/src/plugins/core.cache/doctrine/vendor/composer/autoload_classmap.php
new file mode 100644
index 0000000000..7a91153b0d
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/composer/autoload_classmap.php
@@ -0,0 +1,9 @@
+ array($vendorDir . '/doctrine/cache/lib/Doctrine/Common/Cache'),
+);
diff --git a/core/src/plugins/core.cache/doctrine/vendor/composer/autoload_real.php b/core/src/plugins/core.cache/doctrine/vendor/composer/autoload_real.php
new file mode 100644
index 0000000000..f58b55f299
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/composer/autoload_real.php
@@ -0,0 +1,45 @@
+ $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/composer/installed.json b/core/src/plugins/core.cache/doctrine/vendor/composer/installed.json
new file mode 100644
index 0000000000..d1165376aa
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/composer/installed.json
@@ -0,0 +1,74 @@
+[
+ {
+ "name": "doctrine/cache",
+ "version": "v1.6.0",
+ "version_normalized": "1.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/cache.git",
+ "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
+ "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~5.5|~7.0"
+ },
+ "conflict": {
+ "doctrine/common": ">2.2,<2.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8|~5.0",
+ "predis/predis": "~1.0",
+ "satooshi/php-coveralls": "~0.6"
+ },
+ "time": "2015-12-31 16:37:02",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com"
+ },
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com"
+ }
+ ],
+ "description": "Caching library offering an object-oriented API for many cache backends",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "cache",
+ "caching"
+ ]
+ }
+]
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.coveralls.yml b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.coveralls.yml
new file mode 100644
index 0000000000..0c08233606
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.coveralls.yml
@@ -0,0 +1,4 @@
+# for php-coveralls
+service_name: travis-ci
+src_dir: lib
+coverage_clover: build/logs/clover.xml
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.gitignore b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.gitignore
new file mode 100644
index 0000000000..ca2302312b
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.gitignore
@@ -0,0 +1,4 @@
+vendor/
+build/
+phpunit.xml
+composer.lock
\ No newline at end of file
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.travis.yml b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.travis.yml
new file mode 100644
index 0000000000..a16fd9d930
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/.travis.yml
@@ -0,0 +1,42 @@
+language: php
+
+sudo: false
+
+cache:
+ directories:
+ - vendor
+ - $HOME/.composer/cache
+
+php:
+ - 5.5
+ - 5.6
+ - 7.0
+ - hhvm
+
+services:
+ - riak
+ - mongodb
+ - memcached
+ - redis-server
+
+before_install:
+ - 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:
+ - travis_retry composer install
+
+script:
+ - ./vendor/bin/phpunit -c ./tests/travis/phpunit.travis.xml -v
+
+after_script:
+ - php vendor/bin/coveralls -v
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - php: hhvm
+ - php: 7.0
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/LICENSE b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/LICENSE
new file mode 100644
index 0000000000..8c38cc1bc2
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/LICENSE
@@ -0,0 +1,19 @@
+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
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/README.md b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/README.md
new file mode 100644
index 0000000000..94f80a30ee
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/README.md
@@ -0,0 +1,14 @@
+# Doctrine Cache
+
+Master: [![Build Status](https://secure.travis-ci.org/doctrine/cache.png?branch=master)](http://travis-ci.org/doctrine/cache) [![Coverage Status](https://coveralls.io/repos/doctrine/cache/badge.png?branch=master)](https://coveralls.io/r/doctrine/cache?branch=master)
+
+[![Latest Stable Version](https://poser.pugx.org/doctrine/cache/v/stable.png)](https://packagist.org/packages/doctrine/cache) [![Total Downloads](https://poser.pugx.org/doctrine/cache/downloads.png)](https://packagist.org/packages/doctrine/cache)
+
+Cache component extracted from the Doctrine Common project.
+
+## Changelog
+
+### v1.2
+
+* Added support for MongoDB as Cache Provider
+* Fix namespace version reset
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/UPGRADE.md b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/UPGRADE.md
new file mode 100644
index 0000000000..e1f8a503ee
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/UPGRADE.md
@@ -0,0 +1,16 @@
+# Upgrade to 1.4
+
+## Minor BC Break: `Doctrine\Common\Cache\FileCache#$extension` is now `private`.
+
+If you need to override the value of `Doctrine\Common\Cache\FileCache#$extension`, then use the
+second parameter of `Doctrine\Common\Cache\FileCache#__construct()` instead of overriding
+the property in your own implementation.
+
+## Minor BC Break: file based caches paths changed
+
+`Doctrine\Common\Cache\FileCache`, `Doctrine\Common\Cache\PhpFileCache` and
+`Doctrine\Common\Cache\FilesystemCache` are using a different cache paths structure.
+
+If you rely on warmed up caches for deployments, consider that caches generated
+with `doctrine/cache` `<1.4` are not compatible with the new directory structure,
+and will be ignored.
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/build.properties b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/build.properties
new file mode 100644
index 0000000000..2d98c360aa
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/build.properties
@@ -0,0 +1,3 @@
+# Version class and file
+project.version_class = Doctrine\\Common\\Cache\\Version
+project.version_file = lib/Doctrine/Common/Cache/Version.php
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/build.xml b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/build.xml
new file mode 100644
index 0000000000..a7c52e3cf3
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/build.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/composer.json b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/composer.json
new file mode 100644
index 0000000000..7ef1727a10
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "doctrine/cache",
+ "type": "library",
+ "description": "Caching library offering an object-oriented API for many cache backends",
+ "keywords": ["cache", "caching"],
+ "homepage": "http://www.doctrine-project.org",
+ "license": "MIT",
+ "authors": [
+ {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
+ {"name": "Roman Borschel", "email": "roman@code-factory.org"},
+ {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
+ {"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
+ {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
+ ],
+ "require": {
+ "php": "~5.5|~7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8|~5.0",
+ "satooshi/php-coveralls": "~0.6",
+ "predis/predis": "~1.0"
+ },
+ "conflict": {
+ "doctrine/common": ">2.2,<2.4"
+ },
+ "autoload": {
+ "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Doctrine\\Tests\\": "tests/Doctrine/Tests" }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php
new file mode 100644
index 0000000000..7c617f33da
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php
@@ -0,0 +1,118 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * APC cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @deprecated since version 1.6, use ApcuCache instead
+ * @since 2.0
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author David Abdemoulaie
+ */
+class ApcCache extends CacheProvider
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return apc_fetch($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return apc_exists($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ return apc_store($id, $data, $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ // apc_delete returns false if the id does not exist
+ return apc_delete($id) || ! apc_exists($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ return apc_clear_cache() && apc_clear_cache('user');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetchMultiple(array $keys)
+ {
+ return apc_fetch($keys);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
+ {
+ $result = apc_store($keysAndValues, null, $lifetime);
+
+ return empty($result);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $info = apc_cache_info('', true);
+ $sma = apc_sma_info();
+
+ // @TODO - Temporary fix @see https://github.com/krakjoe/apcu/pull/42
+ if (PHP_VERSION_ID >= 50500) {
+ $info['num_hits'] = isset($info['num_hits']) ? $info['num_hits'] : $info['nhits'];
+ $info['num_misses'] = isset($info['num_misses']) ? $info['num_misses'] : $info['nmisses'];
+ $info['start_time'] = isset($info['start_time']) ? $info['start_time'] : $info['stime'];
+ }
+
+ 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'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcuCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcuCache.php
new file mode 100644
index 0000000000..d86e1be375
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcuCache.php
@@ -0,0 +1,106 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * APCu cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 1.6
+ * @author Kévin Dunglas
+ */
+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'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php
new file mode 100644
index 0000000000..6610cc2173
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php
@@ -0,0 +1,142 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Array cache driver.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.0
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author David Abdemoulaie
+ */
+class ArrayCache extends CacheProvider
+{
+ /**
+ * @var array[] $data each element being a tuple of [$data, $expiration], where the expiration is int|bool
+ */
+ 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)
+ {
+ if (! $this->doContains($id)) {
+ $this->missesCount += 1;
+
+ return false;
+ }
+
+ $this->hitsCount += 1;
+
+ return $this->data[$id][0];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ if (! isset($this->data[$id])) {
+ return false;
+ }
+
+ $expiration = $this->data[$id][1];
+
+ if ($expiration && $expiration < time()) {
+ $this->doDelete($id);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ $this->data[$id] = [$data, $lifeTime ? time() + $lifeTime : false];
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ unset($this->data[$id]);
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ $this->data = [];
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ 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,
+ ];
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php
new file mode 100644
index 0000000000..89fe32307f
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php
@@ -0,0 +1,116 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Interface for cache drivers.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.0
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Fabio B. Silva
+ * @author Kévin Dunglas
+ */
+interface Cache
+{
+ const STATS_HITS = 'hits';
+ const STATS_MISSES = 'misses';
+ const STATS_UPTIME = 'uptime';
+ const STATS_MEMORY_USAGE = 'memory_usage';
+ const STATS_MEMORY_AVAILABLE = 'memory_available';
+ /**
+ * Only for backward compatibility (may be removed in next major release)
+ *
+ * @deprecated
+ */
+ const STATS_MEMORY_AVAILIABLE = 'memory_available';
+
+ /**
+ * Fetches an entry from the cache.
+ *
+ * @param string $id The id of the cache entry to fetch.
+ *
+ * @return mixed The cached data or FALSE, if no cache entry exists for the given id.
+ */
+ public function fetch($id);
+
+ /**
+ * Tests if an entry exists in the cache.
+ *
+ * @param string $id The cache id of the entry to check for.
+ *
+ * @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 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 bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
+ */
+ public function save($id, $data, $lifeTime = 0);
+
+ /**
+ * Deletes a cache entry.
+ *
+ * @param string $id The cache id.
+ *
+ * @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
+ * Deleting a non-existing entry is considered successful.
+ */
+ public function delete($id);
+
+ /**
+ * Retrieves cached information from the data store.
+ *
+ * The server's statistics array has the following values:
+ *
+ * - hits
+ * Number of keys that have been requested and found present.
+ *
+ * - misses
+ * Number of items that have been requested and not found.
+ *
+ * - uptime
+ * Time that the server is running.
+ *
+ * - memory_usage
+ * Memory used by this server to store items.
+ *
+ * - memory_available
+ * Memory allowed to use for storage.
+ *
+ * @since 2.2
+ *
+ * @return array|null An associative array with server's statistics if available, NULL otherwise.
+ */
+ public function getStats();
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php
new file mode 100644
index 0000000000..9f579237a6
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php
@@ -0,0 +1,312 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Base class for cache provider implementations.
+ *
+ * @since 2.2
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Fabio B. Silva
+ */
+abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiGetCache, MultiPutCache
+{
+ const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]';
+
+ /**
+ * The namespace to prefix all cache ids with.
+ *
+ * @var string
+ */
+ private $namespace = '';
+
+ /**
+ * The namespace version.
+ *
+ * @var integer|null
+ */
+ private $namespaceVersion;
+
+ /**
+ * Sets the namespace to prefix all cache ids with.
+ *
+ * @param string $namespace
+ *
+ * @return void
+ */
+ public function setNamespace($namespace)
+ {
+ $this->namespace = (string) $namespace;
+ $this->namespaceVersion = null;
+ }
+
+ /**
+ * Retrieves the namespace that prefixes all cache ids.
+ *
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return $this->namespace;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function fetch($id)
+ {
+ return $this->doFetch($this->getNamespacedId($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ 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);
+ $foundItems = array();
+
+ // 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]) || array_key_exists($namespacedKey, $items)) {
+ $foundItems[$requestedKey] = $items[$namespacedKey];
+ }
+ }
+
+ 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}
+ */
+ public function contains($id)
+ {
+ return $this->doContains($this->getNamespacedId($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save($id, $data, $lifeTime = 0)
+ {
+ return $this->doSave($this->getNamespacedId($id), $data, $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete($id)
+ {
+ return $this->doDelete($this->getNamespacedId($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStats()
+ {
+ return $this->doGetStats();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function flushAll()
+ {
+ return $this->doFlush();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function deleteAll()
+ {
+ $namespaceCacheKey = $this->getNamespaceCacheKey();
+ $namespaceVersion = $this->getNamespaceVersion() + 1;
+
+ if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
+ $this->namespaceVersion = $namespaceVersion;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Prefixes the passed id with the configured namespace value.
+ *
+ * @param string $id The id to namespace.
+ *
+ * @return string The namespaced id.
+ */
+ private function getNamespacedId($id)
+ {
+ $namespaceVersion = $this->getNamespaceVersion();
+
+ return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
+ }
+
+ /**
+ * Returns the namespace cache key.
+ *
+ * @return string
+ */
+ private function getNamespaceCacheKey()
+ {
+ return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
+ }
+
+ /**
+ * Returns the namespace version.
+ *
+ * @return integer
+ */
+ private function getNamespaceVersion()
+ {
+ if (null !== $this->namespaceVersion) {
+ return $this->namespaceVersion;
+ }
+
+ $namespaceCacheKey = $this->getNamespaceCacheKey();
+ $this->namespaceVersion = $this->doFetch($namespaceCacheKey) ?: 1;
+
+ return $this->namespaceVersion;
+ }
+
+ /**
+ * Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it.
+ *
+ * @param array $keys Array of keys to retrieve from cache
+ * @return array Array of values retrieved for the given keys.
+ */
+ protected function doFetchMultiple(array $keys)
+ {
+ $returnValues = array();
+
+ foreach ($keys as $key) {
+ if (false !== ($item = $this->doFetch($key)) || $this->doContains($key)) {
+ $returnValues[$key] = $item;
+ }
+ }
+
+ return $returnValues;
+ }
+
+ /**
+ * Fetches an entry from the cache.
+ *
+ * @param string $id The id of the cache entry to fetch.
+ *
+ * @return mixed|false The cached data or FALSE, if no cache entry exists for the given id.
+ */
+ abstract protected function doFetch($id);
+
+ /**
+ * Tests if an entry exists in the cache.
+ *
+ * @param string $id The cache id of the entry to check for.
+ *
+ * @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.
+ *
+ * @param string $id The cache id.
+ * @param string $data The cache entry/data.
+ * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this
+ * cache entry (0 => infinite lifeTime).
+ *
+ * @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
+ */
+ abstract protected function doSave($id, $data, $lifeTime = 0);
+
+ /**
+ * Deletes a cache entry.
+ *
+ * @param string $id The cache id.
+ *
+ * @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
+ */
+ abstract protected function doDelete($id);
+
+ /**
+ * Flushes all cache entries.
+ *
+ * @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
+ */
+ abstract protected function doFlush();
+
+ /**
+ * Retrieves cached information from the data store.
+ *
+ * @since 2.2
+ *
+ * @return array|null An associative array with server's statistics if available, NULL otherwise.
+ */
+ abstract protected function doGetStats();
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ChainCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ChainCache.php
new file mode 100644
index 0000000000..96c9b5479f
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ChainCache.php
@@ -0,0 +1,147 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Cache provider that allows to easily chain multiple cache providers
+ *
+ * @author Michaël Gallego
+ */
+class ChainCache extends CacheProvider
+{
+ /**
+ * @var CacheProvider[]
+ */
+ private $cacheProviders = array();
+
+ /**
+ * Constructor
+ *
+ * @param CacheProvider[] $cacheProviders
+ */
+ public function __construct($cacheProviders = array())
+ {
+ $this->cacheProviders = $cacheProviders;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setNamespace($namespace)
+ {
+ parent::setNamespace($namespace);
+
+ foreach ($this->cacheProviders as $cacheProvider) {
+ $cacheProvider->setNamespace($namespace);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doFetch($id)
+ {
+ foreach ($this->cacheProviders as $key => $cacheProvider) {
+ if ($cacheProvider->doContains($id)) {
+ $value = $cacheProvider->doFetch($id);
+
+ // We populate all the previous cache layers (that are assumed to be faster)
+ for ($subKey = $key - 1 ; $subKey >= 0 ; $subKey--) {
+ $this->cacheProviders[$subKey]->doSave($id, $value);
+ }
+
+ return $value;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doContains($id)
+ {
+ foreach ($this->cacheProviders as $cacheProvider) {
+ if ($cacheProvider->doContains($id)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ $stored = true;
+
+ foreach ($this->cacheProviders as $cacheProvider) {
+ $stored = $cacheProvider->doSave($id, $data, $lifeTime) && $stored;
+ }
+
+ return $stored;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doDelete($id)
+ {
+ $deleted = true;
+
+ foreach ($this->cacheProviders as $cacheProvider) {
+ $deleted = $cacheProvider->doDelete($id) && $deleted;
+ }
+
+ return $deleted;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doFlush()
+ {
+ $flushed = true;
+
+ foreach ($this->cacheProviders as $cacheProvider) {
+ $flushed = $cacheProvider->doFlush() && $flushed;
+ }
+
+ return $flushed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doGetStats()
+ {
+ // We return all the stats from all adapters
+ $stats = array();
+
+ foreach ($this->cacheProviders as $cacheProvider) {
+ $stats[] = $cacheProvider->doGetStats();
+ }
+
+ return $stats;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php
new file mode 100644
index 0000000000..3a91eaf3a2
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php
@@ -0,0 +1,40 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Interface for cache that can be flushed.
+ *
+ * Intended to be used for partial clearing of a cache namespace. For a more
+ * global "flushing", see {@see FlushableCache}.
+ *
+ * @link www.doctrine-project.org
+ * @since 1.4
+ * @author Adirelle
+ */
+interface ClearableCache
+{
+ /**
+ * Deletes all cache entries in the current cache namespace.
+ *
+ * @return bool TRUE if the cache entries were successfully deleted, FALSE otherwise.
+ */
+ public function deleteAll();
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php
new file mode 100644
index 0000000000..c21691df96
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php
@@ -0,0 +1,121 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use \Couchbase;
+
+/**
+ * Couchbase cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.4
+ * @author Michael Nitschinger
+ */
+class CouchbaseCache extends CacheProvider
+{
+ /**
+ * @var Couchbase|null
+ */
+ private $couchbase;
+
+ /**
+ * Sets the Couchbase instance to use.
+ *
+ * @param Couchbase $couchbase
+ *
+ * @return void
+ */
+ public function setCouchbase(Couchbase $couchbase)
+ {
+ $this->couchbase = $couchbase;
+ }
+
+ /**
+ * Gets the Couchbase instance used by the cache.
+ *
+ * @return Couchbase|null
+ */
+ public function getCouchbase()
+ {
+ return $this->couchbase;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return $this->couchbase->get($id) ?: false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return (null !== $this->couchbase->get($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ if ($lifeTime > 30 * 24 * 3600) {
+ $lifeTime = time() + $lifeTime;
+ }
+ return $this->couchbase->set($id, $data, (int) $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return $this->couchbase->delete($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ return $this->couchbase->flush();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $stats = $this->couchbase->getStats();
+ $servers = $this->couchbase->getServers();
+ $server = explode(":", $servers[0]);
+ $key = $server[0] . ":" . "11210";
+ $stats = $stats[$key];
+ return array(
+ Cache::STATS_HITS => $stats['get_hits'],
+ Cache::STATS_MISSES => $stats['get_misses'],
+ Cache::STATS_UPTIME => $stats['uptime'],
+ Cache::STATS_MEMORY_USAGE => $stats['bytes'],
+ Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php
new file mode 100644
index 0000000000..b2e0427e59
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php
@@ -0,0 +1,286 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Base file cache driver.
+ *
+ * @since 2.3
+ * @author Fabio B. Silva
+ * @author Tobias Schultze
+ */
+abstract class FileCache extends CacheProvider
+{
+ /**
+ * The cache directory.
+ *
+ * @var string
+ */
+ protected $directory;
+
+ /**
+ * The cache file extension.
+ *
+ * @var string
+ */
+ private $extension;
+
+ /**
+ * @var int
+ */
+ private $umask;
+
+ /**
+ * @var int
+ */
+ private $directoryStringLength;
+
+ /**
+ * @var int
+ */
+ private $extensionStringLength;
+
+ /**
+ * @var bool
+ */
+ private $isRunningOnWindows;
+
+ /**
+ * Constructor.
+ *
+ * @param string $directory The cache directory.
+ * @param string $extension The cache file extension.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct($directory, $extension = '', $umask = 0002)
+ {
+ // YES, this needs to be *before* createPathIfNeeded()
+ if ( ! is_int($umask)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'The umask parameter is required to be integer, was: %s',
+ gettype($umask)
+ ));
+ }
+ $this->umask = $umask;
+
+ if ( ! $this->createPathIfNeeded($directory)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'The directory "%s" does not exist and could not be created.',
+ $directory
+ ));
+ }
+
+ if ( ! is_writable($directory)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'The directory "%s" is not writable.',
+ $directory
+ ));
+ }
+
+ // 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');
+ }
+
+ /**
+ * Gets the cache directory.
+ *
+ * @return string
+ */
+ public function getDirectory()
+ {
+ return $this->directory;
+ }
+
+ /**
+ * Gets the cache file extension.
+ *
+ * @return string
+ */
+ public function getExtension()
+ {
+ return $this->extension;
+ }
+
+ /**
+ * @param string $id
+ *
+ * @return string
+ */
+ 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
+ . substr($hash, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . $filename
+ . $this->extension;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ $filename = $this->getFilename($id);
+
+ return @unlink($filename) || ! file_exists($filename);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ foreach ($this->getIterator() as $name => $file) {
+ 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;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $usage = 0;
+ foreach ($this->getIterator() as $name => $file) {
+ if (! $file->isDir() && $this->isFilenameEndingWithExtension($name)) {
+ $usage += $file->getSize();
+ }
+ }
+
+ $free = disk_free_space($this->directory);
+
+ return array(
+ Cache::STATS_HITS => null,
+ Cache::STATS_MISSES => null,
+ Cache::STATS_UPTIME => null,
+ Cache::STATS_MEMORY_USAGE => $usage,
+ Cache::STATS_MEMORY_AVAILABLE => $free,
+ );
+ }
+
+ /**
+ * Create path if needed.
+ *
+ * @param string $path
+ * @return bool TRUE on success or if path already exists, FALSE if path cannot be created.
+ */
+ private function createPathIfNeeded($path)
+ {
+ if ( ! is_dir($path)) {
+ if (false === @mkdir($path, 0777 & (~$this->umask), true) && !is_dir($path)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Writes a string content to file in an atomic way.
+ *
+ * @param string $filename Path to the file where to write the data.
+ * @param string $content The content to write
+ *
+ * @return bool TRUE on success, FALSE if path cannot be created, if path is not writable or an any other error.
+ */
+ protected function writeFile($filename, $content)
+ {
+ $filepath = pathinfo($filename, PATHINFO_DIRNAME);
+
+ if ( ! $this->createPathIfNeeded($filepath)) {
+ return false;
+ }
+
+ if ( ! is_writable($filepath)) {
+ return false;
+ }
+
+ $tmpFile = tempnam($filepath, 'swap');
+ @chmod($tmpFile, 0666 & (~$this->umask));
+
+ if (file_put_contents($tmpFile, $content) !== false) {
+ if (@rename($tmpFile, $filename)) {
+ return true;
+ }
+
+ @unlink($tmpFile);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return \Iterator
+ */
+ private function getIterator()
+ {
+ 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);
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php
new file mode 100644
index 0000000000..d988294f6f
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php
@@ -0,0 +1,111 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Filesystem cache driver.
+ *
+ * @since 2.3
+ * @author Fabio B. Silva
+ */
+class FilesystemCache extends FileCache
+{
+ const EXTENSION = '.doctrinecache.data';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
+ {
+ parent::__construct($directory, $extension, $umask);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ $data = '';
+ $lifetime = -1;
+ $filename = $this->getFilename($id);
+
+ if ( ! is_file($filename)) {
+ return false;
+ }
+
+ $resource = fopen($filename, "r");
+
+ if (false !== ($line = fgets($resource))) {
+ $lifetime = (int) $line;
+ }
+
+ if ($lifetime !== 0 && $lifetime < time()) {
+ fclose($resource);
+
+ return false;
+ }
+
+ while (false !== ($line = fgets($resource))) {
+ $data .= $line;
+ }
+
+ fclose($resource);
+
+ return unserialize($data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ $lifetime = -1;
+ $filename = $this->getFilename($id);
+
+ if ( ! is_file($filename)) {
+ return false;
+ }
+
+ $resource = fopen($filename, "r");
+
+ if (false !== ($line = fgets($resource))) {
+ $lifetime = (int) $line;
+ }
+
+ fclose($resource);
+
+ return $lifetime === 0 || $lifetime > time();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ if ($lifeTime > 0) {
+ $lifeTime = time() + $lifeTime;
+ }
+
+ $data = serialize($data);
+ $filename = $this->getFilename($id);
+
+ return $this->writeFile($filename, $lifeTime . PHP_EOL . $data);
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FlushableCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FlushableCache.php
new file mode 100644
index 0000000000..4311d4f593
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FlushableCache.php
@@ -0,0 +1,37 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Interface for cache that can be flushed.
+ *
+ * @link www.doctrine-project.org
+ * @since 1.4
+ * @author Adirelle
+ */
+interface FlushableCache
+{
+ /**
+ * Flushes all cache entries, globally.
+ *
+ * @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
+ */
+ public function flushAll();
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php
new file mode 100644
index 0000000000..8afaeeacc2
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php
@@ -0,0 +1,126 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use \Memcache;
+
+/**
+ * Memcache cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.0
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author David Abdemoulaie
+ */
+class MemcacheCache extends CacheProvider
+{
+ /**
+ * @var Memcache|null
+ */
+ private $memcache;
+
+ /**
+ * Sets the memcache instance to use.
+ *
+ * @param Memcache $memcache
+ *
+ * @return void
+ */
+ public function setMemcache(Memcache $memcache)
+ {
+ $this->memcache = $memcache;
+ }
+
+ /**
+ * Gets the memcache instance used by the cache.
+ *
+ * @return Memcache|null
+ */
+ public function getMemcache()
+ {
+ return $this->memcache;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return $this->memcache->get($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ $flags = null;
+ $this->memcache->get($id, $flags);
+
+ //if memcache has changed the value of "flags", it means the value exists
+ return ($flags !== null);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ if ($lifeTime > 30 * 24 * 3600) {
+ $lifeTime = time() + $lifeTime;
+ }
+ return $this->memcache->set($id, $data, 0, (int) $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ // Memcache::delete() returns false if entry does not exist
+ return $this->memcache->delete($id) || ! $this->doContains($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ return $this->memcache->flush();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $stats = $this->memcache->getStats();
+ return array(
+ Cache::STATS_HITS => $stats['get_hits'],
+ Cache::STATS_MISSES => $stats['get_misses'],
+ Cache::STATS_UPTIME => $stats['uptime'],
+ Cache::STATS_MEMORY_USAGE => $stats['bytes'],
+ Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php
new file mode 100644
index 0000000000..408e452b90
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php
@@ -0,0 +1,146 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use \Memcached;
+
+/**
+ * Memcached cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.2
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author David Abdemoulaie
+ */
+class MemcachedCache extends CacheProvider
+{
+ /**
+ * @var Memcached|null
+ */
+ private $memcached;
+
+ /**
+ * Sets the memcache instance to use.
+ *
+ * @param Memcached $memcached
+ *
+ * @return void
+ */
+ public function setMemcached(Memcached $memcached)
+ {
+ $this->memcached = $memcached;
+ }
+
+ /**
+ * Gets the memcached instance used by the cache.
+ *
+ * @return Memcached|null
+ */
+ public function getMemcached()
+ {
+ return $this->memcached;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return $this->memcached->get($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetchMultiple(array $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, null, $lifetime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return false !== $this->memcached->get($id)
+ || $this->memcached->getResultCode() !== Memcached::RES_NOTFOUND;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ if ($lifeTime > 30 * 24 * 3600) {
+ $lifeTime = time() + $lifeTime;
+ }
+ return $this->memcached->set($id, $data, (int) $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return $this->memcached->delete($id)
+ || $this->memcached->getResultCode() === Memcached::RES_NOTFOUND;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ return $this->memcached->flush();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $stats = $this->memcached->getStats();
+ $servers = $this->memcached->getServerList();
+ $key = $servers[0]['host'] . ':' . $servers[0]['port'];
+ $stats = $stats[$key];
+ return array(
+ Cache::STATS_HITS => $stats['get_hits'],
+ Cache::STATS_MISSES => $stats['get_misses'],
+ Cache::STATS_UPTIME => $stats['uptime'],
+ Cache::STATS_MEMORY_USAGE => $stats['bytes'],
+ Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MongoDBCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MongoDBCache.php
new file mode 100644
index 0000000000..75fe0ca113
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MongoDBCache.php
@@ -0,0 +1,197 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use MongoBinData;
+use MongoCollection;
+use MongoCursorException;
+use MongoDate;
+
+/**
+ * MongoDB cache provider.
+ *
+ * @since 1.1
+ * @author Jeremy Mikola
+ */
+class MongoDBCache extends CacheProvider
+{
+ /**
+ * The data field will store the serialized PHP value.
+ */
+ const DATA_FIELD = 'd';
+
+ /**
+ * The expiration field will store a MongoDate value indicating when the
+ * cache entry should expire.
+ *
+ * With MongoDB 2.2+, entries can be automatically deleted by MongoDB by
+ * 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.
+ *
+ * The cache provider will also check dates on its own, in case expired
+ * entries are fetched before MongoDB's TTLMonitor pass can expire them.
+ *
+ * @see http://docs.mongodb.org/manual/tutorial/expire-data/
+ */
+ const EXPIRATION_FIELD = 'e';
+
+ /**
+ * @var MongoCollection
+ */
+ private $collection;
+
+ /**
+ * Constructor.
+ *
+ * This provider will default to the write concern and read preference
+ * options set on the MongoCollection instance (or inherited from MongoDB or
+ * MongoClient). Using an unacknowledged write concern (< 1) may make the
+ * return values of delete() and save() unreliable. Reading from secondaries
+ * may make contain() and fetch() unreliable.
+ *
+ * @see http://www.php.net/manual/en/mongo.readpreferences.php
+ * @see http://www.php.net/manual/en/mongo.writeconcerns.php
+ * @param MongoCollection $collection
+ */
+ public function __construct(MongoCollection $collection)
+ {
+ $this->collection = $collection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ $document = $this->collection->findOne(array('_id' => $id), array(self::DATA_FIELD, self::EXPIRATION_FIELD));
+
+ if ($document === null) {
+ return false;
+ }
+
+ if ($this->isExpired($document)) {
+ $this->doDelete($id);
+ return false;
+ }
+
+ return unserialize($document[self::DATA_FIELD]->bin);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ $document = $this->collection->findOne(array('_id' => $id), array(self::EXPIRATION_FIELD));
+
+ if ($document === null) {
+ return false;
+ }
+
+ if ($this->isExpired($document)) {
+ $this->doDelete($id);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ 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;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ $result = $this->collection->remove(array('_id' => $id));
+
+ return isset($result['ok']) ? $result['ok'] == 1 : true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ // Use remove() in lieu of drop() to maintain any collection indexes
+ $result = $this->collection->remove();
+
+ return isset($result['ok']) ? $result['ok'] == 1 : true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $serverStatus = $this->collection->db->command(array(
+ 'serverStatus' => 1,
+ 'locks' => 0,
+ 'metrics' => 0,
+ 'recordStats' => 0,
+ 'repl' => 0,
+ ));
+
+ $collStats = $this->collection->db->command(array('collStats' => 1));
+
+ return array(
+ Cache::STATS_HITS => null,
+ Cache::STATS_MISSES => 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,
+ );
+ }
+
+ /**
+ * Check if the document is expired.
+ *
+ * @param array $document
+ *
+ * @return bool
+ */
+ private function isExpired(array $document)
+ {
+ return isset($document[self::EXPIRATION_FIELD]) &&
+ $document[self::EXPIRATION_FIELD] instanceof MongoDate &&
+ $document[self::EXPIRATION_FIELD]->sec < time();
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MultiGetCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MultiGetCache.php
new file mode 100644
index 0000000000..df7146d78e
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MultiGetCache.php
@@ -0,0 +1,39 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Interface for cache drivers that allows to get many items at once.
+ *
+ * @link www.doctrine-project.org
+ * @since 1.4
+ * @author Asmir Mustafic
+ */
+interface MultiGetCache
+{
+ /**
+ * Returns an associative array of values for keys is found in cache.
+ *
+ * @param string[] $keys Array of keys to retrieve from cache
+ * @return mixed[] Array of retrieved values, indexed by the specified keys.
+ * Values that couldn't be retrieved are not contained in this array.
+ */
+ function fetchMultiple(array $keys);
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MultiPutCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MultiPutCache.php
new file mode 100644
index 0000000000..bf87ea9f1c
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MultiPutCache.php
@@ -0,0 +1,41 @@
+.
+ */
+
+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
+ */
+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);
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php
new file mode 100644
index 0000000000..5e7519674e
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php
@@ -0,0 +1,120 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Php file cache driver.
+ *
+ * @since 2.3
+ * @author Fabio B. Silva
+ */
+class PhpFileCache extends FileCache
+{
+ const EXTENSION = '.doctrinecache.php';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
+ {
+ parent::__construct($directory, $extension, $umask);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ $value = $this->includeFileForId($id);
+
+ if (! $value) {
+ return false;
+ }
+
+ if ($value['lifetime'] !== 0 && $value['lifetime'] < time()) {
+ return false;
+ }
+
+ return $value['data'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ $value = $this->includeFileForId($id);
+
+ if (! $value) {
+ return false;
+ }
+
+ return $value['lifetime'] === 0 || $value['lifetime'] > time();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ if ($lifeTime > 0) {
+ $lifeTime = time() + $lifeTime;
+ }
+
+ if (is_object($data) && ! method_exists($data, '__set_state')) {
+ throw new \InvalidArgumentException(
+ "Invalid argument given, PhpFileCache only allows objects that implement __set_state() " .
+ "and fully support var_export(). You can use the FilesystemCache to save arbitrary object " .
+ "graphs using serialize()/deserialize()."
+ );
+ }
+
+ $filename = $this->getFilename($id);
+
+ $value = array(
+ 'lifetime' => $lifeTime,
+ 'data' => $data
+ );
+
+ $value = var_export($value, true);
+ $code = sprintf('writeFile($filename, $code);
+ }
+
+ /**
+ * @param string $id
+ *
+ * @return array|false
+ */
+ private function includeFileForId($id)
+ {
+ $fileName = $this->getFilename($id);
+
+ // note: error suppression is still faster than `file_exists`, `is_file` and `is_readable`
+ $value = @include $fileName;
+
+ if (! isset($value['lifetime'])) {
+ return false;
+ }
+
+ return $value;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PredisCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PredisCache.php
new file mode 100644
index 0000000000..980e266060
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PredisCache.php
@@ -0,0 +1,136 @@
+
+ */
+class PredisCache extends CacheProvider
+{
+ /**
+ * @var ClientInterface
+ */
+ private $client;
+
+ /**
+ * @param ClientInterface $client
+ *
+ * @return void
+ */
+ public function __construct(ClientInterface $client)
+ {
+ $this->client = $client;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ $result = $this->client->get($id);
+ if (null === $result) {
+ return false;
+ }
+
+ return unserialize($result);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetchMultiple(array $keys)
+ {
+ $fetchedItems = call_user_func_array(array($this->client, 'mget'), $keys);
+
+ 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);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ $data = serialize($data);
+ if ($lifeTime > 0) {
+ $response = $this->client->setex($id, $lifeTime, $data);
+ } else {
+ $response = $this->client->set($id, $data);
+ }
+
+ return $response === true || $response == 'OK';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return $this->client->del($id) >= 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ $response = $this->client->flushdb();
+
+ return $response === true || $response == 'OK';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $info = $this->client->info();
+
+ return array(
+ Cache::STATS_HITS => $info['Stats']['keyspace_hits'],
+ Cache::STATS_MISSES => $info['Stats']['keyspace_misses'],
+ Cache::STATS_UPTIME => $info['Server']['uptime_in_seconds'],
+ Cache::STATS_MEMORY_USAGE => $info['Memory']['used_memory'],
+ Cache::STATS_MEMORY_AVAILABLE => false
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RedisCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RedisCache.php
new file mode 100644
index 0000000000..a4f0e6e416
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RedisCache.php
@@ -0,0 +1,175 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use Redis;
+
+/**
+ * Redis cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.2
+ * @author Osman Ungur
+ */
+class RedisCache extends CacheProvider
+{
+ /**
+ * @var Redis|null
+ */
+ private $redis;
+
+ /**
+ * Sets the redis instance to use.
+ *
+ * @param Redis $redis
+ *
+ * @return void
+ */
+ public function setRedis(Redis $redis)
+ {
+ $redis->setOption(Redis::OPT_SERIALIZER, $this->getSerializerValue());
+ $this->redis = $redis;
+ }
+
+ /**
+ * Gets the redis instance used by the cache.
+ *
+ * @return Redis|null
+ */
+ public function getRedis()
+ {
+ return $this->redis;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return $this->redis->get($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetchMultiple(array $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);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return $this->redis->exists($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ if ($lifeTime > 0) {
+ return $this->redis->setex($id, $lifeTime, $data);
+ }
+
+ return $this->redis->set($id, $data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return $this->redis->delete($id) >= 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ return $this->redis->flushDB();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $info = $this->redis->info();
+ return array(
+ Cache::STATS_HITS => $info['keyspace_hits'],
+ Cache::STATS_MISSES => $info['keyspace_misses'],
+ Cache::STATS_UPTIME => $info['uptime_in_seconds'],
+ Cache::STATS_MEMORY_USAGE => $info['used_memory'],
+ Cache::STATS_MEMORY_AVAILABLE => false
+ );
+ }
+
+ /**
+ * Returns the serializer constant to use. If Redis is compiled with
+ * igbinary support, that is used. Otherwise the default PHP serializer is
+ * used.
+ *
+ * @return integer One of the Redis::SERIALIZER_* constants
+ */
+ protected function getSerializerValue()
+ {
+ if (defined('HHVM_VERSION')) {
+ return Redis::SERIALIZER_PHP;
+ }
+ return defined('Redis::SERIALIZER_IGBINARY') ? Redis::SERIALIZER_IGBINARY : Redis::SERIALIZER_PHP;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php
new file mode 100644
index 0000000000..0baa3f2531
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php
@@ -0,0 +1,250 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use Riak\Bucket;
+use Riak\Connection;
+use Riak\Input;
+use Riak\Exception;
+use Riak\Object;
+
+/**
+ * Riak cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 1.1
+ * @author Guilherme Blanco
+ */
+class RiakCache extends CacheProvider
+{
+ const EXPIRES_HEADER = 'X-Riak-Meta-Expires';
+
+ /**
+ * @var \Riak\Bucket
+ */
+ private $bucket;
+
+ /**
+ * Sets the riak bucket instance to use.
+ *
+ * @param \Riak\Bucket $bucket
+ */
+ public function __construct(Bucket $bucket)
+ {
+ $this->bucket = $bucket;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ try {
+ $response = $this->bucket->get($id);
+
+ // No objects found
+ if ( ! $response->hasObject()) {
+ return false;
+ }
+
+ // Check for attempted siblings
+ $object = ($response->hasSiblings())
+ ? $this->resolveConflict($id, $response->getVClock(), $response->getObjectList())
+ : $response->getFirstObject();
+
+ // Check for expired object
+ if ($this->isExpired($object)) {
+ $this->bucket->delete($object);
+
+ return false;
+ }
+
+ return unserialize($object->getContent());
+ } catch (Exception\RiakException $e) {
+ // Covers:
+ // - Riak\ConnectionException
+ // - Riak\CommunicationException
+ // - Riak\UnexpectedResponseException
+ // - Riak\NotFoundException
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ try {
+ // We only need the HEAD, not the entire object
+ $input = new Input\GetInput();
+
+ $input->setReturnHead(true);
+
+ $response = $this->bucket->get($id, $input);
+
+ // No objects found
+ if ( ! $response->hasObject()) {
+ return false;
+ }
+
+ $object = $response->getFirstObject();
+
+ // Check for expired object
+ if ($this->isExpired($object)) {
+ $this->bucket->delete($object);
+
+ return false;
+ }
+
+ return true;
+ } catch (Exception\RiakException $e) {
+ // Do nothing
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ try {
+ $object = new Object($id);
+
+ $object->setContent(serialize($data));
+
+ if ($lifeTime > 0) {
+ $object->addMetadata(self::EXPIRES_HEADER, (string) (time() + $lifeTime));
+ }
+
+ $this->bucket->put($object);
+
+ return true;
+ } catch (Exception\RiakException $e) {
+ // Do nothing
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ try {
+ $this->bucket->delete($id);
+
+ return true;
+ } catch (Exception\BadArgumentsException $e) {
+ // Key did not exist on cluster already
+ } catch (Exception\RiakException $e) {
+ // Covers:
+ // - Riak\Exception\ConnectionException
+ // - Riak\Exception\CommunicationException
+ // - Riak\Exception\UnexpectedResponseException
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ try {
+ $keyList = $this->bucket->getKeyList();
+
+ foreach ($keyList as $key) {
+ $this->bucket->delete($key);
+ }
+
+ return true;
+ } catch (Exception\RiakException $e) {
+ // Do nothing
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ // Only exposed through HTTP stats API, not Protocol Buffers API
+ return null;
+ }
+
+ /**
+ * Check if a given Riak Object have expired.
+ *
+ * @param \Riak\Object $object
+ *
+ * @return bool
+ */
+ private function isExpired(Object $object)
+ {
+ $metadataMap = $object->getMetadataMap();
+
+ return isset($metadataMap[self::EXPIRES_HEADER])
+ && $metadataMap[self::EXPIRES_HEADER] < time();
+ }
+
+ /**
+ * On-read conflict resolution. Applied approach here is last write wins.
+ * Specific needs may override this method to apply alternate conflict resolutions.
+ *
+ * {@internal Riak does not attempt to resolve a write conflict, and store
+ * it as sibling of conflicted one. By following this approach, it is up to
+ * the next read to resolve the conflict. When this happens, your fetched
+ * object will have a list of siblings (read as a list of objects).
+ * In our specific case, we do not care about the intermediate ones since
+ * they are all the same read from storage, and we do apply a last sibling
+ * (last write) wins logic.
+ * If by any means our resolution generates another conflict, it'll up to
+ * next read to properly solve it.}
+ *
+ * @param string $id
+ * @param string $vClock
+ * @param array $objectList
+ *
+ * @return \Riak\Object
+ */
+ protected function resolveConflict($id, $vClock, array $objectList)
+ {
+ // Our approach here is last-write wins
+ $winner = $objectList[count($objectList)];
+
+ $putInput = new Input\PutInput();
+ $putInput->setVClock($vClock);
+
+ $mergedObject = new Object($id);
+ $mergedObject->setContent($winner->getContent());
+
+ $this->bucket->put($mergedObject, $putInput);
+
+ return $mergedObject;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/SQLite3Cache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/SQLite3Cache.php
new file mode 100644
index 0000000000..0bf6e4d44a
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/SQLite3Cache.php
@@ -0,0 +1,220 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+use SQLite3;
+use SQLite3Result;
+
+/**
+ * SQLite3 cache provider.
+ *
+ * @since 1.4
+ * @author Jake Bell
+ */
+class SQLite3Cache extends CacheProvider
+{
+ /**
+ * The ID field will store the cache key.
+ */
+ const ID_FIELD = 'k';
+
+ /**
+ * The data field will store the serialized PHP value.
+ */
+ const DATA_FIELD = 'd';
+
+ /**
+ * The expiration field will store a date value indicating when the
+ * cache entry should expire.
+ */
+ const EXPIRATION_FIELD = 'e';
+
+ /**
+ * @var SQLite3
+ */
+ private $sqlite;
+
+ /**
+ * @var string
+ */
+ private $table;
+
+ /**
+ * Constructor.
+ *
+ * Calling the constructor will ensure that the database file and table
+ * exist and will create both if they don't.
+ *
+ * @param SQLite3 $sqlite
+ * @param string $table
+ */
+ public function __construct(SQLite3 $sqlite, $table)
+ {
+ $this->sqlite = $sqlite;
+ $this->table = (string) $table;
+
+ list($id, $data, $exp) = $this->getFields();
+
+ return $this->sqlite->exec(sprintf(
+ 'CREATE TABLE IF NOT EXISTS %s(%s TEXT PRIMARY KEY NOT NULL, %s BLOB, %s INTEGER)',
+ $table,
+ $id,
+ $data,
+ $exp
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ if ($item = $this->findById($id)) {
+ return unserialize($item[self::DATA_FIELD]);
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return null !== $this->findById($id, false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ $statement = $this->sqlite->prepare(sprintf(
+ 'INSERT OR REPLACE INTO %s (%s) VALUES (:id, :data, :expire)',
+ $this->table,
+ implode(',', $this->getFields())
+ ));
+
+ $statement->bindValue(':id', $id);
+ $statement->bindValue(':data', serialize($data), SQLITE3_BLOB);
+ $statement->bindValue(':expire', $lifeTime > 0 ? time() + $lifeTime : null);
+
+ return $statement->execute() instanceof SQLite3Result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ list($idField) = $this->getFields();
+
+ $statement = $this->sqlite->prepare(sprintf(
+ 'DELETE FROM %s WHERE %s = :id',
+ $this->table,
+ $idField
+ ));
+
+ $statement->bindValue(':id', $id);
+
+ return $statement->execute() instanceof SQLite3Result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ return $this->sqlite->exec(sprintf('DELETE FROM %s', $this->table));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ // no-op.
+ }
+
+ /**
+ * Find a single row by ID.
+ *
+ * @param mixed $id
+ * @param bool $includeData
+ *
+ * @return array|null
+ */
+ private function findById($id, $includeData = true)
+ {
+ list($idField) = $fields = $this->getFields();
+
+ if (!$includeData) {
+ $key = array_search(static::DATA_FIELD, $fields);
+ unset($fields[$key]);
+ }
+
+ $statement = $this->sqlite->prepare(sprintf(
+ 'SELECT %s FROM %s WHERE %s = :id LIMIT 1',
+ implode(',', $fields),
+ $this->table,
+ $idField
+ ));
+
+ $statement->bindValue(':id', $id, SQLITE3_TEXT);
+
+ $item = $statement->execute()->fetchArray(SQLITE3_ASSOC);
+
+ if ($item === false) {
+ return null;
+ }
+
+ if ($this->isExpired($item)) {
+ $this->doDelete($id);
+
+ return null;
+ }
+
+ return $item;
+ }
+
+ /**
+ * Gets an array of the fields in our table.
+ *
+ * @return array
+ */
+ private function getFields()
+ {
+ return array(static::ID_FIELD, static::DATA_FIELD, static::EXPIRATION_FIELD);
+ }
+
+ /**
+ * Check if the item is expired.
+ *
+ * @param array $item
+ *
+ * @return bool
+ */
+ private function isExpired(array $item)
+ {
+ return isset($item[static::EXPIRATION_FIELD]) &&
+ $item[self::EXPIRATION_FIELD] !== null &&
+ $item[self::EXPIRATION_FIELD] < time();
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Version.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Version.php
new file mode 100644
index 0000000000..eff259ae38
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Version.php
@@ -0,0 +1,25 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+class Version
+{
+ const VERSION = '1.6.0';
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/VoidCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/VoidCache.php
new file mode 100644
index 0000000000..65e8456faa
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/VoidCache.php
@@ -0,0 +1,78 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Void cache driver. The cache could be of use in tests where you don`t need to cache anything.
+ *
+ * @link www.doctrine-project.org
+ * @since 1.5
+ * @author Kotlyar Maksim
+ */
+class VoidCache extends CacheProvider
+{
+ /**
+ * {@inheritDoc}
+ */
+ protected function doFetch($id)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doContains($id)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doDelete($id)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doFlush()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function doGetStats()
+ {
+ return;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php
new file mode 100644
index 0000000000..8a250b29a8
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php
@@ -0,0 +1,109 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * WinCache cache provider.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.2
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author David Abdemoulaie
+ */
+class WinCacheCache extends CacheProvider
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return wincache_ucache_get($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return wincache_ucache_exists($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ return wincache_ucache_set($id, $data, $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return wincache_ucache_delete($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ 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}
+ */
+ protected function doGetStats()
+ {
+ $info = wincache_ucache_info();
+ $meminfo = wincache_ucache_meminfo();
+
+ return array(
+ Cache::STATS_HITS => $info['total_hit_count'],
+ Cache::STATS_MISSES => $info['total_miss_count'],
+ Cache::STATS_UPTIME => $info['total_cache_uptime'],
+ Cache::STATS_MEMORY_USAGE => $meminfo['memory_total'],
+ Cache::STATS_MEMORY_AVAILABLE => $meminfo['memory_free'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php
new file mode 100644
index 0000000000..a2c4ca5662
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php
@@ -0,0 +1,112 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Xcache cache driver.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.0
+ * @author Benjamin Eberlei
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author David Abdemoulaie
+ */
+class XcacheCache extends CacheProvider
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return $this->doContains($id) ? unserialize(xcache_get($id)) : false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return xcache_isset($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ return xcache_set($id, serialize($data), (int) $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return xcache_unset($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ $this->checkAuthorization();
+
+ xcache_clear_cache(XC_TYPE_VAR);
+
+ return true;
+ }
+
+ /**
+ * Checks that xcache.admin.enable_auth is Off.
+ *
+ * @return void
+ *
+ * @throws \BadMethodCallException When xcache.admin.enable_auth is On.
+ */
+ protected function checkAuthorization()
+ {
+ if (ini_get('xcache.admin.enable_auth')) {
+ throw new \BadMethodCallException(
+ 'To use all features of \Doctrine\Common\Cache\XcacheCache, '
+ . 'you must set "xcache.admin.enable_auth" to "Off" in your php.ini.'
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ $this->checkAuthorization();
+
+ $info = xcache_info(XC_TYPE_VAR, 0);
+ return array(
+ Cache::STATS_HITS => $info['hits'],
+ Cache::STATS_MISSES => $info['misses'],
+ Cache::STATS_UPTIME => null,
+ Cache::STATS_MEMORY_USAGE => $info['size'],
+ Cache::STATS_MEMORY_AVAILABLE => $info['avail'],
+ );
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php
new file mode 100644
index 0000000000..6e35ac8236
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php
@@ -0,0 +1,83 @@
+.
+ */
+
+namespace Doctrine\Common\Cache;
+
+/**
+ * Zend Data Cache cache driver.
+ *
+ * @link www.doctrine-project.org
+ * @since 2.0
+ * @author Ralph Schindler
+ * @author Guilherme Blanco
+ */
+class ZendDataCache extends CacheProvider
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch($id)
+ {
+ return zend_shm_cache_fetch($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doContains($id)
+ {
+ return (false !== zend_shm_cache_fetch($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ return zend_shm_cache_store($id, $data, $lifeTime);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete($id)
+ {
+ return zend_shm_cache_delete($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFlush()
+ {
+ $namespace = $this->getNamespace();
+ if (empty($namespace)) {
+ return zend_shm_cache_clear();
+ }
+ return zend_shm_cache_clear($namespace);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doGetStats()
+ {
+ return null;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/phpunit.xml.dist b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/phpunit.xml.dist
new file mode 100644
index 0000000000..40cc24deea
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/phpunit.xml.dist
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+ ./tests/Doctrine/
+
+
+
+
+
+ ./lib/Doctrine/
+
+
+
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php
new file mode 100644
index 0000000000..29af44d257
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php
@@ -0,0 +1,21 @@
+markTestSkipped('The APC cache TTL is not working in a single process/request. See https://bugs.php.net/bug.php?id=58084');
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcuCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcuCacheTest.php
new file mode 100644
index 0000000000..b0e91c3af5
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcuCacheTest.php
@@ -0,0 +1,21 @@
+markTestSkipped('The APC cache TTL is not working in a single process/request. See https://bugs.php.net/bug.php?id=58084');
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php
new file mode 100644
index 0000000000..3be94c6175
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php
@@ -0,0 +1,52 @@
+_getCacheDriver();
+ $cache->fetch('test1');
+ $cache->fetch('test2');
+ $cache->fetch('test3');
+
+ $cache->save('test1', 123);
+ $cache->save('test2', 123);
+
+ $cache->fetch('test1');
+ $cache->fetch('test2');
+ $cache->fetch('test3');
+
+ $stats = $cache->getStats();
+ $this->assertEquals(2, $stats[Cache::STATS_HITS]);
+ $this->assertEquals(5, $stats[Cache::STATS_MISSES]); // +1 for internal call to DoctrineNamespaceCacheKey
+ $this->assertNotNull($stats[Cache::STATS_UPTIME]);
+ $this->assertNull($stats[Cache::STATS_MEMORY_USAGE]);
+ $this->assertNull($stats[Cache::STATS_MEMORY_AVAILABLE]);
+
+ $cache->delete('test1');
+ $cache->delete('test2');
+
+ $cache->fetch('test1');
+ $cache->fetch('test2');
+ $cache->fetch('test3');
+
+ $stats = $cache->getStats();
+ $this->assertEquals(2, $stats[Cache::STATS_HITS]);
+ $this->assertEquals(8, $stats[Cache::STATS_MISSES]); // +1 for internal call to DoctrineNamespaceCacheKey
+ }
+
+ protected function isSharedStorage()
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/BaseFileCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/BaseFileCacheTest.php
new file mode 100644
index 0000000000..689452f24c
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/BaseFileCacheTest.php
@@ -0,0 +1,145 @@
+directory = sys_get_temp_dir() . '/doctrine_cache_'. uniqid();
+ } while (file_exists($this->directory));
+ }
+
+ protected function tearDown()
+ {
+ if ( ! is_dir($this->directory)) {
+ return;
+ }
+
+ $iterator = new RecursiveDirectoryIterator($this->directory);
+
+ foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {
+ if ($file->isFile()) {
+ @unlink($file->getRealPath());
+ } elseif ($file->isDir()) {
+ @rmdir($file->getRealPath());
+ }
+ }
+
+ @rmdir($this->directory);
+ }
+
+ public function testFlushAllRemovesBalancingDirectories()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertTrue($cache->save('key1', 1));
+ $this->assertTrue($cache->save('key2', 2));
+ $this->assertTrue($cache->flushAll());
+
+ $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST);
+
+ $this->assertCount(0, $iterator);
+ }
+
+ protected function isSharedStorage()
+ {
+ return false;
+ }
+
+ public function getPathLengthsToTest()
+ {
+ // Windows officially supports 260 bytes including null terminator
+ // 258 bytes available to use due to php bug #70943
+ // Windows officially supports 260 bytes including null terminator
+ // 259 characters is too large due to PHP bug (https://bugs.php.net/bug.php?id=70943)
+ // 260 characters is too large - null terminator is included in allowable length
+ return array(
+ array(257, false),
+ array(258, false),
+ array(259, true),
+ array(260, true)
+ );
+ }
+
+ private static function getBasePathForWindowsPathLengthTests($pathLength)
+ {
+ return FileCacheTest::getBasePathForWindowsPathLengthTests($pathLength);
+ }
+
+ private static function getKeyAndPathFittingLength($length)
+ {
+ $basePath = self::getBasePathForWindowsPathLengthTests($length);
+
+ $baseDirLength = strlen($basePath);
+ $extensionLength = strlen('.doctrine.cache');
+ $directoryLength = strlen(DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR);
+ $namespaceAndBracketLength = strlen(bin2hex("[][1]"));
+ $keyLength = $length
+ - ($baseDirLength
+ + $extensionLength
+ + $directoryLength
+ + $namespaceAndBracketLength);
+
+ $key = str_repeat('a', floor($keyLength / 2));
+ $namespacedKey = '[' . $key . '][1]';
+
+ $keyHash = hash('sha256', $namespacedKey);
+
+ $keyPath = $basePath
+ . DIRECTORY_SEPARATOR
+ . substr($keyHash, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . bin2hex($namespacedKey)
+ . '.doctrine.cache';
+
+ $hashedKeyPath = $basePath
+ . DIRECTORY_SEPARATOR
+ . substr($keyHash, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . '_' . $keyHash
+ . '.doctrine.cache';
+
+ return array($key, $keyPath, $hashedKeyPath);
+ }
+
+ /**
+ * @dataProvider getPathLengthsToTest
+ */
+ public function testWindowsPathLengthLimitIsCorrectlyHandled($length, $pathShouldBeHashed)
+ {
+ $this->directory = self::getBasePathForWindowsPathLengthTests($length);
+
+ list($key, $keyPath, $hashedKeyPath) = self::getKeyAndPathFittingLength($length);
+
+ $this->assertEquals($length, strlen($keyPath), "Unhashed path should be of correct length.");
+
+ $cacheClass = get_class($this->_getCacheDriver());
+ $cache = new $cacheClass($this->directory, '.doctrine.cache');
+
+ // Trick it into thinking this is windows.
+ $reflClass = new \ReflectionClass('\Doctrine\Common\Cache\FileCache');
+ $reflProp = $reflClass->getProperty('isRunningOnWindows');
+ $reflProp->setAccessible(true);
+ $reflProp->setValue($cache, true);
+ $reflProp->setAccessible(false);
+
+ $cache->save($key, $length);
+ $fetched = $cache->fetch($key);
+ $this->assertEquals($length, $fetched);
+
+ if ($pathShouldBeHashed) {
+ $this->assertFileExists($hashedKeyPath, "Path generated for key should be hashed.");
+ unlink($hashedKeyPath);
+ } else {
+ $this->assertFileExists($keyPath, "Path generated for key should not be hashed.");
+ unlink($keyPath);
+ }
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheProviderTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheProviderTest.php
new file mode 100644
index 0000000000..5e11652cc5
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheProviderTest.php
@@ -0,0 +1,103 @@
+getMockForAbstractClass(
+ 'Doctrine\Common\Cache\CacheProvider',
+ array(),
+ '',
+ true,
+ true,
+ true,
+ array('doFetchMultiple')
+ );
+
+ $cache
+ ->expects($this->once())
+ ->method('doFetchMultiple')
+ ->will($this->returnValue(array(
+ '[foo][1]' => 'bar',
+ '[bar][1]' => 'baz',
+ '[baz][1]' => 'tab',
+ )));
+
+ $this->assertEquals(
+ array('foo' => 'bar', 'bar' => 'baz'),
+ $cache->fetchMultiple(array('foo', 'bar'))
+ );
+ }
+
+ public function testFailedDeleteAllDoesNotChangeNamespaceVersion()
+ {
+ /* @var $cache \Doctrine\Common\Cache\CacheProvider|\PHPUnit_Framework_MockObject_MockObject */
+ $cache = $this->getMockForAbstractClass(
+ 'Doctrine\Common\Cache\CacheProvider',
+ array(),
+ '',
+ true,
+ true,
+ true,
+ array('doFetch', 'doSave', 'doContains')
+ );
+
+ $cache
+ ->expects($this->once())
+ ->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[]')
+ ->will($this->returnValue(false));
+
+ // doSave is only called once from deleteAll as we do not need to persist the default version in getNamespaceVersion()
+ $cache
+ ->expects($this->once())
+ ->method('doSave')
+ ->with('DoctrineNamespaceCacheKey[]')
+ ->will($this->returnValue(false));
+
+ // After a failed deleteAll() the local namespace version is not increased (still 1). Otherwise all data written afterwards
+ // would be lost outside the current instance.
+ $cache
+ ->expects($this->once())
+ ->method('doContains')
+ ->with('[key][1]')
+ ->will($this->returnValue(true));
+
+ $this->assertFalse($cache->deleteAll(), 'deleteAll() returns false when saving the namespace version fails');
+ $cache->contains('key');
+ }
+
+ public function testSaveMultipleNoFail()
+ {
+ /* @var $cache \Doctrine\Common\Cache\CacheProvider|\PHPUnit_Framework_MockObject_MockObject */
+ $cache = $this->getMockForAbstractClass(
+ 'Doctrine\Common\Cache\CacheProvider',
+ array(),
+ '',
+ true,
+ true,
+ true,
+ array('doSave')
+ );
+
+ $cache
+ ->expects($this->at(1))
+ ->method('doSave')
+ ->with('[kerr][1]', 'verr', 0)
+ ->will($this->returnValue(false));
+
+ $cache
+ ->expects($this->at(2))
+ ->method('doSave')
+ ->with('[kok][1]', 'vok', 0)
+ ->will($this->returnValue(true));
+
+ $cache->saveMultiple(array(
+ 'kerr' => 'verr',
+ 'kok' => 'vok',
+ ));
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php
new file mode 100644
index 0000000000..5dd64d7fd9
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php
@@ -0,0 +1,463 @@
+_getCacheDriver();
+
+ // Test saving a value, checking if it exists, and fetching it back
+ $this->assertTrue($cache->save('key', $value));
+ $this->assertTrue($cache->contains('key'));
+ if (is_object($value)) {
+ $this->assertEquals($value, $cache->fetch('key'), 'Objects retrieved from the cache must be equal but not necessarily the same reference');
+ } else {
+ $this->assertSame($value, $cache->fetch('key'), 'Scalar and array data retrieved from the cache must be the same as the original, e.g. same type');
+ }
+
+ // Test deleting a value
+ $this->assertTrue($cache->delete('key'));
+ $this->assertFalse($cache->contains('key'));
+ $this->assertFalse($cache->fetch('key'));
+ }
+
+ /**
+ * @dataProvider provideDataToCache
+ */
+ public function testUpdateExistingEntry($value)
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertTrue($cache->save('key', 'old-value'));
+ $this->assertTrue($cache->contains('key'));
+
+ $this->assertTrue($cache->save('key', $value));
+ $this->assertTrue($cache->contains('key'));
+ if (is_object($value)) {
+ $this->assertEquals($value, $cache->fetch('key'), 'Objects retrieved from the cache must be equal but not necessarily the same reference');
+ } else {
+ $this->assertSame($value, $cache->fetch('key'), 'Scalar and array data retrieved from the cache must be the same as the original, e.g. same type');
+ }
+ }
+
+ public function testCacheKeyIsCaseSensitive()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertTrue($cache->save('key', 'value'));
+ $this->assertTrue($cache->contains('key'));
+ $this->assertSame('value', $cache->fetch('key'));
+
+ $this->assertFalse($cache->contains('KEY'));
+ $this->assertFalse($cache->fetch('KEY'));
+
+ $cache->delete('KEY');
+ $this->assertTrue($cache->contains('key', 'Deleting cache item with different case must not affect other cache item'));
+ }
+
+ public function testFetchMultiple()
+ {
+ $cache = $this->_getCacheDriver();
+ $values = $this->provideDataToCache();
+ $saved = array();
+
+ foreach ($values as $key => $value) {
+ $cache->save($key, $value[0]);
+
+ $saved[$key] = $value[0];
+ }
+
+ $keys = array_keys($saved);
+
+ $this->assertEquals(
+ $saved,
+ $cache->fetchMultiple($keys),
+ 'Testing fetchMultiple with different data types'
+ );
+ $this->assertEquals(
+ array_slice($saved, 0, 1),
+ $cache->fetchMultiple(array_slice($keys, 0, 1)),
+ 'Testing fetchMultiple with a single key'
+ );
+
+ $keysWithNonExisting = array();
+ $keysWithNonExisting[] = 'non_existing1';
+ $keysWithNonExisting[] = $keys[0];
+ $keysWithNonExisting[] = 'non_existing2';
+ $keysWithNonExisting[] = $keys[1];
+ $keysWithNonExisting[] = 'non_existing3';
+
+ $this->assertEquals(
+ array_slice($saved, 0, 2),
+ $cache->fetchMultiple($keysWithNonExisting),
+ 'Testing fetchMultiple with a subset of keys and mixed with non-existing ones'
+ );
+ }
+
+ public function testFetchMultipleWithNoKeys()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertSame(array(), $cache->fetchMultiple(array()));
+ }
+
+ public function testSaveMultiple()
+ {
+ $cache = $this->_getCacheDriver();
+ $cache->deleteAll();
+
+ $data = array_map(function ($value) {
+ return $value[0];
+ }, $this->provideDataToCache());
+
+ $this->assertTrue($cache->saveMultiple($data));
+
+ $keys = array_keys($data);
+
+ $this->assertEquals($data, $cache->fetchMultiple($keys));
+ }
+
+ public function provideDataToCache()
+ {
+ $obj = new \stdClass();
+ $obj->foo = 'bar';
+ $obj2 = new \stdClass();
+ $obj2->bar = 'foo';
+ $obj2->obj = $obj;
+ $obj->obj2 = $obj2;
+
+ return array(
+ 'array' => array(array('one', 2, 3.01)),
+ 'string' => array('value'),
+ 'string_invalid_utf8' => array("\xc3\x28"),
+ 'string_null_byte' => array('with'."\0".'null char'),
+ 'integer' => array(1),
+ 'float' => array(1.5),
+ 'object' => array(new ArrayObject(array('one', 2, 3.01))),
+ 'object_recursive' => array($obj),
+ 'true' => array(true),
+ // the following are considered FALSE in boolean context, but caches should still recognize their existence
+ 'null' => array(null),
+ 'false' => array(false),
+ 'array_empty' => array(array()),
+ 'string_zero' => array('0'),
+ 'integer_zero' => array(0),
+ 'float_zero' => array(0.0),
+ 'string_empty' => array(''),
+ );
+ }
+
+ public function testDeleteIsSuccessfulWhenKeyDoesNotExist()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $cache->delete('key');
+ $this->assertFalse($cache->contains('key'));
+ $this->assertTrue($cache->delete('key'));
+ }
+
+ public function testDeleteAll()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertTrue($cache->save('key1', 1));
+ $this->assertTrue($cache->save('key2', 2));
+ $this->assertTrue($cache->deleteAll());
+ $this->assertFalse($cache->contains('key1'));
+ $this->assertFalse($cache->contains('key2'));
+ }
+
+ /**
+ * @dataProvider provideCacheIds
+ */
+ public function testCanHandleSpecialCacheIds($id)
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertTrue($cache->save($id, 'value'));
+ $this->assertTrue($cache->contains($id));
+ $this->assertEquals('value', $cache->fetch($id));
+
+ $this->assertTrue($cache->delete($id));
+ $this->assertFalse($cache->contains($id));
+ $this->assertFalse($cache->fetch($id));
+ }
+
+ public function testNoCacheIdCollisions()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $ids = $this->provideCacheIds();
+
+ // fill cache with each id having a different value
+ foreach ($ids as $index => $id) {
+ $cache->save($id[0], $index);
+ }
+
+ // then check value of each cache id
+ foreach ($ids as $index => $id) {
+ $value = $cache->fetch($id[0]);
+ $this->assertNotFalse($value, sprintf('Failed to retrieve data for cache id "%s".', $id[0]));
+ if ($index !== $value) {
+ $this->fail(sprintf('Cache id "%s" collides with id "%s".', $id[0], $ids[$value][0]));
+ }
+ }
+ }
+
+ /**
+ * Returns cache ids with special characters that should still work.
+ *
+ * For example, the characters :\/<>"*?| are not valid in Windows filenames. So they must be encoded properly.
+ * Each cache id should be considered different from the others.
+ *
+ * @return array
+ */
+ public function provideCacheIds()
+ {
+ return array(
+ array(':'),
+ array('\\'),
+ array('/'),
+ array('<'),
+ array('>'),
+ array('"'),
+ array('*'),
+ array('?'),
+ array('|'),
+ array('['),
+ array(']'),
+ array('ä'),
+ array('a'),
+ array('é'),
+ array('e'),
+ array('.'), // directory traversal
+ array('..'), // directory traversal
+ array('-'),
+ array('_'),
+ array('$'),
+ array('%'),
+ array(' '),
+ array("\0"),
+ array(''),
+ array(str_repeat('a', 300)), // long key
+ array(str_repeat('a', 113)),
+ );
+ }
+
+ public function testLifetime()
+ {
+ $cache = $this->_getCacheDriver();
+ $cache->save('expire', 'value', 1);
+ $this->assertTrue($cache->contains('expire'), 'Data should not be expired yet');
+ // @TODO should more TTL-based tests pop up, so then we should mock the `time` API instead
+ sleep(2);
+ $this->assertFalse($cache->contains('expire'), 'Data should be expired');
+ }
+
+ public function testNoExpire()
+ {
+ $cache = $this->_getCacheDriver();
+ $cache->save('noexpire', 'value', 0);
+ // @TODO should more TTL-based tests pop up, so then we should mock the `time` API instead
+ sleep(1);
+ $this->assertTrue($cache->contains('noexpire'), 'Data with lifetime of zero should not expire');
+ }
+
+ public function testLongLifetime()
+ {
+ $cache = $this->_getCacheDriver();
+ $cache->save('longlifetime', 'value', 30 * 24 * 3600 + 1);
+ $this->assertTrue($cache->contains('longlifetime'), 'Data with lifetime > 30 days should be accepted');
+ }
+
+ public function testDeleteAllAndNamespaceVersioningBetweenCaches()
+ {
+ if ( ! $this->isSharedStorage()) {
+ $this->markTestSkipped('The cache storage needs to be shared.');
+ }
+
+ $cache1 = $this->_getCacheDriver();
+ $cache2 = $this->_getCacheDriver();
+
+ $this->assertTrue($cache1->save('key1', 1));
+ $this->assertTrue($cache2->save('key2', 2));
+
+ /* Both providers are initialized with the same namespace version, so
+ * they can see entries set by each other.
+ */
+ $this->assertTrue($cache1->contains('key1'));
+ $this->assertTrue($cache1->contains('key2'));
+ $this->assertTrue($cache2->contains('key1'));
+ $this->assertTrue($cache2->contains('key2'));
+
+ /* Deleting all entries through one provider will only increment the
+ * namespace version on that object (and in the cache itself, which new
+ * instances will use to initialize). The second provider will retain
+ * its original version and still see stale data.
+ */
+ $this->assertTrue($cache1->deleteAll());
+ $this->assertFalse($cache1->contains('key1'));
+ $this->assertFalse($cache1->contains('key2'));
+ $this->assertTrue($cache2->contains('key1'));
+ $this->assertTrue($cache2->contains('key2'));
+
+ /* A new cache provider should not see the deleted entries, since its
+ * namespace version will be initialized.
+ */
+ $cache3 = $this->_getCacheDriver();
+ $this->assertFalse($cache3->contains('key1'));
+ $this->assertFalse($cache3->contains('key2'));
+ }
+
+ public function testFlushAll()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->assertTrue($cache->save('key1', 1));
+ $this->assertTrue($cache->save('key2', 2));
+ $this->assertTrue($cache->flushAll());
+ $this->assertFalse($cache->contains('key1'));
+ $this->assertFalse($cache->contains('key2'));
+ }
+
+ public function testFlushAllAndNamespaceVersioningBetweenCaches()
+ {
+ if ( ! $this->isSharedStorage()) {
+ $this->markTestSkipped('The cache storage needs to be shared.');
+ }
+
+ $cache1 = $this->_getCacheDriver();
+ $cache2 = $this->_getCacheDriver();
+
+ /* Deleting all elements from the first provider should increment its
+ * namespace version before saving the first entry.
+ */
+ $cache1->deleteAll();
+ $this->assertTrue($cache1->save('key1', 1));
+
+ /* The second provider will be initialized with the same namespace
+ * version upon its first save operation.
+ */
+ $this->assertTrue($cache2->save('key2', 2));
+
+ /* Both providers have the same namespace version and can see entries
+ * set by each other.
+ */
+ $this->assertTrue($cache1->contains('key1'));
+ $this->assertTrue($cache1->contains('key2'));
+ $this->assertTrue($cache2->contains('key1'));
+ $this->assertTrue($cache2->contains('key2'));
+
+ /* Flushing all entries through one cache will remove all entries from
+ * the cache but leave their namespace version as-is.
+ */
+ $this->assertTrue($cache1->flushAll());
+ $this->assertFalse($cache1->contains('key1'));
+ $this->assertFalse($cache1->contains('key2'));
+ $this->assertFalse($cache2->contains('key1'));
+ $this->assertFalse($cache2->contains('key2'));
+
+ /* Inserting a new entry will use the same, incremented namespace
+ * version, and it will be visible to both providers.
+ */
+ $this->assertTrue($cache1->save('key1', 1));
+ $this->assertTrue($cache1->contains('key1'));
+ $this->assertTrue($cache2->contains('key1'));
+
+ /* A new cache provider will be initialized with the original namespace
+ * version and not share any visibility with the first two providers.
+ */
+ $cache3 = $this->_getCacheDriver();
+ $this->assertFalse($cache3->contains('key1'));
+ $this->assertFalse($cache3->contains('key2'));
+ $this->assertTrue($cache3->save('key3', 3));
+ $this->assertTrue($cache3->contains('key3'));
+ }
+
+ public function testNamespace()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $cache->setNamespace('ns1_');
+
+ $this->assertTrue($cache->save('key1', 1));
+ $this->assertTrue($cache->contains('key1'));
+
+ $cache->setNamespace('ns2_');
+
+ $this->assertFalse($cache->contains('key1'));
+ }
+
+ public function testDeleteAllNamespace()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $cache->setNamespace('ns1');
+ $this->assertFalse($cache->contains('key1'));
+ $cache->save('key1', 'test');
+ $this->assertTrue($cache->contains('key1'));
+
+ $cache->setNamespace('ns2');
+ $this->assertFalse($cache->contains('key1'));
+ $cache->save('key1', 'test');
+ $this->assertTrue($cache->contains('key1'));
+
+ $cache->setNamespace('ns1');
+ $this->assertTrue($cache->contains('key1'));
+ $cache->deleteAll();
+ $this->assertFalse($cache->contains('key1'));
+
+ $cache->setNamespace('ns2');
+ $this->assertTrue($cache->contains('key1'));
+ $cache->deleteAll();
+ $this->assertFalse($cache->contains('key1'));
+ }
+
+ /**
+ * @group DCOM-43
+ */
+ public function testGetStats()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertArrayHasKey(Cache::STATS_HITS, $stats);
+ $this->assertArrayHasKey(Cache::STATS_MISSES, $stats);
+ $this->assertArrayHasKey(Cache::STATS_UPTIME, $stats);
+ $this->assertArrayHasKey(Cache::STATS_MEMORY_USAGE, $stats);
+ $this->assertArrayHasKey(Cache::STATS_MEMORY_AVAILABLE, $stats);
+ }
+
+ public function testSaveReturnsTrueWithAndWithoutTTlSet()
+ {
+ $cache = $this->_getCacheDriver();
+ $cache->deleteAll();
+ $this->assertTrue($cache->save('without_ttl', 'without_ttl'));
+ $this->assertTrue($cache->save('with_ttl', 'with_ttl', 3600));
+ }
+
+ /**
+ * Return whether multiple cache providers share the same storage.
+ *
+ * This is used for skipping certain tests for shared storage behavior.
+ *
+ * @return bool
+ */
+ protected function isSharedStorage()
+ {
+ return true;
+ }
+
+ /**
+ * @return \Doctrine\Common\Cache\CacheProvider
+ */
+ abstract protected function _getCacheDriver();
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ChainCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ChainCacheTest.php
new file mode 100644
index 0000000000..a3c013b8dd
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ChainCacheTest.php
@@ -0,0 +1,99 @@
+markTestSkipped('The ChainCache test uses ArrayCache which does not implement TTL currently.');
+ }
+
+ public function testGetStats()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertInternalType('array', $stats);
+ }
+
+ public function testOnlyFetchFirstOne()
+ {
+ $cache1 = new ArrayCache();
+ $cache2 = $this->getMockForAbstractClass('Doctrine\Common\Cache\CacheProvider');
+
+ $cache2->expects($this->never())->method('doFetch');
+
+ $chainCache = new ChainCache(array($cache1, $cache2));
+ $chainCache->save('id', 'bar');
+
+ $this->assertEquals('bar', $chainCache->fetch('id'));
+ }
+
+ public function testFetchPropagateToFastestCache()
+ {
+ $cache1 = new ArrayCache();
+ $cache2 = new ArrayCache();
+
+ $cache2->save('bar', 'value');
+
+ $chainCache = new ChainCache(array($cache1, $cache2));
+
+ $this->assertFalse($cache1->contains('bar'));
+
+ $result = $chainCache->fetch('bar');
+
+ $this->assertEquals('value', $result);
+ $this->assertTrue($cache2->contains('bar'));
+ }
+
+ public function testNamespaceIsPropagatedToAllProviders()
+ {
+ $cache1 = new ArrayCache();
+ $cache2 = new ArrayCache();
+
+ $chainCache = new ChainCache(array($cache1, $cache2));
+ $chainCache->setNamespace('bar');
+
+ $this->assertEquals('bar', $cache1->getNamespace());
+ $this->assertEquals('bar', $cache2->getNamespace());
+ }
+
+ public function testDeleteToAllProviders()
+ {
+ $cache1 = $this->getMockForAbstractClass('Doctrine\Common\Cache\CacheProvider');
+ $cache2 = $this->getMockForAbstractClass('Doctrine\Common\Cache\CacheProvider');
+
+ $cache1->expects($this->once())->method('doDelete');
+ $cache2->expects($this->once())->method('doDelete');
+
+ $chainCache = new ChainCache(array($cache1, $cache2));
+ $chainCache->delete('bar');
+ }
+
+ public function testFlushToAllProviders()
+ {
+ $cache1 = $this->getMockForAbstractClass('Doctrine\Common\Cache\CacheProvider');
+ $cache2 = $this->getMockForAbstractClass('Doctrine\Common\Cache\CacheProvider');
+
+ $cache1->expects($this->once())->method('doFlush');
+ $cache2->expects($this->once())->method('doFlush');
+
+ $chainCache = new ChainCache(array($cache1, $cache2));
+ $chainCache->flushAll();
+ }
+
+ protected function isSharedStorage()
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php
new file mode 100644
index 0000000000..f42b3a7f7f
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php
@@ -0,0 +1,30 @@
+couchbase = new Couchbase('127.0.0.1', 'Administrator', 'password', 'default');
+ } catch(Exception $ex) {
+ $this->markTestSkipped('Could not instantiate the Couchbase cache because of: ' . $ex);
+ }
+ }
+
+ protected function _getCacheDriver()
+ {
+ $driver = new CouchbaseCache();
+ $driver->setCouchbase($this->couchbase);
+ return $driver;
+ }
+}
\ No newline at end of file
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php
new file mode 100644
index 0000000000..c93b50925a
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php
@@ -0,0 +1,256 @@
+driver = $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array(), '', false
+ );
+ }
+
+ public function testFilenameShouldCreateThePathWithOneSubDirectory()
+ {
+ $cache = $this->driver;
+ $method = new \ReflectionMethod($cache, 'getFilename');
+ $key = 'item-key';
+ $expectedDir = array(
+ '84',
+ );
+ $expectedDir = implode(DIRECTORY_SEPARATOR, $expectedDir);
+
+ $method->setAccessible(true);
+
+ $path = $method->invoke($cache, $key);
+ $dirname = pathinfo($path, PATHINFO_DIRNAME);
+
+ $this->assertEquals(DIRECTORY_SEPARATOR . $expectedDir, $dirname);
+ }
+
+ public function testFileExtensionCorrectlyEscaped()
+ {
+ $driver1 = $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array(__DIR__, '.*')
+ );
+ $driver2 = $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array(__DIR__, '.php')
+ );
+
+ $doGetStats = new \ReflectionMethod($driver1, 'doGetStats');
+
+ $doGetStats->setAccessible(true);
+
+ $stats1 = $doGetStats->invoke($driver1);
+ $stats2 = $doGetStats->invoke($driver2);
+
+ $this->assertSame(0, $stats1[Cache::STATS_MEMORY_USAGE]);
+ $this->assertGreaterThan(0, $stats2[Cache::STATS_MEMORY_USAGE]);
+ }
+
+ /**
+ * @group DCOM-266
+ */
+ public function testFileExtensionSlashCorrectlyEscaped()
+ {
+ $driver = $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array(__DIR__ . '/../', DIRECTORY_SEPARATOR . basename(__FILE__))
+ );
+
+ $doGetStats = new \ReflectionMethod($driver, 'doGetStats');
+
+ $doGetStats->setAccessible(true);
+
+ $stats = $doGetStats->invoke($driver);
+
+ $this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_USAGE]);
+ }
+
+ public function testNonIntUmaskThrowsInvalidArgumentException()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+
+ $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array('', '', 'invalid')
+ );
+ }
+
+ public function testGetDirectoryReturnsRealpathDirectoryString()
+ {
+ $directory = __DIR__ . '/../';
+ $driver = $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array($directory)
+ );
+
+ $doGetDirectory = new \ReflectionMethod($driver, 'getDirectory');
+
+ $actualDirectory = $doGetDirectory->invoke($driver);
+ $expectedDirectory = realpath($directory);
+
+ $this->assertEquals($expectedDirectory, $actualDirectory);
+ }
+
+ public function testGetExtensionReturnsExtensionString()
+ {
+ $directory = __DIR__ . '/../';
+ $extension = DIRECTORY_SEPARATOR . basename(__FILE__);
+ $driver = $this->getMock(
+ 'Doctrine\Common\Cache\FileCache',
+ array('doFetch', 'doContains', 'doSave'),
+ array($directory, $extension)
+ );
+
+ $doGetExtension = new \ReflectionMethod($driver, 'getExtension');
+
+ $actualExtension = $doGetExtension->invoke($driver);
+
+ $this->assertEquals($extension, $actualExtension);
+ }
+
+ const WIN_MAX_PATH_LEN = 258;
+
+ public static function getBasePathForWindowsPathLengthTests($pathLength)
+ {
+ // Not using __DIR__ because it can get screwed up when xdebug debugger is attached.
+ $basePath = realpath(sys_get_temp_dir());
+
+ // Test whether the desired path length is odd or even.
+ $desiredPathLengthIsOdd = ($pathLength % 2) == 1;
+
+ // If the cache key is not too long, the filecache codepath will add
+ // a slash and bin2hex($key). The length of the added portion will be an odd number.
+ // len(desired) = len(base path) + len(slash . bin2hex($key))
+ // odd = even + odd
+ // even = odd + odd
+ $basePathLengthShouldBeOdd = !$desiredPathLengthIsOdd;
+
+ $basePathLengthIsOdd = (strlen($basePath) % 2) == 1;
+
+ // If the base path needs to be odd or even where it is not, we add an odd number of
+ // characters as a pad. In this case, we're adding '\aa' (or '/aa' depending on platform)
+ // This is all to make it so that the key we're testing would result in
+ // a path that is exactly the length we want to test IF the path length limit
+ // were not in place in FileCache.
+ if ($basePathLengthIsOdd != $basePathLengthShouldBeOdd) {
+ $basePath .= DIRECTORY_SEPARATOR . "aa";
+ }
+
+ return $basePath;
+ }
+
+ public static function getKeyAndPathFittingLength($length)
+ {
+ $basePath = self::getBasePathForWindowsPathLengthTests($length);
+
+ $baseDirLength = strlen($basePath);
+ $extensionLength = strlen('.doctrine.cache');
+ $directoryLength = strlen(DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR);
+ $keyLength = $length - ($baseDirLength + $extensionLength + $directoryLength); // - 1 because of slash
+
+ $key = str_repeat('a', floor($keyLength / 2));
+
+ $keyHash = hash('sha256', $key);
+
+ $keyPath = $basePath
+ . DIRECTORY_SEPARATOR
+ . substr($keyHash, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . bin2hex($key)
+ . '.doctrine.cache';
+
+ $hashedKeyPath = $basePath
+ . DIRECTORY_SEPARATOR
+ . substr($keyHash, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . '_' . $keyHash
+ . '.doctrine.cache';
+
+ return array($key, $keyPath, $hashedKeyPath);
+ }
+
+ public function getPathLengthsToTest()
+ {
+ // Windows officially supports 260 bytes including null terminator
+ // 259 characters is too large due to PHP bug (https://bugs.php.net/bug.php?id=70943)
+ // 260 characters is too large - null terminator is included in allowable length
+ return array(
+ array(257, false),
+ array(258, false),
+ array(259, true),
+ array(260, true)
+ );
+ }
+
+ /**
+ * @runInSeparateProcess
+ * @dataProvider getPathLengthsToTest
+ *
+ * @covers \Doctrine\Common\Cache\FileCache::getFilename
+ */
+ public function testWindowsPathLengthLimitationsAreCorrectlyRespected($length, $pathShouldBeHashed)
+ {
+ if (! defined('PHP_WINDOWS_VERSION_BUILD')) {
+ define('PHP_WINDOWS_VERSION_BUILD', 'Yes, this is the "usual suspect", with the usual limitations');
+ }
+
+ $basePath = $this->getBasePathForWindowsPathLengthTests($length);
+
+ $fileCache = $this->getMockForAbstractClass(
+ 'Doctrine\Common\Cache\FileCache',
+ array($basePath, '.doctrine.cache')
+ );
+
+ list($key, $keyPath, $hashedKeyPath) = $this->getKeyAndPathFittingLength($length);
+
+ $getFileName = new \ReflectionMethod($fileCache, 'getFilename');
+
+ $getFileName->setAccessible(true);
+
+ $this->assertEquals(
+ $length,
+ strlen($keyPath),
+ sprintf('Path expected to be %d characters long is %d characters long', $length, strlen($keyPath))
+ );
+
+ if ($pathShouldBeHashed) {
+ $keyPath = $hashedKeyPath;
+ }
+
+ if ($pathShouldBeHashed) {
+ $this->assertSame(
+ $hashedKeyPath,
+ $getFileName->invoke($fileCache, $key),
+ 'Keys should be hashed correctly if they are over the limit.'
+ );
+ } else {
+ $this->assertSame(
+ $keyPath,
+ $getFileName->invoke($fileCache, $key),
+ 'Keys below limit of the allowed length are used directly, unhashed'
+ );
+ }
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php
new file mode 100644
index 0000000000..9e7c9e8185
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php
@@ -0,0 +1,61 @@
+_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNull($stats[Cache::STATS_HITS]);
+ $this->assertNull($stats[Cache::STATS_MISSES]);
+ $this->assertNull($stats[Cache::STATS_UPTIME]);
+ $this->assertEquals(0, $stats[Cache::STATS_MEMORY_USAGE]);
+ $this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_AVAILABLE]);
+ }
+
+ public function testCacheInSharedDirectoryIsPerExtension()
+ {
+ $cache1 = new FilesystemCache($this->directory, '.foo');
+ $cache2 = new FilesystemCache($this->directory, '.bar');
+
+ $this->assertTrue($cache1->save('key1', 11));
+ $this->assertTrue($cache1->save('key2', 12));
+
+ $this->assertTrue($cache2->save('key1', 21));
+ $this->assertTrue($cache2->save('key2', 22));
+
+ $this->assertSame(11, $cache1->fetch('key1'), 'Cache value must not be influenced by a different cache in the same directory but different extension');
+ $this->assertSame(12, $cache1->fetch('key2'));
+ $this->assertTrue($cache1->flushAll());
+ $this->assertFalse($cache1->fetch('key1'), 'flushAll() must delete all items with the current extension');
+ $this->assertFalse($cache1->fetch('key2'));
+
+ $this->assertSame(21, $cache2->fetch('key1'), 'flushAll() must not remove items with a different extension in a shared directory');
+ $this->assertSame(22, $cache2->fetch('key2'));
+ }
+
+ public function testFlushAllWithNoExtension()
+ {
+ $cache = new FilesystemCache($this->directory, '');
+
+ $this->assertTrue($cache->save('key1', 1));
+ $this->assertTrue($cache->save('key2', 2));
+ $this->assertTrue($cache->flushAll());
+ $this->assertFalse($cache->contains('key1'));
+ $this->assertFalse($cache->contains('key2'));
+ }
+
+ protected function _getCacheDriver()
+ {
+ return new FilesystemCache($this->directory);
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php
new file mode 100644
index 0000000000..74853b8491
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php
@@ -0,0 +1,59 @@
+memcache = new Memcache();
+
+ if (@$this->memcache->connect('localhost', 11211) === false) {
+ unset($this->memcache);
+ $this->markTestSkipped('Cannot connect to Memcache.');
+ }
+ }
+
+ protected function tearDown()
+ {
+ if ($this->memcache instanceof Memcache) {
+ $this->memcache->flush();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Memcache does not support " " and null byte as key so we remove them from the tests.
+ */
+ public function provideCacheIds()
+ {
+ $ids = parent::provideCacheIds();
+ unset($ids[21], $ids[22]);
+
+ return $ids;
+ }
+
+ public function testGetMemcacheReturnsInstanceOfMemcache()
+ {
+ $this->assertInstanceOf('Memcache', $this->_getCacheDriver()->getMemcache());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function _getCacheDriver()
+ {
+ $driver = new MemcacheCache();
+ $driver->setMemcache($this->memcache);
+ return $driver;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php
new file mode 100644
index 0000000000..fbcf5c38ed
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php
@@ -0,0 +1,61 @@
+memcached = new Memcached();
+ $this->memcached->setOption(Memcached::OPT_COMPRESSION, false);
+ $this->memcached->addServer('127.0.0.1', 11211);
+
+ if (@fsockopen('127.0.0.1', 11211) === false) {
+ unset($this->memcached);
+ $this->markTestSkipped('Cannot connect to Memcached.');
+ }
+ }
+
+ protected function tearDown()
+ {
+ if ($this->memcached instanceof Memcached) {
+ $this->memcached->flush();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Memcached does not support " ", null byte and very long keys so we remove them from the tests.
+ */
+ public function provideCacheIds()
+ {
+ $ids = parent::provideCacheIds();
+ unset($ids[21], $ids[22], $ids[24]);
+
+ return $ids;
+ }
+
+ public function testGetMemcachedReturnsInstanceOfMemcached()
+ {
+ $this->assertInstanceOf('Memcached', $this->_getCacheDriver()->getMemcached());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function _getCacheDriver()
+ {
+ $driver = new MemcachedCache();
+ $driver->setMemcached($this->memcached);
+ return $driver;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MongoDBCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MongoDBCacheTest.php
new file mode 100644
index 0000000000..fa7cfacd1d
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MongoDBCacheTest.php
@@ -0,0 +1,68 @@
+=')) {
+ $this->markTestSkipped('Mongo >= 1.3.0 is required.');
+ }
+
+ $mongo = new MongoClient();
+ $this->collection = $mongo->selectCollection('doctrine_common_cache', 'test');
+ }
+
+ protected function tearDown()
+ {
+ if ($this->collection instanceof MongoCollection) {
+ $this->collection->drop();
+ }
+ }
+
+ public function testGetStats()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNull($stats[Cache::STATS_HITS]);
+ $this->assertNull($stats[Cache::STATS_MISSES]);
+ $this->assertGreaterThan(0, $stats[Cache::STATS_UPTIME]);
+ $this->assertEquals(0, $stats[Cache::STATS_MEMORY_USAGE]);
+ $this->assertNull($stats[Cache::STATS_MEMORY_AVAILABLE]);
+ }
+
+ /**
+ * @group 108
+ */
+ public function testMongoCursorExceptionsDoNotBubbleUp()
+ {
+ /* @var $collection \MongoCollection|\PHPUnit_Framework_MockObject_MockObject */
+ $collection = $this->getMock('MongoCollection', array(), array(), '', false);
+
+ $collection->expects(self::once())->method('update')->willThrowException(new \MongoCursorException());
+
+ $cache = new MongoDBCache($collection);
+
+ self::assertFalse($cache->save('foo', 'bar'));
+ }
+
+ protected function _getCacheDriver()
+ {
+ return new MongoDBCache($this->collection);
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php
new file mode 100644
index 0000000000..32eec6e28f
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php
@@ -0,0 +1,95 @@
+_getCacheDriver();
+
+ // Test save
+ $cache->save('test_set_state', new SetStateClass(array(1,2,3)));
+
+ //Test __set_state call
+ $this->assertCount(0, SetStateClass::$values);
+
+ // Test fetch
+ $value = $cache->fetch('test_set_state');
+ $this->assertInstanceOf('Doctrine\Tests\Common\Cache\SetStateClass', $value);
+ $this->assertEquals(array(1,2,3), $value->getValue());
+
+ //Test __set_state call
+ $this->assertCount(1, SetStateClass::$values);
+
+ // Test contains
+ $this->assertTrue($cache->contains('test_set_state'));
+ }
+
+ public function testNotImplementsSetState()
+ {
+ $cache = $this->_getCacheDriver();
+
+ $this->setExpectedException('InvalidArgumentException');
+ $cache->save('test_not_set_state', new NotSetStateClass(array(1,2,3)));
+ }
+
+ public function testGetStats()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNull($stats[Cache::STATS_HITS]);
+ $this->assertNull($stats[Cache::STATS_MISSES]);
+ $this->assertNull($stats[Cache::STATS_UPTIME]);
+ $this->assertEquals(0, $stats[Cache::STATS_MEMORY_USAGE]);
+ $this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_AVAILABLE]);
+ }
+
+ protected function _getCacheDriver()
+ {
+ return new PhpFileCache($this->directory);
+ }
+}
+
+class NotSetStateClass
+{
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ public function getValue()
+ {
+ return $this->value;
+ }
+}
+
+class SetStateClass extends NotSetStateClass
+{
+ public static $values = array();
+
+ public static function __set_state($data)
+ {
+ self::$values = $data;
+ return new self($data['value']);
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PredisCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PredisCacheTest.php
new file mode 100644
index 0000000000..e20839dc09
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PredisCacheTest.php
@@ -0,0 +1,87 @@
+markTestSkipped('Predis\Client is missing. Make sure to "composer install" to have all dev dependencies.');
+ }
+
+ $this->client = new Client();
+
+ try {
+ $this->client->connect();
+ } catch (ConnectionException $e) {
+ $this->markTestSkipped('Cannot connect to Redis because of: ' . $e);
+ }
+ }
+
+ public function testHitMissesStatsAreProvided()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNotNull($stats[Cache::STATS_HITS]);
+ $this->assertNotNull($stats[Cache::STATS_MISSES]);
+ }
+
+ /**
+ * @return PredisCache
+ */
+ protected function _getCacheDriver()
+ {
+ return new PredisCache($this->client);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @dataProvider provideDataToCache
+ */
+ public function testSetContainsFetchDelete($value)
+ {
+ if (array() === $value) {
+ $this->markTestIncomplete(
+ 'Predis currently doesn\'t support saving empty array values. '
+ . 'See https://github.com/nrk/predis/issues/241'
+ );
+ }
+
+ parent::testSetContainsFetchDelete($value);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @dataProvider provideDataToCache
+ */
+ public function testUpdateExistingEntry($value)
+ {
+ if (array() === $value) {
+ $this->markTestIncomplete(
+ 'Predis currently doesn\'t support saving empty array values. '
+ . 'See https://github.com/nrk/predis/issues/241'
+ );
+ }
+
+ parent::testUpdateExistingEntry($value);
+ }
+
+ public function testAllowsGenericPredisClient()
+ {
+ /* @var $predisClient \Predis\ClientInterface */
+ $predisClient = $this->getMock('Predis\\ClientInterface');
+
+ $this->assertInstanceOf('Doctrine\\Common\\Cache\\PredisCache', new PredisCache($predisClient));
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php
new file mode 100644
index 0000000000..caaaa06290
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php
@@ -0,0 +1,47 @@
+_redis = new \Redis();
+ $ok = @$this->_redis->connect('127.0.0.1');
+ if (!$ok) {
+ $this->markTestSkipped('Cannot connect to Redis.');
+ }
+ }
+
+ public function testHitMissesStatsAreProvided()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNotNull($stats[Cache::STATS_HITS]);
+ $this->assertNotNull($stats[Cache::STATS_MISSES]);
+ }
+
+ public function testGetRedisReturnsInstanceOfRedis()
+ {
+ $this->assertInstanceOf('Redis', $this->_getCacheDriver()->getRedis());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function _getCacheDriver()
+ {
+ $driver = new RedisCache();
+ $driver->setRedis($this->_redis);
+ return $driver;
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php
new file mode 100644
index 0000000000..e7d5f3dd33
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php
@@ -0,0 +1,58 @@
+connection = new Connection('127.0.0.1', 8087);
+ $this->bucket = new Bucket($this->connection, 'test');
+ } catch (Exception\RiakException $e) {
+ $this->markTestSkipped('Cannot connect to Riak.');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function testGetStats()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNull($stats);
+ }
+
+ /**
+ * Retrieve RiakCache instance.
+ *
+ * @return \Doctrine\Common\Cache\RiakCache
+ */
+ protected function _getCacheDriver()
+ {
+ return new RiakCache($this->bucket);
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/SQLite3CacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/SQLite3CacheTest.php
new file mode 100644
index 0000000000..f0c5b0b592
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/SQLite3CacheTest.php
@@ -0,0 +1,42 @@
+file = tempnam(null, 'doctrine-cache-test-');
+ unlink($this->file);
+ $this->sqlite = new SQLite3($this->file);
+ }
+
+ protected function tearDown()
+ {
+ $this->sqlite = null; // DB must be closed before
+ unlink($this->file);
+ }
+
+ public function testGetStats()
+ {
+ $this->assertNull($this->_getCacheDriver()->getStats());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function _getCacheDriver()
+ {
+ return new SQLite3Cache($this->sqlite, 'test_table');
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/VoidCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/VoidCacheTest.php
new file mode 100644
index 0000000000..8ab7e5b472
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/VoidCacheTest.php
@@ -0,0 +1,58 @@
+assertFalse($cache->contains('foo'));
+ $this->assertFalse($cache->contains('bar'));
+ }
+
+ public function testShouldAlwaysReturnFalseOnFetch()
+ {
+ $cache = new VoidCache();
+
+ $this->assertFalse($cache->fetch('foo'));
+ $this->assertFalse($cache->fetch('bar'));
+ }
+
+ public function testShouldAlwaysReturnTrueOnSaveButNotStoreAnything()
+ {
+ $cache = new VoidCache();
+
+ $this->assertTrue($cache->save('foo', 'fooVal'));
+
+ $this->assertFalse($cache->contains('foo'));
+ $this->assertFalse($cache->fetch('foo'));
+ }
+
+ public function testShouldAlwaysReturnTrueOnDelete()
+ {
+ $cache = new VoidCache();
+
+ $this->assertTrue($cache->delete('foo'));
+ }
+
+ public function testShouldAlwaysReturnNullOnGetStatus()
+ {
+ $cache = new VoidCache();
+
+ $this->assertNull($cache->getStats());
+ }
+
+ public function testShouldAlwaysReturnTrueOnFlush()
+ {
+ $cache = new VoidCache();
+
+ $this->assertTrue($cache->flushAll());
+ }
+}
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php
new file mode 100644
index 0000000000..1dded42478
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php
@@ -0,0 +1,16 @@
+markTestSkipped('Zend Data Cache only works in apache2handler SAPI.');
+ }
+ }
+
+ public function testGetStats()
+ {
+ $cache = $this->_getCacheDriver();
+ $stats = $cache->getStats();
+
+ $this->assertNull($stats);
+ }
+
+ protected function _getCacheDriver()
+ {
+ return new ZendDataCache();
+ }
+}
\ No newline at end of file
diff --git a/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php
new file mode 100644
index 0000000000..e8323d2940
--- /dev/null
+++ b/core/src/plugins/core.cache/doctrine/vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ../Doctrine/
+
+
+
+
+
+ ../../lib/Doctrine/
+
+
+
+
+
+ performance
+
+
+
diff --git a/core/src/plugins/core.cache/manifest.xml b/core/src/plugins/core.cache/manifest.xml
new file mode 100644
index 0000000000..3ddd7b8ff6
--- /dev/null
+++ b/core/src/plugins/core.cache/manifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/plugins/core.conf/class.AbstractAjxpUser.php b/core/src/plugins/core.conf/class.AbstractAjxpUser.php
index 23ac2d25a6..ccbcfea414 100644
--- a/core/src/plugins/core.conf/class.AbstractAjxpUser.php
+++ b/core/src/plugins/core.conf/class.AbstractAjxpUser.php
@@ -433,9 +433,8 @@ public function getBookmarks()
abstract public function load();
public function save($context = "superuser"){
- $kvCache = ConfService::getInstance()->getKeyValueCache();
$this->_save($context);
- $kvCache->save("pydio:user:".$this->getId(), $this);
+ CacheService::save("pydio:user:".$this->getId(), $this);
}
abstract protected function _save($context = "superuser");
diff --git a/core/src/plugins/core.conf/class.AbstractConfDriver.php b/core/src/plugins/core.conf/class.AbstractConfDriver.php
index 4130e95e09..82dcdf1567 100644
--- a/core/src/plugins/core.conf/class.AbstractConfDriver.php
+++ b/core/src/plugins/core.conf/class.AbstractConfDriver.php
@@ -217,7 +217,8 @@ public function savePluginConfig($pluginId, $options)
protected function pluginUsesBootConf($pluginId)
{
return ($pluginId == "core.conf" || strpos($pluginId, "conf.") === 0
- || $pluginId == "core.auth" || strpos($pluginId, "auth.") === 0);
+ || $pluginId == "core.auth" || strpos($pluginId, "auth.") === 0
+ || $pluginId == "core.cache" || strpos($pluginId, "cache.") === 0);
}
/**
@@ -385,8 +386,7 @@ abstract public function pruneTemporaryKeys($keyType, $expiration);
*/
public function createUserObject($userId)
{
- $kvCache = ConfService::getInstance()->getKeyValueCache();
- $test = $kvCache->fetch("pydio:user:".$userId);
+ $test=CacheService::fetch("pydio:user:".$userId);
if($test !== false && is_a($test, "AbstractAjxpUser")){
if($test->personalRole == null){
$test->personalRole = $test->roles["AJXP_USR_/".$userId];
@@ -403,7 +403,7 @@ public function createUserObject($userId)
AuthService::updateAuthProvidedData($abstractUser);
$args = array(&$abstractUser);
AJXP_Controller::applyIncludeHook("include.user.updateUserObject", $args);
- $kvCache->save("pydio:user:".$userId, $abstractUser);
+ CacheService::save("pydio:user:".$userId, $abstractUser);
return $abstractUser;
}