14991f205SGreg Roach<?php 24991f205SGreg Roach 34991f205SGreg Roach/** 44991f205SGreg Roach * webtrees: online genealogy 55bfc6897SGreg Roach * Copyright (C) 2022 webtrees development team 64991f205SGreg Roach * This program is free software: you can redistribute it and/or modify 74991f205SGreg Roach * it under the terms of the GNU General Public License as published by 84991f205SGreg Roach * the Free Software Foundation, either version 3 of the License, or 94991f205SGreg Roach * (at your option) any later version. 104991f205SGreg Roach * This program is distributed in the hope that it will be useful, 114991f205SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 124991f205SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 134991f205SGreg Roach * GNU General Public License for more details. 144991f205SGreg Roach * You should have received a copy of the GNU General Public License 154991f205SGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 164991f205SGreg Roach */ 174991f205SGreg Roach 184991f205SGreg Roachdeclare(strict_types=1); 194991f205SGreg Roach 204991f205SGreg Roachnamespace Fisharebest\Webtrees\Services; 214991f205SGreg Roach 224991f205SGreg Roachuse Fisharebest\Webtrees\Family; 234991f205SGreg Roachuse Fisharebest\Webtrees\GedcomRecord; 244991f205SGreg Roachuse Fisharebest\Webtrees\Individual; 254991f205SGreg Roachuse Fisharebest\Webtrees\Location; 264991f205SGreg Roachuse Fisharebest\Webtrees\Media; 274991f205SGreg Roachuse Fisharebest\Webtrees\Note; 284991f205SGreg Roachuse Fisharebest\Webtrees\Registry; 294991f205SGreg Roachuse Fisharebest\Webtrees\Repository; 304991f205SGreg Roachuse Fisharebest\Webtrees\Source; 314991f205SGreg Roachuse Fisharebest\Webtrees\Submitter; 324991f205SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 334991f205SGreg Roachuse Illuminate\Database\Query\Builder; 344991f205SGreg Roachuse Illuminate\Database\Query\Expression; 354991f205SGreg Roachuse Illuminate\Database\Query\JoinClause; 364991f205SGreg Roachuse Illuminate\Support\Collection; 374991f205SGreg Roach 384991f205SGreg Roachuse function addcslashes; 394991f205SGreg Roach 404991f205SGreg Roach/** 414991f205SGreg Roach * Find records linked to other records 424991f205SGreg Roach */ 434991f205SGreg Roachclass LinkedRecordService 444991f205SGreg Roach{ 454991f205SGreg Roach /** 464991f205SGreg Roach * Find all records linked to a record. 474991f205SGreg Roach * 484991f205SGreg Roach * @param GedcomRecord $record 494991f205SGreg Roach * 504991f205SGreg Roach * @return Collection<int,Family> 514991f205SGreg Roach */ 524991f205SGreg Roach public function allLinkedRecords(GedcomRecord $record): Collection 534991f205SGreg Roach { 544991f205SGreg Roach $like = addcslashes($record->xref(), '\\%_'); 554991f205SGreg Roach 564991f205SGreg Roach $union = DB::table('change') 574991f205SGreg Roach ->where('gedcom_id', '=', $record->tree()->id()) 584991f205SGreg Roach ->where('new_gedcom', 'LIKE', '%@' . $like . '@%') 594991f205SGreg Roach ->where('new_gedcom', 'NOT LIKE', '0 @' . $like . '@%') 604991f205SGreg Roach ->whereIn('change_id', function (Builder $query) use ($record): void { 614991f205SGreg Roach $query 624991f205SGreg Roach ->select(new Expression('MAX(change_id)')) 634991f205SGreg Roach ->from('change') 644991f205SGreg Roach ->where('gedcom_id', '=', $record->tree()->id()) 654991f205SGreg Roach ->where('status', '=', 'pending') 664991f205SGreg Roach ->groupBy(['xref']); 674991f205SGreg Roach }) 684991f205SGreg Roach ->select(['xref']); 694991f205SGreg Roach 704991f205SGreg Roach $xrefs = DB::table('link') 714991f205SGreg Roach ->where('l_file', '=', $record->tree()->id()) 724991f205SGreg Roach ->where('l_to', '=', $record->xref()) 734991f205SGreg Roach ->select(['l_from']) 744991f205SGreg Roach ->union($union) 754991f205SGreg Roach ->pluck('l_from'); 764991f205SGreg Roach 774991f205SGreg Roach return $xrefs->map(static fn (string $xref) => Registry::gedcomRecordFactory()->make($xref, $record->tree())); 784991f205SGreg Roach } 794991f205SGreg Roach 804991f205SGreg Roach /** 814991f205SGreg Roach * Find families linked to a record. 824991f205SGreg Roach * 834991f205SGreg Roach * @param GedcomRecord $record 844991f205SGreg Roach * @param string|null $link_type 854991f205SGreg Roach * 864991f205SGreg Roach * @return Collection<int,Family> 874991f205SGreg Roach */ 884991f205SGreg Roach public function linkedFamilies(GedcomRecord $record, string $link_type = null): Collection 894991f205SGreg Roach { 904991f205SGreg Roach $query = DB::table('families') 914991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 924991f205SGreg Roach $join 934991f205SGreg Roach ->on('l_file', '=', 'f_file') 944991f205SGreg Roach ->on('l_from', '=', 'f_id'); 954991f205SGreg Roach }) 964991f205SGreg Roach ->where('f_file', '=', $record->tree()->id()) 974991f205SGreg Roach ->where('l_to', '=', $record->xref()); 984991f205SGreg Roach 994991f205SGreg Roach if ($link_type !== null) { 1004991f205SGreg Roach $query->where('l_type', '=', $link_type); 1014991f205SGreg Roach } 1024991f205SGreg Roach 1034991f205SGreg Roach return $query 104*0aed7de4SGreg Roach ->distinct() 1054991f205SGreg Roach ->select(['families.*']) 1064991f205SGreg Roach ->get() 1074991f205SGreg Roach ->map(Registry::familyFactory()->mapper($record->tree())) 1084991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 1094991f205SGreg Roach } 1104991f205SGreg Roach 1114991f205SGreg Roach /** 1124991f205SGreg Roach * Find individuals linked to a record. 1134991f205SGreg Roach * 1144991f205SGreg Roach * @param GedcomRecord $record 11592a78a2fSGreg Roach * @param string|null $link_type 1164991f205SGreg Roach * 1174991f205SGreg Roach * @return Collection<int,Individual> 1184991f205SGreg Roach */ 1194991f205SGreg Roach public function linkedIndividuals(GedcomRecord $record, string $link_type = null): Collection 1204991f205SGreg Roach { 1214991f205SGreg Roach $query = DB::table('individuals') 1224991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 1234991f205SGreg Roach $join 1244991f205SGreg Roach ->on('l_file', '=', 'i_file') 1254991f205SGreg Roach ->on('l_from', '=', 'i_id'); 1264991f205SGreg Roach }) 1274991f205SGreg Roach ->where('i_file', '=', $record->tree()->id()) 1284991f205SGreg Roach ->where('l_to', '=', $record->xref()); 1294991f205SGreg Roach 1304991f205SGreg Roach if ($link_type !== null) { 1314991f205SGreg Roach $query->where('l_type', '=', $link_type); 1324991f205SGreg Roach } 1334991f205SGreg Roach 1344991f205SGreg Roach return $query 135*0aed7de4SGreg Roach ->distinct() 1364991f205SGreg Roach ->select(['individuals.*']) 1374991f205SGreg Roach ->get() 1384991f205SGreg Roach ->map(Registry::individualFactory()->mapper($record->tree())) 1394991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 1404991f205SGreg Roach } 1414991f205SGreg Roach 1424991f205SGreg Roach /** 1434991f205SGreg Roach * Find locations linked to a record. 1444991f205SGreg Roach * 1454991f205SGreg Roach * @param GedcomRecord $record 1464991f205SGreg Roach * 1474991f205SGreg Roach * @return Collection<int,Location> 1484991f205SGreg Roach */ 1494991f205SGreg Roach public function linkedLocations(GedcomRecord $record): Collection 1504991f205SGreg Roach { 1514991f205SGreg Roach return DB::table('other') 1524991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 1534991f205SGreg Roach $join 1544991f205SGreg Roach ->on('l_file', '=', 'o_file') 1554991f205SGreg Roach ->on('l_from', '=', 'o_id'); 1564991f205SGreg Roach }) 1574991f205SGreg Roach ->where('o_file', '=', $record->tree()->id()) 1584991f205SGreg Roach ->where('o_type', '=', Location::RECORD_TYPE) 1594991f205SGreg Roach ->where('l_to', '=', $record->xref()) 160*0aed7de4SGreg Roach ->distinct() 1614991f205SGreg Roach ->select(['other.*']) 1624991f205SGreg Roach ->get() 1634991f205SGreg Roach ->map(Registry::locationFactory()->mapper($record->tree())) 1644991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 1654991f205SGreg Roach } 1664991f205SGreg Roach 1674991f205SGreg Roach /** 1684991f205SGreg Roach * Find media objects linked to a record. 1694991f205SGreg Roach * 1704991f205SGreg Roach * @param GedcomRecord $record 1714991f205SGreg Roach * 1724991f205SGreg Roach * @return Collection<int,Media> 1734991f205SGreg Roach */ 1744991f205SGreg Roach public function linkedMedia(GedcomRecord $record): Collection 1754991f205SGreg Roach { 1764991f205SGreg Roach return DB::table('media') 1774991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 1784991f205SGreg Roach $join 1794991f205SGreg Roach ->on('l_file', '=', 'm_file') 1804991f205SGreg Roach ->on('l_from', '=', 'm_id'); 1814991f205SGreg Roach }) 1824991f205SGreg Roach ->where('m_file', '=', $record->tree()->id()) 1834991f205SGreg Roach ->where('l_to', '=', $record->xref()) 184*0aed7de4SGreg Roach ->distinct() 1854991f205SGreg Roach ->select(['media.*']) 1864991f205SGreg Roach ->get() 1874991f205SGreg Roach ->map(Registry::mediaFactory()->mapper($record->tree())) 1884991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 1894991f205SGreg Roach } 1904991f205SGreg Roach 1914991f205SGreg Roach /** 1924991f205SGreg Roach * Find notes linked to a record. 1934991f205SGreg Roach * 1944991f205SGreg Roach * @param GedcomRecord $record 1954991f205SGreg Roach * 1964991f205SGreg Roach * @return Collection<int,Note> 1974991f205SGreg Roach */ 1984991f205SGreg Roach public function linkedNotes(GedcomRecord $record): Collection 1994991f205SGreg Roach { 2004991f205SGreg Roach return DB::table('other') 2014991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 2024991f205SGreg Roach $join 2034991f205SGreg Roach ->on('l_file', '=', 'o_file') 2044991f205SGreg Roach ->on('l_from', '=', 'o_id'); 2054991f205SGreg Roach }) 2064991f205SGreg Roach ->where('o_file', '=', $record->tree()->id()) 2074991f205SGreg Roach ->where('o_type', '=', Note::RECORD_TYPE) 2084991f205SGreg Roach ->where('l_to', '=', $record->xref()) 209*0aed7de4SGreg Roach ->distinct() 2104991f205SGreg Roach ->select(['other.*']) 21186070f86SGreg Roach ->get() 2124991f205SGreg Roach ->map(Registry::noteFactory()->mapper($record->tree())) 2134991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 2144991f205SGreg Roach } 2154991f205SGreg Roach 2164991f205SGreg Roach /** 2174991f205SGreg Roach * Find repositories linked to a record. 2184991f205SGreg Roach * 2194991f205SGreg Roach * @param GedcomRecord $record 2204991f205SGreg Roach * 2214991f205SGreg Roach * @return Collection<int,Repository> 2224991f205SGreg Roach */ 2234991f205SGreg Roach public function linkedRepositories(GedcomRecord $record): Collection 2244991f205SGreg Roach { 2254991f205SGreg Roach return DB::table('other') 2264991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 2274991f205SGreg Roach $join 2284991f205SGreg Roach ->on('l_file', '=', 'o_file') 2294991f205SGreg Roach ->on('l_from', '=', 'o_id'); 2304991f205SGreg Roach }) 2314991f205SGreg Roach ->where('o_file', '=', $record->tree()->id()) 2324991f205SGreg Roach ->where('o_type', '=', Repository::RECORD_TYPE) 2334991f205SGreg Roach ->where('l_to', '=', $record->xref()) 234*0aed7de4SGreg Roach ->distinct() 2354991f205SGreg Roach ->select(['other.*']) 2364991f205SGreg Roach ->get() 2374991f205SGreg Roach ->map(Registry::repositoryFactory()->mapper($record->tree())) 2384991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 2394991f205SGreg Roach } 2404991f205SGreg Roach 2414991f205SGreg Roach /** 2424991f205SGreg Roach * Find sources linked to a record. 2434991f205SGreg Roach * 2444991f205SGreg Roach * @param GedcomRecord $record 2454991f205SGreg Roach * 2464991f205SGreg Roach * @return Collection<int,Source> 2474991f205SGreg Roach */ 2484991f205SGreg Roach public function linkedSources(GedcomRecord $record): Collection 2494991f205SGreg Roach { 2504991f205SGreg Roach return DB::table('sources') 2514991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 2524991f205SGreg Roach $join 2534991f205SGreg Roach ->on('l_file', '=', 's_file') 2544991f205SGreg Roach ->on('l_from', '=', 's_id'); 2554991f205SGreg Roach }) 2564991f205SGreg Roach ->where('s_file', '=', $record->tree()->id()) 2574991f205SGreg Roach ->where('l_to', '=', $record->xref()) 258*0aed7de4SGreg Roach ->distinct() 2594991f205SGreg Roach ->select(['sources.*']) 2604991f205SGreg Roach ->get() 2614991f205SGreg Roach ->map(Registry::sourceFactory()->mapper($record->tree())) 2624991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 2634991f205SGreg Roach } 2644991f205SGreg Roach 2654991f205SGreg Roach /** 2664991f205SGreg Roach * Find submitters linked to a record. 2674991f205SGreg Roach * 2684991f205SGreg Roach * @param GedcomRecord $record 2694991f205SGreg Roach * 2704991f205SGreg Roach * @return Collection<int,Repository> 2714991f205SGreg Roach */ 2724991f205SGreg Roach public function linkedSubmitters(GedcomRecord $record): Collection 2734991f205SGreg Roach { 2744991f205SGreg Roach return DB::table('other') 2754991f205SGreg Roach ->join('link', static function (JoinClause $join): void { 2764991f205SGreg Roach $join 2774991f205SGreg Roach ->on('l_file', '=', 'o_file') 2784991f205SGreg Roach ->on('l_from', '=', 'o_id'); 2794991f205SGreg Roach }) 2804991f205SGreg Roach ->where('o_file', '=', $record->tree()->id()) 2814991f205SGreg Roach ->where('o_type', '=', Submitter::RECORD_TYPE) 2824991f205SGreg Roach ->where('l_to', '=', $record->xref()) 283*0aed7de4SGreg Roach ->distinct() 2844991f205SGreg Roach ->select(['other.*']) 285*0aed7de4SGreg Roach ->distinct() 2864991f205SGreg Roach ->get() 2874991f205SGreg Roach ->map(Registry::repositoryFactory()->mapper($record->tree())) 2884991f205SGreg Roach ->filter(GedcomRecord::accessFilter()); 2894991f205SGreg Roach } 2904991f205SGreg Roach} 291