Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.09% covered (warning)
89.09%
49 / 55
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
EuropeanaResults
89.09% covered (warning)
89.09%
49 / 55
33.33% covered (danger)
33.33%
2 / 6
25.81
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setConfig
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
11.07
 getURL
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
3.71
 init
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
3.01
 process
95.65% covered (success)
95.65%
22 / 23
0.00% covered (danger)
0.00%
0 / 1
6
 getResults
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * EuropeanaResults Recommendations Module
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  Recommendations
25 * @author   Lutz Biedinger <lutz.biedinger@gmail.com>
26 * @author   Demian Katz <demian.katz@villanova.edu>
27 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
28 * @link     https://vufind.org/wiki/development:plugins:recommendation_modules Wiki
29 */
30
31namespace VuFind\Recommend;
32
33use Laminas\Feed\Reader\Reader as FeedReader;
34
35use function count;
36use function intval;
37use function is_object;
38
39/**
40 * EuropeanaResults Recommendations Module
41 *
42 * This class provides recommendations by using the Europeana API.
43 *
44 * @category VuFind
45 * @package  Recommendations
46 * @author   Lutz Biedinger <lutz.biedinger@gmail.com>
47 * @author   Demian Katz <demian.katz@villanova.edu>
48 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
49 * @link     https://vufind.org/wiki/development:plugins:recommendation_modules Wiki
50 */
51class EuropeanaResults implements
52    RecommendInterface,
53    \VuFindHttp\HttpServiceAwareInterface,
54    \Laminas\Log\LoggerAwareInterface
55{
56    use \VuFind\Log\LoggerAwareTrait;
57    use \VuFindHttp\HttpServiceAwareTrait;
58
59    /**
60     * Request parameter for searching
61     *
62     * @var string
63     */
64    protected $requestParam;
65
66    /**
67     * Result limit
68     *
69     * @var int
70     */
71    protected $limit;
72
73    /**
74     * Europeana base URL
75     *
76     * @var string
77     */
78    protected $baseUrl;
79
80    /**
81     * Fully constructed API URL
82     *
83     * @var string
84     */
85    protected $targetUrl;
86
87    /**
88     * Providers to exclude
89     *
90     * @var array
91     */
92    protected $excludeProviders;
93
94    /**
95     * Site to search
96     *
97     * @var string
98     */
99    protected $searchSite;
100
101    /**
102     * Link for more results
103     *
104     * @var string
105     */
106    protected $sitePath;
107
108    /**
109     * API key
110     *
111     * @var string
112     */
113    protected $key;
114
115    /**
116     * Search string
117     *
118     * @var string
119     */
120    protected $lookfor;
121
122    /**
123     * Search results
124     *
125     * @var array
126     */
127    protected $results;
128
129    /**
130     * Constructor
131     *
132     * @param string $key API key
133     */
134    public function __construct($key)
135    {
136        $this->key = $key;
137    }
138
139    /**
140     * Store the configuration of the recommendation module.
141     *
142     * @param string $settings Settings from searches.ini.
143     *
144     * @return void
145     */
146    public function setConfig($settings)
147    {
148        // Parse out parameters:
149        $params = explode(':', $settings);
150        $this->baseUrl = (isset($params[0]) && !empty($params[0]))
151            ? $params[0] : 'api.europeana.eu/api/v2/opensearch.rss';
152        $this->requestParam = (isset($params[1]) && !empty($params[1]))
153            ? $params[1] : 'searchTerms';
154        $this->limit = isset($params[2]) && is_numeric($params[2])
155                        && $params[2] > 0 ? intval($params[2]) : 5;
156        $this->excludeProviders = (isset($params[3]) && !empty($params[3]))
157            ? $params[3] : [];
158        //make array
159        if (!empty($this->excludeProviders)) {
160            $this->excludeProviders = explode(',', $this->excludeProviders);
161        }
162        $this->searchSite = 'Europeana.eu';
163    }
164
165    /**
166     * Build the url which will be send to retrieve the RSS results
167     *
168     * @param string $targetUrl        Base URL
169     * @param string $requestParam     Parameter name to add
170     * @param array  $excludeProviders An array of providers to exclude when
171     * getting results.
172     *
173     * @return string The url to be sent
174     */
175    protected function getURL($targetUrl, $requestParam, $excludeProviders)
176    {
177        // build url
178        $url = $targetUrl . '?' . $requestParam . '=' . $this->lookfor;
179        // add providers to ignore
180        foreach ($excludeProviders as $provider) {
181            $provider = trim($provider);
182            if (!empty($provider)) {
183                $url .= urlencode(' NOT europeana_dataProvider:"' . $provider . '"');
184            }
185        }
186        $url .= '&wskey=' . urlencode($this->key);
187
188        // return complete url
189        return $url;
190    }
191
192    /**
193     * Called before the Search Results object performs its main search
194     * (specifically, in response to \VuFind\Search\SearchRunner::EVENT_CONFIGURED).
195     * This method is responsible for setting search parameters needed by the
196     * recommendation module and for reading any existing search parameters that may
197     * be needed.
198     *
199     * @param \VuFind\Search\Base\Params $params  Search parameter object
200     * @param \Laminas\Stdlib\Parameters $request Parameter object representing user
201     * request.
202     *
203     * @return void
204     */
205    public function init($params, $request)
206    {
207        // Collect the best possible search term(s):
208        $this->lookfor = $request->get('lookfor', '');
209        if (empty($this->lookfor) && is_object($params)) {
210            $this->lookfor = $params->getQuery()->getAllTerms();
211        }
212        $this->lookfor = urlencode(trim($this->lookfor));
213        $this->sitePath = 'http://www.europeana.eu/portal/search.html?query=' .
214            $this->lookfor;
215        $this->targetUrl = $this->getURL(
216            'http://' . $this->baseUrl,
217            $this->requestParam,
218            $this->excludeProviders
219        );
220    }
221
222    /**
223     * Called after the Search Results object has performed its main search. This
224     * may be used to extract necessary information from the Search Results object
225     * or to perform completely unrelated processing.
226     *
227     * @param \VuFind\Search\Base\Results $results Search results object
228     *
229     * @return void
230     */
231    public function process($results)
232    {
233        $this->debug('Pulling feed from ' . $this->targetUrl);
234        if (null !== $this->httpService) {
235            FeedReader::setHttpClient(
236                $this->httpService->createClient($this->targetUrl)
237            );
238        }
239        $parsedFeed = FeedReader::import($this->targetUrl);
240        $resultsProcessed = [];
241        foreach ($parsedFeed as $value) {
242            $link = $value->getLink();
243            if (!empty($link)) {
244                $resultsProcessed[] = [
245                    'title' => $value->getTitle(),
246                    'link' => $link,
247                    'enclosure' => $value->getEnclosure()['url'] ?? null,
248                ];
249            }
250            if (count($resultsProcessed) == $this->limit) {
251                break;
252            }
253        }
254
255        if (!empty($resultsProcessed)) {
256            $this->results = [
257                'worksArray' => $resultsProcessed,
258                'feedTitle' => $this->searchSite,
259                'sourceLink' => $this->sitePath,
260            ];
261        } else {
262            $this->results = false;
263        }
264    }
265
266    /**
267     * Get the results of the query (false if none).
268     *
269     * @return array|bool
270     */
271    public function getResults()
272    {
273        return $this->results;
274    }
275}