From 09a65ec7e53ff6e72819582953a3722ad71faecc Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Fri, 17 Jul 2015 08:41:32 -0400
Subject: [PATCH] Refactored getVisibleSearchResultLimit() to reduce
 redundancy. - Added support for restricted Solr result sets. - Based on work
 in pull request #414.

---
 config/vufind/searches.ini                    |  7 +++++
 .../VuFind/src/VuFind/Search/Base/Options.php | 10 +++++--
 .../VuFind/src/VuFind/Search/Base/Results.php | 29 ++++++++++++-------
 .../VuFind/src/VuFind/Search/EDS/Options.php  | 20 +------------
 .../src/VuFind/Search/Primo/Options.php       | 21 ++------------
 .../VuFind/src/VuFind/Search/Solr/Options.php |  4 +++
 .../src/VuFind/Search/Summon/Options.php      | 21 ++------------
 7 files changed, 43 insertions(+), 69 deletions(-)

diff --git a/config/vufind/searches.ini b/config/vufind/searches.ini
index 274c11cda28..edd90ee5f4c 100644
--- a/config/vufind/searches.ini
+++ b/config/vufind/searches.ini
@@ -26,6 +26,13 @@ default_view         = list
 default_limit        = 20
 ;limit_options        = 10,20,40,60,80,100
 
+; This setting allows to limit pagination of a search result as deep pagination
+; costs a lot of performance and most users are not very likely to navigate
+; further down than 20 pages of a search result.
+; This is especially useful to prevent webcrawlers from descending too deep and
+; eating up search backend performance. Default is set to unlimited.
+;result_limit = 400
+
 ; If this setting is true, boolean operators in searches (AND/OR/NOT) will only
 ; be recognized if they are ALL UPPERCASE.  If set to false, they will be
 ; recognized regardless of case.  If set to a comma-separated list of operators
diff --git a/module/VuFind/src/VuFind/Search/Base/Options.php b/module/VuFind/src/VuFind/Search/Base/Options.php
index 102d11380db..baf551397d1 100644
--- a/module/VuFind/src/VuFind/Search/Base/Options.php
+++ b/module/VuFind/src/VuFind/Search/Base/Options.php
@@ -212,6 +212,13 @@ abstract class Options implements TranslatorAwareInterface
      */
     protected $configLoader;
 
+    /**
+     * Maximum number of results (no limit by default)
+     *
+     * @var int
+     */
+    protected $resultLimit = -1;
+
     /**
      * Constructor
      *
@@ -724,8 +731,7 @@ abstract class Options implements TranslatorAwareInterface
      */
     public function getVisibleSearchResultLimit()
     {
-        // No limit by default:
-        return -1;
+        return intval($this->resultLimit);
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Search/Base/Results.php b/module/VuFind/src/VuFind/Search/Base/Results.php
index 80bed2d0ea6..7ada0ce8b4c 100644
--- a/module/VuFind/src/VuFind/Search/Base/Results.php
+++ b/module/VuFind/src/VuFind/Search/Base/Results.php
@@ -304,11 +304,17 @@ abstract class Results implements ServiceLocatorAwareInterface
      */
     public function getStartRecord()
     {
-        if (!is_null($this->startRecordOverride)) {
+        if (null !== $this->startRecordOverride) {
             return $this->startRecordOverride;
         }
         $params = $this->getParams();
-        return (($params->getPage() - 1) * $params->getLimit()) + 1;
+        $page = $params->getPage();
+        $pageLimit = $params->getLimit();
+        $resultLimit = $this->getOptions()->getVisibleSearchResultLimit();
+        if ($resultLimit > -1 && $resultLimit < $page * $pageLimit) {
+            $page = ceil($resultLimit / $pageLimit);
+        }
+        return (($page - 1) * $pageLimit) + 1;
     }
 
     /**
@@ -319,16 +325,19 @@ abstract class Results implements ServiceLocatorAwareInterface
     public function getEndRecord()
     {
         $total = $this->getResultTotal();
-        $limit = $this->getParams()->getLimit();
-        $page = $this->getParams()->getPage();
-        if ($page * $limit > $total) {
-            // The end of the current page runs past the last record, use total
-            // results
-            return $total;
+        $params = $this->getParams();
+        $page = $params->getPage();
+        $pageLimit = $params->getLimit();
+        $resultLimit = $this->getOptions()->getVisibleSearchResultLimit();
+
+        if ($resultLimit > -1 && $resultLimit < ($page * $pageLimit)) {
+            $record = $resultLimit;
         } else {
-            // Otherwise use the last record on this page
-            return $page * $limit;
+            $record = $page * $pageLimit;
         }
+        // If the end of the current page runs past the last record, use total
+        // results; otherwise use the last record on this page:
+        return ($record > $total) ? $total : $record;
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Search/EDS/Options.php b/module/VuFind/src/VuFind/Search/EDS/Options.php
index d3cd5e05a0f..41327ea4fdc 100644
--- a/module/VuFind/src/VuFind/Search/EDS/Options.php
+++ b/module/VuFind/src/VuFind/Search/EDS/Options.php
@@ -38,13 +38,6 @@ namespace VuFind\Search\EDS;
  */
 class Options extends \VuFind\Search\Base\Options
 {
-    /**
-     * Maximum number of results
-     *
-     * @var int
-     */
-    protected $resultLimit = 100;
-
     /**
      * Available search mode options
      *
@@ -127,6 +120,7 @@ class Options extends \VuFind\Search\Base\Options
         $this->searchIni = $this->facetsIni = 'EDS';
         $searchSettings = $configLoader->get($this->searchIni);
         parent::__construct($configLoader);
+        $this->resultLimit = 100;
         $this->viewOptions = [
             'list|title' => 'Title View', 'list|brief' => 'Brief View',
             'list|detailed' => 'Detailed View'
@@ -237,18 +231,6 @@ class Options extends \VuFind\Search\Base\Options
         return 'eds-advanced';
     }
 
-    /**
-     * If there is a limit to how many search results a user can access, this
-     * method will return that limit.  If there is no limit, this will return
-     * -1.
-     *
-     * @return int
-     */
-    public function getVisibleSearchResultLimit()
-    {
-        return $this->resultLimit;
-    }
-
     /**
      * Set the search options from the Eds API Info methods results
      *
diff --git a/module/VuFind/src/VuFind/Search/Primo/Options.php b/module/VuFind/src/VuFind/Search/Primo/Options.php
index af7f763f49d..7236deb59cb 100644
--- a/module/VuFind/src/VuFind/Search/Primo/Options.php
+++ b/module/VuFind/src/VuFind/Search/Primo/Options.php
@@ -38,13 +38,6 @@ namespace VuFind\Search\Primo;
  */
 class Options extends \VuFind\Search\Base\Options
 {
-    /**
-     * Maximum number of results
-     *
-     * @var int
-     */
-    protected $resultLimit = 3980;
-
     /**
      * Advanced search operators
      *
@@ -101,6 +94,8 @@ class Options extends \VuFind\Search\Base\Options
         // Result limit:
         if (isset($searchSettings->General->result_limit)) {
             $this->resultLimit = $searchSettings->General->result_limit;
+        } else {
+            $this->resultLimit = 3980;  // default
         }
 
         // Search handler setup:
@@ -140,18 +135,6 @@ class Options extends \VuFind\Search\Base\Options
         }
     }
 
-    /**
-     * If there is a limit to how many search results a user can access, this
-     * method will return that limit.  If there is no limit, this will return
-     * -1.
-     *
-     * @return int
-     */
-    public function getVisibleSearchResultLimit()
-    {
-        return intval($this->resultLimit);
-    }
-
     /**
      * Return the route name for the search results action.
      *
diff --git a/module/VuFind/src/VuFind/Search/Solr/Options.php b/module/VuFind/src/VuFind/Search/Solr/Options.php
index efb5cbc75f6..fde902c08f4 100644
--- a/module/VuFind/src/VuFind/Search/Solr/Options.php
+++ b/module/VuFind/src/VuFind/Search/Solr/Options.php
@@ -113,6 +113,10 @@ class Options extends \VuFind\Search\Base\Options
             $this->defaultFilters = $searchSettings->General->default_filters
                 ->toArray();
         }
+        // Result limit:
+        if (isset($searchSettings->General->result_limit)) {
+            $this->resultLimit = $searchSettings->General->result_limit;
+        }
         if (isset($searchSettings->Basic_Searches)) {
             foreach ($searchSettings->Basic_Searches as $key => $value) {
                 $this->basicHandlers[$key] = $value;
diff --git a/module/VuFind/src/VuFind/Search/Summon/Options.php b/module/VuFind/src/VuFind/Search/Summon/Options.php
index 2d567d96b09..ee938d1227c 100644
--- a/module/VuFind/src/VuFind/Search/Summon/Options.php
+++ b/module/VuFind/src/VuFind/Search/Summon/Options.php
@@ -38,13 +38,6 @@ namespace VuFind\Search\Summon;
  */
 class Options extends \VuFind\Search\Base\Options
 {
-    /**
-     * Maximum number of results
-     *
-     * @var int
-     */
-    protected $resultLimit = 400;
-
     /**
      * Maximum number of topic recommendations to show (false for none)
      *
@@ -119,6 +112,8 @@ class Options extends \VuFind\Search\Base\Options
         }
         if (isset($searchSettings->General->result_limit)) {
             $this->resultLimit = $searchSettings->General->result_limit;
+        } else {
+            $this->resultLimit = 400;   // default
         }
 
         // Search handler setup:
@@ -197,18 +192,6 @@ class Options extends \VuFind\Search\Base\Options
         return $this->emptySearchRelevanceOverride;
     }
 
-    /**
-     * If there is a limit to how many search results a user can access, this
-     * method will return that limit.  If there is no limit, this will return
-     * -1.
-     *
-     * @return int
-     */
-    public function getVisibleSearchResultLimit()
-    {
-        return intval($this->resultLimit);
-    }
-
     /**
      * Get the maximum number of topic recommendations (false for none)
      *
-- 
GitLab