Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
DPLATerms
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 8
380
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
 setConfig
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 process
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getResults
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getApiInput
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 processResults
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
56
 isCollapsed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * DPLATerms 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   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/wiki/development:plugins:recommendation_modules Wiki
28 */
29
30namespace VuFind\Recommend;
31
32use Laminas\Http\Client\Adapter\Exception\TimeoutException;
33use Laminas\Http\Client as HttpClient;
34
35use function is_array;
36
37/**
38 * DPLATerms Recommendations Module
39 *
40 * This class uses current search terms to query the DPLA API.
41 *
42 * @category VuFind
43 * @package  Recommendations
44 * @author   Demian Katz <demian.katz@villanova.edu>
45 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
46 * @link     https://vufind.org/wiki/development:plugins:recommendation_modules Wiki
47 */
48class DPLATerms implements RecommendInterface
49{
50    /**
51     * Config
52     *
53     * @var string
54     */
55    protected $apiKey;
56
57    /**
58     * VuFind HTTP Client
59     *
60     * @var HttpClient
61     */
62    protected $client;
63
64    /**
65     * Setting of initial collapsedness
66     *
67     * @var bool
68     */
69    protected $collapsed;
70
71    /**
72     * Search results object
73     *
74     * @var \VuFind\Search\Base\Results
75     */
76    protected $searchObject;
77
78    /**
79     * Map of Solr field names to equivalent API parameters
80     *
81     * @var array
82     */
83    protected $formatMap = [
84        'author_facet'        => 'sourceResource.creator',
85        'building'            => 'provider.name',
86        'format'              => 'sourceResource.format',
87        'geographic_facet'    => 'sourceResource.spatial.region',
88        'institution'         => 'provider.name',
89        'language'            => 'sourceResource.language.name',
90        'publishDate'         => 'sourceResource.date.begin',
91    ];
92
93    /**
94     * List of fields to retrieve from the API
95     *
96     * @var array
97     */
98    protected $returnFields = [
99        'id',
100        'dataProvider',
101        'sourceResource.title',
102        'sourceResource.description',
103    ];
104
105    /**
106     * Constructor
107     *
108     * @param string     $apiKey API key
109     * @param HttpClient $client VuFind HTTP client
110     */
111    public function __construct($apiKey, HttpClient $client)
112    {
113        $this->apiKey = $apiKey;
114        $this->client = $client;
115    }
116
117    /**
118     * Store the configuration of the recommendation module.
119     *
120     * @param string $settings Settings from searches.ini.
121     *
122     * @return void
123     */
124    public function setConfig($settings)
125    {
126        $this->collapsed = filter_var($settings, FILTER_VALIDATE_BOOLEAN);
127    }
128
129    /**
130     * Called before the Search Results object performs its main search
131     * (specifically, in response to \VuFind\Search\SearchRunner::EVENT_CONFIGURED).
132     * This method is responsible for setting search parameters needed by the
133     * recommendation module and for reading any existing search parameters that may
134     * be needed.
135     *
136     * @param \VuFind\Search\Base\Params $params  Search parameter object
137     * @param \Laminas\Stdlib\Parameters $request Parameter object representing user
138     * request.
139     *
140     * @return void
141     *
142     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
143     */
144    public function init($params, $request)
145    {
146        // No action needed.
147    }
148
149    /**
150     * Called after the Search Results object has performed its main search. This
151     * may be used to extract necessary information from the Search Results object
152     * or to perform completely unrelated processing.
153     *
154     * @param \VuFind\Search\Base\Results $results Search results object
155     *
156     * @return void
157     */
158    public function process($results)
159    {
160        $this->searchObject = $results;
161    }
162
163    /**
164     * Get terms related to the query.
165     *
166     * @return array
167     */
168    public function getResults()
169    {
170        $this->client->setUri('http://api.dp.la/v2/items');
171        $this->client->setMethod('GET');
172        $this->client->setParameterGet($this->getApiInput());
173        try {
174            $response = $this->client->send();
175        } catch (TimeoutException $e) {
176            error_log('DPLA API timeout -- skipping recommendations.');
177            return [];
178        }
179        if (!$response->isSuccess()) {
180            return [];
181        }
182        return $this->processResults($response->getBody());
183    }
184
185    /**
186     * Get input parameters for API call.
187     *
188     * @return array
189     */
190    protected function getApiInput()
191    {
192        // Extract the first search term from the search object:
193        $search = $this->searchObject->getParams()->getQuery();
194        $filters = $this->searchObject->getParams()->getRawFilters();
195        $lookfor = ($search instanceof \VuFindSearch\Query\Query)
196            ? $search->getString()
197            : '';
198
199        $params = [
200            'q' => $lookfor,
201            'fields' => implode(',', $this->returnFields),
202            'api_key' => $this->apiKey,
203        ];
204        foreach ($filters as $field => $filter) {
205            if (isset($this->formatMap[$field])) {
206                $params[$this->formatMap[$field]] = implode(',', $filter);
207            }
208        }
209        return $params;
210    }
211
212    /**
213     * Process the API response.
214     *
215     * @param string $response API response
216     *
217     * @return array
218     */
219    protected function processResults($response)
220    {
221        $body = json_decode($response);
222        $results = [];
223        if ($body->count > 0) {
224            $title = 'sourceResource.title';
225            $desc = 'sourceResource.description';
226            foreach ($body->docs as $i => $doc) {
227                $results[$i] = [
228                    'title' => is_array($doc->$title)
229                        ? current($doc->$title)
230                        : $doc->$title,
231                    'provider' => is_array($doc->dataProvider)
232                        ? current($doc->dataProvider)
233                        : $doc->dataProvider,
234                    'link' => 'http://dp.la/item/' . $doc->id,
235                ];
236                if (isset($doc->$desc)) {
237                    $results[$i]['desc'] = is_array($doc->$desc)
238                        ? current($doc->$desc)
239                        : $doc->$desc;
240                }
241            }
242        }
243        return $results;
244    }
245
246    /**
247     * Return the list of facets configured to be collapsed
248     *
249     * @return array
250     */
251    public function isCollapsed()
252    {
253        return $this->collapsed;
254    }
255}