194e35917SGreg Roach<?php 294e35917SGreg Roach 394e35917SGreg Roach/** 494e35917SGreg Roach * webtrees: online genealogy 594e35917SGreg Roach * Copyright (C) 2020 webtrees development team 694e35917SGreg Roach * This program is free software: you can redistribute it and/or modify 794e35917SGreg Roach * it under the terms of the GNU General Public License as published by 894e35917SGreg Roach * the Free Software Foundation, either version 3 of the License, or 994e35917SGreg Roach * (at your option) any later version. 1094e35917SGreg Roach * This program is distributed in the hope that it will be useful, 1194e35917SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 1294e35917SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1394e35917SGreg Roach * GNU General Public License for more details. 1494e35917SGreg Roach * You should have received a copy of the GNU General Public License 1594e35917SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 1694e35917SGreg Roach */ 1794e35917SGreg Roach 1894e35917SGreg Roachdeclare(strict_types=1); 1994e35917SGreg Roach 2094e35917SGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 2194e35917SGreg Roach 2294e35917SGreg Roachuse Fisharebest\Webtrees\Http\ViewResponseTrait; 2394e35917SGreg Roachuse Fisharebest\Webtrees\I18N; 248504fb2dSGreg Roachuse Fisharebest\Webtrees\Module\PlaceHierarchyListModule; 2594e35917SGreg Roachuse Fisharebest\Webtrees\Services\MapDataService; 268504fb2dSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 27ac34be60SRichard Cisséeuse Fisharebest\Webtrees\Services\TreeService; 2811464183SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 2911464183SGreg Roachuse Illuminate\Database\Query\Expression; 3094e35917SGreg Roachuse Psr\Http\Message\ResponseInterface; 3194e35917SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 3294e35917SGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 3311464183SGreg Roachuse stdClass; 34*ed612bd3SGreg Roach 3594e35917SGreg Roachuse function array_reverse; 3694e35917SGreg Roachuse function redirect; 3794e35917SGreg Roachuse function route; 3894e35917SGreg Roach 3994e35917SGreg Roach/** 4094e35917SGreg Roach * Show a list of map data. 4194e35917SGreg Roach */ 4294e35917SGreg Roachclass MapDataList implements RequestHandlerInterface 4394e35917SGreg Roach{ 4494e35917SGreg Roach use ViewResponseTrait; 4594e35917SGreg Roach 4694e35917SGreg Roach /** @var MapDataService */ 4794e35917SGreg Roach private $map_data_service; 4894e35917SGreg Roach 498504fb2dSGreg Roach /** @var ModuleService */ 508504fb2dSGreg Roach private $module_service; 518504fb2dSGreg Roach 52ac34be60SRichard Cissée /** @var TreeService */ 53ac34be60SRichard Cissée private $tree_service; 54ac34be60SRichard Cissée 5594e35917SGreg Roach /** 5694e35917SGreg Roach * Dependency injection. 5794e35917SGreg Roach * 5894e35917SGreg Roach * @param MapDataService $map_data_service 598504fb2dSGreg Roach * @param ModuleService $module_service 60*ed612bd3SGreg Roach * @param TreeService $tree_service 6194e35917SGreg Roach */ 62*ed612bd3SGreg Roach public function __construct( 63*ed612bd3SGreg Roach MapDataService $map_data_service, 64*ed612bd3SGreg Roach ModuleService $module_service, 65*ed612bd3SGreg Roach TreeService $tree_service 66*ed612bd3SGreg Roach ) { 6794e35917SGreg Roach $this->map_data_service = $map_data_service; 688504fb2dSGreg Roach $this->module_service = $module_service; 69ac34be60SRichard Cissée $this->tree_service = $tree_service; 7094e35917SGreg Roach } 7194e35917SGreg Roach 7294e35917SGreg Roach /** 7394e35917SGreg Roach * @param ServerRequestInterface $request 7494e35917SGreg Roach * 7594e35917SGreg Roach * @return ResponseInterface 7694e35917SGreg Roach */ 7794e35917SGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 7894e35917SGreg Roach { 7994e35917SGreg Roach $parent_id = (int) ($request->getQueryParams()['parent_id'] ?? 0); 8094e35917SGreg Roach $title = I18N::translate('Geographic data'); 8194e35917SGreg Roach $parent = $this->map_data_service->findById($parent_id); 8294e35917SGreg Roach 8394e35917SGreg Roach // Request for a non-existent location? 8494e35917SGreg Roach if ($parent_id !== $parent->id()) { 8594e35917SGreg Roach return redirect(route(__CLASS__)); 8694e35917SGreg Roach } 8794e35917SGreg Roach 8894e35917SGreg Roach // Automatically import any new/missing places. 890e50635cSGreg Roach $this->map_data_service->importMissingLocations(); 9094e35917SGreg Roach 919ee82875SGreg Roach $breadcrumbs = [$parent->locationName()]; 929ee82875SGreg Roach 939ee82875SGreg Roach $tmp = $parent->parent(); 9494e35917SGreg Roach 9594e35917SGreg Roach while ($tmp->id() !== 0) { 9694e35917SGreg Roach $breadcrumbs[route(__CLASS__, ['parent_id' => $tmp->id()])] = $tmp->locationName(); 9794e35917SGreg Roach 9894e35917SGreg Roach $tmp = $tmp->parent(); 9994e35917SGreg Roach } 10094e35917SGreg Roach 10194e35917SGreg Roach $breadcrumbs[route(__CLASS__)] = $title; 10294e35917SGreg Roach $breadcrumbs[route(ControlPanel::class)] = I18N::translate('Control panel'); 10394e35917SGreg Roach 104*ed612bd3SGreg Roach $list_module = $this->module_service 105*ed612bd3SGreg Roach ->findByInterface(PlaceHierarchyListModule::class) 106*ed612bd3SGreg Roach ->first(); 1078504fb2dSGreg Roach 10894e35917SGreg Roach $this->layout = 'layouts/administration'; 10994e35917SGreg Roach 11094e35917SGreg Roach return $this->viewResponse('admin/locations', [ 11194e35917SGreg Roach 'active' => $this->map_data_service->activePlaces($parent), 112*ed612bd3SGreg Roach 'all_trees' => $this->tree_service->all(), 11394e35917SGreg Roach 'breadcrumbs' => array_reverse($breadcrumbs), 11494e35917SGreg Roach 'parent_id' => $parent_id, 1150e50635cSGreg Roach 'placelist' => $this->map_data_service->getPlaceListLocation($parent_id), 116*ed612bd3SGreg Roach 'list_module' => $list_module, 1178504fb2dSGreg Roach 'title' => $title, 11894e35917SGreg Roach ]); 11994e35917SGreg Roach } 12011464183SGreg Roach 12111464183SGreg Roach 12211464183SGreg Roach /** 12311464183SGreg Roach * Find all of the places in the hierarchy 12411464183SGreg Roach * 12511464183SGreg Roach * @param int $id 12611464183SGreg Roach * 12711464183SGreg Roach * @return stdClass[] 12811464183SGreg Roach */ 12911464183SGreg Roach private function getPlaceListLocation(int $id): array 13011464183SGreg Roach { 13111464183SGreg Roach return DB::table('placelocation') 13211464183SGreg Roach ->where('pl_parent_id', '=', $id) 13311464183SGreg Roach ->orderBy(new Expression('pl_place /*! COLLATE ' . I18N::collation() . ' */')) 13411464183SGreg Roach ->get() 13511464183SGreg Roach ->map(function (stdClass $row): stdClass { 13611464183SGreg Roach // Find/count places without co-ordinates 13711464183SGreg Roach $children = $this->childLocationStatus((int) $row->pl_id); 13811464183SGreg Roach 13911464183SGreg Roach $row->child_count = (int) $children->child_count; 14011464183SGreg Roach $row->no_coord = (int) $children->no_coord; 14111464183SGreg Roach 14211464183SGreg Roach return $row; 14311464183SGreg Roach }) 14411464183SGreg Roach ->all(); 14511464183SGreg Roach } 14611464183SGreg Roach 14711464183SGreg Roach /** 14811464183SGreg Roach * How many children does place have? How many have co-ordinates? 14911464183SGreg Roach * 15011464183SGreg Roach * @param int $parent_id 15111464183SGreg Roach * 15211464183SGreg Roach * @return stdClass 15311464183SGreg Roach */ 15411464183SGreg Roach private function childLocationStatus(int $parent_id): stdClass 15511464183SGreg Roach { 15611464183SGreg Roach $prefix = DB::connection()->getTablePrefix(); 15711464183SGreg Roach 15811464183SGreg Roach $expression = 15911464183SGreg Roach $prefix . 'p0.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p0.pl_lati, '') = '' OR " . 16011464183SGreg Roach $prefix . 'p1.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p1.pl_lati, '') = '' OR " . 16111464183SGreg Roach $prefix . 'p2.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p2.pl_lati, '') = '' OR " . 16211464183SGreg Roach $prefix . 'p3.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p3.pl_lati, '') = '' OR " . 16311464183SGreg Roach $prefix . 'p4.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p4.pl_lati, '') = '' OR " . 16411464183SGreg Roach $prefix . 'p5.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p5.pl_lati, '') = '' OR " . 16511464183SGreg Roach $prefix . 'p6.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p6.pl_lati, '') = '' OR " . 16611464183SGreg Roach $prefix . 'p7.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p7.pl_lati, '') = '' OR " . 16711464183SGreg Roach $prefix . 'p8.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p8.pl_lati, '') = '' OR " . 16811464183SGreg Roach $prefix . 'p9.pl_place IS NOT NULL AND COALESCE(' . $prefix . "p9.pl_lati, '') = ''"; 16911464183SGreg Roach 17011464183SGreg Roach return DB::table('placelocation AS p0') 17111464183SGreg Roach ->leftJoin('placelocation AS p1', 'p1.pl_parent_id', '=', 'p0.pl_id') 17211464183SGreg Roach ->leftJoin('placelocation AS p2', 'p2.pl_parent_id', '=', 'p1.pl_id') 17311464183SGreg Roach ->leftJoin('placelocation AS p3', 'p3.pl_parent_id', '=', 'p2.pl_id') 17411464183SGreg Roach ->leftJoin('placelocation AS p4', 'p4.pl_parent_id', '=', 'p3.pl_id') 17511464183SGreg Roach ->leftJoin('placelocation AS p5', 'p5.pl_parent_id', '=', 'p4.pl_id') 17611464183SGreg Roach ->leftJoin('placelocation AS p6', 'p6.pl_parent_id', '=', 'p5.pl_id') 17711464183SGreg Roach ->leftJoin('placelocation AS p7', 'p7.pl_parent_id', '=', 'p6.pl_id') 17811464183SGreg Roach ->leftJoin('placelocation AS p8', 'p8.pl_parent_id', '=', 'p7.pl_id') 17911464183SGreg Roach ->leftJoin('placelocation AS p9', 'p9.pl_parent_id', '=', 'p8.pl_id') 18011464183SGreg Roach ->where('p0.pl_parent_id', '=', $parent_id) 18111464183SGreg Roach ->select([new Expression('COUNT(*) AS child_count'), new Expression('SUM(' . $expression . ') AS no_coord')]) 18211464183SGreg Roach ->first(); 18311464183SGreg Roach } 18494e35917SGreg Roach} 185