From 25abc8d5048c2515bd1761960e7781b1ed8bd82e Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Fri, 10 Feb 2017 13:30:36 -0500
Subject: [PATCH] Remove ServiceLocatorAwareInterface from table gateways.
 (#910)

---
 module/VuFind/config/module.config.php        | 19 ++--
 .../src/VuFind/Db/Table/ChangeTracker.php     | 11 ++-
 .../VuFind/src/VuFind/Db/Table/Comments.php   | 11 ++-
 .../src/VuFind/Db/Table/ExternalSession.php   | 11 ++-
 module/VuFind/src/VuFind/Db/Table/Factory.php | 60 +++++++++++--
 module/VuFind/src/VuFind/Db/Table/Gateway.php | 88 ++++++++-----------
 .../src/VuFind/Db/Table/OaiResumption.php     | 11 ++-
 .../src/VuFind/Db/Table/PluginManager.php     | 19 ----
 module/VuFind/src/VuFind/Db/Table/Record.php  |  9 +-
 .../VuFind/src/VuFind/Db/Table/Resource.php   | 28 ++++--
 .../src/VuFind/Db/Table/ResourceTags.php      | 15 +++-
 module/VuFind/src/VuFind/Db/Table/Search.php  | 21 +++--
 module/VuFind/src/VuFind/Db/Table/Session.php |  9 +-
 module/VuFind/src/VuFind/Db/Table/Tags.php    | 19 ++--
 module/VuFind/src/VuFind/Db/Table/User.php    | 26 ++++--
 .../VuFind/src/VuFind/Db/Table/UserCard.php   | 11 ++-
 .../VuFind/src/VuFind/Db/Table/UserList.php   | 25 ++++--
 .../src/VuFind/Db/Table/UserResource.php      | 11 ++-
 .../VuFind/src/VuFindTest/Unit/DbTestCase.php | 40 ++++++---
 .../src/VuFindTest/Autocomplete/TagTest.php   |  3 +-
 .../src/VuFindTest/Record/CacheTest.php       |  3 +-
 .../Controller/SocialstatsControllerTest.php  | 10 ++-
 22 files changed, 297 insertions(+), 163 deletions(-)

diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index b2308287836..10bb79f1883 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -381,21 +381,20 @@ $config = [
             'db_table' => [
                 'abstract_factories' => ['VuFind\Db\Table\PluginFactory'],
                 'factories' => [
+                    'changetracker' => 'VuFind\Db\Table\Factory::getChangeTracker',
+                    'comments' => 'VuFind\Db\Table\Factory::getComments',
+                    'externalsession' => 'VuFind\Db\Table\Factory::getExternalSession',
+                    'oairesumption' => 'VuFind\Db\Table\Factory::getOaiResumption',
+                    'record' => 'VuFind\Db\Table\Factory::getRecord',
                     'resource' => 'VuFind\Db\Table\Factory::getResource',
                     'resourcetags' => 'VuFind\Db\Table\Factory::getResourceTags',
+                    'search' => 'VuFind\Db\Table\Factory::getSearch',
+                    'session' => 'VuFind\Db\Table\Factory::getSession',
                     'tags' => 'VuFind\Db\Table\Factory::getTags',
                     'user' => 'VuFind\Db\Table\Factory::getUser',
+                    'usercard' => 'VuFind\Db\Table\Factory::getUserCard',
                     'userlist' => 'VuFind\Db\Table\Factory::getUserList',
-                ],
-                'invokables' => [
-                    'changetracker' => 'VuFind\Db\Table\ChangeTracker',
-                    'comments' => 'VuFind\Db\Table\Comments',
-                    'externalsession' => 'VuFind\Db\Table\ExternalSession',
-                    'oairesumption' => 'VuFind\Db\Table\OaiResumption',
-                    'record' => 'VuFind\Db\Table\Record',
-                    'search' => 'VuFind\Db\Table\Search',
-                    'session' => 'VuFind\Db\Table\Session',
-                    'userresource' => 'VuFind\Db\Table\UserResource',
+                    'userresource' => 'VuFind\Db\Table\Factory::getUserResource',
                 ],
             ],
             'hierarchy_driver' => [
diff --git a/module/VuFind/src/VuFind/Db/Table/ChangeTracker.php b/module/VuFind/src/VuFind/Db/Table/ChangeTracker.php
index f0eae0978e7..636e896bdb8 100644
--- a/module/VuFind/src/VuFind/Db/Table/ChangeTracker.php
+++ b/module/VuFind/src/VuFind/Db/Table/ChangeTracker.php
@@ -26,6 +26,7 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 
 /**
  * Table Definition for change_tracker
@@ -47,10 +48,16 @@ class ChangeTracker extends Gateway
 
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('change_tracker', 'VuFind\Db\Row\ChangeTracker');
+        parent::__construct(
+            $adapter, $tm, $cfg, 'change_tracker', 'VuFind\Db\Row\ChangeTracker'
+        );
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/Comments.php b/module/VuFind/src/VuFind/Db/Table/Comments.php
index a75089e2eb1..c79e8b039f1 100644
--- a/module/VuFind/src/VuFind/Db/Table/Comments.php
+++ b/module/VuFind/src/VuFind/Db/Table/Comments.php
@@ -26,6 +26,7 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 use Zend\Db\Sql\Expression;
 
 /**
@@ -41,10 +42,16 @@ class Comments extends Gateway
 {
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('comments', 'VuFind\Db\Row\Comments');
+        parent::__construct(
+            $adapter, $tm, $cfg, 'comments', 'VuFind\Db\Row\Comments'
+        );
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/ExternalSession.php b/module/VuFind/src/VuFind/Db/Table/ExternalSession.php
index 3e2763ff15a..39eca53aa81 100644
--- a/module/VuFind/src/VuFind/Db/Table/ExternalSession.php
+++ b/module/VuFind/src/VuFind/Db/Table/ExternalSession.php
@@ -28,6 +28,7 @@
  * @link     https://vufind.org Main Page
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 
 /**
  * Table Definition for external_session
@@ -45,10 +46,16 @@ class ExternalSession extends Gateway
 
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('external_session', 'VuFind\Db\Row\ExternalSession');
+        parent::__construct(
+            $adapter, $tm, $cfg, 'external_session', 'VuFind\Db\Row\ExternalSession'
+        );
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/Factory.php b/module/VuFind/src/VuFind/Db/Table/Factory.php
index 389455d6e65..9b0243c6dac 100644
--- a/module/VuFind/src/VuFind/Db/Table/Factory.php
+++ b/module/VuFind/src/VuFind/Db/Table/Factory.php
@@ -41,6 +41,46 @@ use Zend\ServiceManager\ServiceManager;
  */
 class Factory
 {
+    /**
+     * Construct a generic table object.
+     *
+     * @param string $name Name of table to construct (fully qualified class name,
+     * or else a class name within the current namespace)
+     * @param array  $args Extra constructor arguments
+     *
+     * @return object
+     */
+    public static function getGenericTable($name, $args)
+    {
+        // Prepend the current namespace unless we receive a FQCN:
+        $class = (strpos($name, '\\') === false)
+            ? __NAMESPACE__ . '\\' . $name : $name;
+        if (!class_exists($class)) {
+            throw new \Exception('Cannot construct ' . $class);
+        }
+        if (!($args[0] instanceof ServiceManager)) {
+            throw new \Exception('Service manager missing');
+        }
+        $sm = array_shift($args);
+        $adapter = $sm->getServiceLocator()->get('VuFind\DbAdapter');
+        $config = $sm->getServiceLocator()->get('config');
+        return new $class($adapter, $sm, $config, ...$args);
+    }
+
+    /**
+     * Default factory behavior.
+     *
+     * @param string $name Method name being called
+     * @param array  $args Method arguments
+     *
+     * @return object
+     */
+    public static function __callStatic($name, $args)
+    {
+        // Strip "get" off method name, and use the remainder as the table name:
+        return static::getGenericTable(substr($name, 3), $args);
+    }
+
     /**
      * Construct the Resource table.
      *
@@ -50,37 +90,39 @@ class Factory
      */
     public static function getResource(ServiceManager $sm)
     {
-        return new Resource($sm->getServiceLocator()->get('VuFind\DateConverter'));
+        $converter = $sm->getServiceLocator()->get('VuFind\DateConverter');
+        $loader = $sm->getServiceLocator()->get('VuFind\RecordLoader');
+        return static::getGenericTable('Resource', [$sm, $converter, $loader]);
     }
 
     /**
-     * Construct the Tags table.
+     * Construct the ResourceTags table.
      *
      * @param ServiceManager $sm Service manager.
      *
      * @return User
      */
-    public static function getTags(ServiceManager $sm)
+    public static function getResourceTags(ServiceManager $sm)
     {
         $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config');
         $caseSensitive = isset($config->Social->case_sensitive_tags)
             && $config->Social->case_sensitive_tags;
-        return new Tags($caseSensitive);
+        return static::getGenericTable('ResourceTags', [$sm, $caseSensitive]);
     }
 
     /**
-     * Construct the ResourceTags table.
+     * Construct the Tags table.
      *
      * @param ServiceManager $sm Service manager.
      *
      * @return User
      */
-    public static function getResourceTags(ServiceManager $sm)
+    public static function getTags(ServiceManager $sm)
     {
         $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config');
         $caseSensitive = isset($config->Social->case_sensitive_tags)
             && $config->Social->case_sensitive_tags;
-        return new ResourceTags($caseSensitive);
+        return static::getGenericTable('Tags', [$sm, $caseSensitive]);
     }
 
     /**
@@ -102,7 +144,7 @@ class Factory
             $sessionManager = $sm->getServiceLocator()->get('VuFind\SessionManager');
             $session = new \Zend\Session\Container('Account', $sessionManager);
         }
-        return new User($config, $rowClass, $session);
+        return static::getGenericTable('User', [$sm, $config, $rowClass, $session]);
     }
 
     /**
@@ -116,6 +158,6 @@ class Factory
     {
         $sessionManager = $sm->getServiceLocator()->get('VuFind\SessionManager');
         $session = new \Zend\Session\Container('List', $sessionManager);
-        return new UserList($session);
+        return static::getGenericTable('UserList', [$sm, $session]);
     }
 }
diff --git a/module/VuFind/src/VuFind/Db/Table/Gateway.php b/module/VuFind/src/VuFind/Db/Table/Gateway.php
index 7caccd9b582..f1a85fdebd0 100644
--- a/module/VuFind/src/VuFind/Db/Table/Gateway.php
+++ b/module/VuFind/src/VuFind/Db/Table/Gateway.php
@@ -26,10 +26,9 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
-use Zend\Db\TableGateway\AbstractTableGateway,
-    Zend\Db\TableGateway\Feature,
-    Zend\ServiceManager\ServiceLocatorAwareInterface,
-    Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\Db\Adapter\Adapter;
+use Zend\Db\TableGateway\AbstractTableGateway;
+use Zend\Db\TableGateway\Feature;
 
 /**
  * Generic VuFind table gateway.
@@ -40,56 +39,54 @@ use Zend\Db\TableGateway\AbstractTableGateway,
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     https://vufind.org Main Site
  */
-class Gateway extends AbstractTableGateway implements ServiceLocatorAwareInterface
+class Gateway extends AbstractTableGateway
 {
-    use \Zend\ServiceManager\ServiceLocatorAwareTrait;
-
     /**
-     * Name of class used to represent rows (null for default)
+     * Table manager
      *
-     * @var string
+     * @var PluginManager
      */
-    protected $rowClass = null;
-    
+    protected $tableManager;
+
     /**
      * Constructor
      *
-     * @param string $table    Name of database table to interface with
-     * @param string $rowClass Name of class used to represent rows (null for
+     * @param Adapter       $adapter  Database adapter
+     * @param PluginManager $tm       Table manager
+     * @param array         $cfg      Zend Framework configuration
+     * @param string        $table    Name of database table to interface with
+     * @param string        $rowClass Name of class used to represent rows (null for
      * default)
      */
-    public function __construct($table, $rowClass = null)
-    {
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg, $table,
+        $rowClass = null
+    ) {
+        $this->adapter = $adapter;
+        $this->tableManager = $tm;
         $this->table = $table;
-        $this->rowClass = $rowClass;
-    }
 
-    /**
-     * Set database adapter
-     *
-     * @param \Zend\Db\Adapter\Adapter $adapter Database adapter
-     *
-     * @return void
-     */
-    public function setAdapter(\Zend\Db\Adapter\Adapter $adapter)
-    {
-        $this->adapter = $adapter;
+        $this->initializeFeatures($cfg);
+        $this->initialize();
+
+        if (null !== $rowClass) {
+            $resultSetPrototype = $this->getResultSetPrototype();
+            $resultSetPrototype->setArrayObjectPrototype(
+                $this->initializeRowPrototype($rowClass)
+            );
+        }
     }
 
     /**
-     * Initialize
+     * Initialize features
+     *
+     * @param array $cfg Zend Framework configuration
      *
      * @return void
      */
-    public function initialize()
+    public function initializeFeatures($cfg)
     {
-        if ($this->isInitialized) {
-            return;
-        }
-
         // Special case for PostgreSQL sequences:
         if ($this->adapter->getDriver()->getDatabasePlatformName() == "Postgresql") {
-            $cfg = $this->getServiceLocator()->getServiceLocator()->get('config');
             $maps = isset($cfg['vufind']['pgsql_seq_mapping'])
                 ? $cfg['vufind']['pgsql_seq_mapping'] : null;
             if (isset($maps[$this->table])) {
@@ -103,30 +100,21 @@ class Gateway extends AbstractTableGateway implements ServiceLocatorAwareInterfa
                 );
             }
         }
-
-        parent::initialize();
-        if (null !== $this->rowClass) {
-            $resultSetPrototype = $this->getResultSetPrototype();
-            $resultSetPrototype->setArrayObjectPrototype(
-                $this->initializeRowPrototype()
-            );
-        }
     }
 
     /**
      * Construct the prototype for rows.
      *
+     * @param string $rowClass Name of row class to instantiate
+     *
      * @return object
      */
-    protected function initializeRowPrototype()
+    protected function initializeRowPrototype($rowClass)
     {
-        $prototype = new $this->rowClass($this->getAdapter());
-        if ($prototype instanceof ServiceLocatorAwareInterface) {
-            $prototype->setServiceLocator($this->getServiceLocator());
+        $prototype = new $rowClass($this->getAdapter());
+        if ($prototype instanceof DbTableAwareInterface) {
+            $prototype->setDbTableManager($this->tableManager);
         }
-        \VuFind\ServiceManager\Initializer::initInstance(
-            $prototype, $this->getServiceLocator()->getServiceLocator()
-        );
         return $prototype;
     }
 
@@ -171,6 +159,6 @@ class Gateway extends AbstractTableGateway implements ServiceLocatorAwareInterfa
      */
     public function getDbTable($table)
     {
-        return $this->getServiceLocator()->get($table);
+        return $this->tableManager->get($table);
     }
 }
diff --git a/module/VuFind/src/VuFind/Db/Table/OaiResumption.php b/module/VuFind/src/VuFind/Db/Table/OaiResumption.php
index d90831ef9e7..72a4a453617 100644
--- a/module/VuFind/src/VuFind/Db/Table/OaiResumption.php
+++ b/module/VuFind/src/VuFind/Db/Table/OaiResumption.php
@@ -26,6 +26,7 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 
 /**
  * Table Definition for oai_resumption
@@ -40,10 +41,16 @@ class OaiResumption extends Gateway
 {
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('oai_resumption', 'VuFind\Db\Row\OaiResumption');
+        parent::__construct(
+            $adapter, $tm, $cfg, 'oai_resumption', 'VuFind\Db\Row\OaiResumption'
+        );
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/PluginManager.php b/module/VuFind/src/VuFind/Db/Table/PluginManager.php
index 2ac45b87643..cd36600bef1 100644
--- a/module/VuFind/src/VuFind/Db/Table/PluginManager.php
+++ b/module/VuFind/src/VuFind/Db/Table/PluginManager.php
@@ -26,7 +26,6 @@
  * @link     https://vufind.org/wiki/development:plugins:database_gateways Wiki
  */
 namespace VuFind\Db\Table;
-use Zend\ServiceManager\ConfigInterface;
 
 /**
  * Database table plugin manager
@@ -39,24 +38,6 @@ use Zend\ServiceManager\ConfigInterface;
  */
 class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
 {
-    /**
-     * Constructor
-     *
-     * Make sure table gateways are properly initialized.
-     *
-     * @param ConfigInterface $configuration Configuration settings (optional)
-     */
-    public function __construct(ConfigInterface $configuration = null)
-    {
-        parent::__construct($configuration);
-        $initializer = function ($instance, $manager) {
-            $instance
-                ->setAdapter($manager->getServiceLocator()->get('VuFind\DbAdapter'));
-            $instance->initialize();
-        };
-        $this->addInitializer($initializer, false);
-    }
-
     /**
      * Return the name of the base class or interface that plug-ins must conform
      * to.
diff --git a/module/VuFind/src/VuFind/Db/Table/Record.php b/module/VuFind/src/VuFind/Db/Table/Record.php
index ac614c4b5eb..6802b0ed84f 100644
--- a/module/VuFind/src/VuFind/Db/Table/Record.php
+++ b/module/VuFind/src/VuFind/Db/Table/Record.php
@@ -30,6 +30,7 @@
  */
 namespace VuFind\Db\Table;
 
+use Zend\Db\Adapter\Adapter;
 use Zend\Db\Sql\Predicate\Expression;
 use Zend\Db\Sql\Where;
 
@@ -47,10 +48,14 @@ class Record extends Gateway
 {
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('record', 'VuFind\Db\Row\Record');
+        parent::__construct($adapter, $tm, $cfg, 'record', 'VuFind\Db\Row\Record');
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/Resource.php b/module/VuFind/src/VuFind/Db/Table/Resource.php
index 796c643693d..87172175c86 100644
--- a/module/VuFind/src/VuFind/Db/Table/Resource.php
+++ b/module/VuFind/src/VuFind/Db/Table/Resource.php
@@ -26,6 +26,8 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
+use VuFind\Record\Loader;
+use Zend\Db\Adapter\Adapter;
 use Zend\Db\Sql\Expression;
 
 /**
@@ -46,15 +48,30 @@ class Resource extends Gateway
      */
     protected $dateConverter;
 
+    /**
+     * Record loader
+     *
+     * @var Loader
+     */
+    protected $recordLoader;
+
     /**
      * Constructor
      *
+     * @param Adapter                $adapter   Database adapter
+     * @param PluginManager          $tm        Table manager
+     * @param array                  $cfg       Zend Framework configuration
      * @param \VuFind\Date\Converter $converter Date converter
+     * @param Loader                 $loader    Record loader
      */
-    public function __construct(\VuFind\Date\Converter $converter)
-    {
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg,
+        \VuFind\Date\Converter $converter, Loader $loader
+    ) {
         $this->dateConverter = $converter;
-        parent::__construct('resource', 'VuFind\Db\Row\Resource');
+        $this->recordLoader = $loader;
+        parent::__construct(
+            $adapter, $tm, $cfg, 'resource', 'VuFind\Db\Row\Resource'
+        );
     }
 
     /**
@@ -88,9 +105,8 @@ class Resource extends Gateway
             $result->source = $source;
 
             // Load record if it was not provided:
-            if (is_null($driver)) {
-                $driver = $this->getServiceLocator()->getServiceLocator()
-                    ->get('VuFind\RecordLoader')->load($id, $source);
+            if (null === $driver) {
+                $driver = $this->recordLoader->load($id, $source);
             }
 
             // Load metadata into the database for sorting/failback purposes:
diff --git a/module/VuFind/src/VuFind/Db/Table/ResourceTags.php b/module/VuFind/src/VuFind/Db/Table/ResourceTags.php
index d2a4b60efb7..bb7334db88d 100644
--- a/module/VuFind/src/VuFind/Db/Table/ResourceTags.php
+++ b/module/VuFind/src/VuFind/Db/Table/ResourceTags.php
@@ -26,6 +26,7 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 use Zend\Db\Sql\Expression;
 
 /**
@@ -49,11 +50,17 @@ class ResourceTags extends Gateway
     /**
      * Constructor
      *
-     * @param bool $caseSensitive Are tags case sensitive?
+     * @param Adapter       $adapter       Database adapter
+     * @param PluginManager $tm            Table manager
+     * @param array         $cfg           Zend Framework configuration
+     * @param bool          $caseSensitive Are tags case sensitive?
      */
-    public function __construct($caseSensitive = false)
-    {
-        parent::__construct('resource_tags', 'VuFind\Db\Row\ResourceTags');
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg,
+        $caseSensitive = false
+    ) {
+        parent::__construct(
+            $adapter, $tm, $cfg, 'resource_tags', 'VuFind\Db\Row\ResourceTags'
+        );
         $this->caseSensitive = $caseSensitive;
     }
 
diff --git a/module/VuFind/src/VuFind/Db/Table/Search.php b/module/VuFind/src/VuFind/Db/Table/Search.php
index 55771c400be..1438408314c 100644
--- a/module/VuFind/src/VuFind/Db/Table/Search.php
+++ b/module/VuFind/src/VuFind/Db/Table/Search.php
@@ -29,6 +29,7 @@
  */
 namespace VuFind\Db\Table;
 use minSO;
+use Zend\Db\Adapter\Adapter;
 use Zend\Db\Adapter\ParameterContainer;
 use Zend\Db\TableGateway\Feature;
 
@@ -48,23 +49,25 @@ class Search extends Gateway
 
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('search', 'VuFind\Db\Row\Search');
+        parent::__construct($adapter, $tm, $cfg, 'search', 'VuFind\Db\Row\Search');
     }
 
     /**
-     * Initialize
+     * Initialize features
+     *
+     * @param array $cfg Zend Framework configuration
      *
      * @return void
      */
-    public function initialize()
+    public function initializeFeatures($cfg)
     {
-        if ($this->isInitialized) {
-            return;
-        }
-
         // Special case for PostgreSQL inserts -- we need to provide an extra
         // clue so that the database knows how to write bytea data correctly:
         if ($this->adapter->getDriver()->getDatabasePlatformName() == "Postgresql") {
@@ -78,7 +81,7 @@ class Search extends Gateway
             $this->featureSet->addFeature($eventFeature);
         }
 
-        parent::initialize();
+        parent::initializeFeatures($cfg);
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/Session.php b/module/VuFind/src/VuFind/Db/Table/Session.php
index 6f429836149..0dedfef90d6 100644
--- a/module/VuFind/src/VuFind/Db/Table/Session.php
+++ b/module/VuFind/src/VuFind/Db/Table/Session.php
@@ -29,6 +29,7 @@
  */
 namespace VuFind\Db\Table;
 use VuFind\Exception\SessionExpired as SessionExpiredException;
+use Zend\Db\Adapter\Adapter;
 
 /**
  * Table Definition for session
@@ -46,10 +47,14 @@ class Session extends Gateway
 
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('session', 'VuFind\Db\Row\Session');
+        parent::__construct($adapter, $tm, $cfg, 'session', 'VuFind\Db\Row\Session');
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Db/Table/Tags.php b/module/VuFind/src/VuFind/Db/Table/Tags.php
index 1992d7a3c5d..a0ec1f3591e 100644
--- a/module/VuFind/src/VuFind/Db/Table/Tags.php
+++ b/module/VuFind/src/VuFind/Db/Table/Tags.php
@@ -26,9 +26,10 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
-use Zend\Db\Sql\Expression,
-    Zend\Db\Sql\Predicate\Predicate,
-    Zend\Db\Sql\Select;
+use Zend\Db\Adapter\Adapter;
+use Zend\Db\Sql\Expression;
+use Zend\Db\Sql\Predicate\Predicate;
+use Zend\Db\Sql\Select;
 
 /**
  * Table Definition for tags
@@ -51,11 +52,15 @@ class Tags extends Gateway
     /**
      * Constructor
      *
-     * @param bool $caseSensitive Are tags case sensitive?
+     * @param Adapter       $adapter       Database adapter
+     * @param PluginManager $tm            Table manager
+     * @param array         $cfg           Zend Framework configuration
+     * @param bool          $caseSensitive Are tags case sensitive?
      */
-    public function __construct($caseSensitive = false)
-    {
-        parent::__construct('tags', 'VuFind\Db\Row\Tags');
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg,
+        $caseSensitive = false
+    ) {
+        parent::__construct($adapter, $tm, $cfg, 'tags', 'VuFind\Db\Row\Tags');
         $this->caseSensitive = $caseSensitive;
     }
 
diff --git a/module/VuFind/src/VuFind/Db/Table/User.php b/module/VuFind/src/VuFind/Db/Table/User.php
index f09907a5ba1..9906211f537 100644
--- a/module/VuFind/src/VuFind/Db/Table/User.php
+++ b/module/VuFind/src/VuFind/Db/Table/User.php
@@ -26,7 +26,9 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFind\Db\Table;
-use Zend\Config\Config, Zend\Session\Container;
+use Zend\Config\Config;
+use Zend\Db\Adapter\Adapter;
+use Zend\Session\Container;
 
 /**
  * Table Definition for user
@@ -56,17 +58,21 @@ class User extends Gateway
     /**
      * Constructor
      *
-     * @param Config    $config   VuFind configuration
-     * @param string    $rowClass Name of class for representing rows
-     * @param Container $session  Session container to inject into rows (optional;
-     * used for privacy mode)
+     * @param Adapter       $adapter  Database adapter
+     * @param PluginManager $tm       Table manager
+     * @param array         $cfg      Zend Framework configuration
+     * @param Config        $config   VuFind configuration
+     * @param string        $rowClass Name of class for representing rows
+     * @param Container     $session  Session container to inject into rows
+     * (optional; used for privacy mode)
      */
-    public function __construct(Config $config, $rowClass = 'VuFind\Db\Row\User',
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg,
+        Config $config, $rowClass = 'VuFind\Db\Row\User',
         Container $session = null
     ) {
-        parent::__construct('user', $rowClass);
         $this->config = $config;
         $this->session = $session;
+        parent::__construct($adapter, $tm, $cfg, 'user', $rowClass);
     }
 
     /**
@@ -131,11 +137,13 @@ class User extends Gateway
     /**
      * Construct the prototype for rows.
      *
+     * @param string $rowClass Name of row class to instantiate
+     *
      * @return object
      */
-    protected function initializeRowPrototype()
+    protected function initializeRowPrototype($rowClass)
     {
-        $prototype = parent::initializeRowPrototype();
+        $prototype = parent::initializeRowPrototype($rowClass);
         $prototype->setConfig($this->config);
         if (null !== $this->session && is_callable([$prototype, 'setSession'])) {
             $prototype->setSession($this->session);
diff --git a/module/VuFind/src/VuFind/Db/Table/UserCard.php b/module/VuFind/src/VuFind/Db/Table/UserCard.php
index 590117406ff..4397341e820 100644
--- a/module/VuFind/src/VuFind/Db/Table/UserCard.php
+++ b/module/VuFind/src/VuFind/Db/Table/UserCard.php
@@ -26,6 +26,7 @@
  * @link     https://vufind.org Main Page
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 
 /**
  * Table Definition for user_card
@@ -40,9 +41,15 @@ class UserCard extends Gateway
 {
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('user_card', 'VuFind\Db\Row\UserCard');
+        parent::__construct(
+            $adapter, $tm, $cfg, 'user_card', 'VuFind\Db\Row\UserCard'
+        );
     }
 }
diff --git a/module/VuFind/src/VuFind/Db/Table/UserList.php b/module/VuFind/src/VuFind/Db/Table/UserList.php
index ced6dce5e77..b3a9724b537 100644
--- a/module/VuFind/src/VuFind/Db/Table/UserList.php
+++ b/module/VuFind/src/VuFind/Db/Table/UserList.php
@@ -26,9 +26,10 @@
  * @link     https://vufind.org Main Page
  */
 namespace VuFind\Db\Table;
-use VuFind\Exception\LoginRequired as LoginRequiredException,
-    VuFind\Exception\RecordMissing as RecordMissingException,
-    Zend\Db\Sql\Expression;
+use VuFind\Exception\LoginRequired as LoginRequiredException;
+use VuFind\Exception\RecordMissing as RecordMissingException;
+use Zend\Db\Adapter\Adapter;
+use Zend\Db\Sql\Expression;
 
 /**
  * Table Definition for user_list
@@ -51,13 +52,19 @@ class UserList extends Gateway
     /**
      * Constructor
      *
+     * @param Adapter                 $adapter Database adapter
+     * @param PluginManager           $tm      Table manager
+     * @param array                   $cfg     Zend Framework configuration
      * @param \Zend\Session\Container $session Session container (must use same
      * namespace as container provided to \VuFind\View\Helper\Root\UserList).
      */
-    public function __construct(\Zend\Session\Container $session)
-    {
-        parent::__construct('user_list', 'VuFind\Db\Row\UserList');
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg,
+        \Zend\Session\Container $session
+    ) {
         $this->session = $session;
+        parent::__construct(
+            $adapter, $tm, $cfg, 'user_list', 'VuFind\Db\Row\UserList'
+        );
     }
 
     /**
@@ -142,11 +149,13 @@ class UserList extends Gateway
     /**
      * Construct the prototype for rows.
      *
+     * @param string $rowClass Name of row class to instantiate
+     *
      * @return object
      */
-    protected function initializeRowPrototype()
+    protected function initializeRowPrototype($rowClass)
     {
-        $prototype = parent::initializeRowPrototype();
+        $prototype = parent::initializeRowPrototype($rowClass);
         $prototype->setSession($this->session);
         return $prototype;
     }
diff --git a/module/VuFind/src/VuFind/Db/Table/UserResource.php b/module/VuFind/src/VuFind/Db/Table/UserResource.php
index d47aa91361a..1c1f9605974 100644
--- a/module/VuFind/src/VuFind/Db/Table/UserResource.php
+++ b/module/VuFind/src/VuFind/Db/Table/UserResource.php
@@ -26,6 +26,7 @@
  * @link     https://vufind.org Main Page
  */
 namespace VuFind\Db\Table;
+use Zend\Db\Adapter\Adapter;
 use Zend\Db\Sql\Expression;
 
 /**
@@ -41,10 +42,16 @@ class UserResource extends Gateway
 {
     /**
      * Constructor
+     *
+     * @param Adapter       $adapter Database adapter
+     * @param PluginManager $tm      Table manager
+     * @param array         $cfg     Zend Framework configuration
      */
-    public function __construct()
+    public function __construct(Adapter $adapter, PluginManager $tm, $cfg)
     {
-        parent::__construct('user_resource', 'VuFind\Db\Row\UserResource');
+        parent::__construct(
+            $adapter, $tm, $cfg, 'user_resource', 'VuFind\Db\Row\UserResource'
+        );
     }
 
     /**
diff --git a/module/VuFind/src/VuFindTest/Unit/DbTestCase.php b/module/VuFind/src/VuFindTest/Unit/DbTestCase.php
index 5d0608d4098..5b3abf849af 100644
--- a/module/VuFind/src/VuFindTest/Unit/DbTestCase.php
+++ b/module/VuFind/src/VuFindTest/Unit/DbTestCase.php
@@ -61,10 +61,26 @@ abstract class DbTestCase extends TestCase
                         'abstract_factories' =>
                             ['VuFind\Db\Table\PluginFactory'],
                         'factories' => [
+                            'changetracker' =>
+                                'VuFind\Db\Table\Factory::getChangeTracker',
+                            'comments' => 'VuFind\Db\Table\Factory::getComments',
+                            'externalsession' =>
+                                'VuFind\Db\Table\Factory::getExternalSession',
+                            'oairesumption' =>
+                                'VuFind\Db\Table\Factory::getOaiResumption',
+                            'record' => 'VuFind\Db\Table\Factory::getRecord',
                             'resource' => 'VuFind\Db\Table\Factory::getResource',
+                            'resourcetags' =>
+                                'VuFind\Db\Table\Factory::getResourceTags',
+                            'search' => 'VuFind\Db\Table\Factory::getSearch',
+                            'session' => 'VuFind\Db\Table\Factory::getSession',
+                            'tags' => 'VuFind\Db\Table\Factory::getTags',
                             'user' => 'VuFind\Db\Table\Factory::getUser',
+                            'usercard' => 'VuFind\Db\Table\Factory::getUserCard',
                             'userlist' => 'VuFind\Db\Table\Factory::getUserList',
-                        ]
+                            'userresource' =>
+                                'VuFind\Db\Table\Factory::getUserResource',
+                        ],
                     ]
                 )
             );
@@ -82,16 +98,18 @@ abstract class DbTestCase extends TestCase
                 [
                     'vufind' => [
                         'pgsql_seq_mapping'  => [
-                            'comments'       => ['id', 'comments_id_seq'],
-                            'oai_resumption' => ['id', 'oai_resumption_id_seq'],
-                            'resource'       => ['id', 'resource_id_seq'],
-                            'resource_tags'  => ['id', 'resource_tags_id_seq'],
-                            'search'         => ['id', 'search_id_seq'],
-                            'session'        => ['id', 'session_id_seq'],
-                            'tags'           => ['id', 'tags_id_seq'],
-                            'user'           => ['id', 'user_id_seq'],
-                            'user_list'      => ['id', 'user_list_id_seq'],
-                            'user_resource'  => ['id', 'user_resource_id_seq']
+                            'comments'         => ['id', 'comments_id_seq'],
+                            'external_session' => ['id', 'external_session_id_seq'],
+                            'oai_resumption'   => ['id', 'oai_resumption_id_seq'],
+                            'record'           => ['id', 'record_id_seq'],
+                            'resource'         => ['id', 'resource_id_seq'],
+                            'resource_tags'    => ['id', 'resource_tags_id_seq'],
+                            'search'           => ['id', 'search_id_seq'],
+                            'session'          => ['id', 'session_id_seq'],
+                            'tags'             => ['id', 'tags_id_seq'],
+                            'user'             => ['id', 'user_id_seq'],
+                            'user_list'        => ['id', 'user_list_id_seq'],
+                            'user_resource'    => ['id', 'user_resource_id_seq'],
                         ]
                     ]
                 ]
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Autocomplete/TagTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Autocomplete/TagTest.php
index 17cd49b6f5e..ae1b58bbd0e 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Autocomplete/TagTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Autocomplete/TagTest.php
@@ -67,7 +67,8 @@ class TagTest extends \VuFindTest\Unit\DbTestCase
         ];
 
         // Fake services:
-        $tagTable = $this->getMock('VuFind\Db\Table\Tags', ['matchText']);
+        $tagTable = $this->getMockBuilder('VuFind\Db\Table\Tags')
+            ->disableOriginalConstructor()->setMethods(['matchText'])->getMock();
         $tagTable->expects($this->once())->method('matchText')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue($tags));
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Record/CacheTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Record/CacheTest.php
index bebf604c43c..4e9e68da80c 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Record/CacheTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Record/CacheTest.php
@@ -256,7 +256,8 @@ class CacheTest extends TestCase
             return false;
         };
 
-        $recordTable = $this->getMock('VuFind\Db\Table\Record');
+        $recordTable = $this->getMockBuilder('VuFind\Db\Table\Record')
+            ->disableOriginalConstructor()->getMock();
         $recordTable->method('findRecords')
             ->will($this->returnCallback($findRecordsCallback));
         $recordTable->method('findRecord')
diff --git a/module/VuFindAdmin/tests/unit-tests/src/VuFindTest/Controller/SocialstatsControllerTest.php b/module/VuFindAdmin/tests/unit-tests/src/VuFindTest/Controller/SocialstatsControllerTest.php
index 182ecd0f1c3..effb2172b2d 100644
--- a/module/VuFindAdmin/tests/unit-tests/src/VuFindTest/Controller/SocialstatsControllerTest.php
+++ b/module/VuFindAdmin/tests/unit-tests/src/VuFindTest/Controller/SocialstatsControllerTest.php
@@ -48,13 +48,17 @@ class SocialstatsControllerTest extends \VuFindTest\Unit\TestCase
     {
         // Create mocks to simulate database lookups:
         $c = $this->getMock('VuFindAdmin\Controller\SocialstatsController', ['getTable']);
-        $comments = $this->getMock('VuFind\Db\Table\Comments', ['getStatistics']);
+        $comments = $this->getMockBuilder('VuFind\Db\Table\Comments')
+            ->disableOriginalConstructor()->setMethods(['getStatistics'])->getMock();
         $comments->expects($this->once())->method('getStatistics')->will($this->returnValue('comments-data'));
         $c->expects($this->at(0))->method('getTable')->with($this->equalTo('comments'))->will($this->returnValue($comments));
-        $userresource = $this->getMock('VuFind\Db\Table\UserResource', ['getStatistics']);
+        $userresource = $this->getMockBuilder('VuFind\Db\Table\UserResource')
+            ->setMethods(['getStatistics'])->disableOriginalConstructor()->getMock();
         $userresource->expects($this->once())->method('getStatistics')->will($this->returnValue('userresource-data'));
         $c->expects($this->at(1))->method('getTable')->with($this->equalTo('userresource'))->will($this->returnValue($userresource));
-        $resourcetags = $this->getMock('VuFind\Db\Table\ResourceTags', ['getStatistics']);
+        $resourcetags = $this->getMockBuilder('VuFind\Db\Table\ResourceTags')
+            ->disableOriginalConstructor()->setMethods(['getStatistics'])
+            ->getMock();
         $resourcetags->expects($this->once())->method('getStatistics')->will($this->returnValue('resourcetags-data'));
         $c->expects($this->at(2))->method('getTable')->with($this->equalTo('resourcetags'))->will($this->returnValue($resourcetags));
 
-- 
GitLab