diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 805a2d97ffc219d6506d23e9da54296ee9be6397..517aac13ea2d6bf6fba1d22c5b91d8e98f180239 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -60,7 +60,7 @@ $config = array(
             )
         ),
     ),
-    'auth_handler_manager' => array(
+    'auth_plugin_manager' => array(
         'abstract_factories' => array('VuFind\Auth\PluginFactory'),
         'invokables' => array(
             'database' => 'VuFind\Auth\Database',
@@ -76,7 +76,7 @@ $config = array(
             'sip' => 'Sip2',
         ),
     ),
-    'autocomplete_handler_manager' => array(
+    'autocomplete_plugin_manager' => array(
         'abstract_factories' => array('VuFind\Autocomplete\PluginFactory'),
         'invokables' => array(
             'none' => 'VuFind\Autocomplete\None',
@@ -138,6 +138,62 @@ $config = array(
             'result-scroller' => 'VuFind\Controller\Plugin\ResultScroller',
         )
     ),
+    'ils_driver_plugin_manager' => array(
+        'abstract_factories' => array('VuFind\ILS\Driver\PluginFactory'),
+        'invokables' => array(
+            'aleph' => 'VuFind\ILS\Driver\Aleph',
+            'amicus' => 'VuFind\ILS\Driver\Amicus',
+            'daia' => 'VuFind\ILS\Driver\DAIA',
+            'demo' => 'VuFind\ILS\Driver\Demo',
+            'evergreen' => 'VuFind\ILS\Driver\Evergreen',
+            'horizon' => 'VuFind\ILS\Driver\Horizon',
+            'horizonxmlapi' => 'VuFind\ILS\Driver\HorizonXMLAPI',
+            'innovative' => 'VuFind\ILS\Driver\Innovative',
+            'koha' => 'VuFind\ILS\Driver\Koha',
+            'newgenlib' => 'VuFind\ILS\Driver\NewGenLib',
+            'noils' => 'VuFind\ILS\Driver\NoILS',
+            'pica' => 'VuFind\ILS\Driver\PICA',
+            'sample' => 'VuFind\ILS\Driver\Sample',
+            'symphony' => 'VuFind\ILS\Driver\Symphony',
+            'unicorn' => 'VuFind\ILS\Driver\Unicorn',
+            'virtua' => 'VuFind\ILS\Driver\Virtua',
+            'voyager' => 'VuFind\ILS\Driver\Voyager',
+            'voyagerrestful' => 'VuFind\ILS\Driver\VoyagerRestful',
+            'xcncip' => 'VuFind\ILS\Driver\XCNCIP',
+            'xcncip2' => 'VuFind\ILS\Driver\XCNCIP2',
+        ),
+    ),
+    'recommend_plugin_manager' => array(
+        'abstract_factories' => array('VuFind\Recommend\PluginFactory'),
+        'invokables' => array(
+            'authorfacets' => 'VuFind\Recommend\AuthorFacets',
+            'authorinfo' => 'VuFind\Recommend\AuthorInfo',
+            'authorityrecommend' => 'VuFind\Recommend\AuthorityRecommend',
+            'catalogresults' => 'VuFind\Recommend\CatalogResults',
+            'europeanaresults' => 'VuFind\Recommend\EuropeanaResults',
+            'europeanaresultsdeferred' => 'VuFind\Recommend\EuropeanaResultsDeferred',
+            'expandfacets' => 'VuFind\Recommend\ExpandFacets',
+            'favoritefacets' => 'VuFind\Recommend\FavoriteFacets',
+            'openlibrarysubjects' => 'VuFind\Recommend\OpenLibrarySubjects',
+            'openlibrarysubjectsdeferred' => 'VuFind\Recommend\OpenLibrarySubjectsDeferred',
+            'pubdatevisajax' => 'VuFind\Recommend\PubDateVisAjax',
+            'resultgooglemapajax' => 'VuFind\Recommend\ResultGoogleMapAjax',
+            'sidefacets' => 'VuFind\Recommend\SideFacets',
+            'summondatabases' => 'VuFind\Recommend\SummonDatabases',
+            'summonresults' => 'VuFind\Recommend\SummonResults',
+            'switchtype' => 'VuFind\Recommend\SwitchType',
+            'topfacets' => 'VuFind\Recommend\TopFacets',
+            'worldcatidentities' => 'VuFind\Recommend\WorldCatIdentities',
+            'worldcatterms' => 'VuFind\Recommend\WorldCatTerms',
+        ),
+    ),
+    'search_manager' => array(
+        'default_namespace' => 'VuFind\Search',
+        'namespaces_by_id' => array(
+        ),
+        'aliases' => array(
+        ),
+    ),
     'service_manager' => array(
         'invokables' => array(
             'authmanager' => 'VuFind\Auth\Manager',
@@ -145,7 +201,7 @@ $config = array(
             'sessionmanager' => 'Zend\Session\SessionManager',
         )
     ),
-    'session_handler_manager' => array(
+    'session_plugin_manager' => array(
         'abstract_factories' => array('VuFind\Session\PluginFactory'),
         'invokables' => array(
             'database' => 'VuFind\Session\Database',
diff --git a/module/VuFind/src/VuFind/Auth/Manager.php b/module/VuFind/src/VuFind/Auth/Manager.php
index 1ee745a40f045984d64bdfa737b27a734d387666..5b7c9de23bb208417572847bd25d1f4b31bac8b7 100644
--- a/module/VuFind/src/VuFind/Auth/Manager.php
+++ b/module/VuFind/src/VuFind/Auth/Manager.php
@@ -67,7 +67,7 @@ class Manager implements ServiceLocatorAwareInterface
     protected function getAuth()
     {
         if (!$this->auth) {
-            $manager = $this->getServiceLocator()->get('AuthHandlerManager');
+            $manager = $this->getServiceLocator()->get('AuthPluginManager');
             $this->auth = $manager->get($this->config->Authentication->method);
             $this->auth->setConfig($this->config);
         }
diff --git a/module/VuFind/src/VuFind/Auth/MultiAuth.php b/module/VuFind/src/VuFind/Auth/MultiAuth.php
index bfa4cc02e0ac45ebb48202a051d3396ea6ef9c73..9a043a65d92f539a2f4df02de9867d83ab9adefa 100644
--- a/module/VuFind/src/VuFind/Auth/MultiAuth.php
+++ b/module/VuFind/src/VuFind/Auth/MultiAuth.php
@@ -211,7 +211,7 @@ class MultiAuth extends AbstractBase implements ServiceLocatorAwareInterface
      *
      * @param ServiceLocatorInterface $serviceLocator Locator to register
      *
-     * @return Manager
+     * @return MultiAuth
      */
     public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
     {
diff --git a/module/VuFind/src/VuFind/Auth/PluginFactory.php b/module/VuFind/src/VuFind/Auth/PluginFactory.php
index 818617d0d6d189e7ed728d4111311c322f5dde13..6829ffa269a628e7b8b5240d6e47babc329393a0 100644
--- a/module/VuFind/src/VuFind/Auth/PluginFactory.php
+++ b/module/VuFind/src/VuFind/Auth/PluginFactory.php
@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Authentication
  * @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
@@ -31,7 +31,7 @@ namespace VuFind\Auth;
  * Auth handler plugin factory
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Authentication
  * @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
diff --git a/module/VuFind/src/VuFind/Auth/PluginManager.php b/module/VuFind/src/VuFind/Auth/PluginManager.php
index e7f5e71c4d25957003db8d1c9fade8661f96d908..78c0144f02b9733e872255a47fa944f4a8e32306 100644
--- a/module/VuFind/src/VuFind/Auth/PluginManager.php
+++ b/module/VuFind/src/VuFind/Auth/PluginManager.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Session handler plugin manager
+ * Auth handler plugin manager
  *
  * PHP version 5
  *
@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Authentication
  * @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
@@ -28,10 +28,10 @@
 namespace VuFind\Auth;
 
 /**
- * Session handler plugin manager
+ * Auth handler plugin manager
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Authentication
  * @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
diff --git a/module/VuFind/src/VuFind/Autocomplete/PluginFactory.php b/module/VuFind/src/VuFind/Autocomplete/PluginFactory.php
index cb26dcfea9505f08594910fd6a39e679c34e2c10..5e3025670cc8880b7d59dca4fc8bba69f0dff003 100644
--- a/module/VuFind/src/VuFind/Autocomplete/PluginFactory.php
+++ b/module/VuFind/src/VuFind/Autocomplete/PluginFactory.php
@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Autocomplete
  * @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
@@ -31,7 +31,7 @@ namespace VuFind\Autocomplete;
  * Autocomplete handler plugin factory
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Autocomplete
  * @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
diff --git a/module/VuFind/src/VuFind/Autocomplete/PluginManager.php b/module/VuFind/src/VuFind/Autocomplete/PluginManager.php
index dff684fc82fe81dbbb75070f1ee5605a6d591441..24e60d4d9b84055487a4443da28c2f1fdf3b4976 100644
--- a/module/VuFind/src/VuFind/Autocomplete/PluginManager.php
+++ b/module/VuFind/src/VuFind/Autocomplete/PluginManager.php
@@ -20,19 +20,19 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Autocomplete
  * @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\Autocomplete;
-use VuFind\Config\Reader as ConfigReader, VuFind\Search\Options as SearchOptions;
+use VuFind\Config\Reader as ConfigReader;
 
 /**
  * Autocomplete handler plugin manager
  *
  * @category VuFind2
- * @package  Session_Handlers
+ * @package  Autocomplete
  * @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
@@ -73,7 +73,8 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
 
         // get Autocomplete_Type config
         $searcher = $request->get('searcher', 'Solr');
-        $options = SearchOptions::getInstance($searcher);
+        $options = $this->getServiceLocator()->get('SearchManager')
+            ->setSearchClassId($searcher)->getOptionsInstance();
         $config = ConfigReader::getConfig($options->getSearchIni());
         $types = isset($config->Autocomplete_Types) ?
             $config->Autocomplete_Types->toArray() : array();
diff --git a/module/VuFind/src/VuFind/Autocomplete/Solr.php b/module/VuFind/src/VuFind/Autocomplete/Solr.php
index cc989178fbf8e83ce6a3d81f5ae7b6290345f5eb..1efe1406eb80c27b3d0360569a6a5f76892e1bc8 100644
--- a/module/VuFind/src/VuFind/Autocomplete/Solr.php
+++ b/module/VuFind/src/VuFind/Autocomplete/Solr.php
@@ -27,6 +27,8 @@
  * @link     http://vufind.org/wiki/autocomplete Wiki
  */
 namespace VuFind\Autocomplete;
+use Zend\ServiceManager\ServiceLocatorAwareInterface,
+    Zend\ServiceManager\ServiceLocatorInterface;
 
 /**
  * Solr Autocomplete Module
@@ -39,13 +41,14 @@ namespace VuFind\Autocomplete;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://vufind.org/wiki/autocomplete Wiki
  */
-class Solr implements AutocompleteInterface
+class Solr implements AutocompleteInterface, ServiceLocatorAwareInterface
 {
     protected $handler;
     protected $displayField;
     protected $defaultDisplayField = 'title';
     protected $sortField;
     protected $filters;
+    protected $searchClassId = 'Solr';
     protected $searchObject;
 
 
@@ -91,10 +94,15 @@ class Solr implements AutocompleteInterface
      */
     protected function initSearchObject()
     {
+        // Get the search manager:
+        $sm = $this->getServiceLocator()->getServiceLocator()->get('SearchManager');
+        $sm->setSearchClassId($this->searchClassId);
+
         // Build a new search object:
-        $params = new \VuFind\Search\Solr\Params();
-        $this->searchObject = new \VuFind\Search\Solr\Results($params);
-        $this->searchObject->getOptions()->spellcheckEnabled(false);
+        $params = $sm->getParams();
+        $params->getOptions()->spellcheckEnabled(false);
+        $params->recommendationsEnabled(false);
+        $this->searchObject = $sm->getResults($params);
     }
 
     /**
@@ -279,4 +287,26 @@ class Solr implements AutocompleteInterface
         return true;
     }
 
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return Solr
+     */
+    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->serviceLocator = $serviceLocator;
+        return $this;
+    }
+
+    /**
+     * Get the service locator.
+     *
+     * @return \Zend\ServiceManager\ServiceLocatorInterface
+     */
+    public function getServiceLocator()
+    {
+        return $this->serviceLocator;
+    }
 }
diff --git a/module/VuFind/src/VuFind/Autocomplete/SolrAuth.php b/module/VuFind/src/VuFind/Autocomplete/SolrAuth.php
index daa42eb352b79cb1818aa790d53afe73463a110f..b8efbcda43d4bb682d7fd9038d8538ce87281724 100644
--- a/module/VuFind/src/VuFind/Autocomplete/SolrAuth.php
+++ b/module/VuFind/src/VuFind/Autocomplete/SolrAuth.php
@@ -47,19 +47,6 @@ class SolrAuth extends Solr
     public function __construct()
     {
         $this->defaultDisplayField = 'heading';
-    }
-
-    /**
-     * initSearchObject
-     *
-     * Initialize the search object used for finding recommendations.
-     *
-     * @return void
-     */
-    protected function initSearchObject()
-    {
-        // Build a new search object:
-        $params = new \VuFind\Search\SolrAuth\Params();
-        $this->searchObject = new \VuFind\Search\SolrAuth\Results($params);
+        $this->searchClassId = 'SolrAuth';
     }
 }
diff --git a/module/VuFind/src/VuFind/Autocomplete/SolrReserves.php b/module/VuFind/src/VuFind/Autocomplete/SolrReserves.php
index e6a91ec5a2cc6d715b353a3f29bc7ef01bf6c920..73851191d250d3103cda8bb505dfa37d793766e0 100644
--- a/module/VuFind/src/VuFind/Autocomplete/SolrReserves.php
+++ b/module/VuFind/src/VuFind/Autocomplete/SolrReserves.php
@@ -47,20 +47,6 @@ class SolrReserves extends Solr
     public function __construct()
     {
         $this->defaultDisplayField = 'course';
-    }
-
-    /**
-     * initSearchObject
-     *
-     * Initialize the search object used for finding recommendations.
-     *
-     * @return void
-     */
-    protected function initSearchObject()
-    {
-        // Build a new search object:
-        $params = new \VuFind\Search\SolrReserves\Params();
-        $this->searchObject = new \VuFind\Search\SolrReserves\Results($params);
-        $this->searchObject->getOptions()->spellcheckEnabled(false);
+        $this->searchClassId = 'SolrReserves';
     }
 }
diff --git a/module/VuFind/src/VuFind/Bootstrap.php b/module/VuFind/src/VuFind/Bootstrap.php
index 6fc202d5700e39cca0a1eadbeebbad7cec7ed722..0f1a5135b42299a3f8febf07a828def83dfb059d 100644
--- a/module/VuFind/src/VuFind/Bootstrap.php
+++ b/module/VuFind/src/VuFind/Bootstrap.php
@@ -90,11 +90,13 @@ class Bootstrap
         $config = $app->getConfig();
 
         // Use naming conventions to set up a bunch of services based on namespace:
-        $namespaces = array('Auth', 'Autocomplete', 'Session');
+        $namespaces = array(
+            'Auth', 'Autocomplete', 'ILS\Driver', 'Recommend', 'Session'
+        );
         foreach ($namespaces as $ns) {
-            $serviceName = $ns . 'HandlerManager';
+            $serviceName = str_replace('\\', '', $ns) . 'PluginManager';
             $className = 'VuFind\\' . $ns . '\PluginManager';
-            $configKey = strtolower($ns) . '_handler_manager';
+            $configKey = strtolower(str_replace('\\', '_', $ns)) . '_plugin_manager';
             $service = new $className(
                 new ServiceManagerConfig($config[$configKey])
             );
@@ -103,6 +105,15 @@ class Bootstrap
             }
             $serviceManager->setService($serviceName, $service);
         }
+
+        // Set up search manager a little differently -- it is a more complex class
+        // that doesn't work like the other standard plugin managers.
+        $manager = new \VuFind\Search\Manager($config['search_manager']);
+        $manager->setServiceLocator($serviceManager);
+        $serviceManager->setService('SearchManager', $manager);
+
+        // TODO: factor out static connection manager.
+        \VuFind\Connection\Manager::setServiceLocator($serviceManager);
     }
 
     /**
@@ -138,8 +149,8 @@ class Bootstrap
         // manager and injecting appropriate dependencies:
         $serviceManager = $this->event->getApplication()->getServiceManager();
         $sessionManager = $serviceManager->get('SessionManager');
-        $sessionHandlerManager = $serviceManager->get('SessionHandlerManager');
-        $sessionHandler = $sessionHandlerManager->get($this->config->Session->type);
+        $sessionPluginManager = $serviceManager->get('SessionPluginManager');
+        $sessionHandler = $sessionPluginManager->get($this->config->Session->type);
         $sessionHandler->setConfig($this->config->Session);
         $sessionManager->setSaveHandler($sessionHandler);
 
diff --git a/module/VuFind/src/VuFind/Connection/Manager.php b/module/VuFind/src/VuFind/Connection/Manager.php
index ff8231da477aa65883e9185c2ea77ab53a649192..cdd6d0b3559e1f505b56f5a20e39b270cbf80dc1 100644
--- a/module/VuFind/src/VuFind/Connection/Manager.php
+++ b/module/VuFind/src/VuFind/Connection/Manager.php
@@ -27,7 +27,8 @@
  */
 namespace VuFind\Connection;
 
-use VuFind\Config\Reader as ConfigReader, VuFind\ILS\Connection as ILSConnection;
+use VuFind\Config\Reader as ConfigReader, VuFind\ILS\Connection as ILSConnection,
+    Zend\ServiceManager\ServiceLocatorInterface;
 
 /**
  * Central class for connecting to resources used by VuFind.
@@ -40,6 +41,20 @@ use VuFind\Config\Reader as ConfigReader, VuFind\ILS\Connection as ILSConnection
  */
 class Manager
 {
+    protected static $serviceLocator;
+
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return void
+     */
+    public static function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        self::$serviceLocator = $serviceLocator;
+    }
+
     /**
      * Connect to the catalog.
      *
@@ -52,7 +67,10 @@ class Manager
         // remember the old connection and return that instead of starting over.
         static $catalog = false;
         if ($catalog === false) {
+            $config = ConfigReader::getConfig();
             $catalog = new ILSConnection();
+            $catalog->setServiceLocator(self::$serviceLocator);
+            $catalog->setConfig($config->Catalog);
         }
 
         return $catalog;
diff --git a/module/VuFind/src/VuFind/Controller/AbstractBase.php b/module/VuFind/src/VuFind/Controller/AbstractBase.php
index 4cdfe87efb219f4abfdb510fcb31f67d7f785fac..f66a892559bdf46ed6e939b7b7dc5d400eaf5f90 100644
--- a/module/VuFind/src/VuFind/Controller/AbstractBase.php
+++ b/module/VuFind/src/VuFind/Controller/AbstractBase.php
@@ -191,6 +191,16 @@ class AbstractBase extends AbstractActionController
         return $patron;
     }
 
+    /**
+     * Get the search manager.
+     *
+     * @return \VuFind\Search\Manager
+     */
+    public function getSearchManager()
+    {
+        return $this->getServiceLocator()->get('SearchManager');
+    }
+
     /**
      * Get the full URL to one of VuFind's routes.
      *
diff --git a/module/VuFind/src/VuFind/Controller/AbstractSearch.php b/module/VuFind/src/VuFind/Controller/AbstractSearch.php
index 702a1160142ab8a2972d393130e9bbaa18fd71c8..8b4eeac0046524a92641546cf2b6c4de88168d30 100644
--- a/module/VuFind/src/VuFind/Controller/AbstractSearch.php
+++ b/module/VuFind/src/VuFind/Controller/AbstractSearch.php
@@ -27,8 +27,7 @@
  */
 namespace VuFind\Controller;
 use VuFind\Db\Table\Search as SearchTable, VuFind\Record\Router as RecordRouter,
-    VuFind\Search\Memory, VuFind\Search\Options as SearchOptions,
-    Zend\Stdlib\Parameters;
+    VuFind\Search\Memory, Zend\Stdlib\Parameters;
 
 /**
  * VuFind Search Controller
@@ -79,7 +78,9 @@ class AbstractSearch extends AbstractBase
     public function advancedAction()
     {
         $view = $this->createViewModel();
-        $view->options = SearchOptions::getInstance($this->searchClassId);
+        $view->options = $this->getSearchManager()
+            ->setSearchClassId($this->searchClassId)
+            ->getOptionsInstance();
         if ($view->options->getAdvancedSearchAction() === false) {
             throw new \Exception('Advanced search not supported.');
         }
@@ -113,7 +114,7 @@ class AbstractSearch extends AbstractBase
         if ($search->session_id == $sessId || $search->user_id == $userId) {
             // They do, deminify it to a new object.
             $minSO = unserialize($search->search_object);
-            $savedSearch = $minSO->deminify();
+            $savedSearch = $minSO->deminify($this->getSearchManager());
 
             // Now redirect to the URL associated with the saved search; this
             // simplifies problems caused by mixing different classes of search
@@ -148,8 +149,8 @@ class AbstractSearch extends AbstractBase
             return $this->redirectToSavedSearch($savedId);
         }
 
-        $paramsClass = $this->getParamsClass();
-        $params = new $paramsClass();
+        $manager = $this->getSearchManager()->setSearchClassId($this->searchClassId);
+        $params = $manager->getParams();
         $params->recommendationsEnabled(true);
 
         // Send both GET and POST variables to search class:
@@ -163,8 +164,7 @@ class AbstractSearch extends AbstractBase
         // Attempt to perform the search; if there is a problem, inspect any Solr
         // exceptions to see if we should communicate to the user about them.
         try {
-            $resultsClass = $this->getResultsClass();
-            $results = new $resultsClass($params);
+            $results = $manager->getResults($params);
 
             // Explicitly execute search within controller -- this allows us to
             // catch exceptions more reliably:
@@ -191,7 +191,8 @@ class AbstractSearch extends AbstractBase
                 $sessId = $this->getServiceLocator()->get('SessionManager')->getId();
                 $history = new SearchTable();
                 $history->saveSearch(
-                    $results, $sessId, $history->getSearches(
+                    $this->getSearchManager(), $results, $sessId,
+                    $history->getSearches(
                         $sessId, isset($user->id) ? $user->id : null
                     )
                 );
@@ -210,7 +211,8 @@ class AbstractSearch extends AbstractBase
                 // We need to create and process an "empty results" object to
                 // ensure that recommendation modules and templates behave
                 // properly when displaying the error message.
-                $view->results = new \VuFind\Search\EmptySet\Results($params);
+                $view->results = $this->getSearchManager()
+                    ->setSearchClassId('EmptySet')->getResults($params);
                 $view->results->performAndProcessSearch();
             } else {
                 // Unexpected error -- let's throw this up to the next level.
@@ -264,26 +266,6 @@ class AbstractSearch extends AbstractBase
         return $this->redirect()->toRoute($details['route'], $details['params']);
     }
 
-    /**
-     * Get the name of the class used for setting search parameters.
-     *
-     * @return string
-     */
-    protected function getParamsClass()
-    {
-        return 'VuFind\Search\\' . $this->searchClassId . '\Params';
-    }
-
-    /**
-     * Get the name of the class used for retrieving search results.
-     *
-     * @return string
-     */
-    protected function getResultsClass()
-    {
-        return 'VuFind\Search\\' . $this->searchClassId . '\Results';
-    }
-
     /**
      * Either assign the requested search object to the view or display a flash
      * message indicating why the operation failed.
@@ -314,7 +296,7 @@ class AbstractSearch extends AbstractBase
 
         // Restore the full search object:
         $minSO = unserialize($search->search_object);
-        $savedSearch = $minSO->deminify();
+        $savedSearch = $minSO->deminify($this->getSearchManager());
 
         // Fail if this is not the right type of search:
         if ($savedSearch->getParams()->getSearchType() != 'advanced') {
diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php
index 916423edf9700acaf5d332edb9ce18624d6c24f5..343889fac9dd0a2ee31f0cde634f4e91782d2e28 100644
--- a/module/VuFind/src/VuFind/Controller/AjaxController.php
+++ b/module/VuFind/src/VuFind/Controller/AjaxController.php
@@ -107,11 +107,13 @@ class AjaxController extends AbstractBase
         // Process recommendations -- for now, we assume Solr-based search objects,
         // since deferred recommendations work best for modules that don't care about
         // the details of the search objects anyway:
-        $class = 'VuFind\Recommend\\' . $this->params()->fromQuery('mod');
-        $module = new $class($this->params()->fromQuery('params'));
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $rm = $this->getServiceLocator()->get('RecommendPluginManager');
+        $module = clone($rm->get($this->params()->fromQuery('mod')));
+        $module->setConfig($this->params()->fromQuery('params'));
+        $params = $sm->getParams();
         $module->init($params, $this->getRequest()->getQuery());
-        $results = new \VuFind\Search\Solr\Results($params);
+        $results = $sm->getResults($params);
         $module->process($results);
 
         // Set headers:
@@ -667,9 +669,10 @@ class AjaxController extends AbstractBase
      */
     public function getMapData($fields = array('long_lat'))
     {
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $params->initFromRequest($this->getRequest()->getQuery());
-        $results = new \VuFind\Search\Solr\Results($params);
+        $results = $sm->getResults($params);
 
         $facets = $results->getFullFieldFacets($fields, false);
 
@@ -706,9 +709,10 @@ class AjaxController extends AbstractBase
         // Set layout to render the page inside a lightbox:
         $this->layout()->setTemplate('layout/lightbox');
 
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $params->initFromRequest($this->getRequest()->getQuery());
-        $results = new \VuFind\Search\Solr\Results($params);
+        $results = $sm->getResults($params);
 
         return $this->createViewModel(
             array(
@@ -732,9 +736,10 @@ class AjaxController extends AbstractBase
      */
     public function getVisData($fields = array('publishDate'))
     {
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $params->initFromRequest($this->getRequest()->getQuery());
-        $results = new \VuFind\Search\Solr\Results($params);
+        $results = $sm->getResults($params);
         $filters = $params->getFilters();
         $dateFacets = $this->params()->fromQuery('facetFields');
         $dateFacets = empty($dateFacets) ? array() : explode(':', $dateFacets);
@@ -919,7 +924,7 @@ class AjaxController extends AbstractBase
     {
         $query = $this->getRequest()->getQuery();
         $autocompleteManager = $this->getServiceLocator()
-            ->get('AutocompleteHandlerManager');
+            ->get('AutocompletePluginManager');
         return $this->output(
             $autocompleteManager->getSuggestions($query), self::STATUS_OK
         );
diff --git a/module/VuFind/src/VuFind/Controller/BrowseController.php b/module/VuFind/src/VuFind/Controller/BrowseController.php
index 906cdc6d46ef160390c7562a112c9845a142ab86..3aa3b2c41622b46bf897928df2ddf6cef68bc9ce 100644
--- a/module/VuFind/src/VuFind/Controller/BrowseController.php
+++ b/module/VuFind/src/VuFind/Controller/BrowseController.php
@@ -26,9 +26,7 @@
  * @link     http://vufind.org/wiki/alphabetical_heading_browse Wiki
  */
 namespace VuFind\Controller;
-use VuFind\Config\Reader as ConfigReader, VuFind\Db\Table\Tags as TagsTable,
-    VuFind\Search\Solr\Params as SolrParams,
-    VuFind\Search\Solr\Results as SolrResults;
+use VuFind\Config\Reader as ConfigReader, VuFind\Db\Table\Tags as TagsTable;
 
 /**
  * BrowseController Class
@@ -561,7 +559,8 @@ class BrowseController extends AbstractBase
     protected function getFacetList($facet, $category = null,
         $sort = 'count', $query = '[* TO *]'
     ) {
-        $params = new SolrParams();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $params->addFacet($facet);
         if ($category != null) {
             $query = $category . ':' . $query;
@@ -569,7 +568,7 @@ class BrowseController extends AbstractBase
             $query = $facet . ':' . $query;
         }
         $params->setOverrideQuery($query);
-        $searchObject = new SolrResults($params);
+        $searchObject = $sm->getResults($params);
         // Get limit from config
         $params->setFacetLimit($this->config->Browse->result_limit);
         $params->setLimit(0);
diff --git a/module/VuFind/src/VuFind/Controller/InstallController.php b/module/VuFind/src/VuFind/Controller/InstallController.php
index c4b5aaa5de22fc7358dda4d44df0a66611ea5e97..df1faf18acd614f920e3b3eb334597c2c7b67051 100644
--- a/module/VuFind/src/VuFind/Controller/InstallController.php
+++ b/module/VuFind/src/VuFind/Controller/InstallController.php
@@ -427,7 +427,10 @@ class InstallController extends AbstractBase
             $dir
                 = opendir(APPLICATION_PATH . '/module/VuFind/src/VuFind/ILS/Driver');
             $drivers = array();
-            $blacklist = array('Sample.php', 'Demo.php', 'Interface.php');
+            $blacklist = array(
+                'Sample.php', 'Demo.php', 'DriverInterface.php', 'AbstractBase.php',
+                'PluginManager.php', 'PluginFactory.php'
+            );
             while ($line = readdir($dir)) {
                 if (stristr($line, '.php') && !in_array($line, $blacklist)) {
                     $drivers[] = str_replace('.php', '', $line);
diff --git a/module/VuFind/src/VuFind/Controller/MyResearchController.php b/module/VuFind/src/VuFind/Controller/MyResearchController.php
index 3e3f8dfccd86777a5ea4cec9f6c9c2d214303bb0..29f38853020f450adebf09ca829e2e9e5046ad2e 100644
--- a/module/VuFind/src/VuFind/Controller/MyResearchController.php
+++ b/module/VuFind/src/VuFind/Controller/MyResearchController.php
@@ -530,7 +530,8 @@ class MyResearchController extends AbstractBase
 
         // If we got this far, we just need to display the favorites:
         try {
-            $params = new \VuFind\Search\Favorites\Params();
+            $sm = $this->getSearchManager()->setSearchClassId('Favorites');
+            $params = $sm->getParams();
             $params->setAuthManager($this->getAuthManager());
 
             // We want to merge together GET, POST and route parameters to
@@ -543,7 +544,7 @@ class MyResearchController extends AbstractBase
                 )
             );
 
-            $results = new \VuFind\Search\Favorites\Results($params);
+            $results = $sm->getResults($params);
             $results->performAndProcessSearch();
             return $this->createViewModel(array('results' => $results));
         } catch (ListPermissionException $e) {
diff --git a/module/VuFind/src/VuFind/Controller/OaiController.php b/module/VuFind/src/VuFind/Controller/OaiController.php
index f5ed437591eb868afa9085b2f0bf15bc45c7ca42..a8bc183c9231d9e2cbb4c94c48d0171d10bb08c2 100644
--- a/module/VuFind/src/VuFind/Controller/OaiController.php
+++ b/module/VuFind/src/VuFind/Controller/OaiController.php
@@ -97,6 +97,7 @@ class OaiController extends AbstractBase
         // Build OAI response or die trying:
         try {
             $server = new $serverClass(
+                $this->getSearchManager(),
                 $baseURL, $this->getRequest()->getQuery()->toArray()
             );
             $xml = $server->getResponse();
diff --git a/module/VuFind/src/VuFind/Controller/Plugin/ResultScroller.php b/module/VuFind/src/VuFind/Controller/Plugin/ResultScroller.php
index 67ac9759e872a28e802f615ae5aa7eaa8daa0e5d..c1f8df0d409613496599c9b43ce9444bbea23072 100644
--- a/module/VuFind/src/VuFind/Controller/Plugin/ResultScroller.php
+++ b/module/VuFind/src/VuFind/Controller/Plugin/ResultScroller.php
@@ -333,7 +333,9 @@ class ResultScroller extends AbstractPlugin
             $row = $searchTable->getRowById($this->data->searchId, false);
             if (!empty($row)) {
                 $minSO = unserialize($row->search_object);
-                $search = $minSO->deminify();
+                $search = $minSO->deminify(
+                    $this->getController()->getServiceLocator()->get('SearchManager')
+                );
                 // The saved search does not remember its original limit;
                 // we should reapply it from the session data:
                 $search->getParams()->setLimit($this->data->limit);
diff --git a/module/VuFind/src/VuFind/Controller/SearchController.php b/module/VuFind/src/VuFind/Controller/SearchController.php
index 2b64abfbfe34502b70a86f5e4babbe7f885bdcd2..2dea03953a3b6b9fd8e5a4d162e825051005ae4a 100644
--- a/module/VuFind/src/VuFind/Controller/SearchController.php
+++ b/module/VuFind/src/VuFind/Controller/SearchController.php
@@ -30,9 +30,7 @@ namespace VuFind\Controller;
 use VuFind\Cache\Manager as CacheManager, VuFind\Config\Reader as ConfigReader,
     VuFind\Connection\Manager as ConnectionManager,
     VuFind\Db\Table\Search as SearchTable, VuFind\Exception\Mail as MailException,
-    VuFind\Mailer,
-    VuFind\Search\Memory, VuFind\Search\Solr\Params, VuFind\Search\Solr\Results,
-    VuFind\Solr\Utils as SolrUtils;
+    VuFind\Mailer, VuFind\Search\Memory, VuFind\Solr\Utils as SolrUtils;
 
 /**
  * Redirects the user to the appropriate default VuFind action.
@@ -251,7 +249,7 @@ class SearchController extends AbstractSearch
 
             // Saved searches
             if ($current->saved == 1) {
-                $saved[] = $minSO->deminify();
+                $saved[] = $minSO->deminify($this->getSearchManager());
             } else {
                 // All the others...
 
@@ -263,7 +261,7 @@ class SearchController extends AbstractSearch
                     Memory::forgetSearch();
                 } else {
                     // Otherwise add to the list
-                    $unsaved[] = $minSO->deminify();
+                    $unsaved[] = $minSO->deminify($this->getSearchManager());
                 }
             }
         }
@@ -345,7 +343,8 @@ class SearchController extends AbstractSearch
             $resultPages = 10;
         }
         $catalog = ConnectionManager::connectToCatalog();
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $perPage = $params->getLimit();
         $newItems = $catalog->getNewItems(1, $perPage * $resultPages, $range, $dept);
 
@@ -432,9 +431,10 @@ class SearchController extends AbstractSearch
      */
     public function reservessearchAction()
     {
-        $params = new \VuFind\Search\SolrReserves\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('SolrReserves');
+        $params = $sm->getParams();
         $params->initFromRequest($this->getRequest()->getQuery());
-        $results = new \VuFind\Search\SolrReserves\Results($params);
+        $results = $sm->getResults($params);
         return $this->createViewModel(array('results' => $results));
     }
 
@@ -458,7 +458,8 @@ class SearchController extends AbstractSearch
         $bibIDs = array_unique(array_map($callback, $result));
 
         // Truncate the list if it is too long:
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $limit = $params->getQueryIDLimit();
         if (count($bibIDs) > $limit) {
             $bibIDs = array_slice($bibIDs, 0, $limit);
@@ -504,17 +505,25 @@ class SearchController extends AbstractSearch
             // we may want to make this more flexible later.  Also keep in mind that
             // the template is currently looking for certain hard-coded fields; this
             // should also be made smarter.
-            $params = new Params();
+            $sm = $this->getSearchManager()->setSearchClassId('Solr');
+            $params = $sm->getParams();
             $params->initAdvancedFacets();
 
             // We only care about facet lists, so don't get any results (this helps
             // prevent problems with serialized File_MARC objects in the cache):
             $params->setLimit(0);
 
-            $results = new Results($params);
+            $results = $sm->getResults($params);
             $results->getResults();                     // force processing for cache
+
+            // Temporarily remove the service manager so we can cache the
+            // results (otherwise we'll get errors about serializing closures):
+            $results->unsetServiceLocator();
             $cache->setItem('solrSearchHomeFacets', $results);
         }
+
+        // Restore the real service locator to the object:
+        $results->restoreServiceLocator($this->getServiceLocator());
         return $results;
     }
 
@@ -560,7 +569,7 @@ class SearchController extends AbstractSearch
         // Get suggestions and make sure they are an array (we don't want to JSON
         // encode them into an object):
         $autocompleteManager = $this->getServiceLocator()
-            ->get('AutocompleteHandlerManager');
+            ->get('AutocompletePluginManager');
         $suggestions = $autocompleteManager->getSuggestions(
             $query, 'type', 'lookfor'
         );
diff --git a/module/VuFind/src/VuFind/Db/Table/Search.php b/module/VuFind/src/VuFind/Db/Table/Search.php
index 63a11b27b82350d9da5233f6b6990884261612ae..c32959d91eabd9c70f63936dbd5a39b9618339dc 100644
--- a/module/VuFind/src/VuFind/Db/Table/Search.php
+++ b/module/VuFind/src/VuFind/Db/Table/Search.php
@@ -140,6 +140,7 @@ class Search extends Gateway
     /**
      * Add a search into the search table (history)
      *
+     * @param \VuFind\Search\Manager      $manager       Search manager
      * @param \VuFind\Search\Base\Results $newSearch     Search to save
      * @param string                      $sessionId     Current session ID
      * @param array                       $searchHistory Existing saved searches (for
@@ -147,8 +148,9 @@ class Search extends Gateway
      *
      * @return void
      */
-    public function saveSearch($newSearch, $sessionId, $searchHistory = array())
-    {
+    public function saveSearch($manager, $newSearch, $sessionId,
+        $searchHistory = array()
+    ) {
         // Duplicate elimination
         $dupSaved  = false;
         foreach ($searchHistory as $oldSearch) {
@@ -160,7 +162,7 @@ class Search extends Gateway
                 ? stream_get_contents($oldSearch->search_object)
                 : $oldSearch->search_object
             );
-            $dupSearch = $minSO->deminify();
+            $dupSearch = $minSO->deminify($manager);
             // See if the classes and urls match
             $oldUrl = $dupSearch->getUrlQuery()->getParams();
             $newUrl = $newSearch->getUrlQuery()->getParams();
diff --git a/module/VuFind/src/VuFind/ILS/Connection.php b/module/VuFind/src/VuFind/ILS/Connection.php
index adec157af0f6e7c943a9cc3cc69ad55fffb77513..0ffca7c867ba415281ffbcded37c05efdc2e983d 100644
--- a/module/VuFind/src/VuFind/ILS/Connection.php
+++ b/module/VuFind/src/VuFind/ILS/Connection.php
@@ -30,7 +30,9 @@
  * @link     http://vufind.org/wiki/building_an_ils_driver Wiki
  */
 namespace VuFind\ILS;
-use VuFind\Config\Reader as ConfigReader, VuFind\Exception\ILS as ILSException;
+use VuFind\Config\Reader as ConfigReader, VuFind\Exception\ILS as ILSException,
+    Zend\ServiceManager\ServiceLocatorAwareInterface,
+    Zend\ServiceManager\ServiceLocatorInterface;
 
 /**
  * Catalog Connection Class
@@ -48,52 +50,78 @@ use VuFind\Config\Reader as ConfigReader, VuFind\Exception\ILS as ILSException;
 class Connection
 {
     /**
-     * The class of the appropriate driver.
+     * Has the driver been initialized yet?
      *
-     * @var string
+     * @var bool
      */
-    protected $driverClass;
+    protected $driverInitialized = false;
 
     /**
      * The object of the appropriate driver.
      *
      * @var object
      */
-    protected $driver = false;
+    protected $driver;
 
     /**
-     * Constructor
+     * The service locator
      *
-     * @throws ILSException
+     * @var ServiceLocatorInterface
+     */
+    protected $serviceLocator;
+
+    /**
+     * ILS configuration
+     *
+     * @var \Zend\Config\Config
      */
-    public function __construct()
+    protected $config;
+
+    /**
+     * Set the configuration of the connection.
+     *
+     * @param \Zend\Config\Config $config Configuration representing the [Catalog]
+     * section of config.ini
+     *
+     * @return void
+     */
+    public function setConfig($config)
     {
-        $config = ConfigReader::getConfig();
-        if (!isset($config->Catalog->driver)) {
+        $this->config = $config;
+
+        if (!isset($config->driver)) {
             throw new ILSException('ILS driver setting missing.');
         }
-        $class = 'VuFind\ILS\Driver\\' . $config->Catalog->driver;
-        if (!class_exists($class)) {
+        $driverManager = $this->getServiceLocator()->get('ILSDriverPluginManager');
+        $service = $config->driver;
+        if (!$driverManager->has($service)) {
             // Don't throw ILSException here -- we don't want this to be
             // treated as a login problem; it's more serious than that!
-            throw new \Exception('ILS driver missing: ' . $class);
+            throw new \Exception('ILS driver missing: ' . $service);
         }
-        $this->driverClass = $class;
+        $this->driver = $driverManager->get($service);
 
         // If we're configured to fail over to the NoILS driver, we need
         // to test if the main driver is working.
-        if (isset($config->Catalog->loadNoILSOnFailure)
-            && $config->Catalog->loadNoILSOnFailure
-        ) {
+        if (isset($config->loadNoILSOnFailure) && $config->loadNoILSOnFailure) {
             try {
                 $this->getDriver();
             } catch (\Exception $e) {
-                $this->driver = false;
-                $this->driverClass = 'VuFind\ILS\Driver\NoILS';
+                $this->driver = $driverManager->get('NoILS');
             }
         }
     }
 
+    /**
+     * Get class name of the driver object.
+     *
+     * @return string
+     */
+    public function getDriverClass()
+    {
+        return get_class($this->driver);
+    }
+
     /**
      * Get access to the driver object.
      *
@@ -102,10 +130,10 @@ class Connection
      */
     public function getDriver()
     {
-        if (!$this->driver) {
-            $this->driver = new $this->driverClass;
+        if (!$this->driverInitialized) {
             $this->driver->setConfig($this->getDriverConfig());
             $this->driver->init();
+            $this->driverInitialized = true;
         }
         return $this->driver;
     }
@@ -120,7 +148,7 @@ class Connection
     public function getDriverConfig()
     {
         // Determine config file name based on class name:
-        $parts = explode('\\', $this->driverClass);
+        $parts = explode('\\', $this->getDriverClass());
         $configFile = end($parts) . '.ini';
         $configFilePath = ConfigReader::getConfigPath($configFile);
         return file_exists($configFilePath)
@@ -141,7 +169,7 @@ class Connection
     public function checkFunction($function)
     {
         // Extract the configuration from the driver if available:
-        $functionConfig = method_exists($this->driverClass, 'getConfig')
+        $functionConfig = method_exists($this->getDriverClass(), 'getConfig')
             ? $this->getDriver()->getConfig($function) : false;
 
         // See if we have a corresponding check method to analyze the response:
@@ -170,7 +198,7 @@ class Connection
         $response = false;
 
         if ($this->getHoldsMode() != "none"
-            && method_exists($this->driverClass, 'placeHold')
+            && method_exists($this->getDriverClass(), 'placeHold')
             && isset($functionConfig['HMACKeys'])
         ) {
             $response = array('function' => "placeHold");
@@ -182,7 +210,7 @@ class Connection
             if (isset($functionConfig['extraHoldFields'])) {
                 $response['extraHoldFields'] = $functionConfig['extraHoldFields'];
             }
-        } else if (method_exists($this->driverClass, 'getHoldLink')) {
+        } else if (method_exists($this->getDriverClass(), 'getHoldLink')) {
             $response = array('function' => "getHoldLink");
         }
         return $response;
@@ -203,14 +231,13 @@ class Connection
     protected function checkMethodcancelHolds($functionConfig)
     {
         $response = false;
-        $config = ConfigReader::getConfig();
 
-        if ($config->Catalog->cancel_holds_enabled == true
-            && method_exists($this->driverClass, 'cancelHolds')
+        if ($this->config->cancel_holds_enabled == true
+            && method_exists($this->getDriverClass(), 'cancelHolds')
         ) {
             $response = array('function' => "cancelHolds");
-        } else if ($config->Catalog->cancel_holds_enabled == true
-            && method_exists($this->driverClass, 'getCancelHoldLink')
+        } else if ($this->config->cancel_holds_enabled == true
+            && method_exists($this->getDriverClass(), 'getCancelHoldLink')
         ) {
             $response = array('function' => "getCancelHoldLink");
         }
@@ -231,14 +258,13 @@ class Connection
     protected function checkMethodRenewals($functionConfig)
     {
         $response = false;
-        $config = ConfigReader::getConfig();
 
-        if ($config->Catalog->renewals_enabled == true
-            && method_exists($this->driverClass, 'renewMyItems')
+        if ($this->config->renewals_enabled == true
+            && method_exists($this->getDriverClass(), 'renewMyItems')
         ) {
             $response = array('function' => "renewMyItems");
-        } else if ($config->Catalog->renewals_enabled == true
-            && method_exists($this->driverClass, 'renewMyItemsLink')
+        } else if ($this->config->renewals_enabled == true
+            && method_exists($this->getDriverClass(), 'renewMyItemsLink')
         ) {
             $response = array('function' => "renewMyItemsLink");
         }
@@ -259,7 +285,7 @@ class Connection
      */
     public function checkRequestIsValid($id, $data, $patron)
     {
-        $method = array($this->driverClass, 'checkRequestIsValid');
+        $method = array($this->getDriverClass(), 'checkRequestIsValid');
         if (is_callable($method)) {
             return $this->getDriver()->checkRequestIsValid($id, $data, $patron);
         }
@@ -294,8 +320,8 @@ class Connection
     public function getOfflineMode()
     {
         // Graceful degradation -- return false if no method supported.
-        return method_exists($this->driverClass, 'getOfflineMode') ?
-            $this->getDriver()->getOfflineMode() : false;
+        return method_exists($this->getDriverClass(), 'getOfflineMode')
+            ? $this->getDriver()->getOfflineMode() : false;
     }
 
     /**
@@ -324,8 +350,8 @@ class Connection
     public function hasHoldings($id)
     {
         // Graceful degradation -- return true if no method supported.
-        return method_exists($this->driverClass, 'hasHoldings') ?
-            $this->getDriver()->hasHoldings($id) : true;
+        return method_exists($this->getDriverClass(), 'hasHoldings')
+            ? $this->getDriver()->hasHoldings($id) : true;
     }
 
     /**
@@ -338,8 +364,8 @@ class Connection
     public function loginIsHidden()
     {
         // Graceful degradation -- return false if no method supported.
-        return method_exists($this->driverClass, 'loginIsHidden') ?
-            $this->getDriver()->loginIsHidden() : false;
+        return method_exists($this->getDriverClass(), 'loginIsHidden')
+            ? $this->getDriver()->loginIsHidden() : false;
     }
 
     /**
@@ -354,11 +380,34 @@ class Connection
      */
     public function __call($methodName, $params)
     {
-        if (is_callable(array($this->driverClass, $methodName))) {
+        if (is_callable(array($this->getDriverClass(), $methodName))) {
             return call_user_func_array(
                 array($this->getDriver(), $methodName), $params
             );
         }
         throw new ILSException('Cannot call method: ' . $methodName);
     }
+
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return Connection
+     */
+    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->serviceLocator = $serviceLocator;
+        return $this;
+    }
+
+    /**
+     * Get the service locator.
+     *
+     * @return \Zend\ServiceManager\ServiceLocatorInterface
+     */
+    public function getServiceLocator()
+    {
+        return $this->serviceLocator;
+    }
 }
diff --git a/module/VuFind/src/VuFind/ILS/Driver/PluginFactory.php b/module/VuFind/src/VuFind/ILS/Driver/PluginFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..a92408cda50fa63d6ca8f84ab4ace266c3d10819
--- /dev/null
+++ b/module/VuFind/src/VuFind/ILS/Driver/PluginFactory.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * ILS driver 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  ILS_Drivers
+ * @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\ILS\Driver;
+
+/**
+ * ILS driver plugin factory
+ *
+ * @category VuFind2
+ * @package  ILS_Drivers
+ * @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\ILS\Driver';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/ILS/Driver/PluginManager.php b/module/VuFind/src/VuFind/ILS/Driver/PluginManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac27f6cb1628f200910b8a5b4be892d9ff58044e
--- /dev/null
+++ b/module/VuFind/src/VuFind/ILS/Driver/PluginManager.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * ILS driver 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  ILS_Drivers
+ * @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\ILS\Driver;
+
+/**
+ * ILS driver plugin manager
+ *
+ * @category VuFind2
+ * @package  ILS_Drivers
+ * @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
+{
+    /**
+     * Return the name of the base class or interface that plug-ins must conform
+     * to.
+     *
+     * @return string
+     */
+    protected function getExpectedInterface()
+    {
+        return 'VuFind\ILS\Driver\DriverInterface';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/OAI/Server.php b/module/VuFind/src/VuFind/OAI/Server.php
index 917761621f54a8a2253632a5bc9783aaa189d161..200ecc4d3ce098ebf978edcc40349589e918d29b 100644
--- a/module/VuFind/src/VuFind/OAI/Server.php
+++ b/module/VuFind/src/VuFind/OAI/Server.php
@@ -63,14 +63,20 @@ class Server
     protected $earliestDatestamp = '2000-01-01T00:00:00Z';
     protected $adminEmail;
 
+    // Search manager:
+    protected $searchManager;
+
     /**
      * Constructor
      *
-     * @param string $baseURL The base URL for the OAI server
-     * @param array  $params  The incoming OAI-PMH parameters (i.e. $_GET)
+     * @param \VuFind\Search\Manager $sm      Search manager for retrieving records
+     * @param string                 $baseURL The base URL for the OAI server
+     * @param array                  $params  The incoming OAI-PMH parameters
+     * (i.e. $_GET)
      */
-    public function __construct($baseURL, $params)
+    public function __construct(\VuFind\Search\Manager $sm, $baseURL, $params)
     {
+        $this->searchManager = $sm;
         $this->baseURL = $baseURL;
         $this->params = isset($params) && is_array($params) ? $params : array();
         $this->initializeMetadataFormats(); // Load details on supported formats
@@ -501,10 +507,9 @@ class Server
         // we'll assume that this list is short enough to load in a single response;
         // it may be necessary to implement a resumption token mechanism if this
         // proves not to be the case:
-        $paramsClass = 'VuFind\Search\\' . $this->searchClassId . '\Params';
-        $params = new $paramsClass();
-        $resultsClass = 'VuFind\Search\\' . $this->searchClassId . '\Results';
-        $results = new $resultsClass($params);
+        $this->searchManager->setSearchClassId($this->searchClassId);
+        $params = $this->searchManager->getParams();
+        $results = $this->searchManager->getResults($params);
         try {
             $facets = $results->getFullFieldFacets(array($this->setField));
         } catch (\Exception $e) {
@@ -557,8 +562,8 @@ class Server
         $set = ''
     ) {
         // Set up search parameters:
-        $paramsClass = 'VuFind\Search\\' . $this->searchClassId . '\Params';
-        $params = new $paramsClass();
+        $this->searchManager->setSearchClassId($this->searchClassId);
+        $params = $this->searchManager->getParams();
         $params->setLimit($limit);
         $params->getOptions()->disableHighlighting();
         $params->getOptions()->spellcheckEnabled(false);
@@ -579,8 +584,7 @@ class Server
         }
 
         // Perform a Solr search:
-        $resultsClass = 'VuFind\Search\\' . $this->searchClassId . '\Results';
-        $results = new $resultsClass($params);
+        $results = $this->searchManager->getResults($params);
         $results->overrideStartRecord($offset + 1);
 
         // Return our results:
diff --git a/module/VuFind/src/VuFind/OAI/Server/Auth.php b/module/VuFind/src/VuFind/OAI/Server/Auth.php
index cfb8945086d195df78d0c5c5390db4ee3486ec75..8f66da1e6516c6509a20b8ea032edf9108cf1483 100644
--- a/module/VuFind/src/VuFind/OAI/Server/Auth.php
+++ b/module/VuFind/src/VuFind/OAI/Server/Auth.php
@@ -44,12 +44,14 @@ class Auth extends Base
     /**
      * Constructor
      *
-     * @param string $baseURL The base URL for the OAI server
-     * @param array  $params  The incoming OAI-PMH parameters (i.e. $_GET)
+     * @param \VuFind\Search\Manager $sm      Search manager for retrieving records
+     * @param string                 $baseURL The base URL for the OAI server
+     * @param array                  $params  The incoming OAI-PMH parameters
+     * (i.e. $_GET)
      */
-    public function __construct($baseURL, $params)
+    public function __construct(\VuFind\Search\Manager $sm, $baseURL, $params)
     {
-        parent::__construct($baseURL, $params);
+        parent::__construct($sm, $baseURL, $params);
         $this->core = 'authority';
         $this->searchClassId = 'SolrAuth';
     }
diff --git a/module/VuFind/src/VuFind/Recommend/AbstractSearchManagerAwareModule.php b/module/VuFind/src/VuFind/Recommend/AbstractSearchManagerAwareModule.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3fafcc478907be2693c3d132074c4fcdd53d533
--- /dev/null
+++ b/module/VuFind/src/VuFind/Recommend/AbstractSearchManagerAwareModule.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Abstract base class for accessing the search manager for recommendation purposes.
+ *
+ * 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  Recommendations
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Chris Hallberg <challber@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\Recommend;
+use Zend\ServiceManager\ServiceLocatorInterface,
+    Zend\ServiceManager\ServiceLocatorAwareInterface;
+
+/**
+ * Abstract base class for accessing the search manager for recommendation purposes.
+ *
+ * @category VuFind2
+ * @package  Recommendations
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @author   Chris Hallberg <challber@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
+ */
+abstract class AbstractSearchManagerAwareModule implements RecommendInterface,
+    ServiceLocatorAwareInterface
+{
+    protected $serviceLocator;
+
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return AbstractSearchManagerAwareModule
+     */
+    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->serviceLocator = $serviceLocator;
+        return $this;
+    }
+
+    /**
+     * Get the service locator.
+     *
+     * @return \Zend\ServiceManager\ServiceLocatorInterface
+     */
+    public function getServiceLocator()
+    {
+        return $this->serviceLocator;
+    }
+
+    /**
+     * Get the search manager.
+     *
+     * @return \VuFind\Search\Manager
+     */
+    public function getSearchManager()
+    {
+        return $this->getServiceLocator()->getServiceLocator()->get('SearchManager');
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Recommend/AuthorFacets.php b/module/VuFind/src/VuFind/Recommend/AuthorFacets.php
index 3233bce2b5676abb0079d3b03bdddc845c7ac4e8..a06a3bd588e9d19f7592d14427338f82948071f9 100644
--- a/module/VuFind/src/VuFind/Recommend/AuthorFacets.php
+++ b/module/VuFind/src/VuFind/Recommend/AuthorFacets.php
@@ -27,10 +27,7 @@
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
 namespace VuFind\Recommend;
-use VuFind\Search\SolrAuthorFacets\Options as SolrAuthorFacetsOptions,
-    VuFind\Search\SolrAuthorFacets\Params as SolrAuthorFacetsParams,
-    VuFind\Search\SolrAuthorFacets\Results as SolrAuthorFacetsResults,
-    Zend\Http\Request, Zend\StdLib\Parameters;
+use Zend\Http\Request, Zend\StdLib\Parameters;
 
 /**
  * AuthorFacets Recommendations Module
@@ -45,19 +42,21 @@ use VuFind\Search\SolrAuthorFacets\Options as SolrAuthorFacetsOptions,
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
-class AuthorFacets implements RecommendInterface
+class AuthorFacets extends AbstractSearchManagerAwareModule
 {
     protected $settings;
     protected $searchObject;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Save the basic parameters:
         $this->settings = $settings;
@@ -98,6 +97,16 @@ class AuthorFacets implements RecommendInterface
         $this->results = $results;
     }
 
+    /**
+     * Get results stored in the object.
+     *
+     * @return \VuFind\Search\Base\Results
+     */
+    public function getResults()
+    {
+        return $this->results;
+    }
+
     /**
      * Returns search term.
      *
@@ -126,16 +135,17 @@ class AuthorFacets implements RecommendInterface
         }
 
         // Set up a special limit for the AuthorFacets search object:
-        $options = new SolrAuthorFacetsOptions();
+        $sm = $this->getSearchManager()->setSearchClassId('SolrAuthorFacets');
+        $options = $sm->getOptionsInstance();
         $options->setLimitOptions(array(10));
 
         // Initialize an AuthorFacets search object using parameters from the
         // current Solr search object.
-        $params = new SolrAuthorFacetsParams($options);
+        $params = $sm->getParams($options);
         $params->initFromRequest(new Parameters(array('lookfor' => $lookfor)));
 
         // Send back the results:
-        $results = new SolrAuthorFacetsResults($params);
+        $results = $sm->getResults($params);
         return array(
             // Total authors (currently there is no way to calculate this without
             // risking out-of-memory errors or slow results, so we set this to
diff --git a/module/VuFind/src/VuFind/Recommend/AuthorInfo.php b/module/VuFind/src/VuFind/Recommend/AuthorInfo.php
index bc54993900c1e6005fb160f05d6cd1e3809554e1..8f9d68f3aaef25d75f6799efdf15abd23e0e01b2 100644
--- a/module/VuFind/src/VuFind/Recommend/AuthorInfo.php
+++ b/module/VuFind/src/VuFind/Recommend/AuthorInfo.php
@@ -48,13 +48,15 @@ class AuthorInfo implements RecommendInterface
     protected $lang;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $translator = Translator::getTranslator();
         $this->lang = is_object($translator) ? $translator->getLocale() : 'en';
diff --git a/module/VuFind/src/VuFind/Recommend/AuthorityRecommend.php b/module/VuFind/src/VuFind/Recommend/AuthorityRecommend.php
index ab8fdd2e94c214c5b7be25e92aad3320a43640fe..cbfe4aa57c95e3c889fd998bb29aaef5243e4930 100644
--- a/module/VuFind/src/VuFind/Recommend/AuthorityRecommend.php
+++ b/module/VuFind/src/VuFind/Recommend/AuthorityRecommend.php
@@ -30,8 +30,6 @@
  */
 namespace VuFind\Recommend;
 use VuFind\Exception\Solr as SolrException,
-    VuFind\Search\SolrAuth\Params as SolrAuthParams,
-    VuFind\Search\SolrAuth\Results as SolrAuthResults,
     Zend\Http\Request, Zend\StdLib\Parameters;
 
 /**
@@ -50,21 +48,24 @@ use VuFind\Exception\Solr as SolrException,
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://www.vufind.org  Main Page
  */
-class AuthorityRecommend implements RecommendInterface
+class AuthorityRecommend extends AbstractSearchManagerAwareModule
 {
     protected $searchObject;
     protected $lookfor;
     protected $filters = array();
-    protected $results = array();
+    protected $results;
+    protected $recommendations = array();
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $params = explode(':', $settings);
         for ($i = 0; $i < count($params); $i += 2) {
@@ -107,6 +108,8 @@ class AuthorityRecommend implements RecommendInterface
      */
     public function process($results)
     {
+        $this->results = $results;
+
         // function will return blank on Advanced Search
         if ($results->getParams()->getSearchType()== 'advanced') {
             return;
@@ -132,12 +135,13 @@ class AuthorityRecommend implements RecommendInterface
         // Initialise and process search (ignore Solr errors -- no reason to fail
         // just because search syntax is not compatible with Authority core):
         try {
-            $authParams = new SolrAuthParams();
+            $sm = $this->getSearchManager()->setSearchClassId('SolrAuth');
+            $authParams = $sm->getParams();
             $authParams->initFromRequest($request);
             foreach ($this->filters as $filter) {
                 $authParams->getOptions()->addHiddenFilter($filter);
             }
-            $authResults = new SolrAuthResults($authParams);
+            $authResults = $sm->getResults($authParams);
             $results = $authResults->getResults();
         } catch (SolrException $e) {
             return;
@@ -153,8 +157,8 @@ class AuthorityRecommend implements RecommendInterface
             );
 
             // check for duplicates before adding record to recordSet
-            if (!$this->inArrayR($recordArray['heading'], $this->results)) {
-                array_push($this->results, $recordArray);
+            if (!$this->inArrayR($recordArray['heading'], $this->recommendations)) {
+                array_push($this->recommendations, $recordArray);
             } else {
                 continue;
             }
@@ -162,10 +166,20 @@ class AuthorityRecommend implements RecommendInterface
     }
 
     /**
-     * Get results (for use in the view).
+     * Get recommendations (for use in the view).
      *
      * @return array
      */
+    public function getRecommendations()
+    {
+        return $this->recommendations;
+    }
+
+    /**
+     * Get results stored in the object.
+     *
+     * @return \VuFind\Search\Base\Results
+     */
     public function getResults()
     {
         return $this->results;
@@ -181,7 +195,7 @@ class AuthorityRecommend implements RecommendInterface
      *
      * @return bool
      */
-    public function inArrayR($needle, $haystack)
+    protected function inArrayR($needle, $haystack)
     {
         foreach ($haystack as $v) {
             if ($needle == $v) {
diff --git a/module/VuFind/src/VuFind/Recommend/EuropeanaResults.php b/module/VuFind/src/VuFind/Recommend/EuropeanaResults.php
index 8e21fe248d8ec6fdd08548e7e83e57433664d0d3..c57d644de799699f85c61dfe664e66dbd88457a5 100644
--- a/module/VuFind/src/VuFind/Recommend/EuropeanaResults.php
+++ b/module/VuFind/src/VuFind/Recommend/EuropeanaResults.php
@@ -55,13 +55,15 @@ class EuropeanaResults implements RecommendInterface
     protected $results;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Parse out parameters:
         $params = explode(':', $settings);
diff --git a/module/VuFind/src/VuFind/Recommend/EuropeanaResultsDeferred.php b/module/VuFind/src/VuFind/Recommend/EuropeanaResultsDeferred.php
index 0691eb35d0ebccc076608dd7834c3b037abf7fb9..e4afb7ccd22ef4ee8eaeaeba4485ba6631a82efb 100644
--- a/module/VuFind/src/VuFind/Recommend/EuropeanaResultsDeferred.php
+++ b/module/VuFind/src/VuFind/Recommend/EuropeanaResultsDeferred.php
@@ -47,13 +47,15 @@ class EuropeanaResultsDeferred implements RecommendInterface
     protected $processedParams;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $this->rawParams = $settings;
     }
diff --git a/module/VuFind/src/VuFind/Recommend/ExpandFacets.php b/module/VuFind/src/VuFind/Recommend/ExpandFacets.php
index 0baa798bb1c1821761d1c28d092ae616cfa6c85b..b529e18d9a960124641293433a245c6f56671c33 100644
--- a/module/VuFind/src/VuFind/Recommend/ExpandFacets.php
+++ b/module/VuFind/src/VuFind/Recommend/ExpandFacets.php
@@ -37,20 +37,22 @@ use VuFind\Config\Reader as ConfigReader;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://www.vufind.org  Main Page
  */
-class ExpandFacets implements RecommendInterface
+class ExpandFacets extends AbstractSearchManagerAwareModule
 {
     protected $facets;
     protected $settings;
     protected $searchObject;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Save the basic parameters:
         $this->settings = $settings;
@@ -120,4 +122,15 @@ class ExpandFacets implements RecommendInterface
     {
         return $this->searchObject->getFacetList($this->facets);
     }
+
+    /**
+     * Get an empty search object (the template uses this as the basis for URL
+     * generation).
+     *
+     * @return \VuFind\Search\Base\Results
+     */
+    public function getEmptyResults()
+    {
+        return $this->getSearchManager()->setSearchClassId('Solr')->getResults();
+    }
 }
diff --git a/module/VuFind/src/VuFind/Recommend/FavoriteFacets.php b/module/VuFind/src/VuFind/Recommend/FavoriteFacets.php
index a05df435463b9fea2eee7e18917e96a4eca70a76..69a050f56dec7655211b059e5d2e3c82ef82a36f 100644
--- a/module/VuFind/src/VuFind/Recommend/FavoriteFacets.php
+++ b/module/VuFind/src/VuFind/Recommend/FavoriteFacets.php
@@ -41,13 +41,15 @@ namespace VuFind\Recommend;
 class FavoriteFacets extends SideFacets
 {
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $this->mainFacets = array('lists' => 'Your Lists', 'tags' => 'Your Tags');
     }
diff --git a/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjects.php b/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjects.php
index 23ffe6e81c7ca1fb7bbfcd81c7dbce8d64faf5f5..02765da8a31e5127f7c5b19b60c89d91b610960e 100644
--- a/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjects.php
+++ b/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjects.php
@@ -53,13 +53,15 @@ class OpenLibrarySubjects implements RecommendInterface
     protected $result = false;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Parse out parameters:
         $params = explode(':', $settings);
diff --git a/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjectsDeferred.php b/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjectsDeferred.php
index a69a8e8b8ae2c215eb17004e4780959890c866c8..bed5ccdb8dc2a413910dff93dee8a8991f4fe31b 100644
--- a/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjectsDeferred.php
+++ b/module/VuFind/src/VuFind/Recommend/OpenLibrarySubjectsDeferred.php
@@ -47,13 +47,15 @@ class OpenLibrarySubjectsDeferred extends OpenLibrarySubjects
     protected $processedParams;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $this->rawParams = $settings;
     }
diff --git a/module/VuFind/src/VuFind/Recommend/PluginFactory.php b/module/VuFind/src/VuFind/Recommend/PluginFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..a6bec132de04509773015f4131fe9bf90ac435d5
--- /dev/null
+++ b/module/VuFind/src/VuFind/Recommend/PluginFactory.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Recommendation module 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  Recommendations
+ * @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\Recommend;
+
+/**
+ * Recommendation module plugin factory
+ *
+ * @category VuFind2
+ * @package  Recommendations
+ * @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\Recommend';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Recommend/PluginManager.php b/module/VuFind/src/VuFind/Recommend/PluginManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..86600015ce7c63fdf919035ab0216ff31755c105
--- /dev/null
+++ b/module/VuFind/src/VuFind/Recommend/PluginManager.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Recommendation module 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  Recommendations
+ * @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\Recommend;
+
+/**
+ * Recommendation module plugin manager
+ *
+ * @category VuFind2
+ * @package  Recommendations
+ * @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
+{
+    /**
+     * Return the name of the base class or interface that plug-ins must conform
+     * to.
+     *
+     * @return string
+     */
+    protected function getExpectedInterface()
+    {
+        return 'VuFind\Recommend\RecommendInterface';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Recommend/PubDateVisAjax.php b/module/VuFind/src/VuFind/Recommend/PubDateVisAjax.php
index c952267799ee64a8dc47afd2051cfdb5bdf919d3..110333c59ee525ac4b9ac7b937bbc4ed4c0d6662 100644
--- a/module/VuFind/src/VuFind/Recommend/PubDateVisAjax.php
+++ b/module/VuFind/src/VuFind/Recommend/PubDateVisAjax.php
@@ -47,13 +47,15 @@ class PubDateVisAjax implements RecommendInterface
     protected $dateFacets = array();
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Save the basic parameters:
         $this->settings = $settings;
diff --git a/module/VuFind/src/VuFind/Recommend/RecommendInterface.php b/module/VuFind/src/VuFind/Recommend/RecommendInterface.php
index 034c6141ed02750f9d743b11f266cbf886e858cb..47a3e59b09e11b8cff28b844340a6da56751c9e8 100644
--- a/module/VuFind/src/VuFind/Recommend/RecommendInterface.php
+++ b/module/VuFind/src/VuFind/Recommend/RecommendInterface.php
@@ -49,13 +49,15 @@ namespace VuFind\Recommend;
 interface RecommendInterface
 {
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings);
+    public function setConfig($settings);
 
     /**
      * init
diff --git a/module/VuFind/src/VuFind/Recommend/ResultGoogleMapAjax.php b/module/VuFind/src/VuFind/Recommend/ResultGoogleMapAjax.php
index ec4879b65f21ed0ed4669431a997500d60ca1c4f..3b27714378e637c2ffadf11f9407d4e346f978e3 100644
--- a/module/VuFind/src/VuFind/Recommend/ResultGoogleMapAjax.php
+++ b/module/VuFind/src/VuFind/Recommend/ResultGoogleMapAjax.php
@@ -47,13 +47,15 @@ class ResultGoogleMapAjax implements RecommendInterface
     protected $searchObject;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // No special settings
     }
diff --git a/module/VuFind/src/VuFind/Recommend/SearchObject.php b/module/VuFind/src/VuFind/Recommend/SearchObject.php
index 8f0409b24886a4b7200a3b5bb17fa207347fff44..7233f1d878a3a56a2ac985bf06e40d51f5440ac3 100644
--- a/module/VuFind/src/VuFind/Recommend/SearchObject.php
+++ b/module/VuFind/src/VuFind/Recommend/SearchObject.php
@@ -38,20 +38,22 @@ namespace VuFind\Recommend;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
-abstract class SearchObject implements RecommendInterface
+abstract class SearchObject extends AbstractSearchManagerAwareModule
 {
     protected $results;
     protected $limit;
     protected $requestParam;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $settings = explode(':', $settings);
         $this->requestParam = empty($settings[0]) ? 'lookfor' : $settings[0];
@@ -77,15 +79,13 @@ abstract class SearchObject implements RecommendInterface
     public function init($params, $request)
     {
         // Build a search parameters object:
-        $id = $this->getSearchClassId();
-        $paramsClass = 'VuFind\Search\\' . $id . '\Params';
-        $params = new $paramsClass();
+        $sm = $this->getSearchManager()->setSearchClassId($this->getSearchClassId());
+        $params = $sm->getParams();
         $params->setLimit($this->limit);
         $params->setBasicSearch($request->get($this->requestParam));
 
         // Perform the search:
-        $resultsClass = 'VuFind\Search\\' . $id . '\Results';
-        $this->results = new $resultsClass($params);
+        $this->results = $sm->getResults($params);
         $this->results->performAndProcessSearch();
     }
 
diff --git a/module/VuFind/src/VuFind/Recommend/SideFacets.php b/module/VuFind/src/VuFind/Recommend/SideFacets.php
index 1ed92c9afc807d4ca7b2c4d9915f848495e40fd2..20e3c29d9171da58da98d1987cbcc8216f48d6c8 100644
--- a/module/VuFind/src/VuFind/Recommend/SideFacets.php
+++ b/module/VuFind/src/VuFind/Recommend/SideFacets.php
@@ -47,13 +47,15 @@ class SideFacets implements RecommendInterface
     protected $results;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Parse the additional settings:
         $settings = explode(':', $settings);
@@ -159,4 +161,14 @@ class SideFacets implements RecommendInterface
         }
         return $result;
     }
+
+    /**
+     * Get results stored in the object.
+     *
+     * @return \VuFind\Search\Base\Results
+     */
+    public function getResults()
+    {
+        return $this->results;
+    }
 }
diff --git a/module/VuFind/src/VuFind/Recommend/SummonDatabases.php b/module/VuFind/src/VuFind/Recommend/SummonDatabases.php
index b5fabcfcc0638fedcad9df2e31e390c96df3bfb4..2fb03d579ebe5993acb2576f707e8ff1ce7f58ab 100644
--- a/module/VuFind/src/VuFind/Recommend/SummonDatabases.php
+++ b/module/VuFind/src/VuFind/Recommend/SummonDatabases.php
@@ -26,8 +26,6 @@
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
 namespace VuFind\Recommend;
-use VuFind\Search\Summon\Params as SummonParams,
-    VuFind\Search\Summon\Results as SummonResults;
 
 /**
  * SummonDatabases Recommendations Module
@@ -40,24 +38,26 @@ use VuFind\Search\Summon\Params as SummonParams,
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
-class SummonDatabases implements RecommendInterface
+class SummonDatabases extends AbstractSearchManagerAwareModule
 {
     protected $databases;
-    protected $requestParam;
+    protected $requestParam = 'lookfor';
     protected $lookfor;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Only one setting -- HTTP request field containing search terms (ignored
         // if $searchObject is Summon type).
-        $this->requestParam = empty($settings) ? 'lookfor' : $settings;
+        $this->requestParam = empty($settings) ? $this->requestParam : $settings;
     }
 
     /**
@@ -97,9 +97,10 @@ class SummonDatabases implements RecommendInterface
         // to create a new Summon search object using the specified request 
         // parameter for search terms.
         if ($results->getParams()->getSearchClassId() != 'Summon') {
-            $params = new SummonParams();
+            $sm = $this->getSearchManager()->setSearchClassId('Summon');
+            $params = $sm->getParams();
             $params->setBasicSearch($this->lookfor);
-            $results = new SummonResults($params);
+            $results = $sm->getResults($params);
             $results->performAndProcessSearch();
         }
         $this->databases = $results->getDatabaseRecommendations();
diff --git a/module/VuFind/src/VuFind/Recommend/SwitchType.php b/module/VuFind/src/VuFind/Recommend/SwitchType.php
index 4753020aeb65f200654ad3d6c06bb5178dba9eeb..1ff9cc97b45370b67a135802b723f3b120f951f8 100644
--- a/module/VuFind/src/VuFind/Recommend/SwitchType.php
+++ b/module/VuFind/src/VuFind/Recommend/SwitchType.php
@@ -45,19 +45,18 @@ class SwitchType implements RecommendInterface
     protected $newHandler;      // search handler to try
     protected $newHandlerName;  // on-screen description of handler
     protected $active;          // is this module active?
+    protected $results;         // results object
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
      *
-     * TopFacets:[ini section]:[ini name]
-     *      Display facets listed in the specified section of the specified ini file;
-     *      if [ini name] is left out, it defaults to "facets."
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $params = explode(':', $settings);
         $this->newHandler = !empty($params[0]) ? $params[0] : 'AllFields';
@@ -96,6 +95,7 @@ class SwitchType implements RecommendInterface
     public function process($results)
     {
         $handler = $results->getParams()->getSearchHandler();
+        $this->results = $results;
 
         // If the handler is null, we can't figure out a single handler, so this
         // is probably an advanced search.  In that case, we shouldn't try to change
@@ -105,6 +105,16 @@ class SwitchType implements RecommendInterface
         $this->active = (!is_null($handler) && $handler != $this->newHandler);
     }
 
+    /**
+     * Get results stored in the object.
+     *
+     * @return \VuFind\Search\Base\Results
+     */
+    public function getResults()
+    {
+        return $this->results;
+    }
+
     /**
      * Get the new search handler, or false if it does not apply.
      *
diff --git a/module/VuFind/src/VuFind/Recommend/TopFacets.php b/module/VuFind/src/VuFind/Recommend/TopFacets.php
index 9306a7dd770ef70f22fce4f1ec31887db789d4fb..1570e76d2ad586785d343ff69b72cdd6d8ec7ef3 100644
--- a/module/VuFind/src/VuFind/Recommend/TopFacets.php
+++ b/module/VuFind/src/VuFind/Recommend/TopFacets.php
@@ -48,17 +48,19 @@ class TopFacets implements RecommendInterface
     protected $results;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
-     *
-     * @param string $settings Settings from searches.ini.
+     * Store the configuration of the recommendation module.
      *
      * TopFacets:[ini section]:[ini name]
      *      Display facets listed in the specified section of the specified ini file;
      *      if [ini name] is left out, it defaults to "facets."
+     *
+     * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         $settings = explode(':', $settings);
         $mainSection = empty($settings[0]) ? 'ResultsTop':$settings[0];
@@ -114,6 +116,16 @@ class TopFacets implements RecommendInterface
         $this->results = $results;
     }
 
+    /**
+     * Get results stored in the object.
+     *
+     * @return \VuFind\Search\Base\Results
+     */
+    public function getResults()
+    {
+        return $this->results;
+    }
+
     /**
      * Get facet information taken from the search.
      *
diff --git a/module/VuFind/src/VuFind/Recommend/WorldCatIdentities.php b/module/VuFind/src/VuFind/Recommend/WorldCatIdentities.php
index 7f80a48cc5f1f4e62c3d9aaca9b23dc472e73c1f..13d386302761f18e3dce4df55319f6b5d19f6470 100644
--- a/module/VuFind/src/VuFind/Recommend/WorldCatIdentities.php
+++ b/module/VuFind/src/VuFind/Recommend/WorldCatIdentities.php
@@ -45,13 +45,15 @@ class WorldCatIdentities implements RecommendInterface
     protected $settings;
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Save the basic parameters:
         $this->settings = $settings;
diff --git a/module/VuFind/src/VuFind/Recommend/WorldCatTerms.php b/module/VuFind/src/VuFind/Recommend/WorldCatTerms.php
index 9c8884d4a80a0a96ccec65c9808f2d6f42ce08e6..58bc4c3844ef614734ce15499d9bab052bd0e961 100644
--- a/module/VuFind/src/VuFind/Recommend/WorldCatTerms.php
+++ b/module/VuFind/src/VuFind/Recommend/WorldCatTerms.php
@@ -42,16 +42,18 @@ use VuFind\Connection\WorldCatUtils;
 class WorldCatTerms implements RecommendInterface
 {
     protected $searchObject;
-    protected $vocab;
+    protected $vocab = 'lcsh';
 
     /**
-     * Constructor
+     * setConfig
      *
-     * Establishes base settings for making recommendations.
+     * Store the configuration of the recommendation module.
      *
      * @param string $settings Settings from searches.ini.
+     *
+     * @return void
      */
-    public function __construct($settings)
+    public function setConfig($settings)
     {
         // Pick a vocabulary (either user-specified, or LCSH by default):
         $params = trim($settings);
diff --git a/module/VuFind/src/VuFind/RecordDriver/AbstractBase.php b/module/VuFind/src/VuFind/RecordDriver/AbstractBase.php
index dd2fb868415e14977422f4ed47fa2974fcb67a08..dbbdec8092a26485692bdc40bbb565cb05121ee7 100644
--- a/module/VuFind/src/VuFind/RecordDriver/AbstractBase.php
+++ b/module/VuFind/src/VuFind/RecordDriver/AbstractBase.php
@@ -181,7 +181,7 @@ abstract class AbstractBase
         $user->saveResource(
             $resource, $list,
             isset($params['mytags'])
-                ? Tags::parse(trim($params['mytags'])) : array(),
+            ? Tags::parse(trim($params['mytags'])) : array(),
             isset($params['notes']) ? $params['notes'] : ''
         );
     }
diff --git a/module/VuFind/src/VuFind/Search/Base/Params.php b/module/VuFind/src/VuFind/Search/Base/Params.php
index 948915f4e3f55661a5a94be93315c1476a17091c..a9558886bb364faedc86680301b96e904b200c08 100644
--- a/module/VuFind/src/VuFind/Search/Base/Params.php
+++ b/module/VuFind/src/VuFind/Search/Base/Params.php
@@ -27,7 +27,9 @@
  */
 namespace VuFind\Search\Base;
 use VuFind\Config\Reader as ConfigReader, VuFind\Search\Options as SearchOptions,
-    VuFind\Translator\Translator;
+    VuFind\Translator\Translator,
+    Zend\ServiceManager\ServiceLocatorAwareInterface,
+    Zend\ServiceManager\ServiceLocatorInterface;
 
 /**
  * Abstract parameters search model.
@@ -40,7 +42,7 @@ use VuFind\Config\Reader as ConfigReader, VuFind\Search\Options as SearchOptions
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://www.vufind.org  Main Page
  */
-class Params
+class Params implements ServiceLocatorAwareInterface
 {
     // Search terms
     protected $searchTerms = array();
@@ -65,6 +67,8 @@ class Params
     protected $facetConfig = array();
     protected $checkboxFacets = array();
     protected $filterList = array();
+    // Service locator
+    protected $serviceLocator;
 
     /**
      * Constructor
@@ -89,6 +93,11 @@ class Params
         // If no options have been set, use defaults:
         if (null === $this->options) {
             // Create a copy of the default configuration:
+            /* TODO: change after Search Manager refactoring
+            $default = $this->getSearchManager()
+                ->setSearchClassId($this->getSearchClassId())->getOptionsInstance();
+            $this->options = clone($default);
+             */
             $this->options = clone(
                 SearchOptions::getInstance($this->getSearchClassId())
             );
@@ -127,6 +136,9 @@ class Params
      */
     public function getSearchClassId()
     {
+        /* TODO: change this when Search Manager refactoring is done:
+        return $this->getSearchManager()->extractSearchClassId(get_class($this));
+         */
         return SearchOptions::extractSearchClassId(get_class($this));
     }
 
@@ -782,6 +794,13 @@ class Params
             return;
         }
 
+        // Get the plugin manager (skip recommendations if it is unavailable):
+        $sm = $this->getServiceLocator();
+        if (!is_object($sm) || !$sm->has('RecommendPluginManager')) {
+            return;
+        }
+        $manager = $sm->get('RecommendPluginManager');
+
         // Process recommendations for each location:
         $this->recommend = array(
             'top' => array(), 'side' => array(), 'noresults' => array()
@@ -801,19 +820,20 @@ class Params
                 // Break apart the setting into module name and extra parameters:
                 $current = explode(':', $current);
                 $module = array_shift($current);
-                $class = 'VuFind\Recommend\\' . $module;
                 $params = implode(':', $current);
-
-                // Build a recommendation module with the provided settings.
-                if (class_exists($class)) {
-                    $obj = new $class($params);
-                    $obj->init($this, $request);
-                    $this->recommend[$location][] = $obj;
-                } else {
+                if (!$manager->has($module)) {
                     throw new \Exception(
-                        'Could not load recommendation module: ' . $class
+                        'Could not load recommendation module: ' . $module
                     );
                 }
+
+                // Build a recommendation module with the provided settings.
+                // Create a clone in case the same module is used repeatedly with
+                // different settings.
+                $obj = clone($manager->get($module));
+                $obj->setConfig($params);
+                $obj->init($this, $request);
+                $this->recommend[$location][] = $obj;
             }
         }
     }
@@ -1484,4 +1504,56 @@ class Params
     {
         return $this->selectedShards;
     }
+
+    /**
+     * Unset the service locator.
+     *
+     * @return Params
+     */
+    public function unsetServiceLocator()
+    {
+        $this->serviceLocator = null;
+        $options = $this->getOptions();
+        if (method_exists($options, 'unsetServiceLocator')) {
+            $params->unsetServiceLocator();
+        }
+        return $this;
+    }
+
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return Params
+     */
+    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->serviceLocator = $serviceLocator;
+        return $this;
+    }
+
+    /**
+     * Get the service locator.
+     *
+     * @return \Zend\ServiceManager\ServiceLocatorInterface
+     */
+    public function getServiceLocator()
+    {
+        return $this->serviceLocator;
+    }
+
+    /**
+     * Pull the search manager from the service locator.
+     *
+     * @return \VuFind\Search\Manager
+     */
+    protected function getSearchManager()
+    {
+        $sl = $this->getServiceLocator();
+        if (!is_object($sl)) {
+            throw new \Exception('Could not find service locator');
+        }
+        return $sl->get('SearchManager');
+    }
 }
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Search/Base/Results.php b/module/VuFind/src/VuFind/Search/Base/Results.php
index 265b23423f9632878485a67c219fdc071b618ab7..2c57073ee562619285429e4b36f8374cabb99b59 100644
--- a/module/VuFind/src/VuFind/Search/Base/Results.php
+++ b/module/VuFind/src/VuFind/Search/Base/Results.php
@@ -26,7 +26,9 @@
  * @link     http://www.vufind.org  Main Page
  */
 namespace VuFind\Search\Base;
-use VuFind\Search\UrlQueryHelper, Zend\Paginator\Paginator;
+use VuFind\Search\UrlQueryHelper, Zend\Paginator\Paginator,
+    Zend\ServiceManager\ServiceLocatorAwareInterface,
+    Zend\ServiceManager\ServiceLocatorInterface;
 
 /**
  * Abstract results search model.
@@ -39,7 +41,7 @@ use VuFind\Search\UrlQueryHelper, Zend\Paginator\Paginator;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://www.vufind.org  Main Page
  */
-abstract class Results
+abstract class Results implements ServiceLocatorAwareInterface
 {
     protected $params;
     // Total number of results available
@@ -60,6 +62,8 @@ abstract class Results
     protected $helpers = array();
     // Spelling
     protected $suggestions = null;
+    // Service locator
+    protected $serviceLocator;
 
     /**
      * Constructor
@@ -515,4 +519,81 @@ abstract class Results
         // pull them from the results object.
         return $this->getParams()->getRecommendations($location);
     }
+
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return Results
+     */
+    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->serviceLocator = $serviceLocator;
+        return $this;
+    }
+
+    /**
+     * Restore the service locator (a cascading version of setServiceLocator()).
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return Results
+     */
+    public function restoreServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->setServiceLocator($serviceLocator);
+        $params = $this->getParams();
+        if (method_exists($params, 'setServiceLocator')) {
+            $params->setServiceLocator($serviceLocator);
+        }
+        $options = $this->getOptions();
+        if (method_exists($options, 'setServiceLocator')) {
+            $params->setServiceLocator($serviceLocator);
+        }
+        return $this;
+    }
+
+    /**
+     * Unset the service locator.
+     *
+     * @return Results
+     */
+    public function unsetServiceLocator()
+    {
+        $this->serviceLocator = null;
+        $params = $this->getParams();
+        if (method_exists($params, 'unsetServiceLocator')) {
+            $params->unsetServiceLocator();
+        }
+        $options = $this->getOptions();
+        if (method_exists($options, 'unsetServiceLocator')) {
+            $params->unsetServiceLocator();
+        }
+        return $this;
+    }
+
+    /**
+     * Get the service locator.
+     *
+     * @return \Zend\ServiceManager\ServiceLocatorInterface
+     */
+    public function getServiceLocator()
+    {
+        return $this->serviceLocator;
+    }
+
+    /**
+     * Pull the search manager from the service locator.
+     *
+     * @return \VuFind\Search\Manager
+     */
+    protected function getSearchManager()
+    {
+        $sl = $this->getServiceLocator();
+        if (!is_object($sl)) {
+            throw new \Exception('Could not find service locator');
+        }
+        return $sl->get('SearchManager');
+    }
 }
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Search/Manager.php b/module/VuFind/src/VuFind/Search/Manager.php
new file mode 100644
index 0000000000000000000000000000000000000000..9bce7153e798c4f0938719e3a7584e078334b87a
--- /dev/null
+++ b/module/VuFind/src/VuFind/Search/Manager.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ * Class for managing search (options/params/results) objects.
+ *
+ * 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  Search
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+namespace VuFind\Search;
+use Zend\ServiceManager\ServiceLocatorAwareInterface,
+    Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * Class for managing search (options/params/results) objects.
+ *
+ * @category VuFind2
+ * @package  Search
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+class Manager implements ServiceLocatorAwareInterface
+{
+    protected $config;
+    protected $classId = 'Solr';
+    protected $optionsStore = array();
+
+    /**
+     * Constructor
+     *
+     * @param array $config Configuration from VuFind module
+     */
+    public function __construct($config)
+    {
+        $this->config = $config;
+    }
+
+    /**
+     * Set the search class ID to load.  Implements a fluent interface.
+     *
+     * @param string $id Search class ID
+     *
+     * @return Manager
+     */
+    public function setSearchClassId($id)
+    {
+        $this->classId = $id;
+        return $this;
+    }
+
+    /**
+     * Get the namespace for the current search class ID.
+     *
+     * @return string
+     */
+    public function getNamespace()
+    {
+        // Process aliases first:
+        $key = isset($this->config['aliases'][$this->classId])
+            ? $this->config['aliases'][$this->classId] : $this->classId;
+
+
+        // If we have an explicit namespace configuration, use that next:
+        if (isset($this->config['namespaces_by_id'][$key])) {
+            return $this->config['namespaces_by_id'][$key];
+        }
+
+        // Use default namespace if we got this far:
+        $ns = isset($this->config['default_namespace'])
+            ? $this->config['default_namespace'] : 'VuFind\Search';
+        return $ns . '\\' . $this->classId;
+    }
+
+    /**
+     * Get the options class name for the current search class ID.
+     *
+     * @return string
+     */
+    public function getOptionsClass()
+    {
+        return $this->getNamespace() . '\Options';
+    }
+
+    /**
+     * Get the params class name for the current search class ID.
+     *
+     * @return string
+     */
+    public function getParamsClass()
+    {
+        return $this->getNamespace() . '\Params';
+    }
+
+    /**
+     * Get the results class name for the current search class ID.
+     *
+     * @return string
+     */
+    public function getResultsClass()
+    {
+        return $this->getNamespace() . '\Results';
+    }
+
+    /**
+     * Inject dependencies into an object.
+     *
+     * @param object $obj Object to inject.
+     *
+     * @return void
+     */
+    protected function injectDependencies($obj)
+    {
+        if ($obj instanceof ServiceLocatorAwareInterface) {
+            $obj->setServiceLocator($this->getServiceLocator());
+        }
+    }
+
+    /**
+     * Get an options instance for the current search class ID.
+     *
+     * @return \VuFind\Search\Base\Options
+     */
+    public function getOptionsInstance()
+    {
+        /* TODO -- uncomment this when \VuFind\Search\Options has been factored out
+        if (!isset($this->optionsStore[$this->classId])) {
+            $class = $this->getOptionsClass();
+            $this->optionsStore[$this->classId] = new $class();
+            if (!($this->optionsStore[$this->classId] instanceof Base\Options)) {
+                throw new \Exception('Invalid options object.');
+            }
+            $this->injectDependencies($this->optionsStore[$this->classId]);
+        }
+        return $this->optionsStore[$this->classId];
+         */
+        return Options::getInstance($this->classId);
+    }
+
+    /**
+     * Get a parameters object for the current search class ID.
+     *
+     * @param \VuFind\Search\Base\Options $options Search options to load (null for
+     * defaults).
+     *
+     * @return VuFind\Search\Base\Params
+     */
+    public function getParams($options = null)
+    {
+        $class = $this->getParamsClass();
+        $params = new $class($options);
+        if (!($params instanceof \VuFind\Search\Base\Params)) {
+            throw new \Exception('Invalid params object.');
+        }
+        $this->injectDependencies($params);
+        return $params;
+    }
+
+    /**
+     * Get a results object for the current search class ID.
+     *
+     * @param \VuFind\Search\Base\Params $params Search parameters to load.
+     *
+     * @return VuFind\Search\Base\Results
+     */
+    public function getResults($params = null)
+    {
+        $class = $this->getResultsClass();
+        if (null === $params) {
+            $params = $this->getParams();
+        }
+        $results = new $class($params);
+        if (!($results instanceof \VuFind\Search\Base\Results)) {
+            throw new \Exception('Invalid results object.');
+        }
+        $this->injectDependencies($results);
+        return $results;
+    }
+
+    /**
+     * Extract the name of the search class family from a class name.
+     *
+     * @param string $className Class name to examine.
+     *
+     * @return string
+     */
+    public function extractSearchClassId($className)
+    {
+        // Parse identifier out of class name of format VuFind\Search\[id]\Params:
+        $class = explode('\\', $className);
+        return $class[2];
+    }
+
+    /**
+     * Set the service locator.
+     *
+     * @param ServiceLocatorInterface $serviceLocator Locator to register
+     *
+     * @return Manager
+     */
+    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+    {
+        $this->serviceLocator = $serviceLocator;
+        return $this;
+    }
+
+    /**
+     * Get the service locator.
+     *
+     * @return \Zend\ServiceManager\ServiceLocatorInterface
+     */
+    public function getServiceLocator()
+    {
+        return $this->serviceLocator;
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Search/Minified.php b/module/VuFind/src/VuFind/Search/Minified.php
index 54feccf4505d81f919525c6eb8e74f1c20187997..a7743cc230e18560ab787f89437ff2da3271ef10 100644
--- a/module/VuFind/src/VuFind/Search/Minified.php
+++ b/module/VuFind/src/VuFind/Search/Minified.php
@@ -28,27 +28,21 @@
 namespace VuFind\Search;
 
 /**
- * A minified search object used exclusively for trimming
- *  a search object down to it's barest minimum size
- *  before storage in a cookie or database.
+ * A minified search object used exclusively for trimming a search object down to its
+ * barest minimum size before storage in a cookie or database.
  *
- * It's still contains enough data granularity to
- *  programmatically recreate search urls.
+ * It still contains enough data granularity to programmatically recreate search
+ * URLs.
  *
- * This class isn't intended for general use, but simply
- *  a way of storing/retrieving data from a search object:
+ * This class isn't intended for general use, but simply a way of storing/retrieving
+ * data from a search object:
  *
  * eg. Store
  * $searchHistory[] = serialize($this->minify());
  *
  * eg. Retrieve
- * $searchObject  = SearchObjectFactory::initSearchObject();
- * $searchObject->deminify(unserialize($search));
- *
- * Note: codingStandardsIgnore settings within this class are used to suppress
- *       warnings related to the name not meeting PEAR standards; since there
- *       are serialized versions of this class stored in databases in the wild,
- *       it is too late to easily rename it for standards compliance.
+ * $searchObject = unserialize($search);
+ * $searchObject->deminify($manager);
  *
  * @category VuFind2
  * @package  Search
@@ -128,17 +122,20 @@ class Minified
     /**
      * Turn the current object into search results.
      *
+     * @param \VuFind\Search\Manager $manager Search manager
+     *
      * @return \VuFind\Search\Base\Results
      */
-    public function deminify()
+    public function deminify(\VuFind\Search\Manager $manager)
     {
         // Figure out the parameter and result classes based on the search class ID:
         $this->populateClassNames();
 
         // Deminify everything:
-        $params = new $this->pc();
+        $manager->setSearchClassId($this->cl);
+        $params = $manager->getParams();
         $params->deminify($this);
-        $results = new $this->rc($params);
+        $results = $manager->getResults($params);
         $results->deminify($this);
 
         return $results;
@@ -152,46 +149,34 @@ class Minified
      */
     protected function populateClassNames()
     {
-        // Simple case -- this is a recently-built object which has a search class ID
-        // populated:
-        if (isset($this->cl)) {
-            $this->pc = 'VuFind\Search\\' . $this->cl . '\Params';
-            $this->rc = 'VuFind\Search\\' . $this->cl . '\Results';
-            return;
-        }
-
-        // If we got this far, it's a legacy entry from VuFind 1.x.  We need to
-        // figure out the engine type for the object we're about to construct:
-        switch($this->ty) {
-        case 'Summon':
-        case 'SummonAdvanced':
-            $this->pc = 'VuFind\Search\Summon\Params';
-            $this->rc = 'VuFind\Search\Summon\Results';
-            $fixType = true;
-            break;
-        case 'WorldCat':
-        case 'WorldCatAdvanced':
-            $this->pc = 'VuFind\Search\WorldCat\Params';
-            $this->rc = 'VuFind\Search\WorldCat\Results';
-            $fixType = true;
-            break;
-        case 'Authority':
-        case 'AuthorityAdvanced':
-            $this->pc = 'VuFind\Search\SolrAuth\Params';
-            $this->rc = 'VuFind\Search\SolrAuth\Results';
-            $fixType = true;
-            break;
-        default:
-            $this->pc = 'VuFind\Search\Solr\Params';
-            $this->rc = 'VuFind\Search\Solr\Results';
-            $fixType = false;
-            break;
-        }
+        // If this is a legacy entry from VuFind 1.x, we need to figure out the
+        // search class ID for the object we're about to construct:
+        if (!isset($this->cl)) {
+            $fixType = true;    // by default, assume we need to fix type
+            switch($this->ty) {
+            case 'Summon':
+            case 'SummonAdvanced':
+                $this->cl = 'Summon';
+                break;
+            case 'WorldCat':
+            case 'WorldCatAdvanced':
+                $this->cl = 'WorldCat';
+                break;
+            case 'Authority':
+            case 'AuthorityAdvanced':
+                $this->cl = 'SolrAuth';
+                break;
+            default:
+                $this->cl = 'Solr';
+                $fixType = false;
+                break;
+            }
 
-        // Now rewrite the type if necessary (only needed for legacy objects):
-        if ($fixType) {
-            $this->ty = (substr($this->ty, -8) == 'Advanced')
-                ? 'advanced' : 'basic';
+            // Now rewrite the type if necessary (only needed for legacy objects):
+            if ($fixType) {
+                $this->ty = (substr($this->ty, -8) == 'Advanced')
+                    ? 'advanced' : 'basic';
+            }
         }
     }
 }
diff --git a/module/VuFind/src/VuFind/Statistics/AbstractBase.php b/module/VuFind/src/VuFind/Statistics/AbstractBase.php
index 9bdd41f5466b32141b3e94383e236f31f94369e4..feb0b525b315784c0b571e200a4e8197abd6d625 100644
--- a/module/VuFind/src/VuFind/Statistics/AbstractBase.php
+++ b/module/VuFind/src/VuFind/Statistics/AbstractBase.php
@@ -60,7 +60,7 @@ abstract class AbstractBase implements ServiceLocatorAwareInterface
      *
      * @param ServiceLocatorInterface $serviceLocator Locator to register
      *
-     * @return Manager
+     * @return AbstractBase
      */
     public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
     {
diff --git a/module/VuFind/src/VuFind/Tests/TestCase.php b/module/VuFind/src/VuFind/Tests/TestCase.php
index 5f48900482b88765c7ed66f712dc8792f8f6dd7b..b5284f1cb325a75991e7b96a56b56e04c8d55c3c 100644
--- a/module/VuFind/src/VuFind/Tests/TestCase.php
+++ b/module/VuFind/src/VuFind/Tests/TestCase.php
@@ -41,6 +41,7 @@ namespace VuFind\Tests;
 
 abstract class TestCase extends \PHPUnit_Framework_TestCase
 {
+    protected $searchManager = false;
 
     /**
      * Call protected or private method for side-effect and result.
@@ -100,4 +101,21 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
         $reflectionProperty->setAccessible(true);
         return $reflectionProperty->setValue($object, $value);
     }
+
+    /**
+     * Get a search manager instance for testing search objects.
+     *
+     * @return \VuFind\Search\Manager
+     */
+    public function getSearchManager()
+    {
+        if (!$this->searchManager) {
+            $this->searchManager = new \VuFind\Search\Manager(
+                array('default_namespace' => 'VuFind\Search')
+            );
+            $serviceManager = new \Zend\ServiceManager\ServiceManager();
+            $this->searchManager->setServiceLocator($serviceManager);
+        }
+        return $this->searchManager;
+    }
 }
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Theme/Root/Helper/AbstractServiceLocator.php b/module/VuFind/src/VuFind/Theme/Root/Helper/AbstractServiceLocator.php
index b651cd5657e05c66d8025b62dd5300bf67a6a02f..da81af015a405773cc829d57abfac1f72a3afc48 100644
--- a/module/VuFind/src/VuFind/Theme/Root/Helper/AbstractServiceLocator.php
+++ b/module/VuFind/src/VuFind/Theme/Root/Helper/AbstractServiceLocator.php
@@ -49,7 +49,7 @@ abstract class AbstractServiceLocator extends AbstractHelper
      *
      * @param ServiceLocatorInterface $serviceLocator Locator to register
      *
-     * @return Manager
+     * @return AbstractServiceLocator
      */
     public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
     {
diff --git a/module/VuFind/src/VuFind/Theme/Root/Helper/SearchOptions.php b/module/VuFind/src/VuFind/Theme/Root/Helper/SearchOptions.php
index 5b796e3bc4771f3173df53009cc0b2a124fb41d1..e93c7a92d0c1d53e09810a2cea002689eb308459 100644
--- a/module/VuFind/src/VuFind/Theme/Root/Helper/SearchOptions.php
+++ b/module/VuFind/src/VuFind/Theme/Root/Helper/SearchOptions.php
@@ -26,7 +26,6 @@
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
 namespace VuFind\Theme\Root\Helper;
-use VuFind\Search\Options, Zend\View\Helper\AbstractHelper;
 
 /**
  * "Retrieve search options" view helper
@@ -37,10 +36,10 @@ use VuFind\Search\Options, Zend\View\Helper\AbstractHelper;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://vufind.org/wiki/building_a_recommendations_module Wiki
  */
-class SearchOptions extends AbstractHelper
+class SearchOptions extends AbstractServiceLocator
 {
     /**
-     * Wrapper function to the \VuFind\Search\Options getInstance function
+     * Wrapper to the search manager's getOptionsInstance method
      *
      * @param string $type The search type of the object to retrieve
      *
@@ -48,6 +47,7 @@ class SearchOptions extends AbstractHelper
      */
     public function __invoke($type = 'Solr')
     {
-        return Options::getInstance($type);
+        return $this->getServiceLocator()->get('SearchManager')
+            ->setSearchClassId($type)->getOptionsInstance();
     }
 }
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Translator/Loader/ExtendedIni.php b/module/VuFind/src/VuFind/Translator/Loader/ExtendedIni.php
index ae16efd1564bf1f1926f5a7d795f86800d56fbaf..db1505afbec6ac3d85c5ff1174d67b7ab898e0a4 100644
--- a/module/VuFind/src/VuFind/Translator/Loader/ExtendedIni.php
+++ b/module/VuFind/src/VuFind/Translator/Loader/ExtendedIni.php
@@ -26,7 +26,7 @@
  * @link     http://vufind.org   Main Site
  */
 namespace VuFind\Translator\Loader;
-use Zend\I18n\Translator\Loader\Exception\InvalidArgumentException,
+use Zend\I18n\Exception\InvalidArgumentException,
     Zend\I18n\Translator\Loader\FileLoaderInterface,
     Zend\I18n\Translator\TextDomain;
 
@@ -46,13 +46,13 @@ class ExtendedIni implements FileLoaderInterface
     /**
      * load(): defined by LoaderInterface.
      *
-     * @param string $filename Language file to read
      * @param string $locale   Locale to read from language file
+     * @param string $filename Language file to read
      *
      * @return TextDomain
      * @throws InvalidArgumentException
      */
-    public function load($filename, $locale)
+    public function load($locale, $filename)
     {
         $this->data = new TextDomain();
         if (!file_exists($filename)) {
diff --git a/module/VuFind/tests/Search/Base/ParamsTest.php b/module/VuFind/tests/Search/Base/ParamsTest.php
index e072e78f82c06c5cf01b816cf48631d3e10372b4..0bebb47638bbbb517dd339acdbb97fe671734e8c 100644
--- a/module/VuFind/tests/Search/Base/ParamsTest.php
+++ b/module/VuFind/tests/Search/Base/ParamsTest.php
@@ -49,10 +49,11 @@ class ParamsTest extends \VuFind\Tests\TestCase
     public function testSpellingReplacements()
     {
         // Use Solr options since base options is an abstract class.
-        $options = new \VuFind\Search\Solr\Options();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $options = $sm->getOptionsInstance();
 
         // Create Params object for testing purposes.
-        $params = new \VuFind\Search\Base\Params($options);
+        $params = $sm->setSearchClassId('Base')->getParams($options);
 
         // Key test: word boundaries:
         $params->setBasicSearch('go good googler');
diff --git a/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php b/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php
index 32c23958de864fb421605b93538c09cd2c0c0abb..de7aa5a21c1a088fef01df47284f775facb9d2a6 100644
--- a/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php
+++ b/module/VuFind/tests/Theme/Root/Helper/ResultFeedTest.php
@@ -70,10 +70,11 @@ class ResultFeedTest extends \VuFind\Tests\ViewHelperTestCase
         $request->set('sort', 'title');
         $request->set('view', 'rss');
 
-        $params = new \VuFind\Search\Solr\Params();
+        $sm = $this->getSearchManager()->setSearchClassId('Solr');
+        $params = $sm->getParams();
         $params->initFromRequest($request);
 
-        $results = new \VuFind\Search\Solr\Results($params);
+        $results = $sm->getResults($params);
         $helper = new ResultFeed();
         $helper->setView($this->getPhpRenderer($this->getPlugins()));
         $mockTranslator = function ($str) {
diff --git a/themes/blueprint/templates/Recommend/AuthorFacets.phtml b/themes/blueprint/templates/Recommend/AuthorFacets.phtml
index 0838ef5a237a3f62727c95309cc04f4717b0681c..a7b3d2cd13c2cacd1e8c2ebe67d3e77abb9f67f5 100644
--- a/themes/blueprint/templates/Recommend/AuthorFacets.phtml
+++ b/themes/blueprint/templates/Recommend/AuthorFacets.phtml
@@ -1,4 +1,4 @@
-<? if ($this->results->getResultTotal() > 0): ?>
+<? if ($this->recommend->getResults()->getResultTotal() > 0): ?>
   <? $similarAuthors = $this->recommend->getSimilarAuthors(); ?>
   <? if (!empty($similarAuthors['list'])): ?>
     <div class="authorbox">
diff --git a/themes/blueprint/templates/Recommend/AuthorityRecommend.phtml b/themes/blueprint/templates/Recommend/AuthorityRecommend.phtml
index d8dabd54d18f56543baa13dfb412d74c3bdd6442..5a7cbdbfb8b3d7804150cb462e2d4a0daaa15619 100644
--- a/themes/blueprint/templates/Recommend/AuthorityRecommend.phtml
+++ b/themes/blueprint/templates/Recommend/AuthorityRecommend.phtml
@@ -1,12 +1,16 @@
-<? $data = $this->recommend->getResults(); if (is_array($data) && !empty($data)): ?>
+<?
+    $data = $this->recommend->getRecommendations();
+    $results = $this->recommend->getResults();
+?>
+<? if (is_array($data) && !empty($data)): ?>
   <div class="authoritybox">
     <div><strong><?=$this->transEsc('See also')?>:</strong></div>
     <div>
       <? for ($i = 0; $i < count($data); $i++): ?>
         <?
             // Generate a new search URL that replaces the user's current term with the authority term:
-            $url = $this->url($this->results->getOptions()->getSearchAction())
-                . $this->results->getUrlQuery()->replaceTerm($this->results->getParams()->getDisplayQuery(), $data[$i]['heading']);
+            $url = $this->url($results->getOptions()->getSearchAction())
+                . $results->getUrlQuery()->replaceTerm($results->getParams()->getDisplayQuery(), $data[$i]['heading']);
         ?>
         <a href="<?=$url?>"><?=$this->escapeHtml($data[$i]['heading'])?></a><? if ($i != count($data) - 1): ?>, <? endif; ?>
       <? endfor; ?>
diff --git a/themes/blueprint/templates/Recommend/ExpandFacets.phtml b/themes/blueprint/templates/Recommend/ExpandFacets.phtml
index f2271ade1289ec0cdc30a2fa5bd4cec5a65d9651..49c0b99fb51c5c52920f48090912525de1df4075 100644
--- a/themes/blueprint/templates/Recommend/ExpandFacets.phtml
+++ b/themes/blueprint/templates/Recommend/ExpandFacets.phtml
@@ -1,7 +1,7 @@
 <?
     $expandFacetSet = $this->recommend->getExpandedSet();
     // Get empty search object to use as basis for parameter generation below:
-    $blankResults = new \VuFind\Search\Solr\Results(new \VuFind\Search\Solr\Params());
+    $blankResults = $this->recommend->getEmptyResults();
 ?>
 <? if ($expandFacetSet): ?>
   <div class="sidegroup">
diff --git a/themes/blueprint/templates/Recommend/FavoriteFacets.phtml b/themes/blueprint/templates/Recommend/FavoriteFacets.phtml
index 3ca5f5e814ba35d7945e496d2810b0f84384b37b..802c9a48293564737555aeac8a8504948b3f1270 100644
--- a/themes/blueprint/templates/Recommend/FavoriteFacets.phtml
+++ b/themes/blueprint/templates/Recommend/FavoriteFacets.phtml
@@ -1,3 +1,4 @@
+<? $results = $this->recommend->getResults(); ?>
 <div class="sidegroup">
   <? $sideFacetSet = $this->recommend->getFacetSet(); ?>
 
@@ -22,14 +23,14 @@
   <? if (isset($sideFacetSet['tags']) && !empty($sideFacetSet['tags']['list'])): ?>
     <div class="sidegroup">
       <h4 class="tag"><?=$this->transEsc($sideFacetSet['tags']['label'])?></h4>
-      <? $filterList = $this->results->getParams()->getFilterList(true);
+      <? $filterList = $results->getParams()->getFilterList(true);
          $tagFilterList = isset($filterList[$sideFacetSet['tags']['label']]) ? $filterList[$sideFacetSet['tags']['label']] : null;
          if (!empty($tagFilterList)): ?>
         <strong><?=$this->transEsc('Remove Filters')?></strong>
         <ul class="filters">
         <? $field = $sideFacetSet['tags']['label'];
            foreach ($tagFilterList as $filter): ?>
-          <? $removeLink = $this->currentPath().$this->results->getUrlQuery()->removeFacet($filter['field'], $filter['value']); ?>
+          <? $removeLink = $this->currentPath().$results->getUrlQuery()->removeFacet($filter['field'], $filter['value']); ?>
           <li>
             <a href="<?=$removeLink?>"><img src="<?=$this->imageLink('silk/delete.png')?>" alt="<?=$this->transEsc('Delete') ?>"/></a>
             <a href="<?=$removeLink?>"><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a>
@@ -43,7 +44,7 @@
           <? if ($thisFacet['isApplied']): ?>
             <?=$this->escapeHtml($thisFacet['displayText'])?> <img src="<?=$this->imageLink('silk/tick.png')?>" alt="<?=$this->transEsc('Selected') ?>"/>
           <? else: ?>
-            <a href="<?=$this->currentPath().$this->results->getUrlQuery()->addFacet('tags', $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> (<?=$this->escapeHtml($thisFacet['count'])?>)
+            <a href="<?=$this->currentPath().$results->getUrlQuery()->addFacet('tags', $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> (<?=$this->escapeHtml($thisFacet['count'])?>)
           <? endif; ?>
           </li>
         <? endforeach; ?>
diff --git a/themes/blueprint/templates/Recommend/SideFacets.phtml b/themes/blueprint/templates/Recommend/SideFacets.phtml
index 05c969d175c7394155df961e66961c53efd00893..42646d34a009e15a0bdc7325e9989644fd4683d6 100644
--- a/themes/blueprint/templates/Recommend/SideFacets.phtml
+++ b/themes/blueprint/templates/Recommend/SideFacets.phtml
@@ -1,22 +1,23 @@
+<? $results = $this->recommend->getResults(); ?>
 <div class="sidegroup">
-  <? if ($this->results->getResultTotal() > 0): ?><h4><?=$this->transEsc('Narrow Search')?></h4><? endif; ?>
-  <? $checkboxFilters = $this->results->getParams()->getCheckboxFacets(); if (count($checkboxFilters) > 0): ?>
+  <? if ($results->getResultTotal() > 0): ?><h4><?=$this->transEsc('Narrow Search')?></h4><? endif; ?>
+  <? $checkboxFilters = $results->getParams()->getCheckboxFacets(); if (count($checkboxFilters) > 0): ?>
     <? foreach ($checkboxFilters as $current): ?>
-        <div class="checkboxFilter<?=($this->results->getResultTotal() < 1 && !$current['selected'] && !$current['alwaysVisible']) ? ' hide' : ''?>">
+        <div class="checkboxFilter<?=($results->getResultTotal() < 1 && !$current['selected'] && !$current['alwaysVisible']) ? ' hide' : ''?>">
           <input type="checkbox" name="filter[]" value="<?=$this->escapeHtml($current['filter'])?>"
             <?=$current['selected'] ? 'checked="checked"' : ''?> id="<?=$this->escapeHtml(str_replace(' ', '', $current['desc']))?>"
-            onclick="document.location.href='<?=$current['selected'] ? $this->results->getUrlQuery()->removeFilter($current['filter']) : $this->results->getUrlQuery()->addFilter($current['filter'])?>';" />
+            onclick="document.location.href='<?=$current['selected'] ? $results->getUrlQuery()->removeFilter($current['filter']) : $results->getUrlQuery()->addFilter($current['filter'])?>';" />
           <label for="<?=$this->escapeHtml(str_replace(' ', '', $current['desc']))?>"><?=$this->transEsc($current['desc'])?></label>
         </div>
     <? endforeach; ?>
   <? endif; ?>
-  <? $filterList = $this->results->getParams()->getFilterList(true); if (!empty($filterList)): ?>
+  <? $filterList = $results->getParams()->getFilterList(true); if (!empty($filterList)): ?>
     <strong><?=$this->transEsc('Remove Filters')?></strong>
     <ul class="filters">
     <? foreach ($filterList as $field => $filters): ?>
       <? foreach ($filters as $filter): ?>
         <?
-            $removeLink = $this->currentPath().$this->results->getUrlQuery()->removeFacet($filter['field'], $filter['value']);
+            $removeLink = $this->currentPath().$results->getUrlQuery()->removeFacet($filter['field'], $filter['value']);
             if ($filter['displayText'] == '[* TO *]') $filter['displayText'] = $this->translate('filter_wildcard');
         ?>
         <li>
@@ -28,12 +29,12 @@
     </ul>
   <? endif; ?>
   <? $sideFacetSet = $this->recommend->getFacetSet(); $dateFacets = $this->recommend->getDateFacets(); ?>
-  <? if (!empty($sideFacetSet) && $this->results->getResultTotal() > 0): ?>
+  <? if (!empty($sideFacetSet) && $results->getResultTotal() > 0): ?>
     <? foreach ($sideFacetSet as $title => $cluster): ?>
       <? if (isset($dateFacets[$title])): ?>
         <? /* Load the publication date slider UI widget */ $this->headScript()->appendFile('pubdate_slider.js'); ?>
         <form action="" name="<?=$this->escapeHtml($title)?>Filter" id="<?=$this->escapeHtml($title)?>Filter">
-          <?=$this->results->getUrlQuery()->asHiddenFields(array('filter' => "/^{$title}:.*/"))?>
+          <?=$results->getUrlQuery()->asHiddenFields(array('filter' => "/^{$title}:.*/"))?>
           <input type="hidden" name="daterange[]" value="<?=$this->escapeHtml($title)?>"/>
           <fieldset class="publishDateLimit" id="<?=$this->escapeHtml($title)?>">
             <legend><?=$this->transEsc($cluster['label'])?></legend>
@@ -57,7 +58,7 @@
             <? if ($thisFacet['isApplied']): ?>
               <dd><?=$this->escapeHtml($thisFacet['displayText'])?> <img src="<?=$this->imageLink('silk/tick.png')?>" alt="Selected"/></dd>
             <? else: ?>
-              <dd><a href="<?=$this->currentPath().$this->results->getUrlQuery()->addFacet($title, $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> (<?=$this->escapeHtml($thisFacet['count'])?>)</dd>
+              <dd><a href="<?=$this->currentPath().$results->getUrlQuery()->addFacet($title, $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> (<?=$this->escapeHtml($thisFacet['count'])?>)</dd>
             <? endif; ?>
           <? endforeach; ?>
           <? if ($i > 5): ?><dd><a href="#" onclick="lessFacets('<?=$this->escapeHtml($title)?>'); return false;"><?=$this->transEsc('less')?> ...</a></dd><? endif; ?>
diff --git a/themes/blueprint/templates/Recommend/SwitchType.phtml b/themes/blueprint/templates/Recommend/SwitchType.phtml
index 7129a776b2ca55505ccf9d9e9c3f691059c63df6..48bf99dce3722173bf2a92fc20b228ca8e44946d 100644
--- a/themes/blueprint/templates/Recommend/SwitchType.phtml
+++ b/themes/blueprint/templates/Recommend/SwitchType.phtml
@@ -1,6 +1,6 @@
 <? if ($handler = $this->recommend->getNewHandler()): ?>
   <div class="info">
     <?=$this->transEsc('widen_prefix')?>
-    <a href="<?=$this->results->getUrlQuery()->setHandler($handler)?>"><?=$this->transEsc($this->recommend->getNewHandlerName())?></a>.
+    <a href="<?=$this->recommend->getResults()->getUrlQuery()->setHandler($handler)?>"><?=$this->transEsc($this->recommend->getNewHandlerName())?></a>.
   </div>
 <? endif; ?>
\ No newline at end of file
diff --git a/themes/blueprint/templates/Recommend/TopFacets.phtml b/themes/blueprint/templates/Recommend/TopFacets.phtml
index be69c21f460518bb4dc1e335126b1a1b6961cb94..ac4154c9b0b89f1ec99ae07c4731cd28857bc93d 100644
--- a/themes/blueprint/templates/Recommend/TopFacets.phtml
+++ b/themes/blueprint/templates/Recommend/TopFacets.phtml
@@ -20,7 +20,7 @@
           <? if ($thisFacet['isApplied']): ?>
             <?=$this->escapeHtml($thisFacet['displayText'])?> <img src="<?=$this->imageLink('silk/tick.png')?>" alt="<?=$this->transEsc('Selected') ?>"/>
           <? else: ?>
-            <a href="<?=$this->currentPath().$this->results->getUrlQuery()->addFacet($title, $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> (<?=$thisFacet['count'] ?>)
+            <a href="<?=$this->currentPath().$this->recommend->getResults()->getUrlQuery()->addFacet($title, $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> (<?=$thisFacet['count'] ?>)
           <? endif; ?>
         </span>
         <? if (count($cluster['list']) > $corner && $iter == count($cluster['list'])): ?>
diff --git a/themes/jquerymobile/templates/Recommend/SideFacets-dialog.phtml b/themes/jquerymobile/templates/Recommend/SideFacets-dialog.phtml
index 117650dae8d4319a651b8d65d784d3bcbb4e52e3..9247bc0ee419816a6c8fe89bc60056817919f261 100644
--- a/themes/jquerymobile/templates/Recommend/SideFacets-dialog.phtml
+++ b/themes/jquerymobile/templates/Recommend/SideFacets-dialog.phtml
@@ -1,5 +1,8 @@
-<? $sideFacetSet = $this->recommend->getFacetSet(); ?>
-<? if (!empty($sideFacetSet) && $this->results->getResultTotal() > 0): ?>
+<?
+    $results = $this->recommend->getResults();
+    $sideFacetSet = $this->recommend->getFacetSet();
+?>
+<? if (!empty($sideFacetSet) && $results->getResultTotal() > 0): ?>
   <div data-role="dialog" id="Search-narrow">
     <div data-role="header" data-theme="d" data-position="inline">
       <h1><?=$this->transEsc('Narrow Search')?></h1>
@@ -15,7 +18,7 @@
                 <? if ($thisFacet['isApplied']): ?>
                   <li data-icon="check" class="checked"><a href="" data-rel="back"><?=$this->escapeHtml($thisFacet['displayText'])?></a> <span class="ui-li-count"><?=$this->escapeHtml($thisFacet['count'])?></span></li>
                 <? else: ?>
-                  <li><a rel="external" href="<?=$this->currentPath().$this->results->getUrlQuery()->addFacet($title, $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> <span class="ui-li-count"><?=$this->escapeHtml($thisFacet['count'])?></span></li>
+                  <li><a rel="external" href="<?=$this->currentPath().$results->getUrlQuery()->addFacet($title, $thisFacet['value'])?>"><?=$this->escapeHtml($thisFacet['displayText'])?></a> <span class="ui-li-count"><?=$this->escapeHtml($thisFacet['count'])?></span></li>
                 <? endif; ?>
               <? endforeach; ?>
             </ul>
diff --git a/themes/jquerymobile/templates/Recommend/SideFacets.phtml b/themes/jquerymobile/templates/Recommend/SideFacets.phtml
index c0aa056738532408af1c60b266208a0271f05aee..361f90c5d235e81387fe8fb0d7da0d48e08c225f 100644
--- a/themes/jquerymobile/templates/Recommend/SideFacets.phtml
+++ b/themes/jquerymobile/templates/Recommend/SideFacets.phtml
@@ -1,10 +1,11 @@
-<? $filterList = $this->results->getParams()->getFilterList(true); if (!empty($filterList)): ?>
+<? $results = $this->recommend->getResults(); ?>
+<? $filterList = $results->getParams()->getFilterList(true); if (!empty($filterList)): ?>
   <ul class="filters" data-role="listview" data-inset="true" data-dividertheme="e">
     <li data-role="list-divider"><?=$this->transEsc('adv_search_filters')?></li>
     <? $i = 0; foreach ($filterList as $field => $filters): ?>
       <? foreach ($filters as $filter): ?>
         <?
-            $removeLink = $this->currentPath().$this->results->getUrlQuery()->removeFacet($filter['field'], $filter['value']);
+            $removeLink = $this->currentPath().$results->getUrlQuery()->removeFacet($filter['field'], $filter['value']);
             if ($filter['displayText'] == '[* TO *]') $filter['displayText'] = $this->translate('filter_wildcard');
         ?>
         <li data-icon="minus">
diff --git a/themes/jquerymobile/templates/Recommend/SwitchType.phtml b/themes/jquerymobile/templates/Recommend/SwitchType.phtml
index 7129a776b2ca55505ccf9d9e9c3f691059c63df6..48bf99dce3722173bf2a92fc20b228ca8e44946d 100644
--- a/themes/jquerymobile/templates/Recommend/SwitchType.phtml
+++ b/themes/jquerymobile/templates/Recommend/SwitchType.phtml
@@ -1,6 +1,6 @@
 <? if ($handler = $this->recommend->getNewHandler()): ?>
   <div class="info">
     <?=$this->transEsc('widen_prefix')?>
-    <a href="<?=$this->results->getUrlQuery()->setHandler($handler)?>"><?=$this->transEsc($this->recommend->getNewHandlerName())?></a>.
+    <a href="<?=$this->recommend->getResults()->getUrlQuery()->setHandler($handler)?>"><?=$this->transEsc($this->recommend->getNewHandlerName())?></a>.
   </div>
 <? endif; ?>
\ No newline at end of file