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; }