xref: /webtrees/app/Place.php (revision a25f0a04682c4c39c1947220c90af4118c713952)
1*a25f0a04SGreg Roach<?php
2*a25f0a04SGreg Roachnamespace Webtrees;
3*a25f0a04SGreg Roach
4*a25f0a04SGreg Roach/**
5*a25f0a04SGreg Roach * webtrees: online genealogy
6*a25f0a04SGreg Roach * Copyright (C) 2015 webtrees development team
7*a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify
8*a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by
9*a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or
10*a25f0a04SGreg Roach * (at your option) any later version.
11*a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful,
12*a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*a25f0a04SGreg Roach * GNU General Public License for more details.
15*a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License
16*a25f0a04SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
17*a25f0a04SGreg Roach */
18*a25f0a04SGreg Roach
19*a25f0a04SGreg Roach/**
20*a25f0a04SGreg Roach * Class Place - Gedcom Place functionality.
21*a25f0a04SGreg Roach */
22*a25f0a04SGreg Roachclass Place {
23*a25f0a04SGreg Roach	const GEDCOM_SEPARATOR = ', ';
24*a25f0a04SGreg Roach	private $gedcom_place; // e.g. array("Westminster", "London", "England")
25*a25f0a04SGreg Roach	private $gedcom_id; // We may have the same place in different trees
26*a25f0a04SGreg Roach
27*a25f0a04SGreg Roach	/**
28*a25f0a04SGreg Roach	 * @param string  $gedcom_place
29*a25f0a04SGreg Roach	 * @param integer $gedcom_id
30*a25f0a04SGreg Roach	 */
31*a25f0a04SGreg Roach	public function __construct($gedcom_place, $gedcom_id) {
32*a25f0a04SGreg Roach		if ($gedcom_place) {
33*a25f0a04SGreg Roach			$this->gedcom_place = explode(self::GEDCOM_SEPARATOR, $gedcom_place);
34*a25f0a04SGreg Roach		} else {
35*a25f0a04SGreg Roach			// Empty => "Top level"
36*a25f0a04SGreg Roach			$this->gedcom_place = array();
37*a25f0a04SGreg Roach		}
38*a25f0a04SGreg Roach		$this->gedcom_id = $gedcom_id;
39*a25f0a04SGreg Roach	}
40*a25f0a04SGreg Roach
41*a25f0a04SGreg Roach	/**
42*a25f0a04SGreg Roach	 * @return integer
43*a25f0a04SGreg Roach	 */
44*a25f0a04SGreg Roach	public function getPlaceId() {
45*a25f0a04SGreg Roach		$place_id = 0;
46*a25f0a04SGreg Roach		foreach (array_reverse($this->gedcom_place) as $place) {
47*a25f0a04SGreg Roach			$place_id = Database::prepare(
48*a25f0a04SGreg Roach				"SELECT SQL_CACHE p_id FROM `##places` WHERE p_parent_id = :parent_id AND p_place = :place AND p_file = :tree_id"
49*a25f0a04SGreg Roach			)->execute(array(
50*a25f0a04SGreg Roach				'parent_id' => $place_id,
51*a25f0a04SGreg Roach				'place'     => $place,
52*a25f0a04SGreg Roach				'tree_id'   => $this->gedcom_id,
53*a25f0a04SGreg Roach			))->fetchOne();
54*a25f0a04SGreg Roach		}
55*a25f0a04SGreg Roach
56*a25f0a04SGreg Roach		return $place_id;
57*a25f0a04SGreg Roach	}
58*a25f0a04SGreg Roach
59*a25f0a04SGreg Roach	/**
60*a25f0a04SGreg Roach	 * @return Place
61*a25f0a04SGreg Roach	 */
62*a25f0a04SGreg Roach	public function getParentPlace() {
63*a25f0a04SGreg Roach		return new Place(implode(self::GEDCOM_SEPARATOR, array_slice($this->gedcom_place, 1)), $this->gedcom_id);
64*a25f0a04SGreg Roach	}
65*a25f0a04SGreg Roach
66*a25f0a04SGreg Roach	/**
67*a25f0a04SGreg Roach	 * @return Place[]
68*a25f0a04SGreg Roach	 */
69*a25f0a04SGreg Roach	public function getChildPlaces() {
70*a25f0a04SGreg Roach		$children = array();
71*a25f0a04SGreg Roach		if ($this->getPlaceId()) {
72*a25f0a04SGreg Roach			$parent_text = self::GEDCOM_SEPARATOR . $this->getGedcomName();
73*a25f0a04SGreg Roach		} else {
74*a25f0a04SGreg Roach			$parent_text = '';
75*a25f0a04SGreg Roach		}
76*a25f0a04SGreg Roach
77*a25f0a04SGreg Roach		$rows = Database::prepare(
78*a25f0a04SGreg Roach			"SELECT SQL_CACHE p_place FROM `##places`" .
79*a25f0a04SGreg Roach			" WHERE p_parent_id = :parent_id AND p_file = :tree_id" .
80*a25f0a04SGreg Roach			" ORDER BY p_place COLLATE :collation"
81*a25f0a04SGreg Roach		)->execute(array(
82*a25f0a04SGreg Roach			'parent_id' => $this->getPlaceId(),
83*a25f0a04SGreg Roach			'tree_id'   => $this->gedcom_id,
84*a25f0a04SGreg Roach			'collation' => I18N::$collation,
85*a25f0a04SGreg Roach		))->fetchOneColumn();
86*a25f0a04SGreg Roach		foreach ($rows as $row) {
87*a25f0a04SGreg Roach			$children[] = new Place($row . $parent_text, $this->gedcom_id);
88*a25f0a04SGreg Roach		}
89*a25f0a04SGreg Roach
90*a25f0a04SGreg Roach		return $children;
91*a25f0a04SGreg Roach	}
92*a25f0a04SGreg Roach
93*a25f0a04SGreg Roach	/**
94*a25f0a04SGreg Roach	 * @return string
95*a25f0a04SGreg Roach	 */
96*a25f0a04SGreg Roach	public function getURL() {
97*a25f0a04SGreg Roach		$url = 'placelist.php';
98*a25f0a04SGreg Roach		foreach (array_reverse($this->gedcom_place) as $n => $place) {
99*a25f0a04SGreg Roach			$url .= $n ? '&amp;' : '?';
100*a25f0a04SGreg Roach			$url .= 'parent%5B%5D=' . rawurlencode($place);
101*a25f0a04SGreg Roach		}
102*a25f0a04SGreg Roach		$url .= '&amp;ged=' . rawurlencode(get_gedcom_from_id($this->gedcom_id));
103*a25f0a04SGreg Roach
104*a25f0a04SGreg Roach		return $url;
105*a25f0a04SGreg Roach	}
106*a25f0a04SGreg Roach
107*a25f0a04SGreg Roach	/**
108*a25f0a04SGreg Roach	 * @return string
109*a25f0a04SGreg Roach	 */
110*a25f0a04SGreg Roach	public function getGedcomName() {
111*a25f0a04SGreg Roach		return implode(self::GEDCOM_SEPARATOR, $this->gedcom_place);
112*a25f0a04SGreg Roach	}
113*a25f0a04SGreg Roach
114*a25f0a04SGreg Roach	/**
115*a25f0a04SGreg Roach	 * @return string
116*a25f0a04SGreg Roach	 */
117*a25f0a04SGreg Roach	public function getPlaceName() {
118*a25f0a04SGreg Roach		$place = reset($this->gedcom_place);
119*a25f0a04SGreg Roach
120*a25f0a04SGreg Roach		return $place ? '<span dir="auto">' . Filter::escapeHtml($place) . '</span>' : I18N::translate('unknown');
121*a25f0a04SGreg Roach	}
122*a25f0a04SGreg Roach
123*a25f0a04SGreg Roach	/**
124*a25f0a04SGreg Roach	 * @return bool
125*a25f0a04SGreg Roach	 */
126*a25f0a04SGreg Roach	public function isEmpty() {
127*a25f0a04SGreg Roach		return empty($this->gedcom_place);
128*a25f0a04SGreg Roach	}
129*a25f0a04SGreg Roach
130*a25f0a04SGreg Roach	/**
131*a25f0a04SGreg Roach	 * @return string
132*a25f0a04SGreg Roach	 */
133*a25f0a04SGreg Roach	public function getFullName() {
134*a25f0a04SGreg Roach		if (true) {
135*a25f0a04SGreg Roach			// If a place hierarchy is a single entity
136*a25f0a04SGreg Roach			return '<span dir="auto">' . Filter::escapeHtml(implode(I18N::$list_separator, $this->gedcom_place)) . '</span>';
137*a25f0a04SGreg Roach		} else {
138*a25f0a04SGreg Roach			// If a place hierarchy is a list of distinct items
139*a25f0a04SGreg Roach			$tmp = array();
140*a25f0a04SGreg Roach			foreach ($this->gedcom_place as $place) {
141*a25f0a04SGreg Roach				$tmp[] = '<span dir="auto">' . Filter::escapeHtml($place) . '</span>';
142*a25f0a04SGreg Roach			}
143*a25f0a04SGreg Roach
144*a25f0a04SGreg Roach			return implode(I18N::$list_separator, $tmp);
145*a25f0a04SGreg Roach		}
146*a25f0a04SGreg Roach	}
147*a25f0a04SGreg Roach
148*a25f0a04SGreg Roach	/**
149*a25f0a04SGreg Roach	 * For lists and charts, where the full name won’t fit.
150*a25f0a04SGreg Roach	 *
151*a25f0a04SGreg Roach	 * @return string
152*a25f0a04SGreg Roach	 */
153*a25f0a04SGreg Roach	public function getShortName() {
154*a25f0a04SGreg Roach		global $SHOW_PEDIGREE_PLACES, $SHOW_PEDIGREE_PLACES_SUFFIX;
155*a25f0a04SGreg Roach
156*a25f0a04SGreg Roach		if ($SHOW_PEDIGREE_PLACES >= count($this->gedcom_place)) {
157*a25f0a04SGreg Roach			// A short place name - no need to abbreviate
158*a25f0a04SGreg Roach			return $this->getFullName();
159*a25f0a04SGreg Roach		} else {
160*a25f0a04SGreg Roach			// Abbreviate the place name, for lists
161*a25f0a04SGreg Roach			if ($SHOW_PEDIGREE_PLACES_SUFFIX) {
162*a25f0a04SGreg Roach				// The *last* $SHOW_PEDIGREE_PLACES components
163*a25f0a04SGreg Roach				$short_name = implode(self::GEDCOM_SEPARATOR, array_slice($this->gedcom_place, -$SHOW_PEDIGREE_PLACES));
164*a25f0a04SGreg Roach			} else {
165*a25f0a04SGreg Roach				// The *first* $SHOW_PEDIGREE_PLACES components
166*a25f0a04SGreg Roach				$short_name = implode(self::GEDCOM_SEPARATOR, array_slice($this->gedcom_place, 0, $SHOW_PEDIGREE_PLACES));
167*a25f0a04SGreg Roach			}
168*a25f0a04SGreg Roach			// Add a tool-tip showing the full name
169*a25f0a04SGreg Roach			return '<span title="' . Filter::escapeHtml($this->getGedcomName()) . '" dir="auto">' . Filter::escapeHtml($short_name) . '</span>';
170*a25f0a04SGreg Roach		}
171*a25f0a04SGreg Roach	}
172*a25f0a04SGreg Roach
173*a25f0a04SGreg Roach	/**
174*a25f0a04SGreg Roach	 * For the "view all" option of placelist.php and find.php
175*a25f0a04SGreg Roach	 *
176*a25f0a04SGreg Roach	 * @return string
177*a25f0a04SGreg Roach	 */
178*a25f0a04SGreg Roach	public function getReverseName() {
179*a25f0a04SGreg Roach		$tmp = array();
180*a25f0a04SGreg Roach		foreach (array_reverse($this->gedcom_place) as $place) {
181*a25f0a04SGreg Roach			$tmp[] = '<span dir="auto">' . Filter::escapeHtml($place) . '</span>';
182*a25f0a04SGreg Roach		}
183*a25f0a04SGreg Roach
184*a25f0a04SGreg Roach		return implode(I18N::$list_separator, $tmp);
185*a25f0a04SGreg Roach	}
186*a25f0a04SGreg Roach
187*a25f0a04SGreg Roach	/**
188*a25f0a04SGreg Roach	 * @param integer $gedcom_id
189*a25f0a04SGreg Roach	 *
190*a25f0a04SGreg Roach	 * @return string[]
191*a25f0a04SGreg Roach	 */
192*a25f0a04SGreg Roach	public static function allPlaces($gedcom_id) {
193*a25f0a04SGreg Roach		$places = array();
194*a25f0a04SGreg Roach		$rows =
195*a25f0a04SGreg Roach			Database::prepare(
196*a25f0a04SGreg Roach				"SELECT SQL_CACHE CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place)" .
197*a25f0a04SGreg Roach				" FROM      `##places` AS p1" .
198*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p2 ON (p1.p_parent_id=p2.p_id)" .
199*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p3 ON (p2.p_parent_id=p3.p_id)" .
200*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p4 ON (p3.p_parent_id=p4.p_id)" .
201*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p5 ON (p4.p_parent_id=p5.p_id)" .
202*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p6 ON (p5.p_parent_id=p6.p_id)" .
203*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p7 ON (p6.p_parent_id=p7.p_id)" .
204*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p8 ON (p7.p_parent_id=p8.p_id)" .
205*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p9 ON (p8.p_parent_id=p9.p_id)" .
206*a25f0a04SGreg Roach				" WHERE p1.p_file=?" .
207*a25f0a04SGreg Roach				" ORDER BY CONCAT_WS(', ', p9.p_place, p8.p_place, p7.p_place, p6.p_place, p5.p_place, p4.p_place, p3.p_place, p2.p_place, p1.p_place) COLLATE '" . I18N::$collation . "'"
208*a25f0a04SGreg Roach			)
209*a25f0a04SGreg Roach			->execute(array($gedcom_id))
210*a25f0a04SGreg Roach			->fetchOneColumn();
211*a25f0a04SGreg Roach		foreach ($rows as $row) {
212*a25f0a04SGreg Roach			$places[] = new Place($row, $gedcom_id);
213*a25f0a04SGreg Roach		}
214*a25f0a04SGreg Roach		return $places;
215*a25f0a04SGreg Roach	}
216*a25f0a04SGreg Roach
217*a25f0a04SGreg Roach	/**
218*a25f0a04SGreg Roach	 * @param string  $filter
219*a25f0a04SGreg Roach	 * @param integer $gedcom_id
220*a25f0a04SGreg Roach	 *
221*a25f0a04SGreg Roach	 * @return Place[]
222*a25f0a04SGreg Roach	 */
223*a25f0a04SGreg Roach	public static function findPlaces($filter, $gedcom_id) {
224*a25f0a04SGreg Roach		$places = array();
225*a25f0a04SGreg Roach		$rows =
226*a25f0a04SGreg Roach			Database::prepare(
227*a25f0a04SGreg Roach				"SELECT SQL_CACHE CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place)" .
228*a25f0a04SGreg Roach				" FROM      `##places` AS p1" .
229*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p2 ON (p1.p_parent_id=p2.p_id)" .
230*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p3 ON (p2.p_parent_id=p3.p_id)" .
231*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p4 ON (p3.p_parent_id=p4.p_id)" .
232*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p5 ON (p4.p_parent_id=p5.p_id)" .
233*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p6 ON (p5.p_parent_id=p6.p_id)" .
234*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p7 ON (p6.p_parent_id=p7.p_id)" .
235*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p8 ON (p7.p_parent_id=p8.p_id)" .
236*a25f0a04SGreg Roach				" LEFT JOIN `##places` AS p9 ON (p8.p_parent_id=p9.p_id)" .
237*a25f0a04SGreg Roach				" WHERE CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place) LIKE CONCAT('%', ?, '%') AND CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place) NOT LIKE CONCAT('%,%', ?, '%') AND p1.p_file=?" .
238*a25f0a04SGreg Roach				" ORDER BY  CONCAT_WS(', ', p1.p_place, p2.p_place, p3.p_place, p4.p_place, p5.p_place, p6.p_place, p7.p_place, p8.p_place, p9.p_place) COLLATE '" . I18N::$collation . "'"
239*a25f0a04SGreg Roach			)
240*a25f0a04SGreg Roach			->execute(array($filter, preg_quote($filter), $gedcom_id))
241*a25f0a04SGreg Roach			->fetchOneColumn();
242*a25f0a04SGreg Roach		foreach ($rows as $row) {
243*a25f0a04SGreg Roach			$places[] = new Place($row, $gedcom_id);
244*a25f0a04SGreg Roach		}
245*a25f0a04SGreg Roach		return $places;
246*a25f0a04SGreg Roach	}
247*a25f0a04SGreg Roach}
248