1<?php 2 3namespace Elastica\Query; 4 5use Elastica\Exception\InvalidException; 6 7/** 8 * Geo distance query. 9 * 10 * @author Nicolas Ruflin <spam@ruflin.com> 11 * 12 * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html 13 */ 14abstract class AbstractGeoDistance extends AbstractQuery 15{ 16 public const LOCATION_TYPE_GEOHASH = 'geohash'; 17 public const LOCATION_TYPE_LATLON = 'latlon'; 18 19 /** 20 * Location type. 21 * 22 * Decides if this query uses latitude/longitude or geohash for the location. 23 * Values are "latlon" or "geohash". 24 * 25 * @var string 26 */ 27 protected $_locationType; 28 29 /** 30 * Key. 31 * 32 * @var string 33 */ 34 protected $_key; 35 36 /** 37 * Latitude. 38 * 39 * @var float|null 40 */ 41 protected $_latitude; 42 43 /** 44 * Longitude. 45 * 46 * @var float|null 47 */ 48 protected $_longitude; 49 50 /** 51 * Geohash. 52 * 53 * @var string 54 */ 55 protected $_geohash; 56 57 /** 58 * Create GeoDistance object. 59 * 60 * @param array|string $location Location as array or geohash: array('lat' => 48.86, 'lon' => 2.35) OR 'drm3btev3e86' 61 * 62 * @internal param string $distance Distance 63 */ 64 public function __construct(string $key, $location) 65 { 66 $this->setKey($key); 67 $this->setLocation($location); 68 } 69 70 /** 71 * @return $this 72 */ 73 public function setKey(string $key): self 74 { 75 $this->_key = $key; 76 77 return $this; 78 } 79 80 /** 81 * @param array|string $location 82 * 83 * @throws InvalidException 84 * 85 * @return $this 86 */ 87 public function setLocation($location): self 88 { 89 // Location 90 if (\is_array($location)) { // Latitude/Longitude 91 // Latitude 92 if (isset($location['lat'])) { 93 $this->setLatitude($location['lat']); 94 } else { 95 throw new InvalidException('$location[\'lat\'] has to be set'); 96 } 97 98 // Longitude 99 if (isset($location['lon'])) { 100 $this->setLongitude($location['lon']); 101 } else { 102 throw new InvalidException('$location[\'lon\'] has to be set'); 103 } 104 } elseif (\is_string($location)) { // Geohash 105 $this->setGeohash($location); 106 } else { // Invalid location 107 throw new InvalidException('$location has to be an array (latitude/longitude) or a string (geohash)'); 108 } 109 110 return $this; 111 } 112 113 /** 114 * @return $this 115 */ 116 public function setLatitude(float $latitude): self 117 { 118 $this->_latitude = $latitude; 119 $this->_locationType = self::LOCATION_TYPE_LATLON; 120 121 return $this; 122 } 123 124 /** 125 * @return $this 126 */ 127 public function setLongitude(float $longitude): self 128 { 129 $this->_longitude = $longitude; 130 $this->_locationType = self::LOCATION_TYPE_LATLON; 131 132 return $this; 133 } 134 135 /** 136 * @return $this 137 */ 138 public function setGeohash(string $geohash): self 139 { 140 $this->_geohash = $geohash; 141 $this->_locationType = self::LOCATION_TYPE_GEOHASH; 142 143 return $this; 144 } 145 146 /** 147 * {@inheritdoc} 148 */ 149 public function toArray(): array 150 { 151 $this->setParam($this->_key, $this->_getLocationData()); 152 153 return parent::toArray(); 154 } 155 156 /** 157 * @throws InvalidException 158 * 159 * @return array|string 160 */ 161 protected function _getLocationData() 162 { 163 if (self::LOCATION_TYPE_LATLON === $this->_locationType) { // Latitude/longitude 164 $location = []; 165 166 if (isset($this->_latitude)) { // Latitude 167 $location['lat'] = $this->_latitude; 168 } else { 169 throw new InvalidException('Latitude has to be set'); 170 } 171 172 if (isset($this->_longitude)) { // Geohash 173 $location['lon'] = $this->_longitude; 174 } else { 175 throw new InvalidException('Longitude has to be set'); 176 } 177 } elseif (self::LOCATION_TYPE_GEOHASH === $this->_locationType) { // Geohash 178 $location = $this->_geohash; 179 } else { // Invalid location type 180 throw new InvalidException('Invalid location type'); 181 } 182 183 return $location; 184 } 185} 186