Passed
Branch feature/2.1-geodispersion-dev (1d61a8)
by Jonathan
61:21
created

CertificateDataService::oneLinkedSource()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 11
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 21
rs 8.4444
1
<?php
2
3
/**
4
 * webtrees-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage Certificates
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2021, Jonathan Jaubart
10
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
11
 */
12
13
declare(strict_types=1);
14
15
namespace MyArtJaub\Webtrees\Module\Certificates\Services;
16
17
use Fisharebest\Webtrees\Gedcom;
18
use Fisharebest\Webtrees\GedcomRecord;
19
use Fisharebest\Webtrees\Registry;
20
use Fisharebest\Webtrees\Source;
21
use Illuminate\Database\Capsule\Manager as DB;
22
use Illuminate\Support\Collection;
23
use MyArtJaub\Webtrees\Module\Certificates\Model\Certificate;
24
use Generator;
25
26
/**
27
 * Service for accessing genealogical data linked to a certificate file.
28
 */
29
class CertificateDataService
30
{
31
32
    /**
33
     * Find individuals linked to a certificate.
34
     *
35
     * {@internal Ideally, the underscore should be escaped in the WHERE clause,
36
     * but does not work with Sqlite if no default escape has been defined}
37
     *
38
     * @param Certificate $certificate
39
     * @return Collection
40
     */
41
    public function linkedIndividuals(Certificate $certificate): Collection
42
    {
43
        $tree = $certificate->tree();
44
        return DB::table('individuals')
45
            ->where('i_file', '=', $tree->id())
46
            ->where('i_gedcom', 'like', '% _ACT ' . $this->escapedSqlPath($certificate) . '%')
47
            ->select(['individuals.*'])
48
            ->get()
49
            ->map(Registry::individualFactory()->mapper($tree))
50
            ->filter(GedcomRecord::accessFilter());
51
    }
52
53
    /**
54
     * Find families linked to a certificate.
55
     *
56
     * {@internal Ideally, the underscore should be escaped in the WHERE clause,
57
     * but does not work with Sqlite if no default escape has been defined}
58
     *
59
     * @param Certificate $certificate
60
     * @return Collection
61
     */
62
    public function linkedFamilies(Certificate $certificate): Collection
63
    {
64
        $tree = $certificate->tree();
65
        return DB::table('families')
66
            ->where('f_file', '=', $tree->id())
67
            ->where('f_gedcom', 'like', '% _ACT ' . $this->escapedSqlPath($certificate) . '%')
68
            ->select(['families.*'])
69
            ->get()
70
            ->map(Registry::familyFactory()->mapper($tree))
71
            ->filter(GedcomRecord::accessFilter());
72
    }
73
74
    /**
75
     * Find media objects linked to a certificate.
76
     *
77
     * {@internal Ideally, the underscore should be escaped in the WHERE clause,
78
     * but does not work with Sqlite if no default escape has been defined}
79
     *
80
     * @param Certificate $certificate
81
     * @return Collection
82
     */
83
    public function linkedMedias(Certificate $certificate): Collection
84
    {
85
        $tree = $certificate->tree();
86
        return DB::table('media')
87
            ->where('m_file', '=', $tree->id())
88
            ->where('m_gedcom', 'like', '% _ACT ' . $this->escapedSqlPath($certificate) . '%')
89
            ->select(['media.*'])
90
            ->get()
91
            ->map(Registry::mediaFactory()->mapper($tree))
92
            ->filter(GedcomRecord::accessFilter());
93
    }
94
95
    /**
96
     * Find notes linked to a certificate.
97
     *
98
     * {@internal Ideally, the underscore should be escaped in the WHERE clause,
99
     * but does not work with Sqlite if no default escape has been defined}
100
     *
101
     * @param Certificate $certificate
102
     * @return Collection
103
     */
104
    public function linkedNotes(Certificate $certificate): Collection
105
    {
106
        $tree = $certificate->tree();
107
        return DB::table('other')
108
            ->where('o_file', '=', $tree->id())
109
            ->where('o_type', '=', 'NOTE')
110
            ->where('o_gedcom', 'like', '% _ACT ' . $this->escapedSqlPath($certificate) . '%')
111
            ->select(['other.*'])
112
            ->get()
113
            ->map(Registry::noteFactory()->mapper($tree))
114
            ->filter(GedcomRecord::accessFilter());
115
    }
116
117
    /**
118
     * Return an escaped string to be used in SQL LIKE comparisons.
119
     * This would not work well for Sqlite, if the escape character is not defined.
120
     *
121
     * @param Certificate $certificate
122
     * @return string
123
     */
124
    protected function escapedSqlPath(Certificate $certificate): string
125
    {
126
        return str_replace(array('\\', '%', '_'), array('\\\\', '\\%', '\\_'), $certificate->gedcomPath());
127
    }
128
129
    /**
130
     * Find a source linked to a citation where a certificate file is referenced.
131
     *
132
     * @param Certificate $certificate
133
     * @return Source|NULL
134
     */
135
    public function oneLinkedSource(Certificate $certificate): ?Source
136
    {
137
        $regex_query = preg_quote($certificate->gedcomPath(), '/');
138
        $regex_pattern = '/[1-9] SOUR @(' . Gedcom::REGEX_XREF . ')@(?:\n[2-9]\s(?:(?!SOUR)\w+)\s.*)*\n[2-9] _ACT ' . $regex_query . '/i'; //phpcs:ignore Generic.Files.LineLength.TooLong
139
140
        foreach ($this->linkedRecordsLists($certificate) as $linked_records) {
141
            foreach ($linked_records as $gedcom_record) {
142
                foreach ($gedcom_record->facts() as $fact) {
143
                    if (preg_match_all($regex_pattern, $fact->gedcom(), $matches, PREG_SET_ORDER) >= 1) {
144
                        foreach ($matches as $match) {
145
                            $source = Registry::sourceFactory()->make($match[1], $certificate->tree());
146
                            if ($source !== null && $source->canShowName()) {
147
                                return $source;
148
                            }
149
                        }
150
                    }
151
                }
152
            }
153
        }
154
155
        return null;
156
    }
157
158
    /**
159
     * Yield lists of gedcom records linked to a certificate.
160
     *
161
     * @param Certificate $certificate
162
     * @return Generator
163
     */
164
    protected function linkedRecordsLists(Certificate $certificate): Generator
165
    {
166
        yield $this->linkedIndividuals($certificate);
167
        yield $this->linkedFamilies($certificate);
168
        yield $this->linkedMedias($certificate);
169
        yield $this->linkedNotes($certificate);
170
    }
171
}
172