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 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Statistics\Repository; 21 22use Exception; 23use Fisharebest\Webtrees\Fact; 24use Fisharebest\Webtrees\Header; 25use Fisharebest\Webtrees\Registry; 26use Fisharebest\Webtrees\Statistics\Repository\Interfaces\GedcomRepositoryInterface; 27use Fisharebest\Webtrees\Tree; 28use Illuminate\Database\Capsule\Manager as DB; 29 30use function e; 31use function str_contains; 32use function strpos; 33use function substr; 34 35/** 36 * A repository providing methods for GEDCOM related statistics. 37 */ 38class GedcomRepository implements GedcomRepositoryInterface 39{ 40 private Tree $tree; 41 42 /** 43 * @param Tree $tree 44 */ 45 public function __construct(Tree $tree) 46 { 47 $this->tree = $tree; 48 } 49 50 /** 51 * Get information from the GEDCOM's HEAD record. 52 * 53 * @return array<string> 54 */ 55 private function gedcomHead(): array 56 { 57 $title = ''; 58 $version = ''; 59 $source = ''; 60 61 $head = Registry::headerFactory()->make('HEAD', $this->tree); 62 63 if ($head instanceof Header) { 64 $sour = $head->facts(['SOUR'])->first(); 65 66 if ($sour instanceof Fact) { 67 $source = $sour->value(); 68 $title = $sour->attribute('NAME'); 69 $version = $sour->attribute('VERS'); 70 } 71 } 72 73 return [ 74 $title, 75 $version, 76 $source, 77 ]; 78 } 79 80 /** 81 * @return string 82 */ 83 public function gedcomFilename(): string 84 { 85 return $this->tree->name(); 86 } 87 88 /** 89 * @return int 90 */ 91 public function gedcomId(): int 92 { 93 return $this->tree->id(); 94 } 95 96 /** 97 * @return string 98 */ 99 public function gedcomTitle(): string 100 { 101 return e($this->tree->title()); 102 } 103 104 /** 105 * @return string 106 */ 107 public function gedcomCreatedSoftware(): string 108 { 109 return $this->gedcomHead()[0]; 110 } 111 112 /** 113 * @return string 114 */ 115 public function gedcomCreatedVersion(): string 116 { 117 $head = $this->gedcomHead(); 118 119 // Fix broken version string in Family Tree Maker 120 if (str_contains($head[1], 'Family Tree Maker ')) { 121 $p = strpos($head[1], '(') + 1; 122 $p2 = strpos($head[1], ')'); 123 $head[1] = substr($head[1], $p, $p2 - $p); 124 } 125 126 // Fix EasyTree version 127 if ($head[2] === 'EasyTree') { 128 $head[1] = substr($head[1], 1); 129 } 130 131 return $head[1]; 132 } 133 134 /** 135 * @return string 136 * @throws Exception 137 */ 138 public function gedcomDate(): string 139 { 140 $head = Registry::headerFactory()->make('HEAD', $this->tree); 141 142 if ($head instanceof Header) { 143 $fact = $head->facts(['DATE'])->first(); 144 145 if ($fact instanceof Fact) { 146 return Registry::timestampFactory()->fromString($fact->value(), 'j M Y')->isoFormat('LL'); 147 } 148 } 149 150 return ''; 151 } 152 153 /** 154 * @return string 155 */ 156 public function gedcomUpdated(): string 157 { 158 $row = DB::table('change') 159 ->where('gedcom_id', '=', $this->tree->id()) 160 ->where('status', '=', 'accepted') 161 ->orderBy('change_id', 'DESC') 162 ->select(['change_time']) 163 ->first(); 164 165 if ($row === null) { 166 return $this->gedcomDate(); 167 } 168 169 return Registry::timestampFactory()->fromString($row->change_time)->isoFormat('LL'); 170 } 171 172 /** 173 * @return string 174 */ 175 public function gedcomRootId(): string 176 { 177 return $this->tree->getPreference('PEDIGREE_ROOT_ID'); 178 } 179} 180