xref: /webtrees/app/Location.php (revision 3ff387bf7b92eb2246f9d457c56e819cdec0c584)
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