1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees; 19 20use Exception; 21use stdClass; 22 23/** 24 * Class Location 25 * 26 * @package Fisharebest\Webtrees 27 */ 28class Location 29{ 30 31 /** 32 * @var stdClass $record 33 */ 34 protected $record; 35 36 /** 37 * Location constructor. 38 * 39 * @param string $gedcomName 40 * @param array $record 41 * 42 * @throws Exception 43 */ 44 public function __construct($gedcomName, $record = []) 45 { 46 $tmp = $this->getRecordFromName($gedcomName); 47 if ($tmp !== null) { 48 $this->record = $tmp; 49 } elseif (!empty($record)) { 50 $this->record = (object) $record; 51 } else { 52 $this->record = (object) [ 53 'fqpn' => '', 54 'pl_id' => 0, 55 'pl_parent_id' => 0, 56 'pl_level' => null, 57 'pl_place' => '', 58 'pl_long' => null, 59 'pl_lati' => null, 60 'pl_zoom' => null, 61 'pl_icon' => null, 62 ]; 63 } 64 } 65 66 /** 67 * @return bool 68 */ 69 public function knownLatLon(): bool 70 { 71 return ($this->record->pl_lati && $this->record->pl_long); 72 } 73 74 /** 75 * @param string $format 76 * 77 * @return string|float 78 */ 79 public function getLat($format = 'signed') 80 { 81 switch ($format) { 82 case 'signed': 83 return $this->record->pl_lati ? 84 (float) strtr($this->record->pl_lati, [ 85 'N' => '', 86 'S' => '-', 87 ',' => '.', 88 ]) : $this->record->pl_lati; 89 default: 90 return $this->record->pl_lati; 91 } 92 } 93 94 /** 95 * @param string $format 96 * 97 * @return string|float 98 */ 99 public function getLon($format = 'signed') 100 { 101 switch ($format) { 102 case 'signed': 103 return $this->record->pl_long ? 104 (float) strtr($this->record->pl_long, [ 105 'E' => '', 106 'W' => '-', 107 ',' => '.', 108 ]) : $this->record->pl_long; 109 default: 110 return $this->record->pl_long; 111 } 112 } 113 114 /** 115 * @return array 116 */ 117 public function getLatLonJSArray(): array 118 { 119 return [ 120 $this->getLat('signed'), 121 $this->getLon('signed'), 122 ]; 123 } 124 125 /** 126 * GeoJSON requires the parameters to be in the order longitude, latitude 127 * 128 * @return array 129 */ 130 public function getGeoJsonCoords(): array 131 { 132 return [ 133 $this->getLon('signed'), 134 $this->getLat('signed'), 135 ]; 136 } 137 138 /** 139 * @return string 140 */ 141 public function getId(): string 142 { 143 return $this->record->pl_id; 144 } 145 146 /** 147 * @return string 148 */ 149 public function getLevel(): string 150 { 151 return $this->record->pl_level; 152 } 153 154 /** 155 * @return bool 156 */ 157 public function isValid(): bool 158 { 159 return $this->record->pl_id !== 0; 160 } 161 162 /** 163 * @return string 164 */ 165 public function getPlace(): string 166 { 167 return $this->record->pl_place; 168 } 169 170 /** 171 * @return string|null 172 */ 173 public function getZoom() 174 { 175 return $this->record->pl_zoom; 176 } 177 178 /** 179 * @return string|null 180 */ 181 public function getIcon() 182 { 183 return $this->record->pl_icon; 184 } 185 186 /** 187 * @return stdClass 188 */ 189 public function getRecord(): stdClass 190 { 191 return $this->record; 192 } 193 194 /** 195 * @return int 196 * @throws Exception 197 */ 198 public function add() 199 { 200 $this->record->pl_id = Database::prepare("SELECT IFNULL(MAX(pl_id)+1, 1) FROM `##placelocation`") 201 ->execute() 202 ->fetchOne(); 203 204 Database::prepare( 205 "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES(:id, :parent_id, :level, :place, :long, :lati, :zoom, :icon)" 206 )->execute( 207 [ 208 'id' => $this->record->pl_id, 209 'parent_id' => $this->record->pl_parent_id, 210 'level' => $this->record->pl_level, 211 'place' => $this->record->pl_place, 212 'long' => $this->record->pl_long ?? null, 213 'lati' => $this->record->pl_lati ?? null, 214 'zoom' => $this->record->pl_zoom ?? null, 215 'icon' => $this->record->pl_icon ?? null, 216 ] 217 ); 218 219 return $this->record->pl_id; 220 } 221 222 /** 223 * @param stdClass $new_data 224 * 225 * @throws Exception 226 */ 227 public function update(stdClass $new_data) 228 { 229 Database::prepare( 230 "UPDATE `##placelocation` SET pl_lati=:lati, pl_long=:long, pl_zoom=:zoom, pl_icon=:icon WHERE pl_id=:id" 231 ) 232 ->execute([ 233 'lati' => $new_data->pl_lati ?? $this->record->pl_lati, 234 'long' => $new_data->pl_long ?? $this->record->pl_long, 235 'zoom' => $new_data->pl_zoom ?? $this->record->pl_zoom, 236 'icon' => $new_data->pl_icon ?? $this->record->pl_icon, 237 'id' => $this->record->pl_id, 238 ]); 239 } 240 241 /** 242 * @param string $gedcomName 243 * 244 * @return null|stdClass 245 * @throws Exception 246 */ 247 private function getRecordFromName($gedcomName) 248 { 249 250 return Database::prepare( 251 " 252 SELECT 253 CONCAT_WS(:separator, t1.pl_place, t2.pl_place, t3.pl_place, t4.pl_place, t5.pl_place, t6.pl_place, t7.pl_place, t8.pl_place) AS fqpn, 254 t1.pl_level, t1.pl_place, t1.pl_id, t1.pl_parent_id, t1.pl_lati, t1.pl_long, t1.pl_zoom, t1.pl_icon 255 FROM `##placelocation` AS t1 256 LEFT JOIN `##placelocation` AS t2 ON t1.pl_parent_id = t2.pl_id 257 LEFT JOIN `##placelocation` AS t3 ON t2.pl_parent_id = t3.pl_id 258 LEFT JOIN `##placelocation` AS t4 ON t3.pl_parent_id = t4.pl_id 259 LEFT JOIN `##placelocation` AS t5 ON t4.pl_parent_id = t5.pl_id 260 LEFT JOIN `##placelocation` AS t6 ON t5.pl_parent_id = t6.pl_id 261 LEFT JOIN `##placelocation` AS t7 ON t6.pl_parent_id = t7.pl_id 262 LEFT JOIN `##placelocation` AS t8 ON t7.pl_parent_id = t8.pl_id 263 HAVING fqpn=:gedcomName; 264 " 265 ) 266 ->execute( 267 [ 268 'separator' => Place::GEDCOM_SEPARATOR, 269 'gedcomName' => $gedcomName, 270 ] 271 ) 272 ->fetchOneRow(); 273 } 274} 275