1c9c6f2ecSGreg Roach<?php 2c9c6f2ecSGreg Roach 3c9c6f2ecSGreg Roach/** 4c9c6f2ecSGreg Roach * webtrees: online genealogy 5*d11be702SGreg Roach * Copyright (C) 2023 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 Fisharebest\Webtrees\FlashMessages; 23c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Gedcom; 24c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Html; 25c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\I18N; 26748dbe15SGreg Roachuse Fisharebest\Webtrees\Validator; 27c9c6f2ecSGreg Roachuse GuzzleHttp\Psr7\Request; 28c9c6f2ecSGreg Roachuse Psr\Http\Message\RequestInterface; 29c9c6f2ecSGreg Roachuse Psr\Http\Message\ResponseInterface; 30c9c6f2ecSGreg Roachuse Psr\Http\Message\ServerRequestInterface; 31c9c6f2ecSGreg Roach 32c9c6f2ecSGreg Roachuse function array_filter; 33c9c6f2ecSGreg Roachuse function implode; 34c9c6f2ecSGreg Roachuse function json_decode; 35c9c6f2ecSGreg Roachuse function redirect; 36c9c6f2ecSGreg Roachuse function usort; 37c9c6f2ecSGreg Roach 38c9c6f2ecSGreg Roachuse const JSON_THROW_ON_ERROR; 39c9c6f2ecSGreg Roach 40c9c6f2ecSGreg Roach/** 41c9c6f2ecSGreg Roach * Class OpenRouteServiceAutocomplete - use openrouteservice.org to search for place names 42c9c6f2ecSGreg Roach */ 43c9c6f2ecSGreg Roachclass OpenRouteServiceAutocomplete extends AbstractModule implements ModuleConfigInterface, ModuleMapAutocompleteInterface 44c9c6f2ecSGreg Roach{ 45c9c6f2ecSGreg Roach use ModuleConfigTrait; 46c9c6f2ecSGreg Roach use ModuleMapAutocompleteTrait; 47c9c6f2ecSGreg Roach 48c9c6f2ecSGreg Roach /** 49c9c6f2ecSGreg Roach * Name of the map provider. 50c9c6f2ecSGreg Roach * 51c9c6f2ecSGreg Roach * @return string 52c9c6f2ecSGreg Roach */ 53c9c6f2ecSGreg Roach public function description(): string 54c9c6f2ecSGreg Roach { 55c9c6f2ecSGreg Roach $link = '<a href="https://openrouteservice.org">openrouteservice.org</a>'; 56c9c6f2ecSGreg Roach 57c9c6f2ecSGreg Roach return I18N::translate('Search for place names using %s.', $link); 58c9c6f2ecSGreg Roach } 59c9c6f2ecSGreg Roach 60c9c6f2ecSGreg Roach /** 61c9c6f2ecSGreg Roach * @return ResponseInterface 62c9c6f2ecSGreg Roach */ 63c9c6f2ecSGreg Roach public function getAdminAction(): ResponseInterface 64c9c6f2ecSGreg Roach { 65c9c6f2ecSGreg Roach $this->layout = 'layouts/administration'; 66c9c6f2ecSGreg Roach 67c9c6f2ecSGreg Roach $api_key = $this->getPreference('api_key'); 68c9c6f2ecSGreg Roach 69c9c6f2ecSGreg Roach return $this->viewResponse('modules/openrouteservice/config', [ 70c9c6f2ecSGreg Roach 'api_key' => $api_key, 71c9c6f2ecSGreg Roach 'title' => $this->title(), 72c9c6f2ecSGreg Roach ]); 73c9c6f2ecSGreg Roach } 74c9c6f2ecSGreg Roach 75c9c6f2ecSGreg Roach /** 76c9c6f2ecSGreg Roach * Name of the map provider. 77c9c6f2ecSGreg Roach * 78c9c6f2ecSGreg Roach * @return string 79c9c6f2ecSGreg Roach */ 80c9c6f2ecSGreg Roach public function title(): string 81c9c6f2ecSGreg Roach { 82c9c6f2ecSGreg Roach return I18N::translate('OpenRouteService'); 83c9c6f2ecSGreg Roach } 84c9c6f2ecSGreg Roach 85c9c6f2ecSGreg Roach /** 86c9c6f2ecSGreg Roach * Should this module be enabled when it is first installed? 87c9c6f2ecSGreg Roach * 88c9c6f2ecSGreg Roach * @return bool 89c9c6f2ecSGreg Roach */ 90c9c6f2ecSGreg Roach public function isEnabledByDefault(): bool 91c9c6f2ecSGreg Roach { 92c9c6f2ecSGreg Roach return false; 93c9c6f2ecSGreg Roach } 94c9c6f2ecSGreg Roach 95c9c6f2ecSGreg Roach /** 96c9c6f2ecSGreg Roach * @param ServerRequestInterface $request 97c9c6f2ecSGreg Roach * 98c9c6f2ecSGreg Roach * @return ResponseInterface 99c9c6f2ecSGreg Roach */ 100c9c6f2ecSGreg Roach public function postAdminAction(ServerRequestInterface $request): ResponseInterface 101c9c6f2ecSGreg Roach { 102748dbe15SGreg Roach $api_key = Validator::parsedBody($request)->string('api_key'); 103c9c6f2ecSGreg Roach 104748dbe15SGreg Roach $this->setPreference('api_key', $api_key); 105c9c6f2ecSGreg Roach 106c9c6f2ecSGreg Roach FlashMessages::addMessage(I18N::translate('The preferences for the module “%s” have been updated.', $this->title()), 'success'); 107c9c6f2ecSGreg Roach 108c9c6f2ecSGreg Roach return redirect($this->getConfigLink()); 109c9c6f2ecSGreg Roach } 110c9c6f2ecSGreg Roach 111c9c6f2ecSGreg Roach /** 112c9c6f2ecSGreg Roach * @param string $place 113c9c6f2ecSGreg Roach * 114c9c6f2ecSGreg Roach * @return RequestInterface 115c9c6f2ecSGreg Roach */ 116c9c6f2ecSGreg Roach protected function createPlaceNameSearchRequest(string $place): RequestInterface 117c9c6f2ecSGreg Roach { 118c9c6f2ecSGreg Roach $api_key = $this->getPreference('api_key'); 119c9c6f2ecSGreg Roach 120c9c6f2ecSGreg Roach $uri = Html::url('https://api.openrouteservice.org/geocode/autocomplete', [ 121c9c6f2ecSGreg Roach 'api_key' => $api_key, 122c9c6f2ecSGreg Roach 'text' => $place, 123c9c6f2ecSGreg Roach 'layers' => 'coarse', 124c9c6f2ecSGreg Roach ]); 125c9c6f2ecSGreg Roach 126c9c6f2ecSGreg Roach return new Request('GET', $uri); 127c9c6f2ecSGreg Roach } 128c9c6f2ecSGreg Roach 129c9c6f2ecSGreg Roach /** 130c9c6f2ecSGreg Roach * @param ResponseInterface $response 131c9c6f2ecSGreg Roach * 132c9c6f2ecSGreg Roach * @return array<string> 133c9c6f2ecSGreg Roach */ 134c9c6f2ecSGreg Roach protected function parsePlaceNameSearchResponse(ResponseInterface $response): array 135c9c6f2ecSGreg Roach { 136c9c6f2ecSGreg Roach $body = $response->getBody()->getContents(); 137c9c6f2ecSGreg Roach $places = []; 138c9c6f2ecSGreg Roach $results = json_decode($body, false, 512, JSON_THROW_ON_ERROR); 1392aeda30fSGreg Roach 140c9c6f2ecSGreg Roach foreach ($results->features as $result) { 141cada4c7cSGreg Roach $result->properties->name ??= null; 142cada4c7cSGreg Roach $result->properties->county ??= null; 143cada4c7cSGreg Roach $result->properties->region ??= null; 144cada4c7cSGreg Roach $result->properties->macroregion ??= null; 145cada4c7cSGreg Roach $result->properties->country ??= null; 146cada4c7cSGreg Roach 147c9c6f2ecSGreg Roach if ($result->properties->country === 'United Kingdom') { 148c9c6f2ecSGreg Roach // macroregion will contain England, Scotland, etc. 149c9c6f2ecSGreg Roach $result->properties->country = null; 150f52ec17fSGreg Roach // region will contain the county. 151f52ec17fSGreg Roach $result->properties->region = null; 152c9c6f2ecSGreg Roach } 153c9c6f2ecSGreg Roach 154c9c6f2ecSGreg Roach $parts = [ 155cada4c7cSGreg Roach $result->properties->name, 156cada4c7cSGreg Roach $result->properties->county, 157cada4c7cSGreg Roach $result->properties->region, 158cada4c7cSGreg Roach $result->properties->macroregion, 159cada4c7cSGreg Roach $result->properties->country, 160c9c6f2ecSGreg Roach ]; 161c9c6f2ecSGreg Roach 162c9c6f2ecSGreg Roach $places[] = implode(Gedcom::PLACE_SEPARATOR, array_filter($parts)) ?: $result->properties->label; 163c9c6f2ecSGreg Roach } 164c9c6f2ecSGreg Roach 165c9c6f2ecSGreg Roach usort($places, I18N::comparator()); 166c9c6f2ecSGreg Roach 167c9c6f2ecSGreg Roach return $places; 168c9c6f2ecSGreg Roach } 169c9c6f2ecSGreg Roach} 170