From b110f0eed66165779e5e1a1a8d5e251bfa2f93fc Mon Sep 17 00:00:00 2001
From: Chris Hallberg <crhallberg@gmail.com>
Date: Fri, 16 Dec 2016 13:52:23 -0500
Subject: [PATCH] Remove Statistics Module (#863)

---
 config/vufind/config.ini                      |  38 --
 module/VuFind/config/module.config.php        |  22 +-
 module/VuFind/sql/mysql.sql                   |  33 --
 module/VuFind/sql/pgsql.sql                   |  41 +-
 module/VuFind/src/VuFind/Config/Upgrade.php   |  20 +-
 .../src/VuFind/Controller/AbstractRecord.php  |  13 -
 .../src/VuFind/Controller/AbstractSearch.php  |  13 -
 .../VuFind/src/VuFind/Db/Table/UserStats.php  | 101 ----
 .../src/VuFind/Db/Table/UserStatsFields.php   | 114 ----
 .../Factory/SolrStatsBackendFactory.php       |  68 ---
 module/VuFind/src/VuFind/Service/Factory.php  |  44 --
 .../src/VuFind/Statistics/AbstractBase.php    | 250 --------
 .../VuFind/Statistics/Driver/AbstractBase.php | 111 ----
 .../src/VuFind/Statistics/Driver/Db.php       |  91 ---
 .../src/VuFind/Statistics/Driver/Factory.php  |  74 ---
 .../src/VuFind/Statistics/Driver/File.php     | 126 ----
 .../Statistics/Driver/PluginFactory.php       |  48 --
 .../Statistics/Driver/PluginManager.php       |  66 ---
 .../src/VuFind/Statistics/Driver/Solr.php     | 182 ------
 .../VuFind/src/VuFind/Statistics/Record.php   | 124 ----
 .../VuFind/src/VuFind/Statistics/Search.php   | 141 -----
 .../src/VuFindTest/Config/UpgradeTest.php     |   5 +-
 .../Statistics/Driver/PluginManagerTest.php   |  66 ---
 .../Controller/StatisticsController.php       | 109 ----
 solr/vufind/stats/conf/schema.xml             |  47 --
 solr/vufind/stats/conf/solrconfig.xml         | 536 ------------------
 solr/vufind/stats/core.properties             |   2 -
 themes/bootstrap3/templates/admin/menu.phtml  |   1 -
 .../templates/admin/statistics/home.phtml     |  95 ----
 29 files changed, 15 insertions(+), 2566 deletions(-)
 delete mode 100644 module/VuFind/src/VuFind/Db/Table/UserStats.php
 delete mode 100644 module/VuFind/src/VuFind/Db/Table/UserStatsFields.php
 delete mode 100644 module/VuFind/src/VuFind/Search/Factory/SolrStatsBackendFactory.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/AbstractBase.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/AbstractBase.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/Db.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/Factory.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/File.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/PluginFactory.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/PluginManager.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Driver/Solr.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Record.php
 delete mode 100644 module/VuFind/src/VuFind/Statistics/Search.php
 delete mode 100644 module/VuFind/tests/unit-tests/src/VuFindTest/Statistics/Driver/PluginManagerTest.php
 delete mode 100644 module/VuFindAdmin/src/VuFindAdmin/Controller/StatisticsController.php
 delete mode 100644 solr/vufind/stats/conf/schema.xml
 delete mode 100644 solr/vufind/stats/conf/solrconfig.xml
 delete mode 100644 solr/vufind/stats/core.properties
 delete mode 100644 themes/bootstrap3/templates/admin/statistics/home.phtml

diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index 59b9e5b8f1a..23d160ad661 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -375,44 +375,6 @@ ils_encryption_key = false
 ;[ChoiceAuth]
 ;choice_order = Shibboleth,Database
 
-; This section will allow you to control whether VuFind should record usage
-; statistics.
-[Statistics]
-; You can uncomment one or more of these lines to enable statistics tracking.
-; Each enabled mode will write stats to a different target (Solr stats index,
-; flat file, or database tables).  Some modes require additional settings below.
-;
-; Currently, VuFind stores statistics in two different contexts: searches and
-; record views.  By default, an enabled mode will log both types of stats.  If
-; you want to log different types of stats to different targets, you can use a
-; qualifier -- for example, "mode[] = Solr:Record" and "mode[] = Db:Search".
-; Multiple targets may be separated by commas.  Do not use qualifiers unless you
-; really need to -- logging all statistics to the same target makes reporting
-; more effective.
-;
-; Note: Statistics gathering includes browser detection.  For best results, make
-; sure you have a recent browscap.ini file configured in PHP.  See
-; http://php.net/manual/en/function.get-browser.php#refsect1-function.get-browser-notes
-;mode[] = Solr
-;mode[] = File
-;mode[] = Db
-
-; When using the Solr mode, specify the address of a Solr server containing a
-; "stats" core here; if no URL is specified, [Index]/url below will be used.
-;solr            = http://localhost:8080/solr
-
-; When using the File mode, specify a directory for saving stat files here.
-; NOTE: As currently implemented, File mode is NOT RECOMMENDED FOR USE IN PRODUCTION.
-;file            = /usr/local/vufind/local/logs
-
-; When displaying search statistics in the Admin module, do you want to see a single
-; merged list, or separate grouped lists by module (Solr, Summon, etc.)
-searchesBySource = false
-
-; When display record view statistics in the Admin module, do you want to see a
-; single merged list, or separate grouped lists by module (Solr, Summon, etc.)
-recordsBySource = false
-
 ; This section defines the location/behavior of the Solr index and requires no
 ; changes for most installations
 [Index]
diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 71cecb52bd9..af1819336f9 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -213,7 +213,6 @@ $config = [
             'VuFind\RecordDriverPluginManager' => 'VuFind\Service\Factory::getRecordDriverPluginManager',
             'VuFind\RecordLoader' => 'VuFind\Service\Factory::getRecordLoader',
             'VuFind\RecordRouter' => 'VuFind\Service\Factory::getRecordRouter',
-            'VuFind\RecordStats' => 'VuFind\Service\Factory::getRecordStats',
             'VuFind\RecordTabPluginManager' => 'VuFind\Service\Factory::getRecordTabPluginManager',
             'VuFind\RelatedPluginManager' => 'VuFind\Service\Factory::getRelatedPluginManager',
             'VuFind\ResolverDriverPluginManager' => 'VuFind\Service\Factory::getResolverDriverPluginManager',
@@ -224,13 +223,11 @@ $config = [
             'VuFind\SearchResultsPluginManager' => 'VuFind\Service\Factory::getSearchResultsPluginManager',
             'VuFind\SearchRunner' => 'VuFind\Service\Factory::getSearchRunner',
             'VuFind\SearchSpecsReader' => 'VuFind\Service\Factory::getSearchSpecsReader',
-            'VuFind\SearchStats' => 'VuFind\Service\Factory::getSearchStats',
             'VuFind\SearchTabsHelper' => 'VuFind\Service\Factory::getSearchTabsHelper',
             'VuFind\SessionManager' => 'VuFind\Session\ManagerFactory',
             'VuFind\SessionPluginManager' => 'VuFind\Service\Factory::getSessionPluginManager',
             'VuFind\SMS' => 'VuFind\SMS\Factory',
             'VuFind\Solr\Writer' => 'VuFind\Service\Factory::getSolrWriter',
-            'VuFind\StatisticsDriverPluginManager' => 'VuFind\Service\Factory::getStatisticsDriverPluginManager',
             'VuFind\Tags' => 'VuFind\Service\Factory::getTags',
             'VuFind\Translator' => 'VuFind\Service\Factory::getTranslator',
             'VuFind\WorldCatUtils' => 'VuFind\Service\Factory::getWorldCatUtils',
@@ -398,8 +395,6 @@ $config = [
                     'search' => 'VuFind\Db\Table\Search',
                     'session' => 'VuFind\Db\Table\Session',
                     'userresource' => 'VuFind\Db\Table\UserResource',
-                    'userstats' => 'VuFind\Db\Table\UserStats',
-                    'userstatsfields' => 'VuFind\Db\Table\UserStatsFields',
                 ],
             ],
             'hierarchy_driver' => [
@@ -585,7 +580,6 @@ $config = [
                     'Solr' => 'VuFind\Search\Factory\SolrDefaultBackendFactory',
                     'SolrAuth' => 'VuFind\Search\Factory\SolrAuthBackendFactory',
                     'SolrReserves' => 'VuFind\Search\Factory\SolrReservesBackendFactory',
-                    'SolrStats' => 'VuFind\Search\Factory\SolrStatsBackendFactory',
                     'SolrWeb' => 'VuFind\Search\Factory\SolrWebBackendFactory',
                     'Summon' => 'VuFind\Search\Factory\SummonBackendFactory',
                     'WorldCat' => 'VuFind\Search\Factory\WorldCatBackendFactory',
@@ -595,7 +589,6 @@ $config = [
                     'authority' => 'SolrAuth',
                     'biblio' => 'Solr',
                     'reserves' => 'SolrReserves',
-                    'stats' => 'SolrStats',
                     // Legacy:
                     'VuFind' => 'Solr',
                 ]
@@ -629,20 +622,7 @@ $config = [
                     'memcachesession' => 'Memcache',
                     'mysqlsession' => 'Database',
                 ],
-            ],
-            'statistics_driver' => [
-                'abstract_factories' => ['VuFind\Statistics\Driver\PluginFactory'],
-                'factories' => [
-                    'file' => 'VuFind\Statistics\Driver\Factory::getFile',
-                    'solr' => 'VuFind\Statistics\Driver\Factory::getSolr',
-                ],
-                'invokables' => [
-                    'db' => 'VuFind\Statistics\Driver\Db',
-                ],
-                'aliases' => [
-                    'database' => 'db',
-                ],
-            ],
+            ]
         ],
         // This section behaves just like recorddriver_tabs below, but is used for
         // the collection module instead of the standard record view.
diff --git a/module/VuFind/sql/mysql.sql b/module/VuFind/sql/mysql.sql
index 5fe37443422..79fc0fa231e 100644
--- a/module/VuFind/sql/mysql.sql
+++ b/module/VuFind/sql/mysql.sql
@@ -244,39 +244,6 @@ CREATE TABLE `user_resource` (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
---
--- Table structure for table `user_stats`
---
-
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `user_stats` (
-  `id` varchar(24) NOT NULL,
-  `datestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `browser` varchar(32) NOT NULL,
-  `browserVersion` varchar(8) NOT NULL,
-  `ipaddress` varchar(15) NOT NULL,
-  `referrer` varchar(512) NOT NULL,
-  `url` varchar(512) NOT NULL,
-  `session` varchar(64) NOT NULL,
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `user_stats_fields`
---
-
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `user_stats_fields` (
-  `id` varchar(24) NOT NULL,
-  `field` varchar(32) NOT NULL,
-  `value` varchar(1024) NOT NULL,
-  PRIMARY KEY (`id`,`field`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
 --
 -- Table structure for table `user_card`
 --
diff --git a/module/VuFind/sql/pgsql.sql b/module/VuFind/sql/pgsql.sql
index a63e2bb0425..cc6bf8c392a 100644
--- a/module/VuFind/sql/pgsql.sql
+++ b/module/VuFind/sql/pgsql.sql
@@ -236,45 +236,6 @@ PRIMARY KEY (id)
 
 -- --------------------------------------------------------
 
---
--- Statistics tables
---
-
---
--- Table structure for table statistics
---
-
-DROP TABLE IF EXISTS "user_stats_fields";
-
-CREATE TABLE user_stats_fields (
-id varchar(24) NOT NULL,
-field varchar(32) NOT NULL,
-value varchar(1024) NOT NULL,
-PRIMARY KEY (id, field)
-);
-
--- --------------------------------------------------------
-
---
--- Table structure for table user_stats
---
-
-DROP TABLE IF EXISTS "user_stats";
-
-CREATE TABLE user_stats (
-id varchar(24) NOT NULL,
-datestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-browser varchar(32) NOT NULL,
-browserVersion varchar(8) NOT NULL,
-ipaddress varchar(15) NOT NULL,
-referrer varchar(512) NOT NULL,
-url varchar(512) NOT NULL,
-session varchar(64) NOT NULL,
-PRIMARY KEY (id)
-);
-
--- --------------------------------------------------------
-
 --
 -- Table structure for table record
 --
@@ -294,7 +255,7 @@ CREATE TABLE record (
 
 -- --------------------------------------------------------
 
--- 
+--
 -- Table structure for table user_card
 --
 
diff --git a/module/VuFind/src/VuFind/Config/Upgrade.php b/module/VuFind/src/VuFind/Config/Upgrade.php
index b2de88ca5bc..8e92c1a67f3 100644
--- a/module/VuFind/src/VuFind/Config/Upgrade.php
+++ b/module/VuFind/src/VuFind/Config/Upgrade.php
@@ -552,6 +552,15 @@ class Upgrade
             unset($newConfig['BulkExport']['options']);
         }
 
+        // If [Statistics] is present, warn the user about its deprecation.
+        if (isset($newConfig['Statistics'])) {
+            $this->addWarning(
+                'The Statistics module has been removed from Vufind. ' .
+                'For usage tracking, please configure Google Analytics or Piwik.'
+            );
+            unset($newConfig['Statistics']);
+        }
+
         // Warn the user about Amazon configuration issues:
         $this->checkAmazonConfig($newConfig);
 
@@ -644,17 +653,6 @@ class Upgrade
         // Eliminate obsolete config override settings:
         unset($newConfig['Extra_Config']);
 
-        // Update stats settings:
-        if (isset($newConfig['Statistics']['enabled'])) {
-            // If "enabled" is on, this equates to the new system being in Solr mode:
-            if ($newConfig['Statistics']['enabled']) {
-                $newConfig['Statistics']['mode'] = ['Solr'];
-            }
-
-            // Whether or not "enabled" is on, remove the deprecated setting:
-            unset($newConfig['Statistics']['enabled']);
-        }
-
         // Update generator if it is default value:
         if (isset($newConfig['Site']['generator'])
             && $newConfig['Site']['generator'] == 'VuFind ' . $this->from
diff --git a/module/VuFind/src/VuFind/Controller/AbstractRecord.php b/module/VuFind/src/VuFind/Controller/AbstractRecord.php
index 7d1ecf9d99f..8eff8bfae86 100644
--- a/module/VuFind/src/VuFind/Controller/AbstractRecord.php
+++ b/module/VuFind/src/VuFind/Controller/AbstractRecord.php
@@ -69,13 +69,6 @@ class AbstractRecord extends AbstractBase
      */
     protected $searchClassId = 'Solr';
 
-    /**
-     * Should we log statistics?
-     *
-     * @var bool
-     */
-    protected $logStatistics = true;
-
     /**
      * Record driver
      *
@@ -258,12 +251,6 @@ class AbstractRecord extends AbstractBase
      */
     public function homeAction()
     {
-        // Save statistics:
-        if ($this->logStatistics) {
-            $this->getServiceLocator()->get('VuFind\RecordStats')
-                ->log($this->loadRecord(), $this->getRequest());
-        }
-
         return $this->showTab(
             $this->params()->fromRoute('tab', $this->getDefaultTab())
         );
diff --git a/module/VuFind/src/VuFind/Controller/AbstractSearch.php b/module/VuFind/src/VuFind/Controller/AbstractSearch.php
index 6ce2ba82bb7..c7e20cc4a30 100644
--- a/module/VuFind/src/VuFind/Controller/AbstractSearch.php
+++ b/module/VuFind/src/VuFind/Controller/AbstractSearch.php
@@ -54,13 +54,6 @@ class AbstractSearch extends AbstractBase
      */
     protected $saveToHistory = true;
 
-    /**
-     * Should we log search statistics?
-     *
-     * @var bool
-     */
-    protected $logStatistics = true;
-
     /**
      * Should we remember the search for breadcrumb purposes?
      *
@@ -311,12 +304,6 @@ class AbstractSearch extends AbstractBase
             }
         }
 
-        // Save statistics:
-        if ($this->logStatistics) {
-            $this->getServiceLocator()->get('VuFind\SearchStats')
-                ->log($results, $this->getRequest());
-        }
-
         // Special case: If we're in RSS view, we need to render differently:
         if (isset($view->params) && $view->params->getView() == 'rss') {
             $response = $this->getResponse();
diff --git a/module/VuFind/src/VuFind/Db/Table/UserStats.php b/module/VuFind/src/VuFind/Db/Table/UserStats.php
deleted file mode 100644
index ea4203eb692..00000000000
--- a/module/VuFind/src/VuFind/Db/Table/UserStats.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-/**
- * Table Definition for statistics (user data)
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Db_Table
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Db\Table;
-
-use Zend\Db\Sql\Expression;
-
-/**
- * Table Definition for user statistics
- *
- * @category VuFind
- * @package  Db_Table
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class UserStats extends Gateway
-{
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        parent::__construct('user_stats');
-    }
-
-    /**
-     * Returns the list of most popular browsers with use counts
-     *
-     * @param bool $withVersions Include browser version numbers?
-     * True = versions (Firefox 12.0) False = names only (Firefox).
-     * @param int  $limit        How many to return
-     *
-     * @return array
-     */
-    public function getBrowserStats($withVersions = false, $limit = 5)
-    {
-        $callback = function ($select) use ($withVersions, $limit) {
-            if ($withVersions) {
-                $select->columns(
-                    [
-                        'browserName' => new Expression(
-                            'CONCAT_WS(" ",?,?)',
-                            ['browser', 'browserVersion'],
-                            [
-                                Expression::TYPE_IDENTIFIER,
-                                Expression::TYPE_IDENTIFIER
-                            ]
-                        ),
-                        'count' => new Expression(
-                            'COUNT(DISTINCT (?))',
-                            ['session'],
-                            [Expression::TYPE_IDENTIFIER]
-                        )
-                    ]
-                );
-                $select->group('browserName');
-            } else {
-                $select->columns(
-                    [
-                        'browserName' => 'browser',
-                        'count' => new Expression(
-                            'COUNT(DISTINCT (?))',
-                            ['session'],
-                            [Expression::TYPE_IDENTIFIER]
-                        )
-                    ]
-                );
-                $select->group('browser');
-            }
-            $select->limit($limit);
-            $select->order('count DESC');
-        };
-        
-        return $this->select($callback)->toArray();
-    }
-}
diff --git a/module/VuFind/src/VuFind/Db/Table/UserStatsFields.php b/module/VuFind/src/VuFind/Db/Table/UserStatsFields.php
deleted file mode 100644
index 3a833e08721..00000000000
--- a/module/VuFind/src/VuFind/Db/Table/UserStatsFields.php
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/**
- * Table Definition for statistics
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Db_Table
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Db\Table;
-
-/**
- * Table Definition for statistics
- *
- * @category VuFind
- * @package  Db_Table
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class UserStatsFields extends Gateway
-{
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        parent::__construct('user_stats_fields');
-    }
-
-    /**
-     * Save data to the DB, data to statistics, user data in user_stats
-     *
-     * @param array $stats    data indexed by column name
-     * @param array $userData data indexed by
-     * id, timestamp, browser, ipaddress, referrer, url
-     *
-     * @return null
-     */
-    public function save($stats, $userData)
-    {
-        // Statistics data
-        foreach ($stats as $field => $value) {
-            if (gettype($value) == "boolean") {
-                $value = ($value) ? "true" : "false";
-            }
-            $this->insert(
-                [
-                    'id'    => $userData['id'],
-                    'field' => $field . "",
-                    'value' => $value . "",
-                ]
-            );
-        }
-        // User data
-        $userStats = $this->getDbTable('UserStats');
-        $userStats->insert($userData);
-    }
-
-    /**
-     * Get data for these fields
-     *
-     * @param array $fields What fields of data are we researching?
-     * @param array $values Values to match while we search
-     *
-     * @return associative array
-     */
-    public function getFields($fields, $values = [])
-    {
-        if (empty($fields)) {
-            return null;
-        }
-        if (!is_array($fields)) {
-            $fields = [$fields];
-        }
-        $callback = function ($select) use ($fields, $values) {
-            $select->columns(
-                [$fields[0] => 'value']
-            );
-            $select->where->equalTo('field', $fields[0]);
-            for ($i = 1;$i < count($fields);$i++) {
-                $select->where->equalTo('field' . $i . '.field', $fields[$i]);
-                $select->join(
-                    ['field' . $i => 'user_stats_fields'],
-                    'user_stats_fields.id=field' . $i . '.id',
-                    [$fields[$i] => 'field' . $i . '.value']
-                );
-            }
-            foreach ($values as $key => $value) {
-                $select->where->equalTo($key, $value);
-            }
-        };
-        
-        return $this->select($callback);
-    }
-}
diff --git a/module/VuFind/src/VuFind/Search/Factory/SolrStatsBackendFactory.php b/module/VuFind/src/VuFind/Search/Factory/SolrStatsBackendFactory.php
deleted file mode 100644
index 439744f2d69..00000000000
--- a/module/VuFind/src/VuFind/Search/Factory/SolrStatsBackendFactory.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-/**
- * Factory for the default SOLR backend.
- *
- * PHP version 5
- *
- * Copyright (C) Villanova University 2013.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Search
- * @author   David Maus <maus@hab.de>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Search\Factory;
-
-use VuFindSearch\Backend\Solr\Backend;
-
-/**
- * Factory for the default SOLR backend.
- *
- * @category VuFind
- * @package  Search
- * @author   David Maus <maus@hab.de>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class SolrStatsBackendFactory extends AbstractSolrBackendFactory
-{
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        parent::__construct();
-        $this->solrCore = 'stats';
-        $this->searchConfig = 'searches';
-        $this->searchYaml = 'searchspecs.yaml';
-        $this->facetConfig = 'facets';
-    }
-
-    /**
-     * Get the Solr URL.
-     *
-     * @return string
-     */
-    protected function getSolrUrl()
-    {
-        $config = $this->config->get('config');
-        $base = isset($config->Statistics->solr)
-            ? $config->Statistics->solr : $config->Index->url;
-        return $base . '/' . $this->getSolrCore();
-    }
-}
diff --git a/module/VuFind/src/VuFind/Service/Factory.php b/module/VuFind/src/VuFind/Service/Factory.php
index 39a46be00f3..0118867d1f1 100644
--- a/module/VuFind/src/VuFind/Service/Factory.php
+++ b/module/VuFind/src/VuFind/Service/Factory.php
@@ -625,22 +625,6 @@ class Factory
         );
     }
 
-    /**
-     * Construct the record stats helper.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return \VuFind\Statistics\Record
-     */
-    public static function getRecordStats(ServiceManager $sm)
-    {
-        return new \VuFind\Statistics\Record(
-            $sm->get('VuFind\Config')->get('config'),
-            $sm->get('VuFind\StatisticsDriverPluginManager'),
-            $sm->get('VuFind\SessionManager')->getId()
-        );
-    }
-
     /**
      * Construct the RecordTab Plugin Manager.
      *
@@ -775,22 +759,6 @@ class Factory
         );
     }
 
-    /**
-     * Construct the search stats helper.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return \VuFind\Statistics\Search
-     */
-    public static function getSearchStats(ServiceManager $sm)
-    {
-        return new \VuFind\Statistics\Search(
-            $sm->get('VuFind\Config')->get('config'),
-            $sm->get('VuFind\StatisticsDriverPluginManager'),
-            $sm->get('VuFind\SessionManager')->getId()
-        );
-    }
-
     /**
      * Construct the SearchTabs helper.
      *
@@ -839,18 +807,6 @@ class Factory
         );
     }
 
-    /**
-     * Construct the Statistics\Driver Plugin Manager.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return \VuFind\Statistics\Driver\PluginManager
-     */
-    public static function getStatisticsDriverPluginManager(ServiceManager $sm)
-    {
-        return static::getGenericPluginManager($sm, 'Statistics\Driver');
-    }
-
     /**
      * Construct the tag helper.
      *
diff --git a/module/VuFind/src/VuFind/Statistics/AbstractBase.php b/module/VuFind/src/VuFind/Statistics/AbstractBase.php
deleted file mode 100644
index 4ca00530e4e..00000000000
--- a/module/VuFind/src/VuFind/Statistics/AbstractBase.php
+++ /dev/null
@@ -1,250 +0,0 @@
-<?php
-/**
- * VuFind Stastics Controller
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Page
- */
-namespace VuFind\Statistics;
-use VuFind\Statistics\Driver\PluginManager, Zend\Config\Config;
-
-/**
- * VuFind Search Controller
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Page
- */
-abstract class AbstractBase
-{
-    /**
-     * Array of statistics drivers (null if not yet initialized)
-     *
-     * @var array
-     */
-    protected $drivers = null;
-
-    /**
-     * An identifier of the source of the current set of statistics
-     *
-     * @var string
-     */
-    protected $source;
-
-    /**
-     * Session ID
-     *
-     * @var string
-     */
-    protected $sessId;
-
-    /**
-     * Statistics driver plugin manager
-     *
-     * @var PluginManager
-     */
-    protected $pluginManager;
-
-    /**
-     * VuFind configuration
-     *
-     * @var Config
-     */
-    protected $config;
-
-    /**
-     * Constructor
-     *
-     * @param Config        $config VuFind configuration
-     * @param PluginManager $pm     Statistics driver plugin manager
-     * @param string        $sessId Session ID
-     */
-    public function __construct(Config $config, PluginManager $pm, $sessId)
-    {
-        $this->config = $config;
-        // Source pulled from class name
-        $source = explode('\\', get_class($this));
-        $this->source = end($source);
-        $this->pluginManager = $pm;
-        $this->sessId = $sessId;
-    }
-    
-    /**
-     * Get the stat drivers.
-     *
-     * @return array
-     */
-    protected function getDrivers()
-    {
-        if (null === $this->drivers) {
-            $this->drivers = $this->getDriversForSource($this->source);
-        }
-        return $this->drivers;
-    }
-
-    /**
-     * Create an array of statistics drivers that log a particular type of data.
-     *
-     * @param string $source Name of data type, or null to only obtain objects which
-     * log ALL data types.
-     * @param bool   $getAll If set to true, this parameter causes the method to
-     * ignore $source and return every driver object.  This should only be used
-     * when reading data, never when writing.
-     *
-     * @return array
-     */
-    public function getDriversForSource($source, $getAll = false)
-    {
-        $drivers = [];
-
-        // For each mode
-        if (isset($this->config->Statistics->mode)) {
-            foreach ($this->config->Statistics->mode as $config) {
-                $setting = explode(':', $config);
-
-                // If the config setting has a limiter, we may need to skip this
-                // record, so we should do some checks (unless we're set to accept
-                // any match through the $getAll parameter).
-                if (count($setting) > 1 && !$getAll) {
-                    // If we only want global drivers, we don't want anything with
-                    // limits.
-                    if (null === $source) {
-                        continue;
-                    }
-
-                    // If we got this far, we know that $source is not null; let's
-                    // see if the requested source is supported.
-                    $legalOptions = array_map('trim', explode(',', $setting[1]));
-                    if (!in_array($source, $legalOptions)) {
-                        continue;
-                    }
-                }
-
-                // If we got this far, we want the current option!  Build the driver:
-                $newDriver = $this->pluginManager->get($setting[0]);
-
-                // Set the name of the data source;  we use the special value
-                // "global" to represent global writer requests (the special null
-                // case):
-                $newDriver->setSource(null === $source ? 'global' : $source);
-                $drivers[] = $newDriver;
-            }
-        }
-
-        return $drivers;
-    }
-
-    /**
-     * Chooses the appropriate saving actions and formats based on config
-     *
-     * @param array                        $data    Associative array of data
-     * @param Zend_Controller_Request_Http $request Request data from the controller
-     *
-     * @return void
-     */
-    protected function save($data, $request)
-    {
-        $drivers = $this->getDrivers();
-        if (!empty($drivers)) {
-            $userData = $this->getUserData($request);
-            foreach ($drivers as $writer) {
-                $writer->write($data, $userData);
-            }
-        }
-    }
-
-    /**
-     * Returns a count and most used list
-     *
-     * @param int  $listLength How long the top list is
-     * @param bool $bySource   Sort data by source?
-     *
-     * @return mixed
-     */
-    abstract public function getStatsSummary($listLength, $bySource);
-
-    /**
-     * Returns the common information available without data
-     *
-     * @param Zend_Controller_Request_Http $request Request data from the controller
-     *
-     * @return array commonData
-     */
-    protected function getUserData($request)
-    {
-        $server = $request->getServer();
-        $agent = $server->get('HTTP_USER_AGENT');
-        $parts = explode(' ', $this->getBrowser($agent));
-        $browser = $parts[0];
-        $version = isset($parts[1]) ? $parts[1] : '';
-        return [
-            'id'               => uniqid('', true),
-            'datestamp'        => substr(date('c', strtotime('now')), 0, -6) . 'Z',
-            'browser'          => $browser,
-            'browserVersion'   => $version,
-            'ipaddress'        => $server->get('REMOTE_ADDR'),
-            'referrer'         => ($server->get('HTTP_REFERER') == null)
-                ? 'Manual'
-                : $server->get('HTTP_REFERER'),
-            'url'              => $server->get('REQUEST_URI'),
-            'session'          => $this->sessId
-        ];
-    }
-
-    /**
-     * Parse the browser name and version from the agent string
-     *
-     * @param string $agent Browser user agent string
-     *
-     * @return string browser name and version
-     */
-    public function getBrowser($agent)
-    {
-        // Try to use browscap.ini if available:
-        $browser = @get_browser($agent, true);
-        if (isset($browser['parent'])) {
-            return $browser['parent'];
-        }
-
-        // If browscap.ini didn't work, do our best:
-        if (strpos($agent, "Opera") > -1) {
-            $split = explode(' ', $agent);
-            return str_replace('/', ' ', $split[0]);
-        }
-        if (strpos($agent, "Chrome") > -1) {
-            $split = explode(' ', $agent);
-            return str_replace('/', ' ', $split[count($split) - 2]);
-        }
-        if (strpos($agent, "Firefox") > -1 || strpos($agent, "Safari") > -1) {
-            $split = explode(' ', $agent);
-            return str_replace('/', ' ', end($split));
-        }
-        if (strpos($agent, "compatible;") > -1) {
-            $data = explode("compatible;", $agent);
-            $split = preg_split('/[;\)]/', $data[1]);
-            return str_replace('/', ' ', trim($split[0]));
-        }
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/AbstractBase.php b/module/VuFind/src/VuFind/Statistics/Driver/AbstractBase.php
deleted file mode 100644
index 63228f80d56..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/AbstractBase.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-/**
- * Abstract Base for Statistics Drivers
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Statistics\Driver;
-
-/**
- * Base driver for statistics
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-abstract class AbstractBase
-{
-    /**
-     * Statistics source
-     *
-     * @var string
-     */
-    protected $source = null;
-
-    /**
-     * Get the source that is using the statistics.
-     *
-     * @return string
-     */
-    public function getSource()
-    {
-        return $this->source;
-    }
-
-    /**
-     * Set the source that is using the statistics.
-     *
-     * @param string $source Name of source.
-     *
-     * @return void
-     */
-    public function setSource($source)
-    {
-        $this->source = $source;
-    }
-
-    /**
-     * Write a message to the log.
-     *
-     * @param array $data     Data specific to what we're saving
-     * @param array $userData Browser, IP, urls, etc
-     *
-     * @return void
-     */
-    abstract public function write($data, $userData);
-
-    /**
-     * Get all the instances of a field.
-     *
-     * @param string $field What field of data are we researching?
-     * @param array  $value Extra options for search. Value => match this value
-     *
-     * @return array
-     *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function getFullList($field, $value = [])
-    {
-        // Assume no statistics
-        return [];
-    }
-
-    /**
-     * Returns browser usage statistics
-     *
-     * @param bool $version Include the version numbers in the list
-     * @param int  $limit   How many items to return
-     *
-     * @return array
-     *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function getBrowserStats($version, $limit)
-    {
-        // Assume no statistics
-        return [];
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/Db.php b/module/VuFind/src/VuFind/Statistics/Driver/Db.php
deleted file mode 100644
index e8715af68b0..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/Db.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-/**
- * Database Statistics Driver
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Statistics\Driver;
-
-/**
- * Writer to put statistics into the DB
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class Db extends AbstractBase implements \VuFind\Db\Table\DbTableAwareInterface
-{
-    use \VuFind\Db\Table\DbTableAwareTrait;
-
-    /**
-     * Write a message to the log.
-     *
-     * @param array $data     Data specific to what we're saving
-     * @param array $userData Browser, IP, urls, etc
-     *
-     * @return void
-     */
-    public function write($data, $userData)
-    {
-        // Unset the coded-in datestamp, since the database will auto-generate
-        // it internally with greater accuracy.
-        unset($userData['datestamp']);
-
-        // Make sure the browser version is a legal length.
-        $userData['browserVersion'] = substr($userData['browserVersion'], 0, 8);
-
-        $this->getDbTable('UserStatsFields')->save($data, $userData);
-    }
-
-    /**
-     * Get all the instances of a field.
-     *
-     * @param string $field What field of data are we researching?
-     * @param array  $value Extra options for search. Value => match this value
-     *
-     * @return array
-     */
-    public function getFullList($field, $value = [])
-    {
-        // Use the model
-        return $this->getDbTable('UserStatsFields')->getFields($field, $value)
-            ->toArray();
-    }
-
-    /**
-     * Returns browser usage statistics
-     *
-     * @param bool $version Include the version numbers in the list
-     * @param int  $limit   How many items to return
-     *
-     * @return array
-     */
-    public function getBrowserStats($version, $limit)
-    {
-        $userStats = $this->getDbTable('UserStats');
-        return $userStats->getBrowserStats($version, $limit);
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/Factory.php b/module/VuFind/src/VuFind/Statistics/Driver/Factory.php
deleted file mode 100644
index ff8c7b31a04..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/Factory.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-/**
- * Statistics Driver Factory Class
- *
- * PHP version 5
- *
- * Copyright (C) Villanova University 2014.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:plugins:hierarchy_components Wiki
- */
-namespace VuFind\Statistics\Driver;
-use Zend\ServiceManager\ServiceManager;
-
-/**
- * Statistics Driver Factory Class
- *
- * @category VuFind
- * @package  Statistics
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:plugins:hierarchy_components Wiki
- *
- * @codeCoverageIgnore
- */
-class Factory
-{
-    /**
-     * Factory for File driver.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return File
-     */
-    public static function getFile(ServiceManager $sm)
-    {
-        $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config');
-        $folder = isset($config->Statistics->file)
-            ? $config->Statistics->file : sys_get_temp_dir();
-        return new File($folder);
-    }
-
-    /**
-     * Factory for Solr driver.
-     *
-     * @param ServiceManager $sm Service manager.
-     *
-     * @return Solr
-     */
-    public static function getSolr(ServiceManager $sm)
-    {
-        return new Solr(
-            $sm->getServiceLocator()->get('VuFind\Solr\Writer'),
-            $sm->getServiceLocator()->get('VuFind\Search\BackendManager')
-                ->get('SolrStats')
-        );
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/File.php b/module/VuFind/src/VuFind/Statistics/Driver/File.php
deleted file mode 100644
index 62707954a70..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/File.php
+++ /dev/null
@@ -1,126 +0,0 @@
-<?php
-/**
- * File Statistics Driver
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Statistics\Driver;
-
-/**
- * Writer to put statistics into an XML File
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class File extends AbstractBase
-{
-    /**
-     * Folder where stats will be written.
-     *
-     * @var string
-     */
-    protected $folder;
-
-    /**
-     * Constructor
-     *
-     * @param string $folder Folder where stats will be written.
-     */
-    public function __construct($folder)
-    {
-        $this->folder = $folder;
-    }
-
-    /**
-     * Get the name of the folder for storing statistics.
-     *
-     * @return string
-     */
-    protected function getFolder()
-    {
-        return $this->folder;
-    }
-
-    /**
-     * Write a message to the log.
-     *
-     * @param array $data     Data specific to what we're saving
-     * @param array $userData Browser, IP, urls, etc
-     *
-     * @throws \Exception
-     * @return void
-     */
-    public function write($data, $userData)
-    {
-        $xml = $this->getSaveXML(array_merge($data, $userData), 1);
-        $filename = rtrim($this->getFolder(), '/');
-        if (!file_exists($filename)) {
-            mkdir($filename);
-        }
-        $file = strtolower($this->getSource());
-        $index = (strrpos($file, '.')) ? -1 : strlen($file);
-        $filename .= '/' . substr($file, 0, $index) . '.xml';
-        if (file_exists($filename)) {
-            $file = file_get_contents($filename);
-            // remove <xml .. >
-            $xml .= "\n" . substr($file, 39, strlen($file));
-        } else {
-            $xml .= "\n</xml>";
-        }
-        $file = fopen($filename, 'w');
-        if (!$file) {
-            throw new \Exception('Cannot write to log file.');
-        }
-        fwrite($file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" . $xml);
-        fclose($file);
-    }
-
-    /**
-     * Convert data array to XML
-     *
-     * @param array $data Associative array of data
-     * @param int   $tab  How far the string should be indented with tabs
-     *
-     * @return string
-     */
-    protected function getSaveXML($data, $tab = 0)
-    {
-        $xml = str_repeat("\t", $tab) . "<doc>\n";
-        $tab++;
-        foreach ($data as $tag => $value) {
-            $xml .= str_repeat("\t", $tab);
-            $insert = (strtolower(gettype($value)) == 'boolean')
-                ? ($value)
-                    ? 'true'
-                    : 'false'
-                : $value;
-            $xml .= '<field name="' . $tag . '">' . $insert . "</field>\n";
-        }
-        $tab--;
-        return $xml . str_repeat("\t", $tab) . "</doc>";
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/PluginFactory.php b/module/VuFind/src/VuFind/Statistics/Driver/PluginFactory.php
deleted file mode 100644
index f68608acb45..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/PluginFactory.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * Statistics 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:plugins:statistics_drivers Wiki
- */
-namespace VuFind\Statistics\Driver;
-
-/**
- * Statistics driver plugin factory
- *
- * @category VuFind
- * @package  Statistics
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:plugins:statistics_drivers Wiki
- */
-class PluginFactory extends \VuFind\ServiceManager\AbstractPluginFactory
-{
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        $this->defaultNamespace = 'VuFind\Statistics\Driver';
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/PluginManager.php b/module/VuFind/src/VuFind/Statistics/Driver/PluginManager.php
deleted file mode 100644
index ce032a9b356..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/PluginManager.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * Statistics 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:plugins:statistics_drivers Wiki
- */
-namespace VuFind\Statistics\Driver;
-use Zend\ServiceManager\ConfigInterface;
-
-/**
- * Statistics driver plugin manager
- *
- * @category VuFind
- * @package  Statistics
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:plugins:statistics_drivers Wiki
- */
-class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
-{
-    /**
-     * Constructor
-     *
-     * @param ConfigInterface $configuration Configuration settings (optional)
-     */
-    public function __construct(ConfigInterface $configuration = null)
-    {
-        // Stats drivers are not meant to be shared -- every time we retrieve one,
-        // we are building a brand new object.
-        $this->setShareByDefault(false);
-
-        parent::__construct($configuration);
-    }
-
-    /**
-     * Return the name of the base class or interface that plug-ins must conform
-     * to.
-     *
-     * @return string
-     */
-    protected function getExpectedInterface()
-    {
-        return 'VuFind\Statistics\Driver\AbstractBase';
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Driver/Solr.php b/module/VuFind/src/VuFind/Statistics/Driver/Solr.php
deleted file mode 100644
index 87da4d8aadc..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Driver/Solr.php
+++ /dev/null
@@ -1,182 +0,0 @@
-<?php
-/**
- * Solr Statistics Driver
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFind\Statistics\Driver;
-use VuFind\Solr\Writer;
-use VuFindSearch\Backend\Solr\Backend;
-use VuFindSearch\Query\Query;
-use VuFindSearch\ParamBag;
-
-/**
- * Writer to put statistics to the Solr index
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class Solr extends AbstractBase
-{
-    /**
-     * Solr writer
-     *
-     * @var Writer
-     */
-    protected $solrWriter;
-
-    /**
-     * Solr backend
-     *
-     * @var Backend
-     */
-    protected $solrBackend;
-
-    /**
-     * Constructor
-     *
-     * @param Writer  $writer  Solr writer
-     * @param Backend $backend Solr backend
-     */
-    public function __construct(Writer $writer, Backend $backend)
-    {
-        $this->solrWriter = $writer;
-        $this->solrBackend = $backend;
-    }
-
-    /**
-     * Write a message to the log.     *
-     *
-     * @param array $data     Data specific to what we're saving
-     * @param array $userData Browser, IP, urls, etc
-     *
-     * @return void
-     */
-    public function write($data, $userData)
-    {
-        if (isset($data['phrase']) && $data['phrase'] == '') {
-            $data['phrase'] = '*:*';
-        }
-        $update = new \VuFindSearch\Backend\Solr\Document\UpdateDocument();
-        $update->addRecord(
-            new \VuFindSearch\Backend\Solr\Record\SerializableRecord(
-                array_merge($data, $userData)
-            )
-        );
-        $this->solrWriter->save('SolrStats', $update);
-    }
-
-    /**
-     * Get the total count of a field.
-     *
-     * @param string $field What field of data are we researching?
-     * @param array  $value Extra options for search. Value => match this value
-     *
-     * @return array
-     */
-    public function getFullList($field, $value = ['value' => '[* TO *]'])
-    {
-        $query = new Query($field . ':' . $value['value']);
-        $params = new ParamBag();
-        $params->add('fl', $field);
-        $start = 0;
-        $limit = 1000;
-        $data = [];
-        do {
-            $response = $this->solrBackend->search($query, $start, $limit, $params);
-            $records = $response->getRecords();
-            foreach ($records as $doc) {
-                $data[] = [$field => $doc->$field];
-            }
-            $start += $limit;
-        } while (count($records) > 0);
-        return $data;
-    }
-
-    /**
-     * Returns browser usage statistics
-     *
-     * @param bool $version    Include the version numbers in the list
-     * @param int  $listLength How many items to return
-     *
-     * @return array
-     */
-    public function getBrowserStats($version, $listLength = 5)
-    {
-        $query = new Query('*:*');
-        $params = new ParamBag();
-        $params->add('fl', 'browser,browserVersion');
-        $params->add('group', 'true');
-        $params->add('group.field', 'session');
-        $start = 0;
-        $limit = 1000;
-        $hashes = [];
-        do {
-            $response = $this->solrBackend->search($query, $start, $limit, $params);
-            $groups = $response->getGroups();
-            foreach ($groups['session']['groups'] as $group) {
-                if ($version) {
-                    // Version specific
-                    $browser = $group['doclist']['docs'][0]['browser']
-                        . ' ' . $group['doclist']['docs'][0]['browserVersion'];
-                    if (isset($hashes[$browser])) {
-                        $hashes[$browser] ++;
-                    } elseif (count($hashes) < $limit) {
-                        $hashes[$browser] = 1;
-                    }
-                } else {
-                    // Browser name
-                    if (isset($hashes[$group['doclist']['docs'][0]['browser']])) {
-                        $hashes[$group['doclist']['docs'][0]['browser']] ++;
-                    } elseif (count($hashes) < $limit) {
-                        $hashes[$group['doclist']['docs'][0]['browser']] = 1;
-                    }
-                }
-            }
-            $start += $limit;
-        } while (count($groups['session']['groups']) > 0);
-        $solrBrowsers = [];
-        foreach ($hashes as $browser => $count) {
-            $newBrowser = [
-                'browserName' => $browser,
-                'count' => $count
-            ];
-            // Insert sort (limit to listLength)
-            for ($i = 0;$i < $listLength - 1 && $i < count($solrBrowsers);$i++) {
-                if ($count > $solrBrowsers[$i]['count']) {
-                    // Insert in order
-                    array_splice($solrBrowsers, $i, 0, [$newBrowser]);
-                    continue 2; // Skip the append after this loop
-                }
-            }
-            if (count($solrBrowsers) < $listLength) {
-                $solrBrowsers[] = $newBrowser;
-            }
-        }
-        return $solrBrowsers;
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Record.php b/module/VuFind/src/VuFind/Statistics/Record.php
deleted file mode 100644
index 8446a030739..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Record.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-/**
- * VuFind Statistics Class for Record Views
- *
- * PHP version 5
- *
- * Copyright (C) Villanova University 2009.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development Wiki
- */
-namespace VuFind\Statistics;
-
-/**
- * VuFind Statistics Class for Record Views
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development Wiki
- */
-class Record extends AbstractBase
-{
-    /**
-     * Saves the record view to wherever the config [Statistics] says so
-     *
-     * @param \VuFind\Search\Base\Results  $data    Results from Search controller
-     * @param Zend_Controller_Request_Http $request Request data
-     *
-     * @return void
-     */
-    public function log($data, $request)
-    {
-        $this->save(
-            [
-                'recordId'     => $data->getUniqueId(),
-                'recordSource' => $data->getSourceIdentifier()
-            ],
-            $request
-        );
-    }
-
-    /**
-     * Returns a set of basic statistics including total records
-     * and most commonly viewed records.
-     *
-     * @param int  $listLength How long the top list is
-     * @param bool $bySource   Sort record views by source?
-     *
-     * @return array
-     */
-    public function getStatsSummary($listLength = 5, $bySource = false)
-    {
-        foreach ($this->getDrivers() as $driver) {
-            $summary = $driver->getFullList('recordId');
-            if (!empty($summary)) {
-                $sources = $driver->getFullList('recordSource');
-                $hashes = [];
-                // Generate hashes (faster than grouping by looping)
-                for ($i = 0;$i < count($summary);$i++) {
-                    $source = $sources[$i]['recordSource'];
-                    $id = $summary[$i]['recordId'];
-                    $hashes[$source][$id]
-                        = isset($hashes[$source][$id])
-                        ? $hashes[$source][$id] + 1
-                        : 1;
-                }
-                $top = [];
-                // For each source
-                foreach ($hashes as $source => $records) {
-                    // Using a reference to consolidate code dramatically
-                    $reference = & $top;
-                    if ($bySource) {
-                        $top[$source] = [];
-                        $reference = & $top[$source];
-                    }
-                    // For each record
-                    foreach ($records as $id => $count) {
-                        $newRecord = [
-                            'value'  => $id,
-                            'count'  => $count,
-                            'source' => $source
-                        ];
-                        // Insert sort (limit to listLength)
-                        $refCount = count($reference);
-                        for ($i = 0; $i < $listLength - 1 && $i < $refCount; $i++) {
-                            if ($count > $reference[$i]['count']) {
-                                // Insert in order
-                                array_splice($reference, $i, 0, [$newRecord]);
-                                continue 2; // Skip the append after this loop
-                            }
-                        }
-                        if (count($reference) < $listLength) {
-                            $reference[] = $newRecord;
-                        }
-                    }
-                    $reference = array_slice($reference, 0, $listLength);
-                }
-                return [
-                    'top'   => $top,
-                    'total' => count($summary)
-                ];
-            }
-        }
-        return [];
-    }
-}
diff --git a/module/VuFind/src/VuFind/Statistics/Search.php b/module/VuFind/src/VuFind/Statistics/Search.php
deleted file mode 100644
index 7e1d9c89e68..00000000000
--- a/module/VuFind/src/VuFind/Statistics/Search.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-/**
- * VuFind Statistics Class for Searches
- *
- * PHP version 5
- *
- * Copyright (C) Villanova University 2009.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development Wiki
- */
-namespace VuFind\Statistics;
-
-/**
- * VuFind Statistics Class for Searches
- *
- * @category VuFind
- * @package  Statistics
- * @author   Chris Hallberg <challber@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development Wiki
- */
-class Search extends AbstractBase
-{
-    /**
-     * Saves the search to wherever the config [Statistics] says so
-     *
-     * @param \VuFind\Search\Base\Results  $data    Results from Search controller
-     * @param Zend_Controller_Request_Http $request Request data from the controller
-     *
-     * @return void
-     */
-    public function log($data, $request)
-    {
-        $stat = [
-            'phrase'       => $data->getParams()->getDisplayQuery(),
-            'searchSource' => $data->getParams()->getSearchClassId(),
-            'type'         => $data->getParams()->getSearchHandler(),
-            'resultCount'  => $data->getResultTotal(),
-            'noresults'    => $data->getResultTotal() == 0
-        ];
-        $this->save($stat, $request);
-    }
-
-    /**
-     * Returns a set of basic statistics including total searches,
-     * number of empty searches and most popular search terms.
-     *
-     * @param int  $listLength Number of top searches to return
-     * @param bool $bySource   Separate searches by search source?
-     *
-     * @return array
-     */
-    public function getStatsSummary($listLength = 5, $bySource = false)
-    {
-        foreach ($this->getDrivers() as $driver) {
-            $summary = $driver->getFullList('phrase');
-            if (!empty($summary)) {
-                $sources = $driver->getFullList('searchSource');
-                $hashes = [];
-                // Generate hashes (faster than grouping by looping)
-                for ($i = 0;$i < count($summary);$i++) {
-                    if (!isset($sources[$i]['searchSource'])) {
-                        $sources[$i]['searchSource'] = 'Search';
-                    } else {
-                        // Escape multivalue index
-                        $sources[$i]['searchSource']
-                            = implode(', ', (Array)$sources[$i]['searchSource']);
-                    }
-                    // Escape multivalue index
-                    $summary[$i]['phrase']
-                        = implode(', ', (Array)$summary[$i]['phrase']);
-                    // Store everything in a string array for fast sorting later
-                    $source = $sources[$i]['searchSource'];
-                    $hashes[$source][$summary[$i]['phrase']]
-                        = isset($hashes[$source][$summary[$i]['phrase']])
-                        ? $hashes[$source][$summary[$i]['phrase']] + 1
-                        : 1;
-                }
-                $top = [];
-                // For each source
-                foreach ($hashes as $source => $records) {
-                    // Using a reference to consolidate code dramatically
-                    $reference = & $top;
-                    if ($bySource) {
-                        $top[$source] = [];
-                        $reference = & $top[$source];
-                    }
-                    // For each record
-                    foreach ($records as $phrase => $count) {
-                        $value = ($phrase == '' || $phrase == '*:*')
-                            ? '(empty)'
-                            : $phrase;
-                        $newRecord = [
-                            'value'  => $value,
-                            'count'  => $count,
-                            'source' => $source
-                        ];
-                        // Insert sort (limit to listLength)
-                        $refCount = count($reference);
-                        for ($i = 0; $i < $listLength - 1 && $i < $refCount; $i++) {
-                            if ($count > $reference[$i]['count']) {
-                                // Insert in order
-                                array_splice($reference, $i, 0, [$newRecord]);
-                                continue 2; // Skip the append after this loop
-                            }
-                        }
-                        if (count($reference) < $listLength) {
-                            $reference[] = $newRecord;
-                        }
-                    }
-                    $reference = array_slice($reference, 0, $listLength);
-                }
-                return [
-                    'top'   => $top,
-                    'total' => count($summary),
-                    'empty' => count(
-                        $driver->getFullList('noresults', ['value' => 'true'])
-                    )
-                ];
-            }
-        }
-        return [];
-    }
-}
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php
index 1fa326424f5..a9e21903bd2 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php
@@ -89,7 +89,10 @@ class UpgradeTest extends \VuFindTest\Unit\TestCase
 
         // Prior to 2.4, we expect exactly one warning about using a deprecated
         // theme:
-        $expectedWarnings = [];
+        $expectedWarnings = [
+            'The Statistics module has been removed from Vufind. '
+            . 'For usage tracking, please configure Google Analytics or Piwik.'
+        ];
         if ((float)$version < 1.3) {
             $expectedWarnings[] = "WARNING: This version of VuFind does not support "
                 . "the default theme. Your config.ini [Site] theme setting "
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Statistics/Driver/PluginManagerTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Statistics/Driver/PluginManagerTest.php
deleted file mode 100644
index d7637770909..00000000000
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Statistics/Driver/PluginManagerTest.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * Statistics Driver Plugin Manager Test Class
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Tests
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
- */
-namespace VuFindTest\Statistics\Driver;
-use VuFind\Statistics\Driver\PluginManager;
-
-/**
- * Statistics Driver Plugin Manager Test Class
- *
- * @category VuFind
- * @package  Tests
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
- */
-class PluginManagerTest extends \VuFindTest\Unit\TestCase
-{
-    /**
-     * Test results.
-     *
-     * @return void
-     */
-    public function testShareByDefault()
-    {
-        $pm = new PluginManager(null);
-        $this->assertFalse($pm->shareByDefault());
-    }
-
-    /**
-     * Test expected interface.
-     *
-     * @return void
-     *
-     * @expectedException        Zend\ServiceManager\Exception\RuntimeException
-     * @expectedExceptionMessage Plugin ArrayObject does not belong to VuFind\Statistics\Driver\AbstractBase
-     */
-    public function testExpectedInterface()
-    {
-        $pm = new PluginManager(null);
-        $pm->validatePlugin(new \ArrayObject());
-    }
-}
diff --git a/module/VuFindAdmin/src/VuFindAdmin/Controller/StatisticsController.php b/module/VuFindAdmin/src/VuFindAdmin/Controller/StatisticsController.php
deleted file mode 100644
index 676923e2d8f..00000000000
--- a/module/VuFindAdmin/src/VuFindAdmin/Controller/StatisticsController.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-/**
- * Admin Statistics Controller
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category VuFind
- * @package  Controller
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-namespace VuFindAdmin\Controller;
-
-/**
- * Class controls VuFind statistical data.
- *
- * @category VuFind
- * @package  Controller
- * @author   Demian Katz <demian.katz@villanova.edu>
- * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
- * @link     https://vufind.org Main Site
- */
-class StatisticsController extends AbstractAdmin
-{
-    /**
-     * Statistics reporting
-     *
-     * @return \Zend\View\Model\ViewModel
-     */
-    public function homeAction()
-    {
-       
-        $view = $this->createViewModel();
-        $view->setTemplate('admin/statistics/home');
-        $config = $this->getConfig();
-
-        // Search statistics
-        $search = $this->getServiceLocator()->get('VuFind\SearchStats');
-        $view->searchesBySource = $config->Statistics->searchesBySource ?: false;
-        $searchSummary = $search->getStatsSummary(7, $view->searchesBySource);
-        foreach (['top', 'empty', 'total'] as $section) {
-            $key = $section . 'Searches';
-            $view->$key = isset($searchSummary[$section])
-                ? $searchSummary[$section] : null;
-        }
-
-        // Record statistics
-        $records = $this->getServiceLocator()->get('VuFind\RecordStats');
-        $view->recordsBySource = $config->Statistics->recordsBySource ?: false;
-        $recordSummary = $records->getStatsSummary(5, $view->recordsBySource);
-        $view->topRecords = isset($recordSummary['top'])
-            ? $recordSummary['top'] : null;
-        $view->totalRecordViews = isset($recordSummary['total'])
-            ? $recordSummary['total'] : null;
-
-        // Browser statistics
-        $view->currentBrowser = $search->getBrowser(
-            $this->getRequest()->getServer('HTTP_USER_AGENT')
-        );
-
-        // Look for universal statistics recorder
-        $matchFound = false;
-        foreach ($search->getDriversForSource(null) as $currentDriver) {
-            $browserStats = $currentDriver->getBrowserStats(false, 5);
-            if (!empty($browserStats)) {
-                $matchFound = true;
-                break;
-            }
-        }
-
-        // If no full coverage mode found, take the first valid source
-        if (!$matchFound) {
-            $drivers = $search->getDriversForSource(null, true);
-            foreach ($drivers as $currentDriver) {
-                $browserStats = $currentDriver->getBrowserStats(false, 5);
-                if (!empty($browserStats)) {
-                    $matchFound = true;
-                    break;
-                }
-            }
-        }
-
-        // Initialize browser/version data in view based on what we found above:
-        if ($matchFound) {
-            $view->browserStats = $browserStats;
-            $view->topVersions = $currentDriver->getBrowserStats(true, 5);
-        } else {
-            $view->browserStats = $view->topVersions = null;
-        }
-
-        return $view;
-    }
-}
diff --git a/solr/vufind/stats/conf/schema.xml b/solr/vufind/stats/conf/schema.xml
deleted file mode 100644
index 731133637fb..00000000000
--- a/solr/vufind/stats/conf/schema.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" ?>
-<schema name="VuFind Usage Statistics Index" version="1.1">
-  <types>
-    <!-- Define fieldType long as it is needed by the _version_ field required by Solr 4.x -->
-    <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
-    <fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
-    <fieldtype name="boolean" class="solr.BoolField" sortMissingLast="true" omitNorms="true"/>
-    <fieldtype name="date" class="solr.TrieDateField" sortMissingLast="true" omitNorms="true" precisionStep="6"/>
-  </types>
-  <fields>
-   <!-- Required by Solr 4.x -->
-   <field name="_version_" type="long" indexed="true" stored="true"/>
-   <!-- Core Fields  -->
-   <field name="id" type="string" indexed="true" stored="true"/>
-   <field name="datestamp" type="date" indexed="true" stored="true"/>
-
-   <!-- Institutional Fields -->
-   <field name="institution" type="string" indexed="true" stored="true" multiValued="true"/>
-   <field name="collection" type="string" indexed="true" stored="true" multiValued="true"/>
-
-   <!-- User fields -->
-   <field name="browser" type="string" indexed="true" stored="true"/>
-   <field name="browserVersion" type="string" indexed="true" stored="true"/>
-   <field name="ipaddress" type="string" indexed="true" stored="true"/>
-   <field name="referrer" type="string" indexed="true" stored="true"/>
-   <field name="session" type="string" indexed="true" stored="true"/>
-   <field name="url" type="string" indexed="true"/>
-
-   <!-- Search fields -->
-   <field name="noresults" type="boolean" indexed="true" stored="true"/>
-   <field name="phrase" type="string" indexed="true" stored="true" multiValued="true"/>
-   <field name="resultCount" type="string" indexed="true" stored="true"/>
-   <field name="type" type="string" indexed="true" stored="true" multiValued="true"/>
-   <field name="searchSource" type="string" indexed="true" stored="true"/>
-
-   <!-- Record fields -->
-   <field name="recordId" type="string" indexed="true" stored="true"/>
-   <field name="recordSource" type="string" indexed="true" stored="true"/>
- </fields>
-
- <uniqueKey>id</uniqueKey>
-
- <defaultSearchField>id</defaultSearchField>
-
- <!-- Default Boolean Operator -->
- <solrQueryParser defaultOperator="OR"/>
-</schema>
diff --git a/solr/vufind/stats/conf/solrconfig.xml b/solr/vufind/stats/conf/solrconfig.xml
deleted file mode 100644
index 116cfe925eb..00000000000
--- a/solr/vufind/stats/conf/solrconfig.xml
+++ /dev/null
@@ -1,536 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements.  See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<config>
-  <!-- Set this to 'false' if you want solr to continue working after it has 
-       encountered an severe configuration error.  In a production environment, 
-       you may want solr to keep working even if one handler is mis-configured.
-
-       You may also set this to false using by setting the system property:
-         -Dsolr.abortOnConfigurationError=false
-     -->
-  <abortOnConfigurationError>${solr.abortOnConfigurationError:false}</abortOnConfigurationError>
-
-  <!-- Controls what version of Lucene various components of Solr
-       adhere to.  Generally, you want to use the latest version to
-       get all bug fixes and improvements. It is highly recommended
-       that you fully re-index after changing this setting as it can
-       affect both how text is indexed and queried.
-    -->
-  <luceneMatchVersion>5.5.0</luceneMatchVersion>
-
-  <!-- Used to specify an alternate directory to hold all index data
-       other than the default ./data under the Solr home.
-       If replication is in use, this should match the replication configuration. -->
-  <dataDir>${solr.solr.home:./solr}/stats</dataDir>
-
-  
-  <indexConfig>
-  
-    <useCompoundFile>false</useCompoundFile>
-
-	
-	<!-- ramBufferSizeMB sets the amount of RAM that may be used by Lucene
-      indexing for buffering added documents and deletions before they are
-      flushed to the Directory.
-      maxBufferedDocs sets a limit on the number of documents buffered
-      before flushing.
-      If both ramBufferSizeMB and maxBufferedDocs is set, then
-      Lucene will flush based on whichever limit is hit first.  -->
-    <ramBufferSizeMB>100</ramBufferSizeMB>
-    <!-- <maxBufferedDocs>1000</maxBufferedDocs> -->
-	
-	
-	   <!-- Commit Deletion Policy
-
-         Custom deletion policies can be specified here. The class must
-         implement org.apache.lucene.index.IndexDeletionPolicy.
-
-         http://lucene.apache.org/java/3_5_0/api/core/org/apache/lucene/index/IndexDeletionPolicy.html
-
-         The default Solr IndexDeletionPolicy implementation supports
-         deleting index commit points on number of commits, age of
-         commit point and optimized status.
-         
-         The latest commit point should always be preserved regardless
-         of the criteria.
-    -->
-   <deletionPolicy class="solr.SolrDeletionPolicy">
-      <!-- Keep only optimized commit points -->
-      <str name="keepOptimizedOnly">false</str>
-      <!-- The maximum number of commit points to be kept -->
-      <str name="maxCommitsToKeep">1</str>
-      <!--
-          Delete all commit points once they have reached the given age.
-          Supports DateMathParser syntax e.g.
-
-          <str name="maxCommitAge">30MINUTES</str>
-          <str name="maxCommitAge">1DAY</str>
-      -->
-    </deletionPolicy>
-	
-  </indexConfig>
-
-  <!--	Enables JMX if and only if an existing MBeanServer is found, use 
-  		this if you want to configure JMX through JVM parameters. Remove
-  		this to disable exposing Solr configuration and statistics to JMX.
-  		
-		If you want to connect to a particular server, specify the agentId
-		e.g. <jmx agentId="myAgent" />
-		
-		If you want to start a new MBeanServer, specify the serviceUrl
-		e.g <jmx serviceurl="service:jmx:rmi:///jndi/rmi://localhost:9999/solr" />
-		
-		For more details see http://wiki.apache.org/solr/SolrJmx
-  -->
-  <jmx />
-
-  <!-- the default high-performance update handler -->
-  <updateHandler class="solr.DirectUpdateHandler2">
-
-  
-      <!-- Enables a transaction log, used for real-time get, durability, and
-         and solr cloud replica recovery.  The log can grow as big as
-         uncommitted changes to the index, so use of a hard autoCommit
-         is recommended (see below).
-         "dir" - the target directory for transaction logs, defaults to the
-                solr data directory.  --> 
-    <updateLog>
-      <str name="dir">${solr.ulog.dir:}</str>
-    </updateLog>
-	
-    <!-- A prefix of "solr." for class names is an alias that
-         causes solr to search appropriate packages, including
-         org.apache.solr.(search|update|request|core|analysis)
-     -->
-
-    <!-- Perform a <commit/> automatically under certain conditions:
-         maxDocs - number of updates since last commit is greater than this
-         maxTime - oldest uncommited update (in ms) is this long ago
-    -->
-     <autoCommit> 
-       <maxTime>15000</maxTime> 
-       <openSearcher>false</openSearcher> 
-     </autoCommit>
-
-    <!-- The RunExecutableListener executes an external command.
-         exe - the name of the executable to run
-         dir - dir to use as the current working directory. default="."
-         wait - the calling thread waits until the executable returns. default="true"
-         args - the arguments to pass to the program.  default=nothing
-         env - environment variables to set.  default=nothing
-      -->
-    <!-- A postCommit event is fired after every commit or optimize command
-    <listener event="postCommit" class="solr.RunExecutableListener">
-      <str name="exe">solr/bin/snapshooter</str>
-      <str name="dir">.</str>
-      <bool name="wait">true</bool>
-      <arr name="args"> <str>arg1</str> <str>arg2</str> </arr>
-      <arr name="env"> <str>MYVAR=val1</str> </arr>
-    </listener>
-    -->
-    <!-- A postOptimize event is fired only after every optimize command, useful
-         in conjunction with index distribution to only distribute optimized indices
-    <listener event="postOptimize" class="solr.RunExecutableListener">
-      <str name="exe">snapshooter</str>
-      <str name="dir">solr/bin</str>
-      <bool name="wait">true</bool>
-    </listener>
-    -->
-
-  </updateHandler>
-
-
-  <query>
-    <!-- Maximum number of clauses in a boolean query... can affect
-        range or prefix queries that expand to big boolean
-        queries.  An exception is thrown if exceeded.  -->
-    <maxBooleanClauses>1024</maxBooleanClauses>
-
-    
-    <!-- Cache used by SolrIndexSearcher for filters (DocSets),
-         unordered sets of *all* documents that match a query.
-         When a new searcher is opened, its caches may be prepopulated
-         or "autowarmed" using data from caches in the old searcher.
-         autowarmCount is the number of items to prepopulate.  For LRUCache,
-         the autowarmed items will be the most recently accessed items.
-       Parameters:
-         class - the SolrCache implementation (currently only LRUCache)
-         size - the maximum number of entries in the cache
-         initialSize - the initial capacity (number of entries) of
-           the cache.  (seel java.util.HashMap)
-         autowarmCount - the number of entries to prepopulate from
-           and old cache.
-         -->
-
-    <!-- VuFind uses the default Solr settings for filterCache, which should produce a high
-         hit rate. You can carefully adjust the filterCache and check the hit ratio in 
-         admin>plugins>stats -->
-    <filterCache
-      class="solr.FastLRUCache"
-      size="512"
-      initialSize="512"
-      autowarmCount="256"/>
-
-   <!-- queryResultCache caches results of searches - ordered lists of
-         document ids (DocList) based on a query, a sort, and the range
-         of documents requested.  -->
-    <queryResultCache
-      class="solr.LRUCache"
-      size="512"
-      initialSize="512"
-      autowarmCount="256"/>
-
-  <!-- documentCache caches Lucene Document objects (the stored fields for each document).
-       Since Lucene internal document ids are transient, this cache will not be autowarmed.  -->
-    <documentCache
-      class="solr.LRUCache"
-      size="16384"
-      initialSize="16384"/>
-
-    <!-- If true, stored fields that are not requested will be loaded lazily.
-
-    This can result in a significant speed improvement if the usual case is to
-    not load all stored fields, especially if the skipped fields are large compressed
-    text fields.
-    -->
-    <enableLazyFieldLoading>false</enableLazyFieldLoading>
-
-    <!-- Example of a generic cache.  These caches may be accessed by name
-         through SolrIndexSearcher.getCache(),cacheLookup(), and cacheInsert().
-         The purpose is to enable easy caching of user/application level data.
-         The regenerator argument should be specified as an implementation
-         of solr.search.CacheRegenerator if autowarming is desired.  -->
-    <!--
-    <cache name="myUserCache"
-      class="solr.LRUCache"
-      size="4096"
-      initialSize="1024"
-      autowarmCount="1024"
-      regenerator="org.mycompany.mypackage.MyRegenerator"
-      />
-    -->
-
-   <!-- An optimization that attempts to use a filter to satisfy a search.
-         If the requested sort does not include score, then the filterCache
-         will be checked for a filter matching the query. If found, the filter
-         will be used as the source of document ids, and then the sort will be
-         applied to that.
-    <useFilterForSortedQuery>true</useFilterForSortedQuery>
-   -->
-
-   <!-- An optimization for use with the queryResultCache.  When a search
-         is requested, a superset of the requested number of document ids
-         are collected.  For example, if a search for a particular query
-         requests matching documents 10 through 19, and queryWindowSize is 50,
-         then documents 0 through 49 will be collected and cached.  Any further
-         requests in that range can be satisfied via the cache.  -->
-    <queryResultWindowSize>50</queryResultWindowSize>
-    
-    <!-- Maximum number of documents to cache for any entry in the
-         queryResultCache. -->
-    <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
-
-    <!-- This entry enables an int hash representation for filters (DocSets)
-         when the number of items in the set is less than maxSize.  For smaller
-         sets, this representation is more memory efficient, more efficient to
-         iterate over, and faster to take intersections.  -->
-    <HashDocSet maxSize="3000" loadFactor="0.75"/>
-
-    <!-- a newSearcher event is fired whenever a new searcher is being prepared
-         and there is a current searcher handling requests (aka registered). -->
-    <!-- QuerySenderListener takes an array of NamedList and executes a
-         local query request for each NamedList in sequence. -->
-    <!--
-    <listener event="newSearcher" class="solr.QuerySenderListener">
-      <arr name="queries">
-        <lst> <str name="q">solr</str> <str name="start">0</str> <str name="rows">10</str> </lst>
-        <lst> <str name="q">rocks</str> <str name="start">0</str> <str name="rows">10</str> </lst>
-      </arr>
-    </listener>
-    -->
-
-    <!-- a firstSearcher event is fired whenever a new searcher is being
-         prepared but there is no current registered searcher to handle
-         requests or to gain autowarming data from. -->
-    <!--
-    <listener event="firstSearcher" class="solr.QuerySenderListener">
-      <arr name="queries">
-        <lst> <str name="q">fast_warm</str> <str name="start">0</str> <str name="rows">10</str> </lst>
-      </arr>
-    </listener>
-    -->
-    
-    <!-- If a search request comes in and there is no current registered searcher,
-         then immediately register the still warming searcher and use it.  If
-         "false" then all requests will block until the first searcher is done
-         warming. -->
-    <useColdSearcher>false</useColdSearcher>
-
-    <!-- Maximum number of searchers that may be warming in the background
-      concurrently.  An error is returned if this limit is exceeded. Recommend
-      1-2 for read-only slaves, higher for masters w/o cache warming. -->
-    <maxWarmingSearchers>4</maxWarmingSearchers>
-
-  </query>
-
-  <!-- 
-    Let the dispatch filter handler /select?qt=XXX
-    handleSelect=true will use consistent error handling for /select and /update
-    handleSelect=false will use solr1.1 style error formatting
-    -->
-  <requestDispatcher handleSelect="true" >
-    <!--Make sure your system has some authentication before enabling remote streaming!  -->
-    <requestParsers enableRemoteStreaming="false" 
-                    multipartUploadLimitInKB="2048"
-                    formdataUploadLimitInKB="2048"/>
-        
-    <!-- Set HTTP caching related parameters (for proxy caches and clients).
-          
-         To get the behaviour of Solr 1.2 (ie: no caching related headers)
-         use the never304="true" option and do not specify a value for
-         <cacheControl>
-    -->
-    <!-- <httpCaching never304="true"> -->
-    <httpCaching lastModifiedFrom="openTime"
-                 etagSeed="Solr">
-       <!-- lastModFrom="openTime" is the default, the Last-Modified value
-            (and validation against If-Modified-Since requests) will all be
-            relative to when the current Searcher was opened.
-            You can change it to lastModFrom="dirLastMod" if you want the
-            value to exactly correspond to when the physical index was last
-            modified.
-               
-            etagSeed="..." is an option you can change to force the ETag
-            header (and validation against If-None-Match requests) to be
-            differnet even if the index has not changed (ie: when making
-            significant changes to your config file)
-
-            lastModifiedFrom and etagSeed are both ignored if you use the
-            never304="true" option.
-       -->
-       <!-- If you include a <cacheControl> directive, it will be used to
-            generate a Cache-Control header, as well as an Expires header
-            if the value contains "max-age="
-               
-            By default, no Cache-Control header is generated.
-
-            You can use the <cacheControl> option even if you have set
-            never304="true"
-       -->
-       <!-- <cacheControl>max-age=30, public</cacheControl> -->
-    </httpCaching>
-  </requestDispatcher>
-  
-      
-  <!-- requestHandler plugins... incoming queries will be dispatched to the
-     correct handler based on the path or the qt (query type) param.
-     Names starting with a '/' are accessed with the a path equal to the 
-     registered name.  Names without a leading '/' are accessed with:
-      http://host/app/select?qt=name
-     If no qt is defined, the requestHandler that declares default="true"
-     will be used.
-  -->
-  <requestHandler name="standard" class="solr.StandardRequestHandler" default="true">
-    <!-- default values for query parameters may optionally be defined here
-     <lst name="defaults">
-       <int name="rows">10</int>
-       <str name="fl">*</str>
-       <str name="version">2.1</str>
-     <lst>
-    -->
-    <lst name="defaults">
-      <str name="echoParam">explicit</str>
-    </lst>
-  </requestHandler>
-  
-  
-  <!-- Search component for extracting terms (useful for sitemap generation) -->
-  <searchComponent name="term" class="org.apache.solr.handler.component.TermsComponent">
-  </searchComponent>
-
-  <!--
-   
-   Search components are registered to SolrCore and used by Search Handlers
-   
-   By default, the following components are available:
-    
-   <searchComponent name="query"     class="org.apache.solr.handler.component.QueryComponent" />
-   <searchComponent name="facet"     class="org.apache.solr.handler.component.FacetComponent" />
-   <searchComponent name="mlt"       class="org.apache.solr.handler.component.MoreLikeThisComponent" />
-   <searchComponent name="highlight" class="org.apache.solr.handler.component.HighlightComponent" />
-   <searchComponent name="stats"     class="org.apache.solr.handler.component.StatsComponent" />
-   <searchComponent name="debug"     class="org.apache.solr.handler.component.DebugComponent" />
-  
-   If you register a searchComponent to one of the standard names, that will be used instead.
-  
-   -->
-  
-  <!-- Request handler to extract terms (useful for sitemap generation) -->
-  <requestHandler name="/term" class="org.apache.solr.handler.component.SearchHandler">
-    <arr name="components">
-      <str>term</str>
-    </arr>
-  </requestHandler>
- 
-  <!-- Field Analysis Request Handler
-
-       RequestHandler that provides much the same functionality as
-       analysis.jsp. Provides the ability to specify multiple field
-       types and field names in the same request and outputs
-       index-time and query-time analysis for each of them.
-
-       Request parameters are:
-       analysis.fieldname - field name whose analyzers are to be used
-
-       analysis.fieldtype - field type whose analyzers are to be used
-       analysis.fieldvalue - text for index-time analysis
-       q (or analysis.q) - text for query time analysis
-       analysis.showmatch (true|false) - When set to true and when
-           query analysis is performed, the produced tokens of the
-           field value analysis will be marked as "matched" for every
-           token that is produces by the query analysis
-   -->
-  <requestHandler name="/analysis/field" 
-                  startup="lazy"
-                  class="solr.FieldAnalysisRequestHandler" />
-
-
-  <!-- Document Analysis Handler
-
-       http://wiki.apache.org/solr/AnalysisRequestHandler
-
-       An analysis handler that provides a breakdown of the analysis
-       process of provided documents. This handler expects a (single)
-       content stream with the following format:
-
-       <docs>
-         <doc>
-           <field name="id">1</field>
-           <field name="name">The Name</field>
-           <field name="text">The Text Value</field>
-         </doc>
-         <doc>...</doc>
-         <doc>...</doc>
-         ...
-       </docs>
-
-    Note: Each document must contain a field which serves as the
-    unique key. This key is used in the returned response to associate
-    an analysis breakdown to the analyzed document.
-
-    Like the FieldAnalysisRequestHandler, this handler also supports
-    query analysis by sending either an "analysis.query" or "q"
-    request parameter that holds the query text to be analyzed. It
-    also supports the "analysis.showmatch" parameter which when set to
-    true, all field tokens that match the query tokens will be marked
-    as a "match". 
-  -->
-  <requestHandler name="/analysis/document" 
-                  class="solr.DocumentAnalysisRequestHandler" 
-                  startup="lazy" />
-  
-
-  <!-- CSV update handler, loaded on demand -->
-  <requestHandler name="/update/csv" class="solr.CSVRequestHandler" startup="lazy" />
-
-
-  <!-- ping/healthcheck -->
-  <requestHandler name="/admin/ping" class="PingRequestHandler">
-    <lst name="defaults">
-      <str name="qt">standard</str>
-      <str name="q">solrpingquery</str>
-      <str name="echoParams">all</str>
-    </lst>
-  </requestHandler>
-    
-  <!-- Echo the request contents back to the client -->
-  <requestHandler name="/debug/dump" class="solr.DumpRequestHandler" >
-    <lst name="defaults">
-     <str name="echoParams">explicit</str> <!-- for all params (including the default etc) use: 'all' -->
-     <str name="echoHandler">true</str>
-    </lst>
-  </requestHandler>
-  
-  <searchComponent class="solr.HighlightComponent" name="highlight">
-    <highlighting>
-      <!-- Configure the standard fragmenter -->
-      <!-- This could most likely be commented out in the "default" case -->
-      <fragmenter name="gap" class="org.apache.solr.highlight.GapFragmenter" default="true">
-        <lst name="defaults">
-          <int name="hl.fragsize">100</int>
-        </lst>
-      </fragmenter>
-
-      <!-- A regular-expression-based fragmenter (f.i., for sentence extraction) -->
-      <fragmenter name="regex" class="org.apache.solr.highlight.RegexFragmenter">
-        <lst name="defaults">
-          <!-- slightly smaller fragsizes work better because of slop -->
-          <int name="hl.fragsize">70</int>
-          <!-- allow 50% slop on fragment sizes -->
-          <float name="hl.regex.slop">0.5</float>
-          <!-- a basic sentence pattern -->
-          <str name="hl.regex.pattern">[-\w ,/\n\"']{20,200}</str>
-        </lst>
-      </fragmenter>
-
-      <!-- Configure the standard formatter -->
-      <formatter name="html" class="org.apache.solr.highlight.HtmlFormatter" default="true">
-        <lst name="defaults">
-          <str name="hl.simple.pre"><![CDATA[<em>]]></str>
-          <str name="hl.simple.post"><![CDATA[</em>]]></str>
-        </lst>
-      </formatter>
-    </highlighting>
-  </searchComponent>
-
-  <!-- queryResponseWriter plugins... query responses will be written using the
-    writer specified by the 'wt' request parameter matching the name of a registered
-    writer.
-    The "default" writer is the default and will be used if 'wt' is not specified 
-    in the request. XMLResponseWriter will be used if nothing is specified here.
-    The json, python, and ruby writers are also available by default.
-
-    <queryResponseWriter name="xml" class="org.apache.solr.request.XMLResponseWriter" default="true"/>
-    <queryResponseWriter name="json" class="org.apache.solr.request.JSONResponseWriter"/>
-    <queryResponseWriter name="python" class="org.apache.solr.request.PythonResponseWriter"/>
-    <queryResponseWriter name="ruby" class="org.apache.solr.request.RubyResponseWriter"/>
-    <queryResponseWriter name="php" class="org.apache.solr.request.PHPResponseWriter"/>
-    <queryResponseWriter name="phps" class="org.apache.solr.request.PHPSerializedResponseWriter"/>
-
-    <queryResponseWriter name="custom" class="com.example.MyResponseWriter"/>
-  -->
-
-  <!-- XSLT response writer transforms the XML output by any xslt file found
-       in Solr's conf/xslt directory.  Changes to xslt files are checked for
-       every xsltCacheLifetimeSeconds.  
-   -->
-  <queryResponseWriter name="xslt" class="org.apache.solr.response.XSLTResponseWriter">
-    <int name="xsltCacheLifetimeSeconds">5</int>
-  </queryResponseWriter> 
-    
-  <!-- config for the admin interface --> 
-  <admin>
-    <defaultQuery>shakespeare</defaultQuery>
-    
-    <!-- configure a healthcheck file for servers behind a loadbalancer
-    <healthcheck type="file">server-enabled</healthcheck>
-    -->
-  </admin>
-
-</config>
diff --git a/solr/vufind/stats/core.properties b/solr/vufind/stats/core.properties
deleted file mode 100644
index 84cd043b745..00000000000
--- a/solr/vufind/stats/core.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-# only load this core when it is accessed (since it may never be used):
-loadOnStartup=false
\ No newline at end of file
diff --git a/themes/bootstrap3/templates/admin/menu.phtml b/themes/bootstrap3/templates/admin/menu.phtml
index 404fbdfc95b..ec410878848 100644
--- a/themes/bootstrap3/templates/admin/menu.phtml
+++ b/themes/bootstrap3/templates/admin/menu.phtml
@@ -1,7 +1,6 @@
 <div class="list-group">
   <a href="<?=$this->url('admin')?>" class="list-group-item<?=strtolower($this->layout()->templateName) == "home" ? ' active' : ''?>"><?=$this->transEsc('Home')?></a>
   <a href="<?=$this->url('admin/social')?>" class="list-group-item<?=strtolower($this->layout()->templateName) == "socialstats" ? ' active' : ''?>"><?=$this->transEsc('Social Statistics')?></a>
-  <a href="<?=$this->url('admin/statistics')?>" class="list-group-item<?=strtolower($this->layout()->templateName) == "statistics" ? ' active' : ''?>"><?=$this->transEsc('Statistics')?></a>
   <a href="<?=$this->url('admin/config')?>" class="list-group-item<?=strtolower($this->layout()->templateName) == "config" ? ' active' : ''?>"><?=$this->transEsc('Configuration')?></a>
   <a href="<?=$this->url('admin/maintenance')?>" class="list-group-item<?=strtolower($this->layout()->templateName) == "maintenance" ? ' active' : ''?>"><?=$this->transEsc('System Maintenance')?></a>
   <a href="<?=$this->url('admin/tags')?>" class="list-group-item<?=strtolower($this->layout()->templateName) == "tags" ? ' active' : ''?>"><?=$this->transEsc('Tag Maintenance')?></a>
diff --git a/themes/bootstrap3/templates/admin/statistics/home.phtml b/themes/bootstrap3/templates/admin/statistics/home.phtml
deleted file mode 100644
index 66064a236b4..00000000000
--- a/themes/bootstrap3/templates/admin/statistics/home.phtml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?
-  // Set page title.
-  $this->headTitle($this->translate('VuFind Administration - Statistics'));
-?>
-<style>
-  table {
-    table-layout: fixed;
-    width: 100%;
-  }
-  tr td:first-child {
-    width:50%;
-  }
-</style>
-
-<div class="row">
-  <div class="<?=$this->layoutClass('mainbody')?>">
-    <h2><?=$this->transEsc('Statistics')?></h2>
-
-    <? if(null !== $this->totalSearches || null !== $this->emptySearches || null !== $this->totalRecordViews): ?>
-      <h3>Executive Summary</h3>
-      <table class="table table-striped">
-        <? if(null !== $this->totalSearches): ?><tr><td>Total Searches</td><td><?=$this->totalSearches ?></td></tr><? endif; ?>
-        <? if(null !== $this->emptySearches): ?><tr><td>0 Hit Searches</td><td><?=$this->emptySearches ?></td></tr><? endif; ?>
-        <? if(null !== $this->totalRecordViews): ?><tr><td>Total Record Views</td><td><?=$this->totalRecordViews ?></td></tr><? endif; ?>
-      </table>
-    <? endif; ?>
-
-    <? if(!empty($this->topSearches)): ?>
-      <h3>Top Searches<? if($this->searchesBySource): ?> by Source<? endif; ?></h3>
-      <? if($this->searchesBySource): ?>
-        <? foreach($this->topSearches as $source=>$searches): ?>
-          <?=$source ?>
-          <table class="table table-striped">
-          <? foreach($searches as $search): ?>
-            <tr><td><?=$search['value'] ?></td><td><?=$this->localizedNumber($search['count']) ?></td></tr>
-          <? endforeach; ?>
-          </table>
-        <? endforeach; ?>
-      <? else: ?>
-        <table class="table table-striped">
-          <? foreach($this->topSearches as $search): ?>
-            <tr><td><?=$search['value'] ?></td><td><?=$this->localizedNumber($search['count']) ?></td><td><?=$search['source'] ?></td></tr>
-          <? endforeach; ?>
-        </table>
-      <? endif; ?>
-    <? endif; ?>
-
-    <? if(!empty($this->topRecords)): ?>
-      <h3>Top Records<? if($this->recordsBySource): ?> by Source<? endif; ?></h3>
-      <? if($this->recordsBySource): ?>
-        <? foreach($this->topRecords as $source=>$records): ?>
-          <?=$source ?>
-          <table class="table table-striped">
-          <? foreach($records as $record): ?>
-            <tr><td><?=$record['value'] ?></td><td><?=$this->localizedNumber($record['count']) ?></td></tr>
-          <? endforeach; ?>
-          </table>
-        <? endforeach; ?>
-      <? else: ?>
-        <table class="table table-striped">
-          <? foreach($this->topRecords as $record): ?>
-            <tr><td><?=$record['value'] ?></td><td><?=$this->localizedNumber($record['count']) ?></td><td><?=$record['source'] ?></td></tr>
-          <? endforeach; ?>
-        </table>
-      <? endif; ?>
-    <? endif; ?>
-
-    <? if(!empty($this->browserStats)): ?>
-      <h3>Browser Usage</h3>
-      <?
-        $total = 0;
-        foreach($this->browserStats as $browser) {
-            $total += $browser['count'];
-        }
-      ?>
-      <table class="table table-striped">
-      <? foreach($this->browserStats as $browser): ?>
-        <tr><td><?=$browser['browserName'] ?></td><td><?=$this->localizedNumber($browser['count']) ?></td><td><?=$this->localizedNumber($browser['count']*100/$total, 2) ?>%</td></tr>
-      <? endforeach; ?>
-      </table>
-      <h4>Top Versions</h4>:
-      <? foreach($this->topVersions as $i=>$browser): ?>
-        <span<? if($this->currentBrowser == $browser['browserName']): ?> class="currentBrowser"<? endif; ?>><?=$browser['browserName'] ?> (<?=$this->localizedNumber($browser['count']) ?>)</span><? if(++$i < count($this->topVersions)): ?>,<? endif; ?>
-      <? endforeach; ?>
-    <? endif; ?>
-
-    <? if(empty($this->topSearches) && empty($this->topRecords) && empty($this->browserStats)): ?>
-      No statistic sources.
-    <? endif; ?>
-  </div>
-
-  <div class="<?=$this->layoutClass('sidebar')?>">
-    <?=$this->render("admin/menu.phtml")?>
-  </div>
-</div>
\ No newline at end of file
-- 
GitLab