Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
69.57% covered (warning)
69.57%
64 / 92
60.00% covered (warning)
60.00%
6 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Map
69.57% covered (warning)
69.57%
64 / 92
60.00% covered (warning)
60.00%
6 / 10
66.59
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 supportsAjax
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDescription
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMapGraticule
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBasemap
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isActive
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 getGeoLocationCoords
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
4.01
 getDisplayCoords
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
4
 getMapLabels
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
90
 getMapTabData
88.46% covered (warning)
88.46%
23 / 26
0.00% covered (danger)
0.00%
0 / 1
7.08
1<?php
2
3/**
4 * Map tab
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  RecordTabs
25 * @author   Demian Katz <demian.katz@villanova.edu>
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:record_tabs Wiki
29 */
30
31namespace VuFind\RecordTab;
32
33use VuFind\Config\PathResolver;
34
35use function count;
36
37/**
38 * Map tab
39 *
40 * @category VuFind
41 * @package  RecordTabs
42 * @author   Demian Katz <demian.katz@villanova.edu>
43 * @author   Leila Gonzales <lmg@agiweb.org>
44 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
45 * @link     https://vufind.org/wiki/development:plugins:record_tabs Wiki
46 */
47class Map extends AbstractBase
48{
49    /**
50     * Should Map Tab be displayed?
51     *
52     * @var bool
53     */
54    protected $mapTabDisplay = false;
55
56    /**
57     * Should we display coordinates as part of labels?
58     *
59     * @var bool
60     */
61    protected $displayCoords = false;
62
63    /**
64     * Map labels setting from config.ini.
65     *
66     * @var string
67     */
68    protected $mapLabels = null;
69
70    /**
71     * Display graticule / map lat long grid?
72     *
73     * @var bool
74     */
75    protected $graticule = false;
76
77    /**
78     * Basemap settings
79     *
80     * @var array
81     */
82    protected $basemapOptions = [];
83
84    /**
85     * Configuration file path resolver
86     *
87     * @var PathResolver
88     */
89    protected $pathResolver;
90
91    /**
92     * Constructor
93     *
94     * @param bool         $mapTabDisplay  Display Map
95     * @param array        $basemapOptions basemap settings
96     * @param array        $mapTabOptions  MapTab settings
97     * @param PathResolver $pathResolver   Config file path resolver
98     */
99    public function __construct(
100        $mapTabDisplay = false,
101        $basemapOptions = [],
102        $mapTabOptions = [],
103        PathResolver $pathResolver = null
104    ) {
105        if ($mapTabDisplay) {
106            $this->mapTabDisplay = $mapTabDisplay;
107            $legalOptions = ['displayCoords', 'mapLabels', 'graticule'];
108            foreach ($legalOptions as $option) {
109                if (isset($mapTabOptions[$option])) {
110                    $this->$option = $mapTabOptions[$option];
111                }
112            }
113            $this->basemapOptions[0] = $basemapOptions['basemap_url'];
114            $this->basemapOptions[1] = $basemapOptions['basemap_attribution'];
115        }
116        $this->pathResolver = $pathResolver;
117    }
118
119    /**
120     * Can this tab be loaded via AJAX?
121     *
122     * @return bool
123     */
124    public function supportsAjax()
125    {
126        // No, magic required
127        return false;
128    }
129
130    /**
131     * Get the on-screen description for this tab.
132     *
133     * @return string
134     */
135    public function getDescription()
136    {
137        return 'Map View';
138    }
139
140    /**
141     * Get the map graticule setting.
142     *
143     * @return string
144     */
145    public function getMapGraticule()
146    {
147        return $this->graticule;
148    }
149
150    /**
151     * Get the basemap configuration settings.
152     *
153     * @return array
154     */
155    public function getBasemap()
156    {
157        return $this->basemapOptions;
158    }
159
160    /**
161     * Is this tab active?
162     *
163     * @return bool
164     */
165    public function isActive()
166    {
167        if ($this->mapTabDisplay) {
168            $geocoords = $this->getRecordDriver()->tryMethod('getGeoLocation');
169            return !empty($geocoords);
170        }
171        return false;
172    }
173
174    /**
175     * Get the bbox-geo coordinates.
176     *
177     * @return array
178     */
179    public function getGeoLocationCoords()
180    {
181        $geoCoords = $this->getRecordDriver()->tryMethod('getGeoLocation');
182        if (empty($geoCoords)) {
183            return [];
184        }
185        $coordarray = [];
186        /* Extract coordinates from long_lat field */
187        foreach ($geoCoords as $value) {
188            $match = [];
189            if (preg_match('/ENVELOPE\((.*),(.*),(.*),(.*)\)/', $value, $match)) {
190                $lonW = (float)$match[1];
191                $lonE = (float)$match[2];
192                $latN = (float)$match[3];
193                $latS = (float)$match[4];
194                // Coordinates ordered for display as WSEN
195                array_push($coordarray, [$lonW, $latS, $lonE, $latN]);
196            }
197        }
198        return $coordarray;
199    }
200
201    /**
202     * Get the map display coordinates.
203     *
204     * @return array
205     */
206    public function getDisplayCoords()
207    {
208        $label_coords = [];
209        $coords = $this->getRecordDriver()->tryMethod('getDisplayCoordinates');
210        foreach ($coords as $val) {
211            $coord = explode(' ', $val);
212            $labelW = $coord[0];
213            $labelE = $coord[1];
214            $labelN = $coord[2];
215            $labelS = $coord[3];
216            /* Create coordinate label for map display */
217            if (($labelW == $labelE) && ($labelN == $labelS)) {
218                $labelcoord = $labelS . ' ' . $labelE;
219            } else {
220                /* Coordinate order is min to max on lat and long axes */
221                $labelcoord = $labelS . ' ' . $labelN . ' ' .
222                $labelW . ' ' . $labelE;
223            }
224            array_push($label_coords, $labelcoord);
225        }
226        return $label_coords;
227    }
228
229    /**
230     * Get the map labels.
231     *
232     * @return array
233     */
234    public function getMapLabels()
235    {
236        $mapLabelData = explode(':', $this->mapLabels);
237        if ($mapLabelData[0] == 'driver') {
238            return $this->getRecordDriver()->tryMethod('getCoordinateLabels') ?? [];
239        }
240        $labels = [];
241        if ($mapLabelData[0] == 'file') {
242            $coords = $this->getRecordDriver()->tryMethod('getDisplayCoordinates');
243            /* read lookup file into array */
244            $label_lookup = [];
245            $file = $this->pathResolver
246                ? $this->pathResolver->getConfigPath($mapLabelData[1])
247                : \VuFind\Config\Locator::getConfigPath($mapLabelData[1]);
248            if (file_exists($file)) {
249                $fp = fopen($file, 'r');
250                while (($line = fgetcsv($fp, 0, "\t")) !== false) {
251                    if (count($line) > 1) {
252                        $label_lookup[$line[0]] = $line[1];
253                    }
254                }
255                fclose($fp);
256            }
257            $labels = [];
258            if (null !== $coords) {
259                foreach ($coords as $val) {
260                    /* Collapse spaces to make combined coordinate string to match
261                        against lookup table coordinate */
262                    $coordmatch = implode('', explode(' ', $val));
263                    /* See if coordinate string matches lookup
264                        table coordinates and if so return label */
265                    $labelname = $label_lookup[$coordmatch] ?? '';
266                    array_push($labels, $labelname);
267                }
268            }
269        }
270        return $labels;
271    }
272
273    /**
274     * Construct the map coordinates and labels array.
275     *
276     * @return array
277     */
278    public function getMapTabData()
279    {
280        $geoCoords = $this->getGeoLocationCoords();
281        if (empty($geoCoords)) {
282            return [];
283        }
284        $mapTabData = [];
285        $mapDisplayCoords = [];
286        $mapDisplayLabels = [];
287        if ($this->displayCoords) {
288            $mapDisplayCoords = $this->getDisplayCoords();
289        }
290        if (isset($this->mapLabels)) {
291            $mapDisplayLabels = $this->getMapLabels();
292        }
293        // Pass coordinates, display coordinates, and labels
294        foreach (array_keys($geoCoords) as $key) {
295            $mapCoords = '';
296            $mapLabel = '';
297            if ($this->displayCoords) {
298                $mapCoords = $mapDisplayCoords[$key];
299            }
300            if (isset($this->mapLabels)) {
301                $mapLabel = $mapDisplayLabels[$key];
302            }
303            array_push(
304                $mapTabData,
305                [
306                    $geoCoords[$key][0], $geoCoords[$key][1],
307                    $geoCoords[$key][2], $geoCoords[$key][3],
308                    $mapLabel, $mapCoords,
309                ]
310            );
311        }
312        return $mapTabData;
313    }
314}