aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/location.php
blob: 1534c7d7ba0baf1fb58a7c593727783cda70e002 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<?php
/**
 * Elgg geo-location tagging library.
 *
 * @package Elgg.Core
 * @subpackage Location
 */

/**
 * Encode a location into a latitude and longitude, caching the result.
 *
 * Works by triggering the 'geocode' 'location' plugin
 * hook, and requires a geocoding plugin to be installed.
 *
 * @param string $location The location, e.g. "London", or "24 Foobar Street, Gotham City"
 * @return string|false
 */
function elgg_geocode_location($location) {
	global $CONFIG;

	if (is_array($location)) {
		return false;
	}

	$location = sanitise_string($location);

	// Look for cached version
	$query = "SELECT * from {$CONFIG->dbprefix}geocode_cache WHERE location='$location'";
	$cached_location = get_data_row($query);

	if ($cached_location) {
		return array('lat' => $cached_location->lat, 'long' => $cached_location->long);
	}

	// Trigger geocode event if not cached
	$return = false;
	$return = elgg_trigger_plugin_hook('geocode', 'location', array('location' => $location), $return);

	// If returned, cache and return value
	if (($return) && (is_array($return))) {
		$lat = (float)$return['lat'];
		$long = (float)$return['long'];

		// Put into cache at the end of the page since we don't really care that much
		$query = "INSERT DELAYED INTO {$CONFIG->dbprefix}geocode_cache "
			. " (location, lat, `long`) VALUES ('$location', '{$lat}', '{$long}')"
			. " ON DUPLICATE KEY UPDATE lat='{$lat}', `long`='{$long}'";
		execute_delayed_write_query($query);
	}

	return $return;
}

/**
 * Return entities within a given geographic area.
 *
 * Also accepts all options available to elgg_get_entities().
 *
 * @see elgg_get_entities
 *
 * @param array $options Array in format:
 *
 * 	latitude => FLOAT Latitude of the location
 *
 * 	longitude => FLOAT Longitude of the location
 *
 *  distance => FLOAT/ARR (
 *						latitude => float,
 *						longitude => float,
 *					)
 *					The distance in degrees that determines the search box. A
 *					single float will result in a square in degrees.
 * @warning The Earth is round.
 *
 * @see ElggEntity::setLatLong()
 *
 * @return mixed If count, int. If not count, array. false on errors.
 * @since 1.8.0
 */
function elgg_get_entities_from_location(array $options = array()) {

	global $CONFIG;
	
	if (!isset($options['latitude']) || !isset($options['longitude']) ||
		!isset($options['distance'])) {
		return false;
	}

	if (!is_array($options['distance'])) {
		$lat_distance = (float)$options['distance'];
		$long_distance = (float)$options['distance'];
	} else {
		$lat_distance = (float)$options['distance']['latitude'];
		$long_distance = (float)$options['distance']['longitude'];
	}

	$lat = (float)$options['latitude'];
	$long = (float)$options['longitude'];
	$lat_min = $lat - $lat_distance;
	$lat_max = $lat + $lat_distance;
	$long_min = $long - $long_distance;
	$long_max = $long + $long_distance;

	$wheres = array();
	$wheres[] = "lat_name.string='geo:lat'";
	$wheres[] = "lat_value.string >= $lat_min";
	$wheres[] = "lat_value.string <= $lat_max";
	$wheres[] = "lon_name.string='geo:long'";
	$wheres[] = "lon_value.string >= $long_min";
	$wheres[] = "lon_value.string <= $long_max";

	$joins = array();
	$joins[] = "JOIN {$CONFIG->dbprefix}metadata lat on e.guid=lat.entity_guid";
	$joins[] = "JOIN {$CONFIG->dbprefix}metastrings lat_name on lat.name_id=lat_name.id";
	$joins[] = "JOIN {$CONFIG->dbprefix}metastrings lat_value on lat.value_id=lat_value.id";
	$joins[] = "JOIN {$CONFIG->dbprefix}metadata lon on e.guid=lon.entity_guid";
	$joins[] = "JOIN {$CONFIG->dbprefix}metastrings lon_name on lon.name_id=lon_name.id";
	$joins[] = "JOIN {$CONFIG->dbprefix}metastrings lon_value on lon.value_id=lon_value.id";

	// merge wheres to pass to get_entities()
	if (isset($options['wheres']) && !is_array($options['wheres'])) {
		$options['wheres'] = array($options['wheres']);
	} elseif (!isset($options['wheres'])) {
		$options['wheres'] = array();
	}
	$options['wheres'] = array_merge($options['wheres'], $wheres);

	// merge joins to pass to get_entities()
	if (isset($options['joins']) && !is_array($options['joins'])) {
		$options['joins'] = array($options['joins']);
	} elseif (!isset($options['joins'])) {
		$options['joins'] = array();
	}
	$options['joins'] = array_merge($options['joins'], $joins);

	return elgg_get_entities_from_relationship($options);
}

/**
 * Returns a viewable list of entities from location
 *
 * @param array $options Options array
 *
 * @see elgg_list_entities()
 * @see elgg_get_entities_from_location()
 *
 * @return string The viewable list of entities
 * @since 1.8.0
 */
function elgg_list_entities_from_location(array $options = array()) {
	return elgg_list_entities($options, 'elgg_get_entities_from_location');
}

// Some distances in degrees (approximate)
// @todo huh? see warning on elgg_get_entities_from_location()
define("MILE", 0.01515);
define("KILOMETER", 0.00932);