Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
16.87% covered (danger)
16.87%
14 / 83
38.46% covered (danger)
38.46%
5 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
MapSelection
16.87% covered (danger)
16.87%
14 / 83
38.46% covered (danger)
38.46%
5 / 13
300.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 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 / 31
0.00% covered (danger)
0.00%
0 / 1
30
 getSelectedCoordinates
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultCoordinates
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBasemap
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getHeight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSearchParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getGeoField
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fetchDataFromSearchService
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 getSearchResultCoordinates
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getMapResultCoordinates
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3/**
4 * MapSelection 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   Vaclav Rosecky <xrosecky@gmail.com>
26 * @author   Leila Gonzales <lmg@agiweb.org>
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 VuFindSearch\Backend\Solr\Command\RawJsonSearchCommand;
34use VuFindSearch\Service;
35
36/**
37 * MapSelection Recommendations Module
38 *
39 * @category VuFind
40 * @package  Recommendations
41 * @author   Vaclav Rosecky <xrosecky@gmail.com>
42 * @author   Leila Gonzales <lmg@agiweb.org>
43 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
44 * @link     https://vufind.org/wiki/development:plugins:recommendation_modules Wiki
45 */
46class MapSelection implements
47    \VuFind\Recommend\RecommendInterface,
48    \VuFind\I18n\Translator\TranslatorAwareInterface
49{
50    use \VuFind\I18n\Translator\TranslatorAwareTrait;
51
52    /**
53     * Basemap configuration parameters
54     *
55     * @var array
56     */
57    protected $basemapOptions = [];
58
59    /**
60     * Default coordinates. Order is WENS
61     *
62     * @var array
63     */
64    protected $defaultCoordinates = [];
65
66    /**
67     * The geoField variable name
68     *
69     * @var string
70     */
71    protected $geoField = 'long_lat';
72
73    /**
74     * Height of search map pane
75     *
76     * @var string
77     */
78    protected $height;
79
80    /**
81     * Selected coordinates
82     *
83     * @var string
84     */
85    protected $selectedCoordinates = null;
86
87    /**
88     * Search parameters
89     *
90     * @var object
91     */
92    protected $searchParams = null;
93
94    /**
95     * Search Results coordinates
96     *
97     * @var array
98     */
99    protected $searchResultCoords = [];
100
101    /**
102     * Bbox search box coordinates
103     *
104     * @var array
105     */
106    protected $bboxSearchCoords = [];
107
108    /**
109     * Search service
110     *
111     * @var Service
112     */
113    protected $searchService;
114
115    /**
116     * Query Object
117     *
118     * @var \VuFindSearch\Query\QueryInterface
119     */
120    protected $searchQuery;
121
122    /**
123     * Backend Parameters / Search Filters
124     *
125     * @var \VuFindSearch\ParamBag
126     */
127    protected $searchFilters;
128
129    /**
130     * Constructor
131     *
132     * @param Service $ss                  Search service
133     * @param array   $basemapOptions      Basemap Options
134     * @param array   $mapSelectionOptions Map Options
135     */
136    public function __construct($ss, $basemapOptions, $mapSelectionOptions)
137    {
138        $this->searchService = $ss;
139        $this->basemapOptions = $basemapOptions;
140        $this->defaultCoordinates = explode(
141            ',',
142            $mapSelectionOptions['default_coordinates']
143        );
144        $this->height = $mapSelectionOptions['height'];
145    }
146
147    /**
148     * SetConfig
149     *
150     * Store the configuration of the recommendation module.
151     *
152     * @param string $settings Settings from searches.ini.
153     *
154     * @return void
155     */
156    public function setConfig($settings)
157    {
158    }
159
160    /**
161     * Called before the Search Results object performs its main search
162     * (specifically, in response to \VuFind\Search\SearchRunner::EVENT_CONFIGURED).
163     * This method is responsible for setting search parameters needed by the
164     * recommendation module and for reading any existing search parameters that may
165     * be needed.
166     *
167     * @param \VuFind\Search\Solr\Params $params  Search parameter object
168     * @param \Laminas\Stdlib\Parameters $request Parameter object representing user
169     * request.
170     *
171     * @return void
172     */
173    public function init($params, $request)
174    {
175    }
176
177    /**
178     * Process
179     *
180     * Called after the Search Results object has performed its main search. This
181     * may be used to extract necessary information from the Search Results object
182     * or to perform completely unrelated processing.
183     *
184     * @param \VuFind\Search\Base\Results $results Search results object
185     *
186     * @return void
187     */
188    public function process($results)
189    {
190        $reorder_coords = [];
191        $filters = $results->getParams()->getRawFilters();
192        foreach ($filters as $key => $value) {
193            if ($key == $this->geoField) {
194                $match = [];
195                if (
196                    preg_match(
197                        '/Intersects\(ENVELOPE\((.*), (.*), (.*), (.*)\)\)/',
198                        $value[0],
199                        $match
200                    )
201                ) {
202                    array_push(
203                        $this->bboxSearchCoords,
204                        (float)$match[1],
205                        (float)$match[2],
206                        (float)$match[3],
207                        (float)$match[4]
208                    );
209                    // Need to reorder coords from WENS to WSEN
210                    array_push(
211                        $reorder_coords,
212                        (float)$match[1],
213                        (float)$match[4],
214                        (float)$match[2],
215                        (float)$match[3]
216                    );
217                    $this->selectedCoordinates = $reorder_coords;
218                }
219                $this->searchParams = $results->getUrlQuery()
220                    ->removeFacet($this->geoField, $value[0])->getParams(false);
221            }
222        }
223        if ($this->searchParams == null) {
224            $this->searchParams = $results->getUrlQuery()->getParams(false);
225        }
226        $this->searchFilters = $results->getParams()->getBackendParameters();
227        $this->searchQuery = $results->getParams()->getQuery();
228    }
229
230    /**
231     * GetSelectedCoordinates
232     *
233     * Return coordinates selected by user
234     *
235     * @return array of floats
236     */
237    public function getSelectedCoordinates()
238    {
239        return $this->selectedCoordinates;
240    }
241
242    /**
243     * GetDefaultCoordinates
244     *
245     * Return default coordinates from configuration
246     *
247     * @return array of floats
248     */
249    public function getDefaultCoordinates()
250    {
251        return $this->defaultCoordinates;
252    }
253
254    /**
255     * Get the basemap configuration settings.
256     *
257     * @return array
258     */
259    public function getBasemap()
260    {
261        return [
262            $this->basemapOptions['basemap_url'],
263            $this->basemapOptions['basemap_attribution'],
264        ];
265    }
266
267    /**
268     * GetHeight
269     *
270     * Return height of map in pixels
271     *
272     * @return number
273     */
274    public function getHeight()
275    {
276        return $this->height;
277    }
278
279    /**
280     * GetSearchParams
281     *
282     * Return search params without filter for geographic search
283     *
284     * @return string
285     */
286    public function getSearchParams()
287    {
288        return $this->searchParams;
289    }
290
291    /**
292     * GetGeoField
293     *
294     * Return Solr field to use for geographic search
295     *
296     * @return string
297     */
298    public function getGeoField()
299    {
300        return $this->geoField;
301    }
302
303    /**
304     * Fetch details from search service
305     *
306     * @return array
307     */
308    public function fetchDataFromSearchService()
309    {
310        $params = $this->searchFilters;
311        $params->set('fl', 'id, ' . $this->geoField . ', title');
312        $command = new RawJsonSearchCommand(
313            'Solr',
314            $this->searchQuery,
315            0,
316            10000000,   // set to return all results
317            $params
318        );
319        $response = $this->searchService->invoke($command)->getResult();
320        $defaultTitle = $this->translate('Title not available');
321        $callback = function ($current) use ($defaultTitle) {
322            return [
323                $current->id,
324                $current->{$this->geoField},
325                $current->title ?? $defaultTitle,
326            ];
327        };
328        return array_map($callback, $response->response->docs);
329    }
330
331    /**
332     * Get geo field values for all search results
333     *
334     * @return array
335     */
336    public function getSearchResultCoordinates()
337    {
338        $params = $this->searchFilters;
339        // Check to makes sure we have a geographic search
340        $filters = $params->get('fq');
341        return (!empty($filters) && str_contains($filters[0], $this->geoField))
342            ? $this->fetchDataFromSearchService() : [];
343    }
344
345    /**
346     * Process search result record coordinate values
347     * for Leaflet mapping platform.
348     *
349     * @return array
350     */
351    public function getMapResultCoordinates()
352    {
353        $results = [];
354        $rawCoords = $this->getSearchResultCoordinates();
355        foreach ($rawCoords as $idCoords) {
356            foreach ($idCoords[1] as $coord) {
357                $recCoords = [];
358                $recId = $idCoords[0];
359                $title = $idCoords[2];
360                // convert title to UTF-8
361                $title = mb_convert_encoding($title, 'UTF-8');
362                $patternStr = '/ENVELOPE\((.*),(.*),(.*),(.*)\)/';
363                if (preg_match($patternStr, $coord, $match)) {
364                    $floats = array_map('floatval', $match);
365                    $recCoords = [$floats[1], $floats[2], $floats[3], $floats[4]];
366                }
367                $results[] = [$recId, $title, $recCoords[0],
368                    $recCoords[1], $recCoords[2], $recCoords[3],
369                ];
370            }
371        }
372        return $results;
373    }
374}