167992b6aSRichard Cissee<?php 23976b470SGreg Roach 367992b6aSRichard Cissee/** 467992b6aSRichard Cissee * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 667992b6aSRichard Cissee * This program is free software: you can redistribute it and/or modify 767992b6aSRichard Cissee * it under the terms of the GNU General Public License as published by 867992b6aSRichard Cissee * the Free Software Foundation, either version 3 of the License, or 967992b6aSRichard Cissee * (at your option) any later version. 1067992b6aSRichard Cissee * This program is distributed in the hope that it will be useful, 1167992b6aSRichard Cissee * but WITHOUT ANY WARRANTY; without even the implied warranty of 1267992b6aSRichard Cissee * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1367992b6aSRichard Cissee * GNU General Public License for more details. 1467992b6aSRichard Cissee * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 1667992b6aSRichard Cissee */ 17fcfa147eSGreg Roach 1867992b6aSRichard Cisseedeclare(strict_types=1); 1967992b6aSRichard Cissee 2067992b6aSRichard Cisseenamespace Fisharebest\Webtrees\Module; 2167992b6aSRichard Cissee 2267992b6aSRichard Cisseeuse Fisharebest\Webtrees\Auth; 236f4ec3caSGreg Roachuse Fisharebest\Webtrees\DB; 24c8db8a43SGreg Roachuse Fisharebest\Webtrees\Family; 250e54db38SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MapDataEdit; 2667992b6aSRichard Cisseeuse Fisharebest\Webtrees\I18N; 27c8db8a43SGreg Roachuse Fisharebest\Webtrees\Individual; 28c8db8a43SGreg Roachuse Fisharebest\Webtrees\Location; 294b2f1dbbSGreg Roachuse Fisharebest\Webtrees\Place; 304b2f1dbbSGreg Roachuse Fisharebest\Webtrees\PlaceLocation; 31158900c2SGreg Roachuse Fisharebest\Webtrees\Registry; 32c9c6f2ecSGreg Roachuse Fisharebest\Webtrees\Services\LeafletJsService; 334b2f1dbbSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 344b2f1dbbSGreg Roachuse Fisharebest\Webtrees\Services\SearchService; 355229eadeSGreg Roachuse Fisharebest\Webtrees\Tree; 36b55cbc6bSGreg Roachuse Fisharebest\Webtrees\Validator; 37a020b8bdSGreg Roachuse Illuminate\Database\Query\Builder; 38a020b8bdSGreg Roachuse Illuminate\Database\Query\JoinClause; 396ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 406ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 414b2f1dbbSGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 42f3874e19SGreg Roach 434b2f1dbbSGreg Roachuse function array_chunk; 444b2f1dbbSGreg Roachuse function array_pop; 454b2f1dbbSGreg Roachuse function array_reverse; 464b2f1dbbSGreg Roachuse function ceil; 474b2f1dbbSGreg Roachuse function count; 484b2f1dbbSGreg Roachuse function redirect; 494b2f1dbbSGreg Roachuse function route; 504b2f1dbbSGreg Roachuse function view; 5167992b6aSRichard Cissee 5267992b6aSRichard Cissee/** 5367992b6aSRichard Cissee * Class IndividualListModule 5467992b6aSRichard Cissee */ 554b2f1dbbSGreg Roachclass PlaceHierarchyListModule extends AbstractModule implements ModuleListInterface, RequestHandlerInterface 5667992b6aSRichard Cissee{ 5767992b6aSRichard Cissee use ModuleListTrait; 5867992b6aSRichard Cissee 590e54db38SGreg Roach protected const ROUTE_URL = '/tree/{tree}/place-list{/place_id}'; 604b2f1dbbSGreg Roach 614b2f1dbbSGreg Roach /** @var int The default access level for this module. It can be changed in the control panel. */ 6233c746f1SGreg Roach protected int $access_level = Auth::PRIV_USER; 634b2f1dbbSGreg Roach 64c9c6f2ecSGreg Roach private LeafletJsService $leaflet_js_service; 65c9c6f2ecSGreg Roach 66c9c6f2ecSGreg Roach private ModuleService $module_service; 67c9c6f2ecSGreg Roach 68c9c6f2ecSGreg Roach private SearchService $search_service; 694b2f1dbbSGreg Roach 704b2f1dbbSGreg Roach /** 71c9c6f2ecSGreg Roach * @param LeafletJsService $leaflet_js_service 72c9c6f2ecSGreg Roach * @param ModuleService $module_service 734b2f1dbbSGreg Roach * @param SearchService $search_service 744b2f1dbbSGreg Roach */ 75c9c6f2ecSGreg Roach public function __construct(LeafletJsService $leaflet_js_service, ModuleService $module_service, SearchService $search_service) 764b2f1dbbSGreg Roach { 77c9c6f2ecSGreg Roach $this->leaflet_js_service = $leaflet_js_service; 78c9c6f2ecSGreg Roach $this->module_service = $module_service; 794b2f1dbbSGreg Roach $this->search_service = $search_service; 804b2f1dbbSGreg Roach } 814b2f1dbbSGreg Roach 824b2f1dbbSGreg Roach /** 834b2f1dbbSGreg Roach * Initialization. 844b2f1dbbSGreg Roach * 854b2f1dbbSGreg Roach * @return void 864b2f1dbbSGreg Roach */ 874b2f1dbbSGreg Roach public function boot(): void 884b2f1dbbSGreg Roach { 89158900c2SGreg Roach Registry::routeFactory()->routeMap() 904b2f1dbbSGreg Roach ->get(static::class, static::ROUTE_URL, $this); 914b2f1dbbSGreg Roach } 924b2f1dbbSGreg Roach 9367992b6aSRichard Cissee /** 940cfd6963SGreg Roach * How should this module be identified in the control panel, etc.? 9567992b6aSRichard Cissee * 9667992b6aSRichard Cissee * @return string 9767992b6aSRichard Cissee */ 9867992b6aSRichard Cissee public function title(): string 9967992b6aSRichard Cissee { 10067992b6aSRichard Cissee /* I18N: Name of a module/list */ 10167992b6aSRichard Cissee return I18N::translate('Place hierarchy'); 10267992b6aSRichard Cissee } 10367992b6aSRichard Cissee 10467992b6aSRichard Cissee public function description(): string 10567992b6aSRichard Cissee { 1069e0868cbSGreg Roach /* I18N: Description of the “Place hierarchy” module */ 10767992b6aSRichard Cissee return I18N::translate('The place hierarchy.'); 10867992b6aSRichard Cissee } 10967992b6aSRichard Cissee 11067992b6aSRichard Cissee /** 11167992b6aSRichard Cissee * CSS class for the URL. 11267992b6aSRichard Cissee * 11367992b6aSRichard Cissee * @return string 11467992b6aSRichard Cissee */ 11567992b6aSRichard Cissee public function listMenuClass(): string 11667992b6aSRichard Cissee { 11767992b6aSRichard Cissee return 'menu-list-plac'; 11867992b6aSRichard Cissee } 11967992b6aSRichard Cissee 1204db4b4a9SGreg Roach /** 12124f2a3afSGreg Roach * @return array<string> 1224db4b4a9SGreg Roach */ 12367992b6aSRichard Cissee public function listUrlAttributes(): array 12467992b6aSRichard Cissee { 12567992b6aSRichard Cissee return []; 12667992b6aSRichard Cissee } 1274b2f1dbbSGreg Roach 1284b2f1dbbSGreg Roach /** 1294b2f1dbbSGreg Roach * @param Tree $tree 1304b2f1dbbSGreg Roach * 1314b2f1dbbSGreg Roach * @return bool 1324b2f1dbbSGreg Roach */ 1334b2f1dbbSGreg Roach public function listIsEmpty(Tree $tree): bool 1344b2f1dbbSGreg Roach { 1354b2f1dbbSGreg Roach return !DB::table('places') 1364b2f1dbbSGreg Roach ->where('p_file', '=', $tree->id()) 1374b2f1dbbSGreg Roach ->exists(); 1384b2f1dbbSGreg Roach } 1394b2f1dbbSGreg Roach 1404b2f1dbbSGreg Roach /** 141c9c6f2ecSGreg Roach * @param Tree $tree 14276d39c55SGreg Roach * @param array<bool|int|string|array<string>|null> $parameters 143c9c6f2ecSGreg Roach * 144c9c6f2ecSGreg Roach * @return string 145c9c6f2ecSGreg Roach */ 146c9c6f2ecSGreg Roach public function listUrl(Tree $tree, array $parameters = []): string 147c9c6f2ecSGreg Roach { 148c9c6f2ecSGreg Roach $parameters['tree'] = $tree->name(); 149c9c6f2ecSGreg Roach 150c9c6f2ecSGreg Roach return route(static::class, $parameters); 151c9c6f2ecSGreg Roach } 152c9c6f2ecSGreg Roach 153c9c6f2ecSGreg Roach /** 1544b2f1dbbSGreg Roach * @param ServerRequestInterface $request 1554b2f1dbbSGreg Roach * 1564b2f1dbbSGreg Roach * @return ResponseInterface 1574b2f1dbbSGreg Roach */ 1584b2f1dbbSGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 1594b2f1dbbSGreg Roach { 160b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 161b55cbc6bSGreg Roach $user = Validator::attributes($request)->user(); 1620e54db38SGreg Roach $place_id = Validator::attributes($request)->integer('place_id', 0); 1634b2f1dbbSGreg Roach 1644b2f1dbbSGreg Roach Auth::checkComponentAccess($this, ModuleListInterface::class, $tree, $user); 1654b2f1dbbSGreg Roach 166748dbe15SGreg Roach $action2 = Validator::queryParams($request)->string('action2', 'hierarchy'); 1674b2f1dbbSGreg Roach $place = Place::find($place_id, $tree); 1684b2f1dbbSGreg Roach 1694b2f1dbbSGreg Roach // Request for a non-existent place? 1704b2f1dbbSGreg Roach if ($place_id !== $place->id()) { 1714b2f1dbbSGreg Roach return redirect($place->url()); 1724b2f1dbbSGreg Roach } 1734b2f1dbbSGreg Roach 174c9c6f2ecSGreg Roach $map_providers = $this->module_service->findByInterface(ModuleMapProviderInterface::class); 175c9c6f2ecSGreg Roach 1764b2f1dbbSGreg Roach $content = ''; 177c9c6f2ecSGreg Roach $showmap = $map_providers->isNotEmpty(); 1784b2f1dbbSGreg Roach $data = null; 1794b2f1dbbSGreg Roach 1804b2f1dbbSGreg Roach if ($showmap) { 1814b2f1dbbSGreg Roach $content .= view('modules/place-hierarchy/map', [ 182edfa2139SGreg Roach 'data' => $this->mapData($place), 183c9c6f2ecSGreg Roach 'leaflet_config' => $this->leaflet_js_service->config(), 1844b2f1dbbSGreg Roach ]); 1854b2f1dbbSGreg Roach } 1864b2f1dbbSGreg Roach 1874b2f1dbbSGreg Roach switch ($action2) { 1884b2f1dbbSGreg Roach case 'list': 1894b2f1dbbSGreg Roach default: 1904b2f1dbbSGreg Roach $alt_link = I18N::translate('Show place hierarchy'); 1914b2f1dbbSGreg Roach $alt_url = $this->listUrl($tree, ['action2' => 'hierarchy', 'place_id' => $place_id]); 1924b2f1dbbSGreg Roach $content .= view('modules/place-hierarchy/list', ['columns' => $this->getList($tree)]); 1934b2f1dbbSGreg Roach break; 1944b2f1dbbSGreg Roach case 'hierarchy': 1954b2f1dbbSGreg Roach case 'hierarchy-e': 1964b2f1dbbSGreg Roach $alt_link = I18N::translate('Show all places in a list'); 1974b2f1dbbSGreg Roach $alt_url = $this->listUrl($tree, ['action2' => 'list', 'place_id' => 0]); 1984b2f1dbbSGreg Roach $data = $this->getHierarchy($place); 19961999471SGreg Roach $content .= ($data === null || $showmap) ? '' : view('place-hierarchy', $data); 20061999471SGreg Roach if ($data === null || $action2 === 'hierarchy-e') { 2014b2f1dbbSGreg Roach $content .= view('modules/place-hierarchy/events', [ 2024b2f1dbbSGreg Roach 'indilist' => $this->search_service->searchIndividualsInPlace($place), 2034b2f1dbbSGreg Roach 'famlist' => $this->search_service->searchFamiliesInPlace($place), 2044b2f1dbbSGreg Roach 'tree' => $place->tree(), 2054b2f1dbbSGreg Roach ]); 2064b2f1dbbSGreg Roach } 2074b2f1dbbSGreg Roach } 2084b2f1dbbSGreg Roach 2094b2f1dbbSGreg Roach if ($data !== null && $action2 !== 'hierarchy-e' && $place->gedcomName() !== '') { 2104b2f1dbbSGreg Roach $events_link = $this->listUrl($tree, ['action2' => 'hierarchy-e', 'place_id' => $place_id]); 2114b2f1dbbSGreg Roach } else { 2124b2f1dbbSGreg Roach $events_link = ''; 2134b2f1dbbSGreg Roach } 2144b2f1dbbSGreg Roach 2154b2f1dbbSGreg Roach $breadcrumbs = $this->breadcrumbs($place); 2164b2f1dbbSGreg Roach 2174b2f1dbbSGreg Roach return $this->viewResponse('modules/place-hierarchy/page', [ 2184b2f1dbbSGreg Roach 'alt_link' => $alt_link, 2194b2f1dbbSGreg Roach 'alt_url' => $alt_url, 2204b2f1dbbSGreg Roach 'breadcrumbs' => $breadcrumbs['breadcrumbs'], 2214b2f1dbbSGreg Roach 'content' => $content, 2224b2f1dbbSGreg Roach 'current' => $breadcrumbs['current'], 2234b2f1dbbSGreg Roach 'events_link' => $events_link, 2244b2f1dbbSGreg Roach 'place' => $place, 2254b2f1dbbSGreg Roach 'title' => I18N::translate('Place hierarchy'), 2264b2f1dbbSGreg Roach 'tree' => $tree, 227c9c6f2ecSGreg Roach 'world_url' => $this->listUrl($tree), 2284b2f1dbbSGreg Roach ]); 2294b2f1dbbSGreg Roach } 2304b2f1dbbSGreg Roach 2314b2f1dbbSGreg Roach /** 2320e54db38SGreg Roach * @param Place $place 2334b2f1dbbSGreg Roach * 2344b2f1dbbSGreg Roach * @return array<mixed> 2354b2f1dbbSGreg Roach */ 2360e54db38SGreg Roach protected function mapData(Place $place): array 2374b2f1dbbSGreg Roach { 2380e54db38SGreg Roach $children = $place->getChildPlaces(); 2394b2f1dbbSGreg Roach $features = []; 2404b2f1dbbSGreg Roach $sidebar = ''; 2414b2f1dbbSGreg Roach $show_link = true; 2424b2f1dbbSGreg Roach 2430e54db38SGreg Roach // No children? Show ourself on the map instead. 2440e54db38SGreg Roach if ($children === []) { 2450e54db38SGreg Roach $children[] = $place; 2464b2f1dbbSGreg Roach $show_link = false; 2474b2f1dbbSGreg Roach } 2484b2f1dbbSGreg Roach 2490e54db38SGreg Roach foreach ($children as $id => $child) { 2500e54db38SGreg Roach $location = new PlaceLocation($child->gedcomName()); 2510e54db38SGreg Roach 2520e54db38SGreg Roach if (Auth::isAdmin()) { 2530e54db38SGreg Roach $this_url = route(self::class, ['tree' => $child->tree()->name(), 'place_id' => $place->id()]); 2540e54db38SGreg Roach $edit_url = route(MapDataEdit::class, ['location_id' => $location->id(), 'url' => $this_url]); 2550e54db38SGreg Roach } else { 2560e54db38SGreg Roach $edit_url = ''; 2570e54db38SGreg Roach } 2584b2f1dbbSGreg Roach 25990949315SGreg Roach if ($location->latitude() === null || $location->longitude() === null) { 2604b2f1dbbSGreg Roach $sidebar_class = 'unmapped'; 2614b2f1dbbSGreg Roach } else { 2624b2f1dbbSGreg Roach $sidebar_class = 'mapped'; 2634b2f1dbbSGreg Roach $features[] = [ 2644b2f1dbbSGreg Roach 'type' => 'Feature', 2654b2f1dbbSGreg Roach 'id' => $id, 2664b2f1dbbSGreg Roach 'geometry' => [ 2674b2f1dbbSGreg Roach 'type' => 'Point', 2684b2f1dbbSGreg Roach 'coordinates' => [$location->longitude(), $location->latitude()], 2694b2f1dbbSGreg Roach ], 2704b2f1dbbSGreg Roach 'properties' => [ 2710e54db38SGreg Roach 'tooltip' => $child->gedcomName(), 2724b2f1dbbSGreg Roach 'popup' => view('modules/place-hierarchy/popup', [ 2730e54db38SGreg Roach 'edit_url' => $edit_url, 2740e54db38SGreg Roach 'place' => $child, 2754b2f1dbbSGreg Roach 'latitude' => $location->latitude(), 2764b2f1dbbSGreg Roach 'longitude' => $location->longitude(), 2770e54db38SGreg Roach 'showlink' => $show_link, 2784b2f1dbbSGreg Roach ]), 2794b2f1dbbSGreg Roach ], 2804b2f1dbbSGreg Roach ]; 2814b2f1dbbSGreg Roach } 2824b2f1dbbSGreg Roach 283a020b8bdSGreg Roach $stats = [ 2840e54db38SGreg Roach Family::RECORD_TYPE => $this->familyPlaceLinks($child)->count(), 2850e54db38SGreg Roach Individual::RECORD_TYPE => $this->individualPlaceLinks($child)->count(), 2860e54db38SGreg Roach Location::RECORD_TYPE => $this->locationPlaceLinks($child)->count(), 287a020b8bdSGreg Roach ]; 2884b2f1dbbSGreg Roach 2894b2f1dbbSGreg Roach $sidebar .= view('modules/place-hierarchy/sidebar', [ 2900e54db38SGreg Roach 'edit_url' => $edit_url, 2914b2f1dbbSGreg Roach 'id' => $id, 2920e54db38SGreg Roach 'place' => $child, 2930e54db38SGreg Roach 'showlink' => $show_link, 2944b2f1dbbSGreg Roach 'sidebar_class' => $sidebar_class, 295c8db8a43SGreg Roach 'stats' => $stats, 2964b2f1dbbSGreg Roach ]); 2974b2f1dbbSGreg Roach } 2984b2f1dbbSGreg Roach 2994b2f1dbbSGreg Roach return [ 3000e54db38SGreg Roach 'bounds' => (new PlaceLocation($place->gedcomName()))->boundingRectangle(), 3014b2f1dbbSGreg Roach 'sidebar' => $sidebar, 3024b2f1dbbSGreg Roach 'markers' => [ 3034b2f1dbbSGreg Roach 'type' => 'FeatureCollection', 3044b2f1dbbSGreg Roach 'features' => $features, 305c9c6f2ecSGreg Roach ], 306c9c6f2ecSGreg Roach ]; 307c9c6f2ecSGreg Roach } 308c9c6f2ecSGreg Roach 309c9c6f2ecSGreg Roach /** 310c9c6f2ecSGreg Roach * @param Tree $tree 311c9c6f2ecSGreg Roach * 312c9c6f2ecSGreg Roach * @return array<array<Place>> 313c9c6f2ecSGreg Roach */ 314c9c6f2ecSGreg Roach private function getList(Tree $tree): array 315c9c6f2ecSGreg Roach { 316c9c6f2ecSGreg Roach $places = $this->search_service->searchPlaces($tree, '') 317f25fc0f9SGreg Roach ->sort(static fn (Place $x, Place $y): int => I18N::comparator()($x->gedcomName(), $y->gedcomName())) 318c9c6f2ecSGreg Roach ->all(); 319c9c6f2ecSGreg Roach 320c9c6f2ecSGreg Roach $count = count($places); 321c9c6f2ecSGreg Roach 322c9c6f2ecSGreg Roach if ($places === []) { 323c9c6f2ecSGreg Roach return []; 324c9c6f2ecSGreg Roach } 325c9c6f2ecSGreg Roach 326c9c6f2ecSGreg Roach $columns = $count > 20 ? 3 : 2; 327c9c6f2ecSGreg Roach 328c9c6f2ecSGreg Roach return array_chunk($places, (int) ceil($count / $columns)); 329c9c6f2ecSGreg Roach } 330c9c6f2ecSGreg Roach 331c9c6f2ecSGreg Roach /** 332c9c6f2ecSGreg Roach * @param Place $place 333c9c6f2ecSGreg Roach * 334bd29d468SGreg Roach * @return array{columns:array<array<Place>>,place:Place,tree:Tree,col_class:string}|null 335c9c6f2ecSGreg Roach */ 336*1ff45046SGreg Roach private function getHierarchy(Place $place): array|null 337c9c6f2ecSGreg Roach { 338c9c6f2ecSGreg Roach $child_places = $place->getChildPlaces(); 339c9c6f2ecSGreg Roach $numfound = count($child_places); 340c9c6f2ecSGreg Roach 341c9c6f2ecSGreg Roach if ($numfound > 0) { 342c9c6f2ecSGreg Roach $divisor = $numfound > 20 ? 3 : 2; 343c9c6f2ecSGreg Roach 344c9c6f2ecSGreg Roach return [ 345c9c6f2ecSGreg Roach 'tree' => $place->tree(), 346c9c6f2ecSGreg Roach 'col_class' => 'w-' . ($divisor === 2 ? '25' : '50'), 347c9c6f2ecSGreg Roach 'columns' => array_chunk($child_places, (int) ceil($numfound / $divisor)), 348c9c6f2ecSGreg Roach 'place' => $place, 349c9c6f2ecSGreg Roach ]; 350c9c6f2ecSGreg Roach } 351c9c6f2ecSGreg Roach 352c9c6f2ecSGreg Roach return null; 353c9c6f2ecSGreg Roach } 354c9c6f2ecSGreg Roach 355c9c6f2ecSGreg Roach /** 356c9c6f2ecSGreg Roach * @param Place $place 357c9c6f2ecSGreg Roach * 358bd29d468SGreg Roach * @return array{breadcrumbs:array<Place>,current:Place|null} 359c9c6f2ecSGreg Roach */ 360c9c6f2ecSGreg Roach private function breadcrumbs(Place $place): array 361c9c6f2ecSGreg Roach { 362c9c6f2ecSGreg Roach $breadcrumbs = []; 363c9c6f2ecSGreg Roach if ($place->gedcomName() !== '') { 364c9c6f2ecSGreg Roach $breadcrumbs[] = $place; 365c9c6f2ecSGreg Roach $parent_place = $place->parent(); 366c9c6f2ecSGreg Roach while ($parent_place->gedcomName() !== '') { 367c9c6f2ecSGreg Roach $breadcrumbs[] = $parent_place; 368c9c6f2ecSGreg Roach $parent_place = $parent_place->parent(); 369c9c6f2ecSGreg Roach } 370c9c6f2ecSGreg Roach $breadcrumbs = array_reverse($breadcrumbs); 371c9c6f2ecSGreg Roach $current = array_pop($breadcrumbs); 372c9c6f2ecSGreg Roach } else { 373c9c6f2ecSGreg Roach $current = null; 374c9c6f2ecSGreg Roach } 375c9c6f2ecSGreg Roach 376c9c6f2ecSGreg Roach return [ 377c9c6f2ecSGreg Roach 'breadcrumbs' => $breadcrumbs, 378c9c6f2ecSGreg Roach 'current' => $current, 3794b2f1dbbSGreg Roach ]; 3804b2f1dbbSGreg Roach } 381a020b8bdSGreg Roach 382a020b8bdSGreg Roach /** 383a020b8bdSGreg Roach * @param Place $place 384a020b8bdSGreg Roach * 385a020b8bdSGreg Roach * @return Builder 386a020b8bdSGreg Roach */ 387a020b8bdSGreg Roach private function placeLinks(Place $place): Builder 388a020b8bdSGreg Roach { 389a020b8bdSGreg Roach return DB::table('places') 390a020b8bdSGreg Roach ->join('placelinks', static function (JoinClause $join): void { 391a020b8bdSGreg Roach $join 392a020b8bdSGreg Roach ->on('pl_file', '=', 'p_file') 393a020b8bdSGreg Roach ->on('pl_p_id', '=', 'p_id'); 394a020b8bdSGreg Roach }) 395a020b8bdSGreg Roach ->where('p_file', '=', $place->tree()->id()) 396a020b8bdSGreg Roach ->where('p_id', '=', $place->id()); 397a020b8bdSGreg Roach } 398a020b8bdSGreg Roach 399a020b8bdSGreg Roach /** 400a020b8bdSGreg Roach * @param Place $place 401a020b8bdSGreg Roach * 402a020b8bdSGreg Roach * @return Builder 403a020b8bdSGreg Roach */ 404a020b8bdSGreg Roach private function familyPlaceLinks(Place $place): Builder 405a020b8bdSGreg Roach { 406a020b8bdSGreg Roach return $this->placeLinks($place) 407a020b8bdSGreg Roach ->join('families', static function (JoinClause $join): void { 408a020b8bdSGreg Roach $join 409a020b8bdSGreg Roach ->on('pl_file', '=', 'f_file') 410a020b8bdSGreg Roach ->on('pl_gid', '=', 'f_id'); 411a020b8bdSGreg Roach }); 412a020b8bdSGreg Roach } 413a020b8bdSGreg Roach 414a020b8bdSGreg Roach /** 415a020b8bdSGreg Roach * @param Place $place 416a020b8bdSGreg Roach * 417a020b8bdSGreg Roach * @return Builder 418a020b8bdSGreg Roach */ 419a020b8bdSGreg Roach private function individualPlaceLinks(Place $place): Builder 420a020b8bdSGreg Roach { 421a020b8bdSGreg Roach return $this->placeLinks($place) 422a020b8bdSGreg Roach ->join('individuals', static function (JoinClause $join): void { 423a020b8bdSGreg Roach $join 424a020b8bdSGreg Roach ->on('pl_file', '=', 'i_file') 425a020b8bdSGreg Roach ->on('pl_gid', '=', 'i_id'); 426a020b8bdSGreg Roach }); 427a020b8bdSGreg Roach } 428a020b8bdSGreg Roach 429a020b8bdSGreg Roach /** 430a020b8bdSGreg Roach * @param Place $place 431a020b8bdSGreg Roach * 432a020b8bdSGreg Roach * @return Builder 433a020b8bdSGreg Roach */ 434a020b8bdSGreg Roach private function locationPlaceLinks(Place $place): Builder 435a020b8bdSGreg Roach { 436a020b8bdSGreg Roach return $this->placeLinks($place) 437a020b8bdSGreg Roach ->join('other', static function (JoinClause $join): void { 438a020b8bdSGreg Roach $join 439a020b8bdSGreg Roach ->on('pl_file', '=', 'o_file') 440a020b8bdSGreg Roach ->on('pl_gid', '=', 'o_id'); 441a020b8bdSGreg Roach }) 442a020b8bdSGreg Roach ->where('o_type', '=', Location::RECORD_TYPE); 443a020b8bdSGreg Roach } 44467992b6aSRichard Cissee} 445