Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SearchRunner
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 4
132
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 run
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
42
 setEventManager
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getEventManager
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3/**
4 * VuFind Search Runner
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2010.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  Search
25 * @author   Demian Katz <demian.katz@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org Main Page
28 */
29
30namespace VuFind\Search;
31
32use Laminas\EventManager\EventManager;
33use Laminas\EventManager\EventManagerInterface;
34use Laminas\Stdlib\Parameters;
35use VuFind\Search\Results\PluginManager as ResultsManager;
36use VuFind\Search\Solr\AbstractErrorListener as ErrorListener;
37
38use function is_array;
39use function is_callable;
40
41/**
42 * VuFind Search Runner
43 *
44 * @category VuFind
45 * @package  Search
46 * @author   Demian Katz <demian.katz@villanova.edu>
47 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
48 * @link     https://vufind.org Main Page
49 */
50class SearchRunner
51{
52    /**
53     * Event identifiers.
54     *
55     * @var string
56     */
57    public const EVENT_CONFIGURED = 'configured';
58    public const EVENT_COMPLETE = 'complete';
59
60    /**
61     * Event manager.
62     *
63     * @var EventManager
64     */
65    protected $events = null;
66
67    /**
68     * Search results object manager.
69     *
70     * @var ResultsManager
71     */
72    protected $resultsManager;
73
74    /**
75     * Counter of how many searches we have run (for differentiating listeners).
76     *
77     * @var int
78     */
79    protected $searchId = 0;
80
81    /**
82     * Constructor
83     *
84     * @param ResultsManager $resultsManager Results manager
85     * @param EventManager   $events         Event manager (optional)
86     */
87    public function __construct(
88        ResultsManager $resultsManager,
89        EventManager $events = null
90    ) {
91        $this->resultsManager = $resultsManager;
92        if (null !== $events) {
93            $this->setEventManager($events);
94        }
95    }
96
97    /**
98     * Run the search.
99     *
100     * @param array|Parameters $rawRequest    Incoming parameters for search
101     * @param string           $searchClassId Type of search to perform
102     * @param mixed            $setupCallback Optional callback for setting up params
103     * and attaching listeners; if provided, will be passed three parameters:
104     * this object, the search parameters object, and a unique identifier for
105     * the current running search.
106     * @param string           $lastView      Last valid view parameter loaded
107     * from a previous search (optional; used for view persistence).
108     *
109     * @return \VuFind\Search\Base\Results
110     *
111     * @throws \VuFindSearch\Backend\Exception\BackendException
112     */
113    public function run(
114        $rawRequest,
115        $searchClassId = 'Solr',
116        $setupCallback = null,
117        $lastView = null
118    ) {
119        // Increment the ID counter, then save the current value to a variable;
120        // since events within this run could theoretically trigger additional
121        // runs of the SearchRunner, we can't rely on the property value past
122        // this point!
123        $this->searchId++;
124        $runningSearchId = $this->searchId;
125
126        // Format the request object:
127        $request = $rawRequest instanceof Parameters
128            ? $rawRequest
129            : new Parameters(is_array($rawRequest) ? $rawRequest : []);
130
131        // Set up the search:
132        $results = $this->resultsManager->get($searchClassId);
133        $params = $results->getParams();
134        $params->setLastView($lastView);
135        $params->initFromRequest($request);
136
137        if (is_callable($setupCallback)) {
138            $setupCallback($this, $params, $runningSearchId);
139        }
140
141        // Trigger the "configuration done" event.
142        $this->getEventManager()->trigger(
143            self::EVENT_CONFIGURED,
144            $this,
145            compact('params', 'request', 'runningSearchId')
146        );
147
148        // Attempt to perform the search; if there is a problem, inspect any Solr
149        // exceptions to see if we should communicate to the user about them.
150        try {
151            // Explicitly execute search within controller -- this allows us to
152            // catch exceptions more reliably:
153            $results->performAndProcessSearch();
154        } catch (\VuFindSearch\Backend\Exception\BackendException $e) {
155            if ($e->hasTag(ErrorListener::TAG_PARSER_ERROR)) {
156                // We need to create and process an "empty results" object to
157                // ensure that recommendation modules and templates behave
158                // properly when displaying the error message.
159                $results = $this->resultsManager->get('EmptySet');
160                $results->setParams($params);
161                $results->performAndProcessSearch();
162            } else {
163                throw $e;
164            }
165        }
166
167        // Trigger the "search completed" event.
168        $this->getEventManager()->trigger(
169            self::EVENT_COMPLETE,
170            $this,
171            compact('results', 'runningSearchId')
172        );
173
174        return $results;
175    }
176
177    /**
178     * Set EventManager instance.
179     *
180     * @param EventManagerInterface $events Event manager
181     *
182     * @return void
183     */
184    public function setEventManager(EventManagerInterface $events)
185    {
186        $events->setIdentifiers([__CLASS__]);
187        $this->events = $events;
188    }
189
190    /**
191     * Return EventManager instance.
192     *
193     * Lazy loads a new EventManager if none was set.
194     *
195     * @return EventManagerInterface
196     */
197    public function getEventManager()
198    {
199        if (!$this->events) {
200            $this->setEventManager(new EventManager());
201        }
202        return $this->events;
203    }
204}