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 20class Location { 21 22 /** 23 * @var \stdClass $record 24 */ 25 protected $record; 26 27 /** 28 * Location constructor. 29 * @param string $gedcomName 30 * @param array $record 31 * @throws \Exception 32 */ 33 public function __construct($gedcomName, $record=[]) { 34 $tmp = $this->getRecordFromName($gedcomName); 35 if ($tmp !== null) { 36 $this->record = $tmp; 37 } elseif (!empty($record)) { 38 $this->record = (object)$record; 39 } else { 40 $this->record = (object)[ 41 'fqpn' => '', 42 'pl_id' => 0, 43 'pl_parent_id' => 0, 44 'pl_level' => null, 45 'pl_place' => '', 46 'pl_long' => null, 47 'pl_lati' => null, 48 'pl_zoom' => null, 49 'pl_icon' => null, 50 ]; 51 } 52 } 53 54 /** 55 * @return bool 56 */ 57 public function knownLatLon() { 58 return ($this->record->pl_lati && $this->record->pl_long); 59 } 60 61 /** 62 * @param string $format 63 * 64 * @return string|float 65 */ 66 public function getLat($format = 'signed') { 67 switch ($format) { 68 case 'signed': 69 return $this->record->pl_lati ? 70 (float)strtr($this->record->pl_lati, ['N' => '', 'S' => '-', ',' => '.']) : 71 $this->record->pl_lati; 72 default: 73 return $this->record->pl_lati; 74 } 75 } 76 77 /** 78 * @param string $format 79 * 80 * @return string|float 81 */ 82 public function getLon($format = 'signed') { 83 switch ($format) { 84 case 'signed': 85 return $this->record->pl_long ? 86 (float)strtr($this->record->pl_long, ['E' => '', 'W' => '-', ',' => '.']) : 87 $this->record->pl_long; 88 default: 89 return $this->record->pl_long; 90 } 91 } 92 93 /** 94 * @return array 95 */ 96 public function getLatLonJSArray() { 97 return [$this->getLat('signed'), $this->getLon('signed')]; 98 } 99 100 /** 101 * GeoJSON requires the parameters to be in the order longitude, latitude 102 * 103 * @return array 104 */ 105 public function getGeoJsonCoords() { 106 return [$this->getLon('signed'), $this->getLat('signed')]; 107 } 108 109 /** 110 * @return string 111 */ 112 public function getId() { 113 return $this->record->pl_id; 114 } 115 116 /** 117 * @return string 118 */ 119 public function getLevel() { 120 return $this->record->pl_level; 121 } 122 123 /** 124 * @return bool 125 */ 126 public function isValid() { 127 return $this->record->pl_id !== 0; 128 } 129 130 /** 131 * @return string 132 */ 133 public function getPlace() { 134 return $this->record->pl_place; 135 } 136 137 /** 138 * @return string|null 139 */ 140 public function getZoom() { 141 return $this->record->pl_zoom; 142 } 143 144 /** 145 * @return string|null 146 */ 147 public function getIcon() { 148 return $this->record->pl_icon; 149 } 150 151 /** 152 * @return \stdClass 153 */ 154 public function getRecord() { 155 return $this->record; 156 } 157 158 /** 159 * @throws \Exception 160 */ 161 public function add() { 162 $this->record->pl_id = Database::prepare("SELECT IFNULL(MAX(pl_id)+1, 1) FROM `##placelocation`") 163 ->execute() 164 ->fetchOne(); 165 166 Database::prepare( 167 "INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) 168 VALUES(:id, :parent_id, :level, :place, :long, :lati, :zoom, :icon)" 169 )->execute( 170 [ 171 'id' => $this->record->pl_id, 172 'parent_id' => $this->record->pl_parent_id, 173 'level' => $this->record->pl_level, 174 'place' => $this->record->pl_place, 175 'long' => $this->record->pl_long ?? null, 176 'lati' => $this->record->pl_lati ?? null, 177 'zoom' => $this->record->pl_zoom ?? null, 178 'icon' => $this->record->pl_icon ?? null, 179 ] 180 ); 181 182 return $this->record->pl_id; 183 } 184 185 /** 186 * @param \stdClass $new_data 187 * @throws \Exception 188 */ 189 public function update($new_data) { 190 Database::prepare( 191 "UPDATE `##placelocation` SET pl_lati=:lati, pl_long=:long, pl_zoom=:zoom, pl_icon=:icon WHERE pl_id=:id" 192 ) 193 ->execute([ 194 'lati' => $new_data->pl_lati ?? $this->record->pl_lati, 195 'long' => $new_data->pl_long ?? $this->record->pl_long, 196 'zoom' => $new_data->pl_zoom ?? $this->record->pl_zoom, 197 'icon' => $new_data->pl_icon ?? $this->record->pl_icon, 198 'id' => $this->record->pl_id, 199 ]); 200 } 201 202 /** 203 * @param string $gedcomName 204 * @return null|\stdClass 205 * @throws \Exception 206 */ 207 private function getRecordFromName($gedcomName) { 208 209 return Database::prepare( 210 " 211 SELECT 212 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, 213 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 214 FROM `##placelocation` AS t1 215 LEFT JOIN `##placelocation` AS t2 ON t1.pl_parent_id = t2.pl_id 216 LEFT JOIN `##placelocation` AS t3 ON t2.pl_parent_id = t3.pl_id 217 LEFT JOIN `##placelocation` AS t4 ON t3.pl_parent_id = t4.pl_id 218 LEFT JOIN `##placelocation` AS t5 ON t4.pl_parent_id = t5.pl_id 219 LEFT JOIN `##placelocation` AS t6 ON t5.pl_parent_id = t6.pl_id 220 LEFT JOIN `##placelocation` AS t7 ON t6.pl_parent_id = t7.pl_id 221 LEFT JOIN `##placelocation` AS t8 ON t7.pl_parent_id = t8.pl_id 222 HAVING fqpn=:gedcomName; 223 " 224 ) 225 ->execute( 226 [ 227 'separator' => Place::GEDCOM_SEPARATOR, 228 'gedcomName' => $gedcomName, 229 ] 230 ) 231 ->fetchOneRow(); 232 } 233} 234