Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.00% |
38 / 40 |
|
88.24% |
15 / 17 |
CRAP | |
0.00% |
0 / 1 |
RecordCollection | |
95.00% |
38 / 40 |
|
88.24% |
15 / 17 |
25 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getSpellcheck | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
getTotal | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFacets | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
setFilteredFacetCounts | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getFilteredFacetCounts | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setFacets | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getQueryFacets | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getPivotFacets | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
getGroups | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHighlighting | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCursorMark | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getMaxScore | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getResponseHeader | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSolrParameters | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSpellcheckQuery | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getRawSpellcheckSuggestions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | /** |
4 | * Simple JSON-based record collection. |
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 David Maus <maus@hab.de> |
26 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
27 | * @link https://vufind.org |
28 | */ |
29 | |
30 | namespace VuFindSearch\Backend\Solr\Response\Json; |
31 | |
32 | use VuFindSearch\Response\AbstractRecordCollection; |
33 | |
34 | use function array_key_exists; |
35 | |
36 | /** |
37 | * Simple JSON-based record collection. |
38 | * |
39 | * @category VuFind |
40 | * @package Search |
41 | * @author David Maus <maus@hab.de> |
42 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
43 | * @link https://vufind.org |
44 | */ |
45 | class RecordCollection extends AbstractRecordCollection |
46 | { |
47 | /** |
48 | * Template of deserialized SOLR response. |
49 | * |
50 | * @see \VuFindSearch\Backend\Solr\Response\Json\RecordCollection::__construct() |
51 | * |
52 | * @var array |
53 | */ |
54 | protected static $template = [ |
55 | 'responseHeader' => [], |
56 | 'response' => ['numFound' => 0, 'start' => 0], |
57 | 'spellcheck' => ['suggestions' => []], |
58 | 'facet_counts' => [], |
59 | ]; |
60 | |
61 | /** |
62 | * Deserialized SOLR response. |
63 | * |
64 | * @var array |
65 | */ |
66 | protected $response; |
67 | |
68 | /** |
69 | * Spellcheck information. |
70 | * |
71 | * @var Spellcheck |
72 | */ |
73 | protected $spellcheck; |
74 | |
75 | /** |
76 | * Facet fields. |
77 | * |
78 | * @var array |
79 | */ |
80 | protected $facetFields = null; |
81 | |
82 | /** |
83 | * How many facet values have been filtered out, indexed by field. |
84 | * |
85 | * @var array |
86 | */ |
87 | protected $filteredFacetCounts = []; |
88 | |
89 | /** |
90 | * Constructor. |
91 | * |
92 | * @param array $response Deserialized SOLR response |
93 | * |
94 | * @return void |
95 | */ |
96 | public function __construct(array $response) |
97 | { |
98 | if ( |
99 | array_key_exists('response', $response) |
100 | && null === $response['response'] |
101 | ) { |
102 | unset($response['response']); |
103 | } |
104 | $this->response = array_replace_recursive(static::$template, $response); |
105 | $this->offset = $this->response['response']['start']; |
106 | $this->rewind(); |
107 | } |
108 | |
109 | /** |
110 | * Return spellcheck information. |
111 | * |
112 | * @return Spellcheck |
113 | */ |
114 | public function getSpellcheck() |
115 | { |
116 | if (!$this->spellcheck) { |
117 | $this->spellcheck = new Spellcheck( |
118 | $this->getRawSpellcheckSuggestions(), |
119 | $this->getSpellcheckQuery() |
120 | ); |
121 | } |
122 | return $this->spellcheck; |
123 | } |
124 | |
125 | /** |
126 | * Return total number of records found. |
127 | * |
128 | * @return int |
129 | */ |
130 | public function getTotal() |
131 | { |
132 | return $this->response['response']['numFound']; |
133 | } |
134 | |
135 | /** |
136 | * Return available facets. |
137 | * |
138 | * Returns an associative array with the field name as key. The value is an |
139 | * associative array of available facets for the field, indexed by facet value. |
140 | * |
141 | * @return array |
142 | */ |
143 | public function getFacets() |
144 | { |
145 | if (null === $this->facetFields) { |
146 | $this->facetFields = []; |
147 | $facetFieldData = $this->response['facet_counts']['facet_fields'] ?? []; |
148 | foreach ($facetFieldData as $field => $facetData) { |
149 | $values = []; |
150 | foreach ($facetData as $value) { |
151 | $values[$value[0]] = $value[1]; |
152 | } |
153 | $this->facetFields[$field] = $values; |
154 | } |
155 | } |
156 | return $this->facetFields; |
157 | } |
158 | |
159 | /** |
160 | * Set filtered facet data. |
161 | * |
162 | * @param array $counts Counts of filtered facet values, indexed by field name. |
163 | * |
164 | * @return void |
165 | */ |
166 | public function setFilteredFacetCounts(array $counts): void |
167 | { |
168 | $this->filteredFacetCounts = $counts; |
169 | } |
170 | |
171 | /** |
172 | * Get filtered facet data. |
173 | * |
174 | * @return array |
175 | */ |
176 | public function getFilteredFacetCounts(): array |
177 | { |
178 | return $this->filteredFacetCounts; |
179 | } |
180 | |
181 | /** |
182 | * Set facets. |
183 | * |
184 | * @param array $facets Facet fields |
185 | * |
186 | * @return void |
187 | */ |
188 | public function setFacets(array $facets): void |
189 | { |
190 | $this->facetFields = $facets; |
191 | } |
192 | |
193 | /** |
194 | * Return available query facets. |
195 | * |
196 | * Returns an associative array with the internal field name as key. The |
197 | * value is an associative array of the available facets for the field, |
198 | * indexed by facet value. |
199 | * |
200 | * @return array |
201 | */ |
202 | public function getQueryFacets() |
203 | { |
204 | return $this->response['facet_counts']['facet_queries'] ?? []; |
205 | } |
206 | |
207 | /** |
208 | * Return available pivot facets. |
209 | * |
210 | * Returns an associative array with the internal field name as key. The |
211 | * value is an associative array of the available facets for the field, |
212 | * indexed by facet value. |
213 | * |
214 | * @return array |
215 | */ |
216 | public function getPivotFacets() |
217 | { |
218 | $result = []; |
219 | foreach ( |
220 | $this->response['facet_counts']['facet_pivot'] ?? [] as $facetData |
221 | ) { |
222 | foreach ($facetData as $current) { |
223 | $result[$current['value']] = $current; |
224 | } |
225 | } |
226 | return $result; |
227 | } |
228 | |
229 | /** |
230 | * Get grouped results. |
231 | * |
232 | * @return array |
233 | */ |
234 | public function getGroups() |
235 | { |
236 | return $this->response['grouped'] ?? []; |
237 | } |
238 | |
239 | /** |
240 | * Get highlighting details. |
241 | * |
242 | * @return array |
243 | */ |
244 | public function getHighlighting() |
245 | { |
246 | return $this->response['highlighting'] ?? []; |
247 | } |
248 | |
249 | /** |
250 | * Get cursorMark. |
251 | * |
252 | * @return string |
253 | */ |
254 | public function getCursorMark() |
255 | { |
256 | return $this->response['nextCursorMark'] ?? ''; |
257 | } |
258 | |
259 | /** |
260 | * Gets the highest relevance to search. |
261 | * |
262 | * @return mixed |
263 | */ |
264 | public function getMaxScore() |
265 | { |
266 | return $this->response['response']['maxScore'] ?? null; |
267 | } |
268 | |
269 | /** |
270 | * Get response header. |
271 | * |
272 | * @return array |
273 | */ |
274 | public function getResponseHeader() |
275 | { |
276 | return $this->response['responseHeader'] ?? []; |
277 | } |
278 | |
279 | /** |
280 | * Get raw Solr input parameters from the response. |
281 | * |
282 | * @return array |
283 | */ |
284 | protected function getSolrParameters() |
285 | { |
286 | return $this->response['responseHeader']['params'] ?? []; |
287 | } |
288 | |
289 | /** |
290 | * Extract the best matching Spellcheck query from the raw Solr input parameters. |
291 | * |
292 | * @return string |
293 | */ |
294 | protected function getSpellcheckQuery() |
295 | { |
296 | $params = $this->getSolrParameters(); |
297 | return $params['spellcheck.q'] ?? ($params['q'] ?? ''); |
298 | } |
299 | |
300 | /** |
301 | * Get raw Solr Spellcheck suggestions. |
302 | * |
303 | * @return array |
304 | */ |
305 | protected function getRawSpellcheckSuggestions() |
306 | { |
307 | return $this->response['spellcheck']['suggestions'] ?? []; |
308 | } |
309 | } |