1 | <?php |
||
2 | |||
3 | /** |
||
4 | * webtrees: online genealogy |
||
5 | * Copyright (C) 2022 webtrees development team |
||
6 | * This program is free software: you can redistribute it and/or modify |
||
7 | * it under the terms of the GNU General Public License as published by |
||
8 | * the Free Software Foundation, either version 3 of the License, or |
||
9 | * (at your option) any later version. |
||
10 | * This program is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | * GNU General Public License for more details. |
||
14 | * You should have received a copy of the GNU General Public License |
||
15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||
16 | */ |
||
17 | |||
18 | declare(strict_types=1); |
||
19 | |||
20 | namespace Fisharebest\Webtrees\Functions; |
||
21 | |||
22 | use Fisharebest\Webtrees\Age; |
||
23 | use Fisharebest\Webtrees\Date; |
||
24 | use Fisharebest\Webtrees\Fact; |
||
25 | use Fisharebest\Webtrees\Family; |
||
26 | use Fisharebest\Webtrees\Filter; |
||
27 | use Fisharebest\Webtrees\Gedcom; |
||
28 | use Fisharebest\Webtrees\GedcomRecord; |
||
29 | use Fisharebest\Webtrees\GedcomTag; |
||
30 | use Fisharebest\Webtrees\Header; |
||
31 | use Fisharebest\Webtrees\I18N; |
||
32 | use Fisharebest\Webtrees\Individual; |
||
33 | use Fisharebest\Webtrees\Media; |
||
34 | use Fisharebest\Webtrees\Note; |
||
35 | use Fisharebest\Webtrees\Place; |
||
36 | use Fisharebest\Webtrees\Registry; |
||
37 | use Fisharebest\Webtrees\Repository; |
||
38 | use Fisharebest\Webtrees\Source; |
||
39 | use Fisharebest\Webtrees\Submission; |
||
40 | use Fisharebest\Webtrees\Submitter; |
||
41 | use Fisharebest\Webtrees\Tree; |
||
42 | use Illuminate\Support\Collection; |
||
43 | use Illuminate\Support\Str; |
||
44 | use LogicException; |
||
45 | use Ramsey\Uuid\Uuid; |
||
46 | |||
47 | use function array_filter; |
||
48 | use function array_intersect; |
||
49 | use function array_merge; |
||
50 | use function array_search; |
||
51 | use function e; |
||
52 | use function explode; |
||
53 | use function in_array; |
||
54 | use function preg_match; |
||
55 | use function preg_match_all; |
||
56 | use function preg_replace_callback; |
||
57 | use function preg_split; |
||
58 | use function str_contains; |
||
59 | use function strip_tags; |
||
60 | use function strlen; |
||
61 | use function strpos; |
||
62 | use function strtoupper; |
||
63 | use function substr; |
||
64 | use function trim; |
||
65 | use function uasort; |
||
66 | use function var_export; |
||
67 | use function view; |
||
68 | |||
69 | use const PREG_SET_ORDER; |
||
70 | use const PREG_SPLIT_NO_EMPTY; |
||
71 | |||
72 | /** |
||
73 | * Class FunctionsPrint - common functions |
||
74 | * |
||
75 | * @deprecated since 2.0.6. Will be removed in 2.1.0 |
||
76 | */ |
||
77 | class FunctionsPrint |
||
78 | { |
||
79 | /** |
||
80 | * print a note record |
||
81 | * |
||
82 | * @param Tree $tree |
||
83 | * @param string $text |
||
84 | * @param int $nlevel the level of the note record |
||
85 | * @param string $nrec the note record to print |
||
86 | * |
||
87 | * @return string |
||
88 | */ |
||
89 | private static function printNoteRecord(Tree $tree, string $text, int $nlevel, string $nrec): string |
||
90 | { |
||
91 | $element = Registry::elementFactory()->make('NOTE:CONC'); |
||
92 | |||
93 | $text .= Functions::getCont($nlevel, $nrec); |
||
94 | |||
95 | if (preg_match('/^0 @(' . Gedcom::REGEX_XREF . ')@ NOTE/', $nrec, $match)) { |
||
96 | // Shared note. |
||
97 | $note = Registry::noteFactory()->make($match[1], $tree); |
||
98 | // It must exist. |
||
99 | assert($note instanceof Note); |
||
100 | |||
101 | $label = I18N::translate('Shared note'); |
||
102 | $html = $element->value($note->getNote(), $tree); |
||
103 | $first_line = '<a href="' . e($note->url()) . '">' . $note->fullName() . '</a>'; |
||
104 | |||
105 | $one_line_only = strip_tags($note->fullName()) === strip_tags($note->getNote()); |
||
106 | } else { |
||
107 | // Inline note. |
||
108 | $label = I18N::translate('Note'); |
||
109 | $html = $element->value($text, $tree); |
||
110 | |||
111 | [$first_line] = explode("\n", strip_tags($html)); |
||
112 | // Use same logic as note objects |
||
113 | $first_line = Str::limit($first_line, 100, I18N::translate('…')); |
||
114 | |||
115 | $one_line_only = !str_contains($text, "\n") && mb_strlen($text) <= 100; |
||
116 | } |
||
117 | |||
118 | if ($one_line_only) { |
||
119 | return |
||
120 | '<div class="fact_NOTE">' . |
||
121 | I18N::translate( |
||
122 | '<span class="label">%1$s:</span> <span class="field" dir="auto">%2$s</span>', |
||
123 | $label, |
||
124 | $first_line |
||
125 | ) . |
||
126 | '</div>'; |
||
127 | } |
||
128 | |||
129 | $id = 'collapse-' . Uuid::uuid4()->toString(); |
||
130 | $expanded = (bool) $tree->getPreference('EXPAND_NOTES'); |
||
131 | |||
132 | return |
||
133 | '<div class="fact_NOTE">' . |
||
134 | '<a href="#' . e($id) . '" role="button" data-toggle="collapse" aria-controls="' . e($id) . '" aria-expanded="' . ($expanded ? 'true' : 'false') . '">' . |
||
135 | view('icons/expand') . |
||
136 | view('icons/collapse') . |
||
137 | '</a>' . |
||
138 | '<span class="label">' . $label . ':</span> ' . |
||
139 | $first_line . |
||
140 | '</div>' . |
||
141 | '<div id="' . e($id) . '" class="markdown collapse ' . ($expanded ? 'show' : '') . '">' . |
||
142 | $html . |
||
143 | '</div>'; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * Print all of the notes in this fact record |
||
148 | * |
||
149 | * @param Tree $tree |
||
150 | * @param string $factrec The fact to print the notes from |
||
151 | * @param int $level The level of the notes |
||
152 | * |
||
153 | * @return string HTML |
||
154 | */ |
||
155 | public static function printFactNotes(Tree $tree, string $factrec, int $level): string |
||
156 | { |
||
157 | $data = ''; |
||
158 | $previous_spos = 0; |
||
159 | $nlevel = $level + 1; |
||
160 | $ct = preg_match_all("/$level NOTE (.*)/", $factrec, $match, PREG_SET_ORDER); |
||
161 | for ($j = 0; $j < $ct; $j++) { |
||
162 | $spos1 = strpos($factrec, $match[$j][0], $previous_spos); |
||
163 | $spos2 = strpos($factrec . "\n$level", "\n$level", $spos1 + 1); |
||
164 | if (!$spos2) { |
||
165 | $spos2 = strlen($factrec); |
||
166 | } |
||
167 | $previous_spos = $spos2; |
||
168 | $nrec = substr($factrec, $spos1, $spos2 - $spos1); |
||
169 | if (!isset($match[$j][1])) { |
||
170 | $match[$j][1] = ''; |
||
171 | } |
||
172 | if (!preg_match('/^@(' . Gedcom::REGEX_XREF . ')@$/', $match[$j][1], $nmatch)) { |
||
173 | $data .= self::printNoteRecord($tree, $match[$j][1], $nlevel, $nrec); |
||
174 | } else { |
||
175 | $note = Registry::noteFactory()->make($nmatch[1], $tree); |
||
176 | if ($note) { |
||
177 | if ($note->canShow()) { |
||
178 | $noterec = $note->gedcom(); |
||
179 | $nt = preg_match("/0 @$nmatch[1]@ NOTE (.*)/", $noterec, $n1match); |
||
180 | $data .= self::printNoteRecord($tree, $nt > 0 ? $n1match[1] : '', 1, $noterec); |
||
181 | } |
||
182 | } else { |
||
183 | $data = '<div class="fact_NOTE"><span class="label">' . I18N::translate('Note') . '</span>: <span class="field error">' . $nmatch[1] . '</span></div>'; |
||
184 | } |
||
185 | } |
||
186 | } |
||
187 | |||
188 | return $data; |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * Format age of parents in HTML |
||
193 | * |
||
194 | * @param Individual $person child |
||
195 | * @param Date $birth_date |
||
196 | * |
||
197 | * @return string HTML |
||
198 | */ |
||
199 | public static function formatParentsAges(Individual $person, Date $birth_date): string |
||
200 | { |
||
201 | $html = ''; |
||
202 | $families = $person->childFamilies(); |
||
203 | // Multiple sets of parents (e.g. adoption) cause complications, so ignore. |
||
204 | if ($birth_date->isOK() && $families->count() === 1) { |
||
205 | $family = $families->first(); |
||
206 | foreach ($family->spouses() as $parent) { |
||
207 | if ($parent->getBirthDate()->isOK()) { |
||
208 | $sex = '<small>' . view('icons/sex', ['sex' => $parent->sex()]) . '</small>'; |
||
209 | $age = new Age($parent->getBirthDate(), $birth_date); |
||
210 | $deatdate = $parent->getDeathDate(); |
||
211 | switch ($parent->sex()) { |
||
212 | case 'F': |
||
213 | // Highlight mothers who die in childbirth or shortly afterwards |
||
214 | if ($deatdate->isOK() && $deatdate->maximumJulianDay() < $birth_date->minimumJulianDay() + 90) { |
||
215 | $html .= ' <span title="' . I18N::translate('Death of a mother') . '" class="parentdeath">' . $sex . I18N::number($age->ageYears()) . '</span>'; |
||
216 | } else { |
||
217 | $html .= ' <span title="' . I18N::translate('Mother’s age') . '">' . $sex . I18N::number($age->ageYears()) . '</span>'; |
||
218 | } |
||
219 | break; |
||
220 | case 'M': |
||
221 | // Highlight fathers who die before the birth |
||
222 | if ($deatdate->isOK() && $deatdate->maximumJulianDay() < $birth_date->minimumJulianDay()) { |
||
223 | $html .= ' <span title="' . I18N::translate('Death of a father') . '" class="parentdeath">' . $sex . I18N::number($age->ageYears()) . '</span>'; |
||
224 | } else { |
||
225 | $html .= ' <span title="' . I18N::translate('Father’s age') . '">' . $sex . I18N::number($age->ageYears()) . '</span>'; |
||
226 | } |
||
227 | break; |
||
228 | default: |
||
229 | $html .= ' <span title="' . I18N::translate('Parent’s age') . '">' . $sex . I18N::number($age->ageYears()) . '</span>'; |
||
230 | break; |
||
231 | } |
||
232 | } |
||
233 | } |
||
234 | if ($html) { |
||
235 | $html = '<span class="age">' . $html . '</span>'; |
||
236 | } |
||
237 | } |
||
238 | |||
239 | return $html; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Convert a GEDCOM age string to localized text. |
||
244 | * |
||
245 | * @param string $age_string |
||
246 | * |
||
247 | * @return string |
||
248 | */ |
||
249 | public static function formatGedcomAge(string $age_string): string |
||
250 | { |
||
251 | switch (strtoupper($age_string)) { |
||
252 | case 'CHILD': |
||
253 | return I18N::translate('Child'); |
||
254 | case 'INFANT': |
||
255 | return I18N::translate('Infant'); |
||
256 | case 'STILLBORN': |
||
257 | return I18N::translate('Stillborn'); |
||
258 | default: |
||
259 | return (string) preg_replace_callback( |
||
260 | [ |
||
261 | '/(\d+)([ymwd])/', |
||
262 | ], |
||
263 | static function (array $match): string { |
||
264 | $num = (int) $match[1]; |
||
265 | |||
266 | switch ($match[2]) { |
||
267 | case 'y': |
||
268 | return I18N::plural('%s year', '%s years', $num, I18N::number($num)); |
||
269 | case 'm': |
||
270 | return I18N::plural('%s month', '%s months', $num, I18N::number($num)); |
||
271 | case 'w': |
||
272 | return I18N::plural('%s week', '%s weeks', $num, I18N::number($num)); |
||
273 | case 'd': |
||
274 | return I18N::plural('%s day', '%s days', $num, I18N::number($num)); |
||
275 | default: |
||
276 | throw new LogicException('Should never get here'); |
||
277 | } |
||
278 | }, |
||
279 | $age_string |
||
280 | ) ; |
||
281 | } |
||
282 | } |
||
283 | |||
284 | /** |
||
285 | * Print fact DATE/TIME |
||
286 | * |
||
287 | * @param Fact $event event containing the date/age |
||
288 | * @param GedcomRecord $record the person (or couple) whose ages should be printed |
||
289 | * @param bool $anchor option to print a link to calendar |
||
290 | * @param bool $time option to print TIME value |
||
291 | * |
||
292 | * @return string |
||
293 | */ |
||
294 | public static function formatFactDate(Fact $event, GedcomRecord $record, bool $anchor, bool $time): string |
||
295 | { |
||
296 | $factrec = $event->gedcom(); |
||
297 | $html = ''; |
||
298 | // Recorded age |
||
299 | if (preg_match('/\n2 AGE (.+)/', $factrec, $match)) { |
||
300 | $fact_age = self::formatGedcomAge($match[1]); |
||
301 | } else { |
||
302 | $fact_age = ''; |
||
303 | } |
||
304 | if (preg_match('/\n2 HUSB\n3 AGE (.+)/', $factrec, $match)) { |
||
305 | $husb_age = self::formatGedcomAge($match[1]); |
||
306 | } else { |
||
307 | $husb_age = ''; |
||
308 | } |
||
309 | if (preg_match('/\n2 WIFE\n3 AGE (.+)/', $factrec, $match)) { |
||
310 | $wife_age = self::formatGedcomAge($match[1]); |
||
311 | } else { |
||
312 | $wife_age = ''; |
||
313 | } |
||
314 | |||
315 | // Calculated age |
||
316 | $fact = $event->getTag(); |
||
0 ignored issues
–
show
|
|||
317 | if (preg_match('/\n2 DATE (.+)/', $factrec, $match)) { |
||
318 | $date = new Date($match[1]); |
||
319 | $html .= ' ' . $date->display($anchor); |
||
320 | // time |
||
321 | if ($time && preg_match('/\n3 TIME (.+)/', $factrec, $match)) { |
||
322 | $html .= ' – <span class="date">' . $match[1] . '</span>'; |
||
323 | } |
||
324 | if ($record instanceof Individual) { |
||
325 | if ( |
||
326 | in_array($fact, Gedcom::BIRTH_EVENTS, true) && |
||
327 | $record === $event->record() && |
||
0 ignored issues
–
show
|
|||
328 | $record->tree()->getPreference('SHOW_PARENTS_AGE') === '1' |
||
329 | ) { |
||
330 | // age of parents at child birth |
||
331 | $html .= self::formatParentsAges($record, $date); |
||
332 | } |
||
333 | if ($fact !== 'BIRT' && $fact !== 'CHAN' && $fact !== '_TODO') { |
||
334 | // age at event |
||
335 | $birth_date = $record->getBirthDate(); |
||
336 | // Can't use getDeathDate(), as this also gives BURI/CREM events, which |
||
337 | // wouldn't give the correct "days after death" result for people with |
||
338 | // no DEAT. |
||
339 | $death_event = $record->facts(['DEAT'])->first(); |
||
340 | if ($death_event instanceof Fact) { |
||
341 | $death_date = $death_event->date(); |
||
342 | } else { |
||
343 | $death_date = new Date(''); |
||
344 | } |
||
345 | $ageText = ''; |
||
346 | if ($fact === 'DEAT' || Date::compare($date, $death_date) <= 0 || !$record->isDead()) { |
||
347 | // Before death, print age |
||
348 | $age = (string) new Age($birth_date, $date); |
||
349 | |||
350 | // Only show calculated age if it differs from recorded age |
||
351 | if ($age !== '') { |
||
352 | if ( |
||
353 | $fact_age !== '' && $fact_age !== $age || |
||
354 | $fact_age === '' && $husb_age === '' && $wife_age === '' || |
||
355 | $husb_age !== '' && $husb_age !== $age && $record->sex() === 'M' || |
||
356 | $wife_age !== '' && $wife_age !== $age && $record->sex() === 'F' |
||
357 | ) { |
||
358 | switch ($record->sex()) { |
||
359 | case 'M': |
||
360 | /* I18N: The age of an individual at a given date */ |
||
361 | $ageText = I18N::translateContext('Male', '(aged %s)', $age); |
||
362 | break; |
||
363 | case 'F': |
||
364 | /* I18N: The age of an individual at a given date */ |
||
365 | $ageText = I18N::translateContext('Female', '(aged %s)', $age); |
||
366 | break; |
||
367 | default: |
||
368 | /* I18N: The age of an individual at a given date */ |
||
369 | $ageText = I18N::translate('(aged %s)', $age); |
||
370 | break; |
||
371 | } |
||
372 | } |
||
373 | } |
||
374 | } |
||
375 | if ($fact !== 'DEAT' && $death_date->isOK() && Date::compare($death_date, $date) <= 0) { |
||
376 | $death_day = $death_date->minimumDate()->day(); |
||
377 | $event_day = $date->minimumDate()->day(); |
||
378 | if ($death_day !== 0 && $event_day !== 0 && Date::compare($death_date, $date) === 0) { |
||
379 | // On the exact date of death? |
||
380 | // NOTE: this path is never reached. Keep the code (translation) in case |
||
381 | // we decide to re-introduce it. |
||
382 | $ageText = I18N::translate('(on the date of death)'); |
||
383 | } else { |
||
384 | // After death |
||
385 | $age = (string) new Age($death_date, $date); |
||
386 | $ageText = I18N::translate('(%s after death)', $age); |
||
387 | } |
||
388 | // Family events which occur after death are probably errors |
||
389 | if ($event->record() instanceof Family) { |
||
390 | $ageText .= view('icons/warning'); |
||
391 | } |
||
392 | } |
||
393 | if ($ageText !== '') { |
||
394 | $html .= ' <span class="age">' . $ageText . '</span>'; |
||
395 | } |
||
396 | } |
||
397 | } |
||
398 | } |
||
399 | // print gedcom ages |
||
400 | $age_labels = [ |
||
401 | I18N::translate('Age') => $fact_age, |
||
402 | I18N::translate('Husband') => $husb_age, |
||
403 | I18N::translate('Wife') => $wife_age, |
||
404 | ]; |
||
405 | |||
406 | foreach (array_filter($age_labels) as $label => $age) { |
||
407 | $html .= ' <span class="label">' . $label . ':</span> <span class="age">' . $age . '</span>'; |
||
408 | } |
||
409 | |||
410 | return $html; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * print fact PLACe TEMPle STATus |
||
415 | * |
||
416 | * @param Fact $event gedcom fact record |
||
417 | * @param bool $anchor to print a link to placelist |
||
418 | * @param bool $sub_records to print place subrecords |
||
419 | * @param bool $lds to print LDS TEMPle and STATus |
||
420 | * |
||
421 | * @return string HTML |
||
422 | */ |
||
423 | public static function formatFactPlace(Fact $event, $anchor = false, $sub_records = false, $lds = false): string |
||
424 | { |
||
425 | $tree = $event->record()->tree(); |
||
426 | |||
427 | if ($anchor) { |
||
428 | // Show the full place name, for facts/events tab |
||
429 | $html = $event->place()->fullName(true); |
||
430 | } else { |
||
431 | // Abbreviate the place name, for chart boxes |
||
432 | return $event->place()->shortName(); |
||
433 | } |
||
434 | |||
435 | if ($sub_records) { |
||
436 | $placerec = Functions::getSubRecord(2, '2 PLAC', $event->gedcom()); |
||
437 | if ($placerec !== '') { |
||
438 | if (preg_match_all('/\n3 (?:_HEB|ROMN) (.+)/', $placerec, $matches)) { |
||
439 | foreach ($matches[1] as $match) { |
||
440 | $wt_place = new Place($match, $tree); |
||
441 | $html .= ' - ' . $wt_place->fullName(); |
||
442 | } |
||
443 | } |
||
444 | $map_lati = ''; |
||
445 | $cts = preg_match('/\d LATI (.*)/', $placerec, $match); |
||
446 | if ($cts > 0) { |
||
447 | $map_lati = $match[1]; |
||
448 | $html .= '<br><span class="label">' . I18N::translate('Latitude') . ': </span>' . $map_lati; |
||
449 | } |
||
450 | $map_long = ''; |
||
451 | $cts = preg_match('/\d LONG (.*)/', $placerec, $match); |
||
452 | if ($cts > 0) { |
||
453 | $map_long = $match[1]; |
||
454 | $html .= ' <span class="label">' . I18N::translate('Longitude') . ': </span>' . $map_long; |
||
455 | } |
||
456 | if ($map_lati && $map_long) { |
||
457 | $map_lati = trim(strtr($map_lati, 'NSEW,�', ' - -. ')); // S5,6789 ==> -5.6789 |
||
458 | $map_long = trim(strtr($map_long, 'NSEW,�', ' - -. ')); // E3.456� ==> 3.456 |
||
459 | |||
460 | $html .= '<a href="https://maps.google.com/maps?q=' . e($map_lati) . ',' . e($map_long) . '" rel="nofollow" target="_top" title="' . I18N::translate('Google Mapsâ„¢') . '">' . |
||
461 | view('icons/google-maps') . |
||
462 | '<span class="sr-only">' . I18N::translate('Google Mapsâ„¢') . '</span>' . |
||
463 | '</a>'; |
||
464 | |||
465 | $html .= '<a href="https://www.bing.com/maps/?lvl=15&cp=' . e($map_lati) . '~' . e($map_long) . '" rel="nofollow" target="_top" title="' . I18N::translate('Bing Mapsâ„¢') . '">' . |
||
466 | view('icons/bing-maps') . |
||
467 | '<span class="sr-only">' . I18N::translate('Bing Mapsâ„¢') . '</span>' . |
||
468 | '</a>'; |
||
469 | |||
470 | $html .= '<a href="https://www.openstreetmap.org/#map=15/' . e($map_lati) . '/' . e($map_long) . '" rel="nofollow" target="_top" title="' . I18N::translate('OpenStreetMapâ„¢') . '">' . |
||
471 | view('icons/openstreetmap') . |
||
472 | '<span class="sr-only">' . I18N::translate('OpenStreetMapâ„¢') . '</span>' . |
||
473 | '</a>'; |
||
474 | } |
||
475 | if (preg_match('/\d NOTE (.*)/', $placerec, $match)) { |
||
476 | $html .= '<br>' . self::printFactNotes($tree, $placerec, 3); |
||
477 | } |
||
478 | } |
||
479 | } |
||
480 | if ($lds) { |
||
481 | if (preg_match('/2 TEMP (.*)/', $event->gedcom(), $match)) { |
||
482 | $element = Registry::elementFactory()->make($event->tag() . ':TEMP'); |
||
483 | $html .= $element->labelValue($match[1], $tree); |
||
484 | } |
||
485 | if (preg_match('/2 STAT (.*)/', $event->gedcom(), $match)) { |
||
486 | $element = Registry::elementFactory()->make($event->tag() . ':STAT'); |
||
487 | $html .= $element->labelValue($match[1], $tree); |
||
488 | if (preg_match('/3 DATE (.*)/', $event->gedcom(), $match)) { |
||
489 | $date = new Date($match[1]); |
||
490 | $element = Registry::elementFactory()->make($event->tag() . ':STAT:DATE'); |
||
491 | $html .= $element->labelValue($date->display(), $tree); |
||
492 | } |
||
493 | } |
||
494 | } |
||
495 | |||
496 | return $html; |
||
497 | } |
||
498 | |||
499 | /** |
||
500 | * Check for facts that may exist only once for a certain record type. |
||
501 | * If the fact already exists in the second array, delete it from the first one. |
||
502 | * |
||
503 | * @param array<string> $uniquefacts |
||
504 | * @param Collection<Fact> $recfacts |
||
505 | * |
||
506 | * @return array<string> |
||
507 | */ |
||
508 | public static function checkFactUnique(array $uniquefacts, Collection $recfacts): array |
||
509 | { |
||
510 | foreach ($recfacts as $factarray) { |
||
511 | $fact = $factarray->getTag(); |
||
512 | |||
513 | $key = array_search($fact, $uniquefacts, true); |
||
514 | if ($key !== false) { |
||
515 | unset($uniquefacts[$key]); |
||
516 | } |
||
517 | } |
||
518 | |||
519 | return $uniquefacts; |
||
520 | } |
||
521 | |||
522 | /** |
||
523 | * Print a new fact box on details pages |
||
524 | * |
||
525 | * @param GedcomRecord $record the person, family, source etc the fact will be added to |
||
526 | * @param Collection<Fact> $usedfacts an array of facts already used in this record |
||
527 | * @param string $type the type of record INDI, FAM, SOUR etc |
||
528 | * |
||
529 | * @return void |
||
530 | */ |
||
531 | public static function printAddNewFact(GedcomRecord $record, Collection $usedfacts, string $type): void |
||
532 | { |
||
533 | $tree = $record->tree(); |
||
534 | |||
535 | // -- Add from pick list |
||
536 | switch ($type) { |
||
537 | case Individual::RECORD_TYPE: |
||
538 | $addfacts = preg_split('/[, ;:]+/', $tree->getPreference('INDI_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); |
||
539 | $uniquefacts = preg_split('/[, ;:]+/', $tree->getPreference('INDI_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); |
||
540 | $quickfacts = preg_split('/[, ;:]+/', $tree->getPreference('INDI_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); |
||
541 | break; |
||
542 | |||
543 | case Family::RECORD_TYPE: |
||
544 | $addfacts = preg_split('/[, ;:]+/', $tree->getPreference('FAM_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); |
||
545 | $uniquefacts = preg_split('/[, ;:]+/', $tree->getPreference('FAM_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); |
||
546 | $quickfacts = preg_split('/[, ;:]+/', $tree->getPreference('FAM_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); |
||
547 | break; |
||
548 | |||
549 | case Source::RECORD_TYPE: |
||
550 | $addfacts = preg_split('/[, ;:]+/', $tree->getPreference('SOUR_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); |
||
551 | $uniquefacts = preg_split('/[, ;:]+/', $tree->getPreference('SOUR_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); |
||
552 | $quickfacts = preg_split('/[, ;:]+/', $tree->getPreference('SOUR_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); |
||
553 | break; |
||
554 | |||
555 | case Note::RECORD_TYPE: |
||
556 | $addfacts = preg_split('/[, ;:]+/', $tree->getPreference('NOTE_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); |
||
557 | $uniquefacts = preg_split('/[, ;:]+/', $tree->getPreference('NOTE_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); |
||
558 | $quickfacts = preg_split('/[, ;:]+/', $tree->getPreference('NOTE_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); |
||
559 | break; |
||
560 | |||
561 | case Repository::RECORD_TYPE: |
||
562 | $addfacts = preg_split('/[, ;:]+/', $tree->getPreference('REPO_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); |
||
563 | $uniquefacts = preg_split('/[, ;:]+/', $tree->getPreference('REPO_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); |
||
564 | $quickfacts = preg_split('/[, ;:]+/', $tree->getPreference('REPO_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); |
||
565 | break; |
||
566 | |||
567 | case Media::RECORD_TYPE: |
||
568 | $addfacts = ['NOTE']; |
||
569 | $uniquefacts = []; |
||
570 | $quickfacts = []; |
||
571 | break; |
||
572 | default: |
||
573 | return; |
||
574 | } |
||
575 | $addfacts = array_merge(self::checkFactUnique($uniquefacts, $usedfacts), $addfacts); |
||
576 | $quickfacts = array_intersect($quickfacts, $addfacts); |
||
577 | $translated_addfacts = []; |
||
578 | foreach ($addfacts as $addfact) { |
||
579 | $translated_addfacts[$addfact] = GedcomTag::getLabel($record->tag() . ':' . $addfact); |
||
580 | } |
||
581 | uasort($translated_addfacts, static function (string $x, string $y): int { |
||
582 | return I18N::strcasecmp(I18N::translate($x), I18N::translate($y)); |
||
583 | }); |
||
584 | |||
585 | echo view('edit/add-fact-row', [ |
||
586 | 'add_facts' => $translated_addfacts, |
||
587 | 'quick_facts' => $quickfacts, |
||
588 | 'record' => $record, |
||
589 | 'tree' => $tree, |
||
590 | ]); |
||
591 | } |
||
592 | } |
||
593 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.