17c7d1e03SGreg Roach<?php 27c7d1e03SGreg Roach 37c7d1e03SGreg Roach/** 47c7d1e03SGreg Roach * webtrees: online genealogy 589f7189bSGreg Roach * Copyright (C) 2021 webtrees development team 67c7d1e03SGreg Roach * This program is free software: you can redistribute it and/or modify 77c7d1e03SGreg Roach * it under the terms of the GNU General Public License as published by 87c7d1e03SGreg Roach * the Free Software Foundation, either version 3 of the License, or 97c7d1e03SGreg Roach * (at your option) any later version. 107c7d1e03SGreg Roach * This program is distributed in the hope that it will be useful, 117c7d1e03SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 127c7d1e03SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 137c7d1e03SGreg Roach * GNU General Public License for more details. 147c7d1e03SGreg Roach * 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/>. 167c7d1e03SGreg Roach */ 177c7d1e03SGreg Roach 187c7d1e03SGreg Roachdeclare(strict_types=1); 197c7d1e03SGreg Roach 207c7d1e03SGreg Roachnamespace Fisharebest\Webtrees\Services; 217c7d1e03SGreg Roach 22*e22e42f7SGreg Roachuse Fisharebest\Webtrees\Fact; 237c7d1e03SGreg Roachuse Fisharebest\Webtrees\Gedcom; 24c2ed51d1SGreg Roachuse Fisharebest\Webtrees\Registry; 257c7d1e03SGreg Roachuse Fisharebest\Webtrees\Tree; 267c7d1e03SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 277c7d1e03SGreg Roach 287c7d1e03SGreg Roachuse function array_merge; 297c7d1e03SGreg Roachuse function array_unique; 307c7d1e03SGreg Roachuse function assert; 317c7d1e03SGreg Roachuse function count; 327c7d1e03SGreg Roachuse function preg_match_all; 337c7d1e03SGreg Roachuse function str_replace; 347c7d1e03SGreg Roachuse function trim; 357c7d1e03SGreg Roach 367c7d1e03SGreg Roach/** 377c7d1e03SGreg Roach * Utilities to edit/save GEDCOM data. 387c7d1e03SGreg Roach */ 397c7d1e03SGreg Roachclass GedcomEditService 407c7d1e03SGreg Roach{ 417c7d1e03SGreg Roach /** @var string[] */ 427c7d1e03SGreg Roach public $glevels = []; 437c7d1e03SGreg Roach 447c7d1e03SGreg Roach /** @var string[] */ 457c7d1e03SGreg Roach public $tag = []; 467c7d1e03SGreg Roach 477c7d1e03SGreg Roach /** @var string[] */ 487c7d1e03SGreg Roach public $islink = []; 497c7d1e03SGreg Roach 507c7d1e03SGreg Roach /** @var string[] */ 517c7d1e03SGreg Roach public $text = []; 527c7d1e03SGreg Roach 537c7d1e03SGreg Roach /** @var string[] */ 547c7d1e03SGreg Roach protected $glevelsSOUR = []; 557c7d1e03SGreg Roach 567c7d1e03SGreg Roach /** @var string[] */ 577c7d1e03SGreg Roach protected $tagSOUR = []; 587c7d1e03SGreg Roach 597c7d1e03SGreg Roach /** @var string[] */ 607c7d1e03SGreg Roach protected $islinkSOUR = []; 617c7d1e03SGreg Roach 627c7d1e03SGreg Roach /** @var string[] */ 637c7d1e03SGreg Roach protected $textSOUR = []; 647c7d1e03SGreg Roach 657c7d1e03SGreg Roach /** @var string[] */ 667c7d1e03SGreg Roach protected $glevelsRest = []; 677c7d1e03SGreg Roach 687c7d1e03SGreg Roach /** @var string[] */ 697c7d1e03SGreg Roach protected $tagRest = []; 707c7d1e03SGreg Roach 717c7d1e03SGreg Roach /** @var string[] */ 727c7d1e03SGreg Roach protected $islinkRest = []; 737c7d1e03SGreg Roach 747c7d1e03SGreg Roach /** @var string[] */ 757c7d1e03SGreg Roach protected $textRest = []; 767c7d1e03SGreg Roach 777c7d1e03SGreg Roach /** 787c7d1e03SGreg Roach * This function splits the $glevels, $tag, $islink, and $text arrays so that the 797c7d1e03SGreg Roach * entries associated with a SOUR record are separate from everything else. 807c7d1e03SGreg Roach * 817c7d1e03SGreg Roach * Input arrays: 827c7d1e03SGreg Roach * - $glevels[] - an array of the gedcom level for each line that was edited 837c7d1e03SGreg Roach * - $tag[] - an array of the tags for each gedcom line that was edited 847c7d1e03SGreg Roach * - $islink[] - an array of 1 or 0 values to indicate when the text is a link element 857c7d1e03SGreg Roach * - $text[] - an array of the text data for each line 867c7d1e03SGreg Roach * 877c7d1e03SGreg Roach * Output arrays: 887c7d1e03SGreg Roach * ** For the SOUR record: 897c7d1e03SGreg Roach * - $glevelsSOUR[] - an array of the gedcom level for each line that was edited 907c7d1e03SGreg Roach * - $tagSOUR[] - an array of the tags for each gedcom line that was edited 917c7d1e03SGreg Roach * - $islinkSOUR[] - an array of 1 or 0 values to indicate when the text is a link element 927c7d1e03SGreg Roach * - $textSOUR[] - an array of the text data for each line 937c7d1e03SGreg Roach * ** For the remaining records: 947c7d1e03SGreg Roach * - $glevelsRest[] - an array of the gedcom level for each line that was edited 957c7d1e03SGreg Roach * - $tagRest[] - an array of the tags for each gedcom line that was edited 967c7d1e03SGreg Roach * - $islinkRest[] - an array of 1 or 0 values to indicate when the text is a link element 977c7d1e03SGreg Roach * - $textRest[] - an array of the text data for each line 987c7d1e03SGreg Roach * 997c7d1e03SGreg Roach * @return void 1007c7d1e03SGreg Roach */ 1017c7d1e03SGreg Roach public function splitSource(): void 1027c7d1e03SGreg Roach { 1037c7d1e03SGreg Roach $this->glevelsSOUR = []; 1047c7d1e03SGreg Roach $this->tagSOUR = []; 1057c7d1e03SGreg Roach $this->islinkSOUR = []; 1067c7d1e03SGreg Roach $this->textSOUR = []; 1077c7d1e03SGreg Roach 1087c7d1e03SGreg Roach $this->glevelsRest = []; 1097c7d1e03SGreg Roach $this->tagRest = []; 1107c7d1e03SGreg Roach $this->islinkRest = []; 1117c7d1e03SGreg Roach $this->textRest = []; 1127c7d1e03SGreg Roach 1137c7d1e03SGreg Roach $inSOUR = false; 1147c7d1e03SGreg Roach $levelSOUR = 0; 1157c7d1e03SGreg Roach 1167c7d1e03SGreg Roach // Assume all arrays are the same size. 1177c7d1e03SGreg Roach $count = count($this->glevels); 1187c7d1e03SGreg Roach 1197c7d1e03SGreg Roach for ($i = 0; $i < $count; $i++) { 1207c7d1e03SGreg Roach if ($inSOUR) { 1217c7d1e03SGreg Roach if ($levelSOUR < $this->glevels[$i]) { 1227c7d1e03SGreg Roach $dest = 'S'; 1237c7d1e03SGreg Roach } else { 1247c7d1e03SGreg Roach $inSOUR = false; 1257c7d1e03SGreg Roach $dest = 'R'; 1267c7d1e03SGreg Roach } 1277c7d1e03SGreg Roach } elseif ($this->tag[$i] === 'SOUR') { 1287c7d1e03SGreg Roach $inSOUR = true; 1297c7d1e03SGreg Roach $levelSOUR = $this->glevels[$i]; 1307c7d1e03SGreg Roach $dest = 'S'; 1317c7d1e03SGreg Roach } else { 1327c7d1e03SGreg Roach $dest = 'R'; 1337c7d1e03SGreg Roach } 1347c7d1e03SGreg Roach 1357c7d1e03SGreg Roach if ($dest === 'S') { 1367c7d1e03SGreg Roach $this->glevelsSOUR[] = $this->glevels[$i]; 1377c7d1e03SGreg Roach $this->tagSOUR[] = $this->tag[$i]; 1387c7d1e03SGreg Roach $this->islinkSOUR[] = $this->islink[$i]; 1397c7d1e03SGreg Roach $this->textSOUR[] = $this->text[$i]; 1407c7d1e03SGreg Roach } else { 1417c7d1e03SGreg Roach $this->glevelsRest[] = $this->glevels[$i]; 1427c7d1e03SGreg Roach $this->tagRest[] = $this->tag[$i]; 1437c7d1e03SGreg Roach $this->islinkRest[] = $this->islink[$i]; 1447c7d1e03SGreg Roach $this->textRest[] = $this->text[$i]; 1457c7d1e03SGreg Roach } 1467c7d1e03SGreg Roach } 1477c7d1e03SGreg Roach } 1487c7d1e03SGreg Roach 1497c7d1e03SGreg Roach /** 1507c7d1e03SGreg Roach * Add new GEDCOM lines from the $xxxRest interface update arrays, which 1517c7d1e03SGreg Roach * were produced by the splitSOUR() function. 1527c7d1e03SGreg Roach * See the FunctionsEdit::handle_updatesges() function for details. 1537c7d1e03SGreg Roach * 1547c7d1e03SGreg Roach * @param string $inputRec 1557c7d1e03SGreg Roach * 1567c7d1e03SGreg Roach * @return string 1577c7d1e03SGreg Roach */ 1587c7d1e03SGreg Roach public function updateRest(string $inputRec): string 1597c7d1e03SGreg Roach { 1607c7d1e03SGreg Roach if (count($this->tagRest) === 0) { 1617c7d1e03SGreg Roach return $inputRec; // No update required 1627c7d1e03SGreg Roach } 1637c7d1e03SGreg Roach 1647c7d1e03SGreg Roach // Save original interface update arrays before replacing them with the xxxRest ones 1657c7d1e03SGreg Roach $glevelsSave = $this->glevels; 1667c7d1e03SGreg Roach $tagSave = $this->tag; 1677c7d1e03SGreg Roach $islinkSave = $this->islink; 1687c7d1e03SGreg Roach $textSave = $this->text; 1697c7d1e03SGreg Roach 1707c7d1e03SGreg Roach $this->glevels = $this->glevelsRest; 1717c7d1e03SGreg Roach $this->tag = $this->tagRest; 1727c7d1e03SGreg Roach $this->islink = $this->islinkRest; 1737c7d1e03SGreg Roach $this->text = $this->textRest; 1747c7d1e03SGreg Roach 1757c7d1e03SGreg Roach $myRecord = $this->handleUpdates($inputRec, 'no'); // Now do the update 1767c7d1e03SGreg Roach 1777c7d1e03SGreg Roach // Restore the original interface update arrays (just in case ...) 1787c7d1e03SGreg Roach $this->glevels = $glevelsSave; 1797c7d1e03SGreg Roach $this->tag = $tagSave; 1807c7d1e03SGreg Roach $this->islink = $islinkSave; 1817c7d1e03SGreg Roach $this->text = $textSave; 1827c7d1e03SGreg Roach 1837c7d1e03SGreg Roach return $myRecord; 1847c7d1e03SGreg Roach } 1857c7d1e03SGreg Roach 1867c7d1e03SGreg Roach /** 1877c7d1e03SGreg Roach * Add new gedcom lines from interface update arrays 1887c7d1e03SGreg Roach * The edit_interface and FunctionsEdit::add_simple_tag function produce the following 1897c7d1e03SGreg Roach * arrays incoming from the $_POST form 1907c7d1e03SGreg Roach * - $glevels[] - an array of the gedcom level for each line that was edited 1917c7d1e03SGreg Roach * - $tag[] - an array of the tags for each gedcom line that was edited 1927c7d1e03SGreg Roach * - $islink[] - an array of 1 or 0 values to tell whether the text is a link element and should be surrounded by @@ 1937c7d1e03SGreg Roach * - $text[] - an array of the text data for each line 1947c7d1e03SGreg Roach * With these arrays you can recreate the gedcom lines like this 1957c7d1e03SGreg Roach * <code>$glevel[0].' '.$tag[0].' '.$text[0]</code> 1967c7d1e03SGreg Roach * There will be an index in each of these arrays for each line of the gedcom 1977c7d1e03SGreg Roach * fact that is being edited. 1987c7d1e03SGreg Roach * If the $text[] array is empty for the given line, then it means that the 1997c7d1e03SGreg Roach * user removed that line during editing or that the line is supposed to be 2007c7d1e03SGreg Roach * empty (1 DEAT, 1 BIRT) for example. To know if the line should be removed 2017c7d1e03SGreg Roach * there is a section of code that looks ahead to the next lines to see if there 2027c7d1e03SGreg Roach * are sub lines. For example we don't want to remove the 1 DEAT line if it has 2037c7d1e03SGreg Roach * a 2 PLAC or 2 DATE line following it. If there are no sub lines, then the line 2047c7d1e03SGreg Roach * can be safely removed. 2057c7d1e03SGreg Roach * 2067c7d1e03SGreg Roach * @param string $newged the new gedcom record to add the lines to 2077c7d1e03SGreg Roach * @param string $levelOverride Override GEDCOM level specified in $glevels[0] 2087c7d1e03SGreg Roach * 2097c7d1e03SGreg Roach * @return string The updated gedcom record 2107c7d1e03SGreg Roach */ 211c8183f29SGreg Roach public function handleUpdates(string $newged, string $levelOverride = 'no'): string 2127c7d1e03SGreg Roach { 2137c7d1e03SGreg Roach if ($levelOverride === 'no') { 2147c7d1e03SGreg Roach $levelAdjust = 0; 2157c7d1e03SGreg Roach } else { 2167c7d1e03SGreg Roach $levelAdjust = 1; 2177c7d1e03SGreg Roach } 2187c7d1e03SGreg Roach 2197c7d1e03SGreg Roach // Assert all arrays are the same size. 2207c7d1e03SGreg Roach assert(count($this->glevels) === count($this->tag)); 2217c7d1e03SGreg Roach assert(count($this->glevels) === count($this->text)); 2227c7d1e03SGreg Roach assert(count($this->glevels) === count($this->islink)); 2237c7d1e03SGreg Roach 2247c7d1e03SGreg Roach $count = count($this->glevels); 2257c7d1e03SGreg Roach 2267c7d1e03SGreg Roach for ($j = 0; $j < $count; $j++) { 2277c7d1e03SGreg Roach // Look for empty SOUR reference with non-empty sub-records. 2287c7d1e03SGreg Roach // This can happen when the SOUR entry is deleted but its sub-records 2297c7d1e03SGreg Roach // were incorrectly left intact. 2307c7d1e03SGreg Roach // The sub-records should be deleted. 2317c7d1e03SGreg Roach if ($this->tag[$j] === 'SOUR' && ($this->text[$j] === '@@' || $this->text[$j] === '')) { 2327c7d1e03SGreg Roach $this->text[$j] = ''; 2337c7d1e03SGreg Roach $k = $j + 1; 2347c7d1e03SGreg Roach while ($k < $count && $this->glevels[$k] > $this->glevels[$j]) { 2357c7d1e03SGreg Roach $this->text[$k] = ''; 2367c7d1e03SGreg Roach $k++; 2377c7d1e03SGreg Roach } 2387c7d1e03SGreg Roach } 2397c7d1e03SGreg Roach 2407c7d1e03SGreg Roach if (trim($this->text[$j]) !== '') { 2417c7d1e03SGreg Roach $pass = true; 2427c7d1e03SGreg Roach } else { 2437c7d1e03SGreg Roach //-- for facts with empty values they must have sub records 2447c7d1e03SGreg Roach //-- this section checks if they have subrecords 2457c7d1e03SGreg Roach $k = $j + 1; 2467c7d1e03SGreg Roach $pass = false; 2477c7d1e03SGreg Roach while ($k < $count && $this->glevels[$k] > $this->glevels[$j]) { 2487c7d1e03SGreg Roach if ($this->text[$k] !== '') { 249c2ed51d1SGreg Roach if ($this->tag[$j] !== 'OBJE' || $this->tag[$k] === 'FILE') { 2507c7d1e03SGreg Roach $pass = true; 2517c7d1e03SGreg Roach break; 2527c7d1e03SGreg Roach } 2537c7d1e03SGreg Roach } 2547c7d1e03SGreg Roach $k++; 2557c7d1e03SGreg Roach } 2567c7d1e03SGreg Roach } 2577c7d1e03SGreg Roach 2587c7d1e03SGreg Roach //-- if the value is not empty or it has sub lines 2597c7d1e03SGreg Roach //--- then write the line to the gedcom record 2607c7d1e03SGreg Roach //-- we have to let some emtpy text lines pass through... (DEAT, BIRT, etc) 2617c7d1e03SGreg Roach if ($pass) { 2627c7d1e03SGreg Roach $newline = (int) $this->glevels[$j] + $levelAdjust . ' ' . $this->tag[$j]; 2637c7d1e03SGreg Roach if ($this->text[$j] !== '') { 2647c7d1e03SGreg Roach if ($this->islink[$j]) { 26565de9aa7SGreg Roach $newline .= ' @' . trim($this->text[$j], '@') . '@'; 2667c7d1e03SGreg Roach } else { 2677c7d1e03SGreg Roach $newline .= ' ' . $this->text[$j]; 2687c7d1e03SGreg Roach } 2697c7d1e03SGreg Roach } 2707c7d1e03SGreg Roach $next_level = 1 + (int) $this->glevels[$j] + $levelAdjust; 2717c7d1e03SGreg Roach 2727c7d1e03SGreg Roach $newged .= "\n" . str_replace("\n", "\n" . $next_level . ' CONT ', $newline); 2737c7d1e03SGreg Roach } 2747c7d1e03SGreg Roach } 2757c7d1e03SGreg Roach 2767c7d1e03SGreg Roach return $newged; 2777c7d1e03SGreg Roach } 2787c7d1e03SGreg Roach 2797c7d1e03SGreg Roach /** 2807c7d1e03SGreg Roach * Create a form to add a new fact. 2817c7d1e03SGreg Roach * 2827c7d1e03SGreg Roach * @param ServerRequestInterface $request 2837c7d1e03SGreg Roach * @param Tree $tree 2847c7d1e03SGreg Roach * @param string $fact 2857c7d1e03SGreg Roach * 2867c7d1e03SGreg Roach * @return string 2877c7d1e03SGreg Roach */ 28824f2a3afSGreg Roach public function addNewFact(ServerRequestInterface $request, Tree $tree, string $fact): string 2897c7d1e03SGreg Roach { 2907c7d1e03SGreg Roach $params = (array) $request->getParsedBody(); 2917c7d1e03SGreg Roach 2927c7d1e03SGreg Roach $FACT = $params[$fact]; 2937c7d1e03SGreg Roach $DATE = $params[$fact . '_DATE'] ?? ''; 2947c7d1e03SGreg Roach $PLAC = $params[$fact . '_PLAC'] ?? ''; 2957c7d1e03SGreg Roach 2967c7d1e03SGreg Roach if ($DATE !== '' || $PLAC !== '' || $FACT !== '' && $FACT !== 'Y') { 2977c7d1e03SGreg Roach if ($FACT !== '' && $FACT !== 'Y') { 2987c7d1e03SGreg Roach $gedrec = "\n1 " . $fact . ' ' . $FACT; 2997c7d1e03SGreg Roach } else { 3007c7d1e03SGreg Roach $gedrec = "\n1 " . $fact; 3017c7d1e03SGreg Roach } 3027c7d1e03SGreg Roach if ($DATE !== '') { 3037c7d1e03SGreg Roach $gedrec .= "\n2 DATE " . $DATE; 3047c7d1e03SGreg Roach } 3057c7d1e03SGreg Roach if ($PLAC !== '') { 3067c7d1e03SGreg Roach $gedrec .= "\n2 PLAC " . $PLAC; 3077c7d1e03SGreg Roach 3087c7d1e03SGreg Roach if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_PLAC_FACTS'), $match)) { 3097c7d1e03SGreg Roach foreach ($match[1] as $tag) { 3107c7d1e03SGreg Roach $TAG = $params[$fact . '_' . $tag]; 3117c7d1e03SGreg Roach if ($TAG !== '') { 3127c7d1e03SGreg Roach $gedrec .= "\n3 " . $tag . ' ' . $TAG; 3137c7d1e03SGreg Roach } 3147c7d1e03SGreg Roach } 3157c7d1e03SGreg Roach } 31650f35038SGreg Roach $LATI = $params[$fact . '_LATI'] ?? ''; 31750f35038SGreg Roach $LONG = $params[$fact . '_LONG'] ?? ''; 3187c7d1e03SGreg Roach if ($LATI !== '' || $LONG !== '') { 3197c7d1e03SGreg Roach $gedrec .= "\n3 MAP\n4 LATI " . $LATI . "\n4 LONG " . $LONG; 3207c7d1e03SGreg Roach } 3217c7d1e03SGreg Roach } 3227c7d1e03SGreg Roach if ((bool) ($params['SOUR_' . $fact] ?? false)) { 3237c7d1e03SGreg Roach return $this->updateSource($gedrec, 'yes'); 3247c7d1e03SGreg Roach } 3257c7d1e03SGreg Roach 3267c7d1e03SGreg Roach return $gedrec; 3277c7d1e03SGreg Roach } 3287c7d1e03SGreg Roach 3297c7d1e03SGreg Roach if ($FACT === 'Y') { 3307c7d1e03SGreg Roach if ((bool) ($params['SOUR_' . $fact] ?? false)) { 3317c7d1e03SGreg Roach return $this->updateSource("\n1 " . $fact . ' Y', 'yes'); 3327c7d1e03SGreg Roach } 3337c7d1e03SGreg Roach 3347c7d1e03SGreg Roach return "\n1 " . $fact . ' Y'; 3357c7d1e03SGreg Roach } 3367c7d1e03SGreg Roach 3377c7d1e03SGreg Roach return ''; 3387c7d1e03SGreg Roach } 3397c7d1e03SGreg Roach 3407c7d1e03SGreg Roach /** 3417c7d1e03SGreg Roach * Add new GEDCOM lines from the $xxxSOUR interface update arrays, which 3427c7d1e03SGreg Roach * were produced by the splitSOUR() function. 3437c7d1e03SGreg Roach * See the FunctionsEdit::handle_updatesges() function for details. 3447c7d1e03SGreg Roach * 3457c7d1e03SGreg Roach * @param string $inputRec 3467c7d1e03SGreg Roach * @param string $levelOverride 3477c7d1e03SGreg Roach * 3487c7d1e03SGreg Roach * @return string 3497c7d1e03SGreg Roach */ 3507c7d1e03SGreg Roach public function updateSource(string $inputRec, string $levelOverride = 'no'): string 3517c7d1e03SGreg Roach { 3527c7d1e03SGreg Roach if (count($this->tagSOUR) === 0) { 3537c7d1e03SGreg Roach return $inputRec; // No update required 3547c7d1e03SGreg Roach } 3557c7d1e03SGreg Roach 3567c7d1e03SGreg Roach // Save original interface update arrays before replacing them with the xxxSOUR ones 3577c7d1e03SGreg Roach $glevelsSave = $this->glevels; 3587c7d1e03SGreg Roach $tagSave = $this->tag; 3597c7d1e03SGreg Roach $islinkSave = $this->islink; 3607c7d1e03SGreg Roach $textSave = $this->text; 3617c7d1e03SGreg Roach 3627c7d1e03SGreg Roach $this->glevels = $this->glevelsSOUR; 3637c7d1e03SGreg Roach $this->tag = $this->tagSOUR; 3647c7d1e03SGreg Roach $this->islink = $this->islinkSOUR; 3657c7d1e03SGreg Roach $this->text = $this->textSOUR; 3667c7d1e03SGreg Roach 3677c7d1e03SGreg Roach $myRecord = $this->handleUpdates($inputRec, $levelOverride); // Now do the update 3687c7d1e03SGreg Roach 3697c7d1e03SGreg Roach // Restore the original interface update arrays (just in case ...) 3707c7d1e03SGreg Roach $this->glevels = $glevelsSave; 3717c7d1e03SGreg Roach $this->tag = $tagSave; 3727c7d1e03SGreg Roach $this->islink = $islinkSave; 3737c7d1e03SGreg Roach $this->text = $textSave; 3747c7d1e03SGreg Roach 3757c7d1e03SGreg Roach return $myRecord; 3767c7d1e03SGreg Roach } 3777c7d1e03SGreg Roach 3787c7d1e03SGreg Roach /** 3797c7d1e03SGreg Roach * Create a form to add a sex record. 3807c7d1e03SGreg Roach * 3817c7d1e03SGreg Roach * @param ServerRequestInterface $request 3827c7d1e03SGreg Roach * 3837c7d1e03SGreg Roach * @return string 3847c7d1e03SGreg Roach */ 3857c7d1e03SGreg Roach public function addNewSex(ServerRequestInterface $request): string 3867c7d1e03SGreg Roach { 3877c7d1e03SGreg Roach $params = (array) $request->getParsedBody(); 3887c7d1e03SGreg Roach 3897c7d1e03SGreg Roach switch ($params['SEX']) { 3907c7d1e03SGreg Roach case 'M': 3917c7d1e03SGreg Roach return "\n1 SEX M"; 3927c7d1e03SGreg Roach case 'F': 3937c7d1e03SGreg Roach return "\n1 SEX F"; 3947c7d1e03SGreg Roach default: 3957c7d1e03SGreg Roach return "\n1 SEX U"; 3967c7d1e03SGreg Roach } 3977c7d1e03SGreg Roach } 3987c7d1e03SGreg Roach 3997c7d1e03SGreg Roach /** 4007c7d1e03SGreg Roach * Assemble the pieces of a newly created record into gedcom 4017c7d1e03SGreg Roach * 4027c7d1e03SGreg Roach * @param ServerRequestInterface $request 4037c7d1e03SGreg Roach * @param Tree $tree 4047c7d1e03SGreg Roach * 4057c7d1e03SGreg Roach * @return string 4067c7d1e03SGreg Roach */ 4077c7d1e03SGreg Roach public function addNewName(ServerRequestInterface $request, Tree $tree): string 4087c7d1e03SGreg Roach { 4097c7d1e03SGreg Roach $params = (array) $request->getParsedBody(); 4107c7d1e03SGreg Roach $gedrec = "\n1 NAME " . $params['NAME']; 4117c7d1e03SGreg Roach 4127c7d1e03SGreg Roach $tags = [ 4137c7d1e03SGreg Roach 'NPFX', 4147c7d1e03SGreg Roach 'GIVN', 4157c7d1e03SGreg Roach 'SPFX', 4167c7d1e03SGreg Roach 'SURN', 4177c7d1e03SGreg Roach 'NSFX', 4187c7d1e03SGreg Roach 'NICK', 4197c7d1e03SGreg Roach ]; 4207c7d1e03SGreg Roach 4217c7d1e03SGreg Roach if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_NAME_FACTS'), $match)) { 4227c7d1e03SGreg Roach $tags = array_merge($tags, $match[1]); 4237c7d1e03SGreg Roach } 4247c7d1e03SGreg Roach 4257c7d1e03SGreg Roach // Paternal and Polish and Lithuanian surname traditions can also create a _MARNM 4267c7d1e03SGreg Roach $SURNAME_TRADITION = $tree->getPreference('SURNAME_TRADITION'); 4277c7d1e03SGreg Roach if ($SURNAME_TRADITION === 'paternal' || $SURNAME_TRADITION === 'polish' || $SURNAME_TRADITION === 'lithuanian') { 4287c7d1e03SGreg Roach $tags[] = '_MARNM'; 4297c7d1e03SGreg Roach } 4307c7d1e03SGreg Roach 4317c7d1e03SGreg Roach foreach (array_unique($tags) as $tag) { 4327c7d1e03SGreg Roach $TAG = $params[$tag]; 4337c7d1e03SGreg Roach 4347c7d1e03SGreg Roach if ($TAG !== '') { 4357c7d1e03SGreg Roach $gedrec .= "\n2 " . $tag . ' ' . $TAG; 4367c7d1e03SGreg Roach } 4377c7d1e03SGreg Roach } 4387c7d1e03SGreg Roach 4397c7d1e03SGreg Roach return $gedrec; 4407c7d1e03SGreg Roach } 441c2ed51d1SGreg Roach 442c2ed51d1SGreg Roach /** 443c2ed51d1SGreg Roach * Reassemble edited GEDCOM fields into a GEDCOM fact/event string. 444c2ed51d1SGreg Roach * 445c2ed51d1SGreg Roach * @param string $record_type 446c2ed51d1SGreg Roach * @param array<string> $levels 447c2ed51d1SGreg Roach * @param array<string> $tags 448c2ed51d1SGreg Roach * @param array<string> $values 449c2ed51d1SGreg Roach * 450c2ed51d1SGreg Roach * @return string 451c2ed51d1SGreg Roach */ 452c2ed51d1SGreg Roach public function editLinesToGedcom(string $record_type, array $levels, array $tags, array $values): string 453c2ed51d1SGreg Roach { 454c2ed51d1SGreg Roach // Assert all arrays are the same size. 455c2ed51d1SGreg Roach $count = count($levels); 456c2ed51d1SGreg Roach assert($count > 0); 457c2ed51d1SGreg Roach assert(count($tags) === $count); 458c2ed51d1SGreg Roach assert(count($values) === $count); 459c2ed51d1SGreg Roach 460c2ed51d1SGreg Roach $gedcom_lines = []; 461c2ed51d1SGreg Roach $hierarchy = [$record_type]; 462c2ed51d1SGreg Roach 463c2ed51d1SGreg Roach for ($i = 0; $i < $count; $i++) { 464c2ed51d1SGreg Roach $hierarchy[$levels[$i]] = $tags[$i]; 465c2ed51d1SGreg Roach 466c2ed51d1SGreg Roach $full_tag = implode(':', array_slice($hierarchy, 0, 1 + (int) $levels[$i])); 467c2ed51d1SGreg Roach $element = Registry::elementFactory()->make($full_tag); 468c2ed51d1SGreg Roach $values[$i] = $element->canonical($values[$i]); 469c2ed51d1SGreg Roach 470c2ed51d1SGreg Roach // If "1 FACT Y" has a DATE or PLAC, then delete the value of Y 471c2ed51d1SGreg Roach if ($levels[$i] === '1' && $values[$i] === 'Y') { 472c2ed51d1SGreg Roach for ($j = $i + 1; $j < $count && $levels[$j] > $levels[$i]; ++$j) { 473c2ed51d1SGreg Roach if ($levels[$j] === '2' && ($tags[$j] === 'DATE' || $tags[$j] === 'PLAC') && $values[$j] !== '') { 474c2ed51d1SGreg Roach $values[$i] = ''; 475c2ed51d1SGreg Roach break; 476c2ed51d1SGreg Roach } 477c2ed51d1SGreg Roach } 478c2ed51d1SGreg Roach } 479c2ed51d1SGreg Roach 480c2ed51d1SGreg Roach // Include this line if there is a value - or if there is a child record with a value. 481c2ed51d1SGreg Roach $include = $values[$i] !== ''; 482c2ed51d1SGreg Roach 483c2ed51d1SGreg Roach for ($j = $i + 1; !$include && $j < $count && $levels[$j] > $levels[$i]; $j++) { 484c2ed51d1SGreg Roach $include = $values[$j] !== ''; 485c2ed51d1SGreg Roach } 486c2ed51d1SGreg Roach 487c2ed51d1SGreg Roach if ($include) { 488c2ed51d1SGreg Roach if ($values[$i] === '') { 489c2ed51d1SGreg Roach $gedcom_lines[] = $levels[$i] . ' ' . $tags[$i]; 490c2ed51d1SGreg Roach } else { 491f7c88e25SGreg Roach if ($tags[$i] === 'CONC') { 492f7c88e25SGreg Roach $next_level = (int) $levels[$i]; 493f7c88e25SGreg Roach } else { 494c2ed51d1SGreg Roach $next_level = 1 + (int) $levels[$i]; 495f7c88e25SGreg Roach } 496c2ed51d1SGreg Roach 497c2ed51d1SGreg Roach $gedcom_lines[] = $levels[$i] . ' ' . $tags[$i] . ' ' . str_replace("\n", "\n" . $next_level . ' CONT ', $values[$i]); 498c2ed51d1SGreg Roach } 499c2ed51d1SGreg Roach } 500c2ed51d1SGreg Roach } 501c2ed51d1SGreg Roach 502c2ed51d1SGreg Roach return implode("\n", $gedcom_lines); 503c2ed51d1SGreg Roach } 504*e22e42f7SGreg Roach 505*e22e42f7SGreg Roach /** 506*e22e42f7SGreg Roach * Add blank lines, to allow a user to add/edit new values. 507*e22e42f7SGreg Roach * 508*e22e42f7SGreg Roach * @param Fact $fact 509*e22e42f7SGreg Roach * @param bool $include_hidden 510*e22e42f7SGreg Roach * 511*e22e42f7SGreg Roach * @return string 512*e22e42f7SGreg Roach */ 513*e22e42f7SGreg Roach public function insertMissingSubtags(Fact $fact, bool $include_hidden): string 514*e22e42f7SGreg Roach { 515*e22e42f7SGreg Roach return $fact->record()->insertMissingLevels($fact->tag(), $fact->gedcom(), $include_hidden); 516*e22e42f7SGreg Roach } 5177c7d1e03SGreg Roach} 518