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 ]) : 89 $this->record->pl_lati; 90 default: 91 return $this->record->pl_lati; 92 } 93 } 94 95 /** 96 * @param string $format 97 * 98 * @return string|float 99 */ 100 public function getLon($format = 'signed') 101 { 102 switch ($format) { 103 case 'signed': 104 return $this->record->pl_long ? 105 (float)strtr($this->record->pl_long, [ 106 'E' => '', 107 'W' => '-', 108 ',' => '.', 109 ]) : 110 $this->record->pl_long; 111 default: 112 return $this->record->pl_long; 113 } 114 } 115 116 /** 117 * @return array 118 */ 119 public function getLatLonJSArray(): array 120 { 121 return [ 122 $this->getLat('signed'), 123 $this->getLon('signed'), 124 ]; 125 } 126 127 /** 128 * GeoJSON requires the parameters to be in the order longitude, latitude 129 * 130 * @return array 131 */ 132 public function getGeoJsonCoords(): array 133 { 134 return [ 135 $this->getLon('signed'), 136 $this->getLat('signed'), 137 ]; 138 } 139 140 /** 141 * @return string 142 */ 143 public function getId(): string 144 { 145 return $this->record->pl_id; 146 } 147 148 /** 149 * @return string 150 */ 151 public function getLevel(): string 152 { 153 return $this->record->pl_level; 154 } 155 156 /** 157 * @return bool 158 */ 159 public function isValid(): bool 160 { 161 return $this->record->pl_id !== 0; 162 } 163 164 /** 165 * @return string 166 */ 167 public function getPlace(): string 168 { 169 return $this->record->pl_place; 170 } 171 172 /** 173 * @return string|null 174 */ 175 public function getZoom() 176 { 177 return $this->record->pl_zoom; 178 } 179 180 /** 181 * @return string|null 182 */ 183 public function getIcon() 184 { 185 return $this->record->pl_icon; 186 } 187 188 /** 189 * @return stdClass 190 */ 191 public function getRecord(): stdClass 192 { 193 return $this->record; 194 } 195 196 /** 197 * @throws Exception 198 */ 199 public function add() 200 { 201 $this->record->pl_id = Database::prepare("SELECT IFNULL(MAX(pl_id)+1, 1) FROM `##placelocation`") 202 ->execute() 203 ->fetchOne(); 204 205 Database::prepare( 206 "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)" 207 )->execute( 208 [ 209 'id' => $this->record->pl_id, 210 'parent_id' => $this->record->pl_parent_id, 211 'level' => $this->record->pl_level, 212 'place' => $this->record->pl_place, 213 'long' => $this->record->pl_long ?? null, 214 'lati' => $this->record->pl_lati ?? null, 215 'zoom' => $this->record->pl_zoom ?? null, 216 'icon' => $this->record->pl_icon ?? null, 217 ] 218 ); 219 220 return $this->record->pl_id; 221 } 222 223 /** 224 * @param stdClass $new_data 225 * 226 * @throws Exception 227 */ 228 public function update(stdClass $new_data) 229 { 230 Database::prepare( 231 "UPDATE `##placelocation` SET pl_lati=:lati, pl_long=:long, pl_zoom=:zoom, pl_icon=:icon WHERE pl_id=:id" 232 ) 233 ->execute([ 234 'lati' => $new_data->pl_lati ?? $this->record->pl_lati, 235 'long' => $new_data->pl_long ?? $this->record->pl_long, 236 'zoom' => $new_data->pl_zoom ?? $this->record->pl_zoom, 237 'icon' => $new_data->pl_icon ?? $this->record->pl_icon, 238 'id' => $this->record->pl_id, 239 ]); 240 } 241 242 /** 243 * @param string $gedcomName 244 * 245 * @return null|stdClass 246 * @throws Exception 247 */ 248 private function getRecordFromName($gedcomName) 249 { 250 251 return Database::prepare( 252 " 253 SELECT 254 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, 255 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 256 FROM `##placelocation` AS t1 257 LEFT JOIN `##placelocation` AS t2 ON t1.pl_parent_id = t2.pl_id 258 LEFT JOIN `##placelocation` AS t3 ON t2.pl_parent_id = t3.pl_id 259 LEFT JOIN `##placelocation` AS t4 ON t3.pl_parent_id = t4.pl_id 260 LEFT JOIN `##placelocation` AS t5 ON t4.pl_parent_id = t5.pl_id 261 LEFT JOIN `##placelocation` AS t6 ON t5.pl_parent_id = t6.pl_id 262 LEFT JOIN `##placelocation` AS t7 ON t6.pl_parent_id = t7.pl_id 263 LEFT JOIN `##placelocation` AS t8 ON t7.pl_parent_id = t8.pl_id 264 HAVING fqpn=:gedcomName; 265 " 266 ) 267 ->execute( 268 [ 269 'separator' => Place::GEDCOM_SEPARATOR, 270 'gedcomName' => $gedcomName, 271 ] 272 ) 273 ->fetchOneRow(); 274 } 275} 276