From 8d3a0624efd0c5f400df67478d5b657e3db04698 Mon Sep 17 00:00:00 2001 From: Demian Katz <demian.katz@villanova.edu> Date: Wed, 29 Aug 2012 08:26:41 -0400 Subject: [PATCH] Set up session handlers to use a plugin manager; adjusted handler classes to use a setConfig() method instead of constructor injection to allow plugin manager compatibility. --- module/VuFind/src/VuFind/Bootstrap.php | 53 +++++++--- .../ServiceManager/AbstractPluginFactory.php | 97 +++++++++++++++++++ .../ServiceManager/AbstractPluginManager.php | 65 +++++++++++++ .../src/VuFind/Session/AbstractBase.php | 10 +- module/VuFind/src/VuFind/Session/Database.php | 8 +- module/VuFind/src/VuFind/Session/File.php | 59 +++++------ module/VuFind/src/VuFind/Session/Memcache.php | 46 ++++----- .../src/VuFind/Session/PluginFactory.php | 48 +++++++++ .../src/VuFind/Session/PluginManager.php | 55 +++++++++++ 9 files changed, 365 insertions(+), 76 deletions(-) create mode 100644 module/VuFind/src/VuFind/ServiceManager/AbstractPluginFactory.php create mode 100644 module/VuFind/src/VuFind/ServiceManager/AbstractPluginManager.php create mode 100644 module/VuFind/src/VuFind/Session/PluginFactory.php create mode 100644 module/VuFind/src/VuFind/Session/PluginManager.php diff --git a/module/VuFind/src/VuFind/Bootstrap.php b/module/VuFind/src/VuFind/Bootstrap.php index ddc785c468a..361b4de6c42 100644 --- a/module/VuFind/src/VuFind/Bootstrap.php +++ b/module/VuFind/src/VuFind/Bootstrap.php @@ -31,7 +31,8 @@ use VuFind\Config\Reader as ConfigReader, VuFind\Theme\Initializer as ThemeInitializer, VuFind\Translator\Translator, Zend\Console\Console, Zend\Db\TableGateway\Feature\GlobalAdapterFeature as DbGlobalAdapter, - Zend\Mvc\MvcEvent, Zend\Mvc\Router\Http\RouteMatch; + Zend\Mvc\MvcEvent, Zend\Mvc\Router\Http\RouteMatch, + Zend\ServiceManager\Config as ServiceManagerConfig; /** * VuFind Bootstrapper @@ -77,7 +78,36 @@ class Bootstrap } /** - * Set up the default database adapter. Do this first since the session handler + * Set up plugin managers. + * + * @return void + */ + protected function initPluginManagers() + { + $serviceManager = $this->event->getApplication()->getServiceManager(); + $config = new ServiceManagerConfig( + array( + 'abstract_factories' => array('VuFind\Session\PluginFactory'), + 'invokables' => array( + 'database' => 'VuFind\Session\Database', + 'file' => 'VuFind\Session\File', + 'memcache' => 'VuFind\Session\Memcache', + ), + 'aliases' => array( + // for legacy 1.x compatibility + 'filesession' => 'File', + 'memcachesession' => 'Memcache', + 'mysqlsession' => 'Database', + ), + ) + ); + $serviceManager->setService( + 'SessionHandlerManager', new \VuFind\Session\PluginManager($config) + ); + } + + /** + * Set up the default database adapter. Do this early since the session handler * may depend on database access. * * @return void @@ -105,21 +135,14 @@ class Bootstrap throw new \Exception('Cannot initialize session; configuration missing'); } - // Register a session manager in the service manager: + // Set up the session handler by retrieving all the pieces from the service + // manager and injecting appropriate dependencies: $serviceManager = $this->event->getApplication()->getServiceManager(); $sessionManager = $serviceManager->get('SessionManager'); - - // Set up session handler (after manipulating the type setting for legacy - // compatibility -- VuFind 1.x used MySQL instead of Database and had - // "Session" as part of the configuration string): - $type = ucwords( - str_replace('session', '', strtolower($this->config->Session->type)) - ); - if ($type == 'Mysql') { - $type = 'Database'; - } - $class = 'VuFind\Session\\' . $type; - $sessionManager->setSaveHandler(new $class($this->config->Session)); + $sessionHandlerManager = $serviceManager->get('SessionHandlerManager'); + $sessionHandler = $sessionHandlerManager->get($this->config->Session->type); + $sessionHandler->setConfig($this->config->Session); + $sessionManager->setSaveHandler($sessionHandler); // Start up the session: $sessionManager->start(); diff --git a/module/VuFind/src/VuFind/ServiceManager/AbstractPluginFactory.php b/module/VuFind/src/VuFind/ServiceManager/AbstractPluginFactory.php new file mode 100644 index 00000000000..b5d9a4aea58 --- /dev/null +++ b/module/VuFind/src/VuFind/ServiceManager/AbstractPluginFactory.php @@ -0,0 +1,97 @@ +<?php +/** + * VuFind Abstract Plugin Factory + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package ServiceManager + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_recommendations_module Wiki + */ +namespace VuFind\ServiceManager; +use Zend\ServiceManager\AbstractFactoryInterface, + Zend\ServiceManager\ServiceLocatorInterface; + +/** + * VuFind Abstract Plugin Factory + * + * @category VuFind2 + * @package ServiceManager + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_search_object Wiki + */ +abstract class AbstractPluginFactory implements AbstractFactoryInterface +{ + protected $defaultNamespace; + + /** + * Get the name of a class for a given plugin name. + * + * @param string $name Name of service + * @param string $requestedName Unfiltered name of service + * + * @return string Fully qualified class name + */ + protected function getClassName($name, $requestedName) + { + // If we have a FQCN, return it as-is; otherwise, prepend the default prefix: + if (strpos($name, '\\') === false) { + // First try the raw service name, then try a normalized version: + $name = $this->defaultNamespace . '\\' . $requestedName; + if (!class_exists($name)) { + $name = $this->defaultNamespace . '\\' . ucwords(strtolower($name)); + } + } + return $name; + } + + /** + * Can we create a service for the specified name? + * + * @param ServiceLocatorInterface $serviceLocator Service locator + * @param string $name Name of service + * @param string $requestedName Unfiltered name of service + * + * @return bool + */ + public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, + $name, $requestedName + ) { + $className = $this->getClassName($name, $requestedName); + return class_exists($className); + } + + /** + * Create a service for the specified name. + * + * @param ServiceLocatorInterface $serviceLocator Service locator + * @param string $name Name of service + * @param string $requestedName Unfiltered name of service + * + * @return object + */ + public function createServiceWithName(ServiceLocatorInterface $serviceLocator, + $name, $requestedName + ) { + $class = $this->getClassName($name, $requestedName); + return new $class(); + } +} diff --git a/module/VuFind/src/VuFind/ServiceManager/AbstractPluginManager.php b/module/VuFind/src/VuFind/ServiceManager/AbstractPluginManager.php new file mode 100644 index 00000000000..3201131af92 --- /dev/null +++ b/module/VuFind/src/VuFind/ServiceManager/AbstractPluginManager.php @@ -0,0 +1,65 @@ +<?php +/** + * VuFind Plugin Manager + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package ServiceManager + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_recommendations_module Wiki + */ +namespace VuFind\ServiceManager; +use Zend\ServiceManager\AbstractPluginManager as Base, + Zend\ServiceManager\Exception\RuntimeException as ServiceManagerRuntimeException; + +/** + * VuFind Plugin Manager + * + * @category VuFind2 + * @package ServiceManager + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/building_a_search_object Wiki + */ +abstract class AbstractPluginManager extends Base +{ + protected $expectedInterface; + + /** + * Validate the plugin + * + * Checks that the filter loaded is either a valid callback or an instance + * of FilterInterface. + * + * @param mixed $plugin Plugin to validate + * + * @throws ServiceManagerRuntimeException if invalid + * @return void + */ + public function validatePlugin($plugin) + { + if (!($plugin instanceof $this->expectedInterface)) { + throw new ServiceManagerRuntimeException( + 'Plugin ' . get_class($plugin) . ' does not belong to ' + . $this->expectedInterface + ); + } + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Session/AbstractBase.php b/module/VuFind/src/VuFind/Session/AbstractBase.php index 15c52e4ba06..1772cfacdf5 100644 --- a/module/VuFind/src/VuFind/Session/AbstractBase.php +++ b/module/VuFind/src/VuFind/Session/AbstractBase.php @@ -40,19 +40,23 @@ use VuFind\Db\Table\Search as SearchTable, */ abstract class AbstractBase implements SaveHandlerInterface { - public $lifetime = 3600; + protected $lifetime = 3600; + protected $config = null; /** - * Constructor. + * Set configuration. * * @param \Zend\Config\Config $config Session configuration ([Session] section of * config.ini) + * + * @return void */ - public function __construct($config) + public function setConfig($config) { if (isset($config->lifetime)) { $this->lifetime = $config->lifetime; } + $this->config = $config; } /** diff --git a/module/VuFind/src/VuFind/Session/Database.php b/module/VuFind/src/VuFind/Session/Database.php index c1ee7abd8c9..8855c1db1d2 100644 --- a/module/VuFind/src/VuFind/Session/Database.php +++ b/module/VuFind/src/VuFind/Session/Database.php @@ -44,17 +44,11 @@ class Database extends AbstractBase /** * Constructor. - * - * @param \Zend\Config\Config $config Session configuration ([Session] section of - * config.ini) */ - public function __construct($config) + public function __construct() { // Create database connection: $this->table = new SessionTable(); - - // Call standard session initialization from this point. - parent::__construct($config); } /** diff --git a/module/VuFind/src/VuFind/Session/File.php b/module/VuFind/src/VuFind/Session/File.php index 86c708999c9..2ddb7a3b1cb 100644 --- a/module/VuFind/src/VuFind/Session/File.php +++ b/module/VuFind/src/VuFind/Session/File.php @@ -38,36 +38,37 @@ namespace VuFind\Session; */ class File extends AbstractBase { - protected $path; + protected $path = false; /** - * Constructor. + * Get the file path for writing sessions. * - * @param \Zend\Config\Config $config Session configuration ([Session] section of - * config.ini) + * @throws \Exception + * @return string */ - public function __construct($config) + protected function getPath() { - // Set defaults if nothing set in config file. - if (isset($config->file_save_path)) { - $this->path = $config->file_save_path; - } else { - $tempdir = function_exists('sys_get_temp_dir') - ? sys_get_temp_dir() : DIRECTORY_SEPARATOR . 'tmp'; - $this->path = $tempdir . DIRECTORY_SEPARATOR . 'vufind_sessions'; - } + if (!$this->path) { + // Set defaults if nothing set in config file. + if (isset($this->config->file_save_path)) { + $this->path = $this->config->file_save_path; + } else { + $tempdir = function_exists('sys_get_temp_dir') + ? sys_get_temp_dir() : DIRECTORY_SEPARATOR . 'tmp'; + $this->path = $tempdir . DIRECTORY_SEPARATOR . 'vufind_sessions'; + } - // Die if the session directory does not exist and cannot be created. - if (!file_exists($this->path) || !is_dir($this->path)) { - if (!@mkdir($this->path)) { - throw new \Exception( - "Cannot access session save path: " . $this->path - ); + // Die if the session directory does not exist and cannot be created. + if (!file_exists($this->path) || !is_dir($this->path)) { + if (!mkdir($this->path)) { + throw new \Exception( + "Cannot access session save path: " . $this->path + ); + } } } - // Call standard session initialization from this point. - parent::__construct($config); + return $this->path; } /** @@ -80,7 +81,7 @@ class File extends AbstractBase */ public function read($sess_id) { - $sess_file = $this->path . '/sess_' . $sess_id; + $sess_file = $this->getPath() . '/sess_' . $sess_id; if (!file_exists($sess_file)) { return ''; } @@ -91,7 +92,7 @@ class File extends AbstractBase return ''; } - return (string)@file_get_contents($sess_file); + return (string)file_get_contents($sess_file); } /** @@ -104,8 +105,8 @@ class File extends AbstractBase */ public function write($sess_id, $data) { - $sess_file = $this->path . '/sess_' . $sess_id; - if ($fp = @fopen($sess_file, "w")) { + $sess_file = $this->getPath() . '/sess_' . $sess_id; + if ($fp = fopen($sess_file, "w")) { $return = fwrite($fp, $data); fclose($fp); if ($return !== false) { @@ -133,8 +134,8 @@ class File extends AbstractBase parent::destroy($sess_id); // Perform file-specific cleanup: - $sess_file = $this->path . '/sess_' . $sess_id; - return(@unlink($sess_file)); + $sess_file = $this->getPath() . '/sess_' . $sess_id; + return(unlink($sess_file)); } /** @@ -147,9 +148,9 @@ class File extends AbstractBase */ public function gc($maxlifetime) { - foreach (glob($this->path . "/sess_*") as $filename) { + foreach (glob($this->getPath() . "/sess_*") as $filename) { if (filemtime($filename) + $maxlifetime < time()) { - @unlink($filename); + unlink($filename); } } return true; diff --git a/module/VuFind/src/VuFind/Session/Memcache.php b/module/VuFind/src/VuFind/Session/Memcache.php index 5783c1cfb99..977f25b59a2 100644 --- a/module/VuFind/src/VuFind/Session/Memcache.php +++ b/module/VuFind/src/VuFind/Session/Memcache.php @@ -41,32 +41,34 @@ namespace VuFind\Session; */ class Memcache extends AbstractBase { - protected $connection; + protected $connection = false; /** - * Constructor. + * Get connection to Memcache * - * @param \Zend\Config\Config $config Session configuration ([Session] section of - * config.ini) + * @throws \Exception + * @return \Memcache */ - public function __construct($config) + public function getConnection() { - // Set defaults if nothing set in config file. - $host = isset($config->memcache_host) ? $config->memcache_host : 'localhost'; - $port = isset($config->memcache_port) ? $config->memcache_port : 11211; - $timeout = isset($config->memcache_connection_timeout) - ? $config->memcache_connection_timeout : 1; + if (!$this->connection) { + // Set defaults if nothing set in config file. + $host = isset($this->config->memcache_host) + ? $this->config->memcache_host : 'localhost'; + $port = isset($this->config->memcache_port) + ? $this->config->memcache_port : 11211; + $timeout = isset($this->config->memcache_connection_timeout) + ? $this->config->memcache_connection_timeout : 1; - // Connect to Memcache: - $this->connection = new \Memcache(); - if (!@$this->connection->connect($host, $port, $timeout)) { - throw new \Exception( - "Could not connect to Memcache (host = {$host}, port = {$port})." - ); + // Connect to Memcache: + $this->connection = new \Memcache(); + if (!$this->connection->connect($host, $port, $timeout)) { + throw new \Exception( + "Could not connect to Memcache (host = {$host}, port = {$port})." + ); + } } - - // Call standard session initialization from this point. - parent::__construct($config); + return $this->connection; } /** @@ -79,7 +81,7 @@ class Memcache extends AbstractBase */ public function read($sess_id) { - return $this->connection->get("vufind_sessions/{$sess_id}"); + return $this->getConnection()->get("vufind_sessions/{$sess_id}"); } /** @@ -92,7 +94,7 @@ class Memcache extends AbstractBase */ public function write($sess_id, $data) { - return $this->connection->set( + return $this->getConnection()->set( "vufind_sessions/{$sess_id}", $data, 0, $this->lifetime ); } @@ -111,6 +113,6 @@ class Memcache extends AbstractBase parent::destroy($sess_id); // Perform Memcache-specific cleanup: - return $this->connection->delete("vufind_sessions/{$sess_id}"); + return $this->getConnection()->delete("vufind_sessions/{$sess_id}"); } } \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Session/PluginFactory.php b/module/VuFind/src/VuFind/Session/PluginFactory.php new file mode 100644 index 00000000000..8ac38a7dff5 --- /dev/null +++ b/module/VuFind/src/VuFind/Session/PluginFactory.php @@ -0,0 +1,48 @@ +<?php +/** + * Session handler plugin factory + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Session_Handlers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/creating_a_session_handler Wiki + */ +namespace VuFind\Session; + +/** + * Session handler plugin factory + * + * @category VuFind2 + * @package Session_Handlers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/creating_a_session_handler Wiki + */ +class PluginFactory extends \VuFind\ServiceManager\AbstractPluginFactory +{ + /** + * Constructor + */ + public function __construct() + { + $this->defaultNamespace = 'VuFind\Session'; + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Session/PluginManager.php b/module/VuFind/src/VuFind/Session/PluginManager.php new file mode 100644 index 00000000000..fc71c7c13ed --- /dev/null +++ b/module/VuFind/src/VuFind/Session/PluginManager.php @@ -0,0 +1,55 @@ +<?php +/** + * Session handler plugin manager + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Session_Handlers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/creating_a_session_handler Wiki + */ +namespace VuFind\Session; +use Zend\ServiceManager\ConfigInterface; + +/** + * Session handler plugin manager + * + * @category VuFind2 + * @package Session_Handlers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/creating_a_session_handler Wiki + */ +class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager +{ + /** + * Constructor + * + * Add a default initializer to ensure the plugin is valid after instance + * creation. + * + * @param null|ConfigInterface $configuration Configuration + */ + public function __construct(ConfigInterface $configuration = null) + { + $this->expectedInterface = 'Zend\Session\SaveHandler\SaveHandlerInterface'; + parent::__construct($configuration); + } +} \ No newline at end of file -- GitLab