xref: /webtrees/app/Module/ModuleMapGeoLocationTrait.php (revision d85de00fd5bcdcfbee029fa7c1da0240428565da)
1c9c6f2ecSGreg Roach<?php
2c9c6f2ecSGreg Roach
3c9c6f2ecSGreg Roach/**
4c9c6f2ecSGreg Roach * webtrees: online genealogy
5c9c6f2ecSGreg Roach * Copyright (C) 2021 webtrees development team
6c9c6f2ecSGreg Roach * This program is free software: you can redistribute it and/or modify
7c9c6f2ecSGreg Roach * it under the terms of the GNU General Public License as published by
8c9c6f2ecSGreg Roach * the Free Software Foundation, either version 3 of the License, or
9c9c6f2ecSGreg Roach * (at your option) any later version.
10c9c6f2ecSGreg Roach * This program is distributed in the hope that it will be useful,
11c9c6f2ecSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
12c9c6f2ecSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13c9c6f2ecSGreg Roach * GNU General Public License for more details.
14c9c6f2ecSGreg Roach * You should have received a copy of the GNU General Public License
15c9c6f2ecSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>.
16c9c6f2ecSGreg Roach */
17c9c6f2ecSGreg Roach
18c9c6f2ecSGreg Roachdeclare(strict_types=1);
19c9c6f2ecSGreg Roach
20c9c6f2ecSGreg Roachnamespace Fisharebest\Webtrees\Module;
21c9c6f2ecSGreg Roach
22c9c6f2ecSGreg Roachuse Fig\Http\Message\StatusCodeInterface;
23c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Html;
24c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\I18N;
25c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Registry;
26c9c6f2ecSGreg Roachuse GuzzleHttp\Client;
27c9c6f2ecSGreg Roachuse GuzzleHttp\Psr7\Request;
28c9c6f2ecSGreg Roachuse JsonException;
29c9c6f2ecSGreg Roachuse Psr\Http\Message\RequestInterface;
30c9c6f2ecSGreg Roachuse Psr\Http\Message\ResponseInterface;
31c9c6f2ecSGreg Roach
32c9c6f2ecSGreg Roachuse function json_decode;
33c9c6f2ecSGreg Roach
34c9c6f2ecSGreg Roachuse const JSON_THROW_ON_ERROR;
35c9c6f2ecSGreg Roach
36c9c6f2ecSGreg Roach/**
37c9c6f2ecSGreg Roach * Trait ModuleMapGeoLocationTrait - default implementation of ModuleMapGeoLocationInterface
38c9c6f2ecSGreg Roach */
39c9c6f2ecSGreg Roachtrait ModuleMapGeoLocationTrait
40c9c6f2ecSGreg Roach{
41c9c6f2ecSGreg Roach    /**
42c9c6f2ecSGreg Roach     * A sentence describing what this module does.
43c9c6f2ecSGreg Roach     *
44c9c6f2ecSGreg Roach     * @return string
45c9c6f2ecSGreg Roach     */
46c9c6f2ecSGreg Roach    public function description(): string
47c9c6f2ecSGreg Roach    {
48c9c6f2ecSGreg Roach        return I18N::translate('Use an external service to find locations.');
49c9c6f2ecSGreg Roach    }
50c9c6f2ecSGreg Roach
51c9c6f2ecSGreg Roach    /**
52c9c6f2ecSGreg Roach     * @param string $place
53c9c6f2ecSGreg Roach     *
54c9c6f2ecSGreg Roach     * @return array<string>
55c9c6f2ecSGreg Roach     */
56c9c6f2ecSGreg Roach    public function searchPlaceNames(string $place): array
57c9c6f2ecSGreg Roach    {
58c9c6f2ecSGreg Roach        if (strlen($place) <= 2) {
59c9c6f2ecSGreg Roach            return [];
60c9c6f2ecSGreg Roach        }
61c9c6f2ecSGreg Roach
62c9c6f2ecSGreg Roach        $key   = $this->name() . $place;
63c9c6f2ecSGreg Roach        $cache = Registry::cache()->file();
64c9c6f2ecSGreg Roach        $ttl   = 86400;
65c9c6f2ecSGreg Roach
66c9c6f2ecSGreg Roach        return $cache->remember($key, function () use ($place) {
67c9c6f2ecSGreg Roach            $request = $this->searchLocationsRequest($place);
68c9c6f2ecSGreg Roach
69c9c6f2ecSGreg Roach            $client = new Client([
70c9c6f2ecSGreg Roach                'timeout' => 3,
71c9c6f2ecSGreg Roach            ]);
72c9c6f2ecSGreg Roach
73c9c6f2ecSGreg Roach            $response = $client->send($request);
74c9c6f2ecSGreg Roach
75c9c6f2ecSGreg Roach            if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) {
76c9c6f2ecSGreg Roach                return $this->extractLocationsFromResponse($response);
77c9c6f2ecSGreg Roach            }
78c9c6f2ecSGreg Roach
79c9c6f2ecSGreg Roach            return [];
80c9c6f2ecSGreg Roach        }, $ttl);
81c9c6f2ecSGreg Roach    }
82c9c6f2ecSGreg Roach
83c9c6f2ecSGreg Roach    /**
84c9c6f2ecSGreg Roach     * @param string $place
85c9c6f2ecSGreg Roach     *
86c9c6f2ecSGreg Roach     * @return RequestInterface
87c9c6f2ecSGreg Roach     */
88c9c6f2ecSGreg Roach    protected function searchLocationsRequest(string $place): RequestInterface
89c9c6f2ecSGreg Roach    {
90c9c6f2ecSGreg Roach        $uri = Html::url('https://nominatim.openstreetmap.org/search', [
91c9c6f2ecSGreg Roach            'accept-language' => I18N::languageTag(),
92c9c6f2ecSGreg Roach            'format'          => 'jsonv2',
93c9c6f2ecSGreg Roach            'limit'           => 50,
94c9c6f2ecSGreg Roach            'q'               => $place,
95c9c6f2ecSGreg Roach        ]);
96c9c6f2ecSGreg Roach
97c9c6f2ecSGreg Roach        return new Request('GET', $uri);
98c9c6f2ecSGreg Roach    }
99c9c6f2ecSGreg Roach
100c9c6f2ecSGreg Roach    /**
101c9c6f2ecSGreg Roach     * @param ResponseInterface $response
102c9c6f2ecSGreg Roach     *
103c9c6f2ecSGreg Roach     * @return array<string>
104c9c6f2ecSGreg Roach     */
105c9c6f2ecSGreg Roach    protected function extractLocationsFromResponse(ResponseInterface $response): array
106c9c6f2ecSGreg Roach    {
107c9c6f2ecSGreg Roach        $body = $response->getBody()->getContents();
108c9c6f2ecSGreg Roach
109c9c6f2ecSGreg Roach        try {
110*d85de00fSGreg Roach            return json_decode($body, false, 512, JSON_THROW_ON_ERROR);
111c9c6f2ecSGreg Roach        } catch (JsonException $ex) {
112c9c6f2ecSGreg Roach            return [];
113c9c6f2ecSGreg Roach        }
114c9c6f2ecSGreg Roach    }
115c9c6f2ecSGreg Roach}
116