5 require_once(CONST_BasePath.'/lib/lib.php');
9 * Collection of search constraints that are independent of the
10 * actual interpretation of the search query.
12 * The search context is shared between all SearchDescriptions. This
13 * object mainly serves as context provider for the database queries.
14 * Therefore most data is directly cached as SQL statements.
18 /// Search radius around a given Near reference point.
19 private $fNearRadius = false;
20 /// True if search must be restricted to viewbox only.
21 public $bViewboxBounded = false;
23 /// Reference point for search (as SQL).
25 /// Viewbox selected for search (as SQL).
26 public $sqlViewboxSmall = '';
27 /// Viewbox with a larger buffer around (as SQL).
28 public $sqlViewboxLarge = '';
29 /// Reference along a route (as SQL).
30 public $sqlViewboxCentre = '';
31 /// List of countries to restrict search to (as SQL).
32 public $sqlCountryList = '';
33 /// List of place IDs to exclude (as SQL).
34 private $sqlExcludeList = '';
38 * Check if a reference point is defined.
40 * @return bool True if a reference point is defined.
42 public function hasNearPoint()
44 return $this->fNearRadius !== false;
48 * Get radius around reference point.
50 * @return float Search radius around reference point.
52 public function nearRadius()
54 return $this->fNearRadius;
58 * Set search reference point in WGS84.
60 * If set, then only places around this point will be taken into account.
62 * @param float $fLat Latitude of point.
63 * @param float $fLon Longitude of point.
64 * @param float $fRadius Search radius around point.
68 public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
70 $this->fNearRadius = $fRadius;
71 $this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
75 * Check if the search is geographically restricted.
77 * Searches are restricted if a reference point is given or if
78 * a bounded viewbox is set.
80 * @return bool True, if the search is geographically bounded.
82 public function isBoundedSearch()
84 return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
88 * Set rectangular viewbox.
90 * The viewbox may be bounded which means that no search results
91 * must be outside the viewbox.
93 * @param float[4] $aViewBox Coordinates of the viewbox.
94 * @param bool $bBounded True if the viewbox is bounded.
98 public function setViewboxFromBox(&$aViewBox, $bBounded)
100 $this->bViewboxBounded = $bBounded;
101 $this->sqlViewboxCentre = '';
103 $this->sqlViewboxSmall = sprintf(
104 'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
111 $fHeight = $aViewBox[0] - $aViewBox[2];
112 $fWidth = $aViewBox[1] - $aViewBox[3];
114 $this->sqlViewboxLarge = sprintf(
115 'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
116 max($aViewBox[0], $aViewBox[2]) + $fHeight,
117 max($aViewBox[1], $aViewBox[3]) + $fWidth,
118 min($aViewBox[0], $aViewBox[2]) - $fHeight,
119 min($aViewBox[1], $aViewBox[3]) - $fWidth
124 * Set viewbox along a route.
126 * The viewbox may be bounded which means that no search results
127 * must be outside the viewbox.
129 * @param object $oDB DB connection to use for computing the box.
130 * @param string[] $aRoutePoints List of x,y coordinates along a route.
131 * @param float $fRouteWidth Buffer around the route to use.
132 * @param bool $bBounded True if the viewbox bounded.
136 public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
138 $this->bViewboxBounded = $bBounded;
139 $this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
141 foreach ($aRoutePoints as $aPoint) {
142 $fPoint = (float)$aPoint;
143 $this->sqlViewboxCentre .= $sSep.$fPoint;
144 $sSep = ($sSep == ' ') ? ',' : ' ';
146 $this->sqlViewboxCentre .= ")'::geometry,4326)";
148 $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
149 $sGeom = chksql($oDB->getOne('select '.$sSQL), 'Could not get small viewbox');
150 $this->sqlViewboxSmall = "'".$sGeom."'::geometry";
152 $sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
153 $sGeom = chksql($oDB->getOne('select '.$sSQL), 'Could not get large viewbox');
154 $this->sqlViewboxLarge = "'".$sGeom."'::geometry";
158 * Set list of excluded place IDs.
160 * @param integer[] $aExcluded List of IDs.
164 public function setExcludeList($aExcluded)
166 $this->sqlExcludeList = ' not in ('.join(',', $aExcluded).')';
170 * Set list of countries to restrict search to.
172 * @param string[] $aCountries List of two-letter lower-case country codes.
176 public function setCountryList($aCountries)
178 $this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
182 * Extract a reference point from a query string.
184 * @param string $sQuery Query to scan.
186 * @return string The remaining query string.
188 public function setNearPointFromQuery($sQuery)
190 $aResult = parseLatLon($sQuery);
192 if ($aResult !== false
193 && $aResult[1] <= 90.1
194 && $aResult[1] >= -90.1
195 && $aResult[2] <= 180.1
196 && $aResult[2] >= -180.1
198 $this->setNearPoint($aResult[1], $aResult[2]);
199 $sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
206 * Get an SQL snipped for computing the distance from the reference point.
208 * @param string $sObj SQL variable name to compute the distance from.
210 * @return string An SQL string.
212 public function distanceSQL($sObj)
214 return 'ST_Distance('.$this->sqlNear.", $sObj)";
218 * Get an SQL snipped for checking if something is within range of the
221 * @param string $sObj SQL variable name to compute if it is within range.
223 * @return string An SQL string.
225 public function withinSQL($sObj)
227 return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
231 * Get an SQL snipped of the importance factor of the viewbox.
233 * The importance factor is computed by checking if an object is within
234 * the viewbox and/or the extended version of the viewbox.
236 * @param string $sObj SQL variable name of object to weight the importance
238 * @return string SQL snipped of the factor with a leading multiply sign.
240 public function viewboxImportanceSQL($sObj)
244 if ($this->sqlViewboxSmall) {
245 $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
247 if ($this->sqlViewboxLarge) {
248 $sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
255 * SQL snipped checking if a place ID should be excluded.
257 * @param string $sVariable SQL variable name of place ID to check,
258 * potentially prefixed with more SQL.
260 * @return string SQL snippet.
262 public function excludeSQL($sVariable)
264 if ($this->sqlExcludeList) {
265 return $sVariable.$this->sqlExcludeList;