Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 194
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Location
0.00% covered (danger)
0.00%
0 / 194
0.00% covered (danger)
0.00%
0 / 8
1560
0.00% covered (danger)
0.00%
0 / 1
 fetchId
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 fetchList
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 fetchFromCsv
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
6
 searchAll
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
56
 readSearchResultList
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
56
 fetchGeoJsonLocations
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
12
 fetchGeoJson
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
72
 fetchLocationsForCompilation
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3/**
4 * @package ClientDldb
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsdldb\Elastic;
9
10use BO\Zmsdldb\Entity\Location as Entity;
11use BO\Zmsdldb\Collection\Locations as Collection;
12use BO\Zmsdldb\File\Location as Base;
13
14/**
15 * @SuppressWarnings(Coupling)
16 */
17class Location extends Base
18{
19    /**
20     *
21     * @return Entity|false
22     */
23    #[\Override]
24    public function fetchId(mixed $itemId)
25    {
26        if ($itemId) {
27            $query = Helper::boolFilteredQuery();
28            $query->getFilter()->addMust(Helper::idsFilter($this->locale . $itemId));
29            $result = $this->access()
30                ->getIndex()
31                ->getType('location')
32                ->search($query, 1);
33
34            if ($result->count() == 1) {
35                $locationList = $result->getResults();
36                return new Entity($locationList[0]->getData());
37            }
38        }
39        return false;
40    }
41
42    /**
43     *
44     * @return Collection
45     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
46     */
47    #[\Override]
48    public function fetchList(bool|string $service_csv = '', bool $mixLanguages = false)
49    {
50        $query = Helper::boolFilteredQuery();
51        $limit = 10000;
52        $query->getFilter()->addMust(Helper::localeFilter($this->locale));
53        /** @psalm-suppress RiskyTruthyFalsyComparison */
54        if (is_string($service_csv) && $service_csv !== '') {
55            foreach (explode(',', $service_csv) as $service_id) {
56                $filter = new \Elastica\Filter\Term(array(
57                    'services.service' => $service_id
58                ));
59                $query->getFilter()->addMust($filter);
60            }
61        }
62        $resultList = $this->access()
63            ->getIndex()
64            ->getType('location')
65            ->search($query, $limit);
66
67        $locationList = new Collection();
68        foreach ($resultList as $result) {
69            $location = new Entity($result->getData());
70            $locationList[$location['id']] = $location;
71        }
72        return $locationList;
73    }
74
75    /**
76     *
77     * @return Collection
78     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
79     */
80    #[\Override]
81    public function fetchFromCsv(mixed $location_csv, bool $mixLanguages = false)
82    {
83        $query = Helper::boolFilteredQuery();
84        $filter = new \Elastica\Filter\Ids();
85        $ids = explode(',', $location_csv);
86        $ids = array_map(function ($value) {
87            return $this->locale . $value;
88        }, $ids);
89        $filter->setIds($ids);
90        $query->getFilter()->addMust($filter);
91        $resultList = $this->access()
92            ->getIndex()
93            ->getType('location')
94            ->search($query, 10000);
95        $locationList = new Collection();
96        foreach ($resultList as $result) {
97            $location = new Entity($result->getData());
98            $locationList[$location['id']] = $location;
99        }
100        return $locationList;
101    }
102
103    /**
104     *
105     * @return \BO\Zmsdldb\Collection\Authorities
106     * @psalm-api
107     */
108    public function searchAll(mixed $querystring, string $service_csv = '')
109    {
110        $query = Helper::boolFilteredQuery();
111        $mainquery = new \Elastica\Query();
112        $limit = 1000;
113        $searchquery = new \Elastica\Query\QueryString();
114        if ($querystring > 10000 && $querystring < 15000) {
115            // if it is a postal code, sort by distance and limit results
116            $coordinates = \BO\Zmsdldb\Plz\Coordinates::zip2LatLon($querystring);
117            if (false !== $coordinates) {
118                $searchquery->setQuery('*');
119                $mainquery->addSort([
120                    "_geo_distance" => [
121                        "geo" => [
122                            "lat" => $coordinates['lat'],
123                            "lon" => $coordinates['lon']
124                        ],
125                        "order" => "asc",
126                        "unit" => "km"
127                    ]
128                ]);
129                $limit = 5;
130            }
131        } elseif ('' === trim($querystring)) {
132            // if empty, find all and trust in the filter
133            $searchquery->setQuery('*');
134        } else {
135            $searchquery->setQuery($querystring);
136        }
137        $searchquery->setFields([
138            'name^9',
139            'authority.name^5',
140            'address.street',
141            'address.postal_code^9'
142        ]);
143        $query->getQuery()->addShould($searchquery);
144        /** @psalm-suppress RiskyTruthyFalsyComparison */
145        if ($service_csv) {
146            foreach (explode(',', $service_csv) as $service_id) {
147                $filter = new \Elastica\Filter\Term(array(
148                    'services.service' => $service_id
149                ));
150                $query->getFilter()->addMust($filter);
151            }
152        }
153        $mainquery->setQuery($query);
154        $resultList = $this->access()
155            ->getIndex()
156            ->getType('location')
157            ->search($mainquery, $limit);
158        return $this->access()
159            ->fromAuthority()
160            ->fromLocationResults($resultList);
161    }
162
163    /**
164     * search locations
165     * this function is similar to self::searchAll() but it might get different boosts in the future
166     *
167     * @return \BO\Zmsdldb\Collection\Authorities
168     */
169    #[\Override]
170    public function readSearchResultList(mixed $query, string $service_csv = '')
171    {
172        $boolquery = Helper::boolFilteredQuery();
173        $boolquery->getFilter()->addMust(Helper::localeFilter($this->locale));
174        $mainquery = new \Elastica\Query();
175        $limit = 1000;
176        //$sort = true;
177        $searchquery = new \Elastica\Query\QueryString();
178        if ($query > 10000 && $query < 15000) {
179            // if it is a postal code, sort by distance and limit results
180            $coordinates = \BO\Zmsdldb\Plz\Coordinates::zip2LatLon($query);
181            if (false !== $coordinates) {
182                $searchquery->setQuery('*');
183                $mainquery->addSort([
184                    "_geo_distance" => [
185                        "geo" => [
186                            "lat" => $coordinates['lat'],
187                            "lon" => $coordinates['lon']
188                        ],
189                        "order" => "asc",
190                        "unit" => "km"
191                    ]
192                ]);
193                $limit = 5;
194                //$sort = false;
195            }
196        } elseif ('' === trim($query)) {
197            // if empty, find all and trust in the filter
198            $searchquery->setQuery('*');
199        } else {
200            $searchquery->setQuery($query);
201        }
202        $searchquery->setFields([
203            'name^9',
204            'authority.name^5',
205            'address.street',
206            'address.postal_code^9'
207        ]);
208        $boolquery->getQuery()->addShould($searchquery);
209        /** @psalm-suppress RiskyTruthyFalsyComparison */
210        if ($service_csv) {
211            foreach (explode(',', $service_csv) as $service_id) {
212                $filter = new \Elastica\Filter\Term(array(
213                    'services.service' => $service_id
214                ));
215                $boolquery->getFilter()->addMust($filter);
216            }
217        }
218        $mainquery->setQuery($boolquery);
219        $resultList = $this->access()
220            ->getIndex()
221            ->getType('location')
222            ->search($mainquery, $limit);
223        return $this->access()
224            ->fromAuthority()
225            ->fromLocationResults($resultList);
226    }
227
228    protected function fetchGeoJsonLocations(mixed $category, mixed $getAll): mixed
229    {
230        $query = new \Elastica\Query();
231        $query->setSource(['id', 'name', 'address.*', 'geo.*', 'meta.*', 'category.*']);
232
233        $filter =  new \Elastica\Query\MatchAll();
234
235        if (!empty($category) && false === $getAll) {
236            $filter = new \Elastica\Query\BoolQuery();
237            $termFilter = new \Elastica\Query\Term(['category.identifier' => $category]);
238            $filter->addMust($termFilter);
239        }
240        $query->setQuery($filter);
241        $query->addSort(['office' => ['order' => 'asc']]);
242        $query->addSort(['name' => ['order' => 'asc']]);
243        $resultList = $this->access()
244            ->getIndex()
245            ->getType('location')
246            ->search($query, 1000)
247        ;
248        return $resultList;
249    }
250
251    /**
252     * @todo Refactoring required, functions in this class should return entities, not JSON data
253     *
254     * @psalm-api
255     *
256     * @return ((string|string[])[]|bool|mixed|string)[][]
257     *
258     */
259    public function fetchGeoJson(mixed $category = null, bool $getAll = false)
260    {
261        $resultList = $this->fetchGeoJsonLocations($category, $getAll);
262        $geoJson = [];
263        // TODO check refactoring: the following lines were ineffective cause the line $geoJson=[] happened afterwards
264        //if (!empty($category) && false === $getAll) {
265        //    $geoJson['category'] = $category;
266        //}
267        foreach ($resultList as $result) {
268            $location = new Entity($result->getData());
269            if (empty($location['category']['identifier'])) {
270                continue;
271            }
272            if (!isset($geoJson[$location['category']['identifier']])) {
273                $geoJson[$location['category']['identifier']] = [
274                    'name' => $location['category']['name'],
275                    'type' => 'cluster',
276                    'active' => (
277                        !empty($category)
278                        && $category == $location['category']['identifier'] ? true : (
279                            !empty($category) && $category != $location['category']['identifier'] ? false : true
280                        )
281                    ),
282                    'data' => ['type' => 'FeatureCollection', 'features' => []]
283                ];
284            }
285            $geoJson[$location['category']['identifier']]['data']['features'][] = $location->getGeoJson();
286        }
287
288        return $geoJson;
289    }
290
291    /**
292     * @psalm-api
293     *
294     * @return Collection
295     */
296    public function fetchLocationsForCompilation(array $authoritys = [], array $locations = [])
297    {
298        $limit = 1000;
299
300        $localeFilter = new \Elastica\Query\Term(array(
301            'meta.locale' => $this->locale
302        ));
303
304        $boolquery = new \Elastica\Query\BoolQuery();
305        $boolquery->addMust($localeFilter);
306
307        if (!empty($authoritys)) {
308            $authorityFilter = new \Elastica\Query\Terms('authority.id', array_values($authoritys));
309            $boolquery->addMust($authorityFilter);
310        }
311        if (!empty($locations)) {
312            $locationFilter = new \Elastica\Query\Terms('id', array_values($locations));
313            $boolquery->addMust($locationFilter);
314        }
315
316        $query = \Elastica\Query::create($boolquery);
317        $query->addSort(['sort' => 'asc']);
318        #print_r(json_encode($query->toArray()));exit;
319        $resultList = $this
320            ->access()
321            ->getIndex()
322            ->getType('location')
323            ->search($query, $limit)
324        ;
325
326        $locationList = new Collection();
327        foreach ($resultList as $result) {
328            $location = new Entity($result->getData());
329            $locationList[$location['id']] = $location;
330        }
331        return $locationList;
332    }
333}