xref: /webtrees/app/Services/LinkedRecordService.php (revision 2c6f1bd538f46b93645991518398bb087011cb42)
14991f205SGreg Roach<?php
24991f205SGreg Roach
34991f205SGreg Roach/**
44991f205SGreg Roach * webtrees: online genealogy
5d11be702SGreg Roach * Copyright (C) 2023 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
226f4ec3caSGreg Roachuse Fisharebest\Webtrees\DB;
234991f205SGreg Roachuse Fisharebest\Webtrees\Family;
244991f205SGreg Roachuse Fisharebest\Webtrees\GedcomRecord;
254991f205SGreg Roachuse Fisharebest\Webtrees\Individual;
264991f205SGreg Roachuse Fisharebest\Webtrees\Location;
274991f205SGreg Roachuse Fisharebest\Webtrees\Media;
284991f205SGreg Roachuse Fisharebest\Webtrees\Note;
294991f205SGreg Roachuse Fisharebest\Webtrees\Registry;
304991f205SGreg Roachuse Fisharebest\Webtrees\Repository;
314991f205SGreg Roachuse Fisharebest\Webtrees\Source;
324991f205SGreg Roachuse Fisharebest\Webtrees\Submitter;
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
62059898c9SGreg 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     */
88*2c6f1bd5SGreg Roach    public function linkedFamilies(GedcomRecord $record, string|null $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
1040aed7de4SGreg 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     */
119*2c6f1bd5SGreg Roach    public function linkedIndividuals(GedcomRecord $record, string|null $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
1350aed7de4SGreg 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())
1600aed7de4SGreg 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())
1840aed7de4SGreg 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())
2090aed7de4SGreg 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())
2340aed7de4SGreg 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())
2580aed7de4SGreg 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())
2830aed7de4SGreg Roach            ->distinct()
2844991f205SGreg Roach            ->select(['other.*'])
2850aed7de4SGreg Roach            ->distinct()
2864991f205SGreg Roach            ->get()
2874991f205SGreg Roach            ->map(Registry::repositoryFactory()->mapper($record->tree()))
2884991f205SGreg Roach            ->filter(GedcomRecord::accessFilter());
2894991f205SGreg Roach    }
2904991f205SGreg Roach}
291