Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
RecommendListener
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 5
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 attach
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 setConfig
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onSearchConfigured
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
56
 onSearchComplete
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3/**
4 * Recommend listener.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2013.
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 Site
28 */
29
30namespace VuFind\Search;
31
32use Laminas\EventManager\EventInterface;
33use Laminas\EventManager\SharedEventManagerInterface;
34use VuFind\Recommend\PluginManager;
35
36/**
37 * Recommend listener.
38 *
39 * @category VuFind
40 * @package  Search
41 * @author   Demian Katz <demian.katz@villanova.edu>
42 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
43 * @link     https://vufind.org Main Site
44 */
45class RecommendListener
46{
47    /**
48     * Recommendation configuration.
49     *
50     * @var array
51     */
52    protected $config = [];
53
54    /**
55     * Recommendation modules, indexed by location.
56     *
57     * @var array
58     */
59    protected $objects = [];
60
61    /**
62     * Recommendation module plugin manager.
63     *
64     * @var PluginManager
65     */
66    protected $pluginManager;
67
68    /**
69     * The ID of the search for which this listener should respond. Value is set
70     * by \VuFind\Search\SearchRunner and makes sure that each search run by the
71     * runner is handled by its own independent RecommendListener. Otherwise,
72     * the wrong recommendations might be injected into the wrong objects!
73     *
74     * @var int
75     */
76    protected $searchId;
77
78    /**
79     * Constructor.
80     *
81     * @param PluginManager $pluginManager Plugin manager for recommendation
82     * modules
83     * @param int           $searchId      The ID of the search for which this
84     * listener should respond
85     */
86    public function __construct(PluginManager $pluginManager, $searchId)
87    {
88        $this->pluginManager = $pluginManager;
89        $this->searchId = $searchId;
90    }
91
92    /**
93     * Attach listener to shared event manager.
94     *
95     * @param SharedEventManagerInterface $manager Shared event manager
96     *
97     * @return void
98     */
99    public function attach(SharedEventManagerInterface $manager)
100    {
101        $manager->attach(
102            \VuFind\Search\SearchRunner::class,
103            SearchRunner::EVENT_CONFIGURED,
104            [$this, 'onSearchConfigured']
105        );
106        $manager->attach(
107            \VuFind\Search\SearchRunner::class,
108            SearchRunner::EVENT_COMPLETE,
109            [$this, 'onSearchComplete']
110        );
111    }
112
113    /**
114     * Set configuration
115     *
116     * @param array $config Configuration array
117     *
118     * @return void
119     */
120    public function setConfig($config)
121    {
122        $this->config = $config;
123    }
124
125    /**
126     * Set up recommendation modules.
127     *
128     * @param EventInterface $event Event
129     *
130     * @return EventInterface
131     */
132    public function onSearchConfigured(EventInterface $event)
133    {
134        // Make sure we're triggering in the appropriate context:
135        if ($this->searchId != $event->getParam('runningSearchId')) {
136            return;
137        }
138        $params = $event->getParam('params');
139        $request = $event->getParam('request');
140
141        // Process recommendations for each location:
142        $this->objects = [
143            'top' => [], 'side' => [], 'noresults' => [],
144            'bottom' => [],
145        ];
146        foreach ($this->config as $location => $currentSet) {
147            // If the current location is disabled, skip processing!
148            if (empty($currentSet)) {
149                continue;
150            }
151            // Now loop through all recommendation settings for the location.
152            foreach ((array)$currentSet as $current) {
153                // Break apart the setting into module name and extra parameters:
154                $current = explode(':', $current);
155                $module = array_shift($current);
156                if (empty($module)) {
157                    continue;
158                }
159                $config = implode(':', $current);
160                if (!$this->pluginManager->has($module)) {
161                    throw new \Exception(
162                        'Could not load recommendation module: ' . $module
163                    );
164                }
165
166                // Build a recommendation module with the provided settings.
167                $obj = $this->pluginManager->get($module);
168                $obj->setConfig($config);
169                $obj->init($params, $request);
170                $this->objects[$location][] = $obj;
171            }
172        }
173
174        return $event;
175    }
176
177    /**
178     * Inject additional spelling suggestions.
179     *
180     * @param EventInterface $event Event
181     *
182     * @return EventInterface
183     */
184    public function onSearchComplete(EventInterface $event)
185    {
186        // Make sure we're triggering in the appropriate context:
187        if ($this->searchId != $event->getParam('runningSearchId')) {
188            return;
189        }
190        $results = $event->getParam('results');
191        // Process recommendations:
192        foreach ($this->objects as $currentSet) {
193            foreach ($currentSet as $current) {
194                $current->process($results);
195            }
196        }
197        $results->setRecommendations($this->objects);
198        return $event;
199    }
200}