oDB =& $oDB;
$this->oPlaceLookup = new PlaceLookup($this->oDB);
$this->oTokenizer = new \Nominatim\Tokenizer($this->oDB);
}
public function setLanguagePreference($aLangPref)
{
$this->aLangPrefOrder = $aLangPref;
}
public function getMoreUrlParams()
{
if ($this->aStructuredQuery) {
$aParams = $this->aStructuredQuery;
} else {
$aParams = array('q' => $this->sQuery);
}
$aParams = array_merge($aParams, $this->oPlaceLookup->getMoreUrlParams());
if ($this->aExcludePlaceIDs) {
$aParams['exclude_place_ids'] = implode(',', $this->aExcludePlaceIDs);
}
if ($this->bBoundedSearch) {
$aParams['bounded'] = '1';
}
if ($this->aCountryCodes) {
$aParams['countrycodes'] = implode(',', $this->aCountryCodes);
}
if ($this->aViewBox) {
$aParams['viewbox'] = join(',', $this->aViewBox);
}
return $aParams;
}
public function setLimit($iLimit = 10)
{
if ($iLimit > 50) {
$iLimit = 50;
} elseif ($iLimit < 1) {
$iLimit = 1;
}
$this->iFinalLimit = $iLimit;
$this->iLimit = $iLimit + min($iLimit, 10);
}
public function setFeatureType($sFeatureType)
{
switch ($sFeatureType) {
case 'country':
$this->setRankRange(4, 4);
break;
case 'state':
$this->setRankRange(8, 8);
break;
case 'city':
$this->setRankRange(14, 16);
break;
case 'settlement':
$this->setRankRange(8, 20);
break;
}
}
public function setRankRange($iMin, $iMax)
{
$this->iMinAddressRank = $iMin;
$this->iMaxAddressRank = $iMax;
}
public function setViewbox($aViewbox)
{
$aBox = array_map('floatval', $aViewbox);
$this->aViewBox[0] = max(-180.0, min($aBox[0], $aBox[2]));
$this->aViewBox[1] = max(-90.0, min($aBox[1], $aBox[3]));
$this->aViewBox[2] = min(180.0, max($aBox[0], $aBox[2]));
$this->aViewBox[3] = min(90.0, max($aBox[1], $aBox[3]));
if ($this->aViewBox[2] - $this->aViewBox[0] < 0.000000001
|| $this->aViewBox[3] - $this->aViewBox[1] < 0.000000001
) {
userError("Bad parameter 'viewbox'. Not a box.");
}
}
private function viewboxImportanceFactor($fX, $fY)
{
if (!$this->aViewBox) {
return 1;
}
$fWidth = ($this->aViewBox[2] - $this->aViewBox[0])/2;
$fHeight = ($this->aViewBox[3] - $this->aViewBox[1])/2;
$fXDist = abs($fX - ($this->aViewBox[0] + $this->aViewBox[2])/2);
$fYDist = abs($fY - ($this->aViewBox[1] + $this->aViewBox[3])/2);
if ($fXDist <= $fWidth && $fYDist <= $fHeight) {
return 1;
}
if ($fXDist <= $fWidth * 3 && $fYDist <= 3 * $fHeight) {
return 0.5;
}
return 0.25;
}
public function setQuery($sQueryString)
{
$this->sQuery = $sQueryString;
$this->aStructuredQuery = false;
}
public function getQueryString()
{
return $this->sQuery;
}
public function loadParamArray($oParams, $sForceGeometryType = null)
{
$this->bBoundedSearch = $oParams->getBool('bounded', $this->bBoundedSearch);
$this->setLimit($oParams->getInt('limit', $this->iFinalLimit));
$this->iOffset = $oParams->getInt('offset', $this->iOffset);
$this->bFallback = $oParams->getBool('fallback', $this->bFallback);
// List of excluded Place IDs - used for more acurate pageing
$sExcluded = $oParams->getStringList('exclude_place_ids');
if ($sExcluded) {
foreach ($sExcluded as $iExcludedPlaceID) {
$iExcludedPlaceID = (int)$iExcludedPlaceID;
if ($iExcludedPlaceID) {
$aExcludePlaceIDs[$iExcludedPlaceID] = $iExcludedPlaceID;
}
}
if (isset($aExcludePlaceIDs)) {
$this->aExcludePlaceIDs = $aExcludePlaceIDs;
}
}
// Only certain ranks of feature
$sFeatureType = $oParams->getString('featureType');
if (!$sFeatureType) {
$sFeatureType = $oParams->getString('featuretype');
}
if ($sFeatureType) {
$this->setFeatureType($sFeatureType);
}
// Country code list
$sCountries = $oParams->getStringList('countrycodes');
if ($sCountries) {
foreach ($sCountries as $sCountryCode) {
if (preg_match('/^[a-zA-Z][a-zA-Z]$/', $sCountryCode)) {
$aCountries[] = strtolower($sCountryCode);
}
}
if (isset($aCountries)) {
$this->aCountryCodes = $aCountries;
}
}
$aViewbox = $oParams->getStringList('viewboxlbrt');
if ($aViewbox) {
if (count($aViewbox) != 4) {
userError("Bad parameter 'viewboxlbrt'. Expected 4 coordinates.");
}
$this->setViewbox($aViewbox);
} else {
$aViewbox = $oParams->getStringList('viewbox');
if ($aViewbox) {
if (count($aViewbox) != 4) {
userError("Bad parameter 'viewbox'. Expected 4 coordinates.");
}
$this->setViewBox($aViewbox);
} else {
$aRoute = $oParams->getStringList('route');
$fRouteWidth = $oParams->getFloat('routewidth');
if ($aRoute && $fRouteWidth) {
$this->aRoutePoints = $aRoute;
$this->aRouteWidth = $fRouteWidth;
}
}
}
$this->oPlaceLookup->loadParamArray($oParams, $sForceGeometryType);
$this->oPlaceLookup->setIncludeAddressDetails($oParams->getBool('addressdetails', false));
}
public function setQueryFromParams($oParams)
{
// Search query
$sQuery = $oParams->getString('q');
if (!$sQuery) {
$this->setStructuredQuery(
$oParams->getString('amenity'),
$oParams->getString('street'),
$oParams->getString('city'),
$oParams->getString('county'),
$oParams->getString('state'),
$oParams->getString('country'),
$oParams->getString('postalcode')
);
} else {
$this->setQuery($sQuery);
}
}
public function loadStructuredAddressElement($sValue, $sKey, $iNewMinAddressRank, $iNewMaxAddressRank, $aItemListValues)
{
$sValue = trim($sValue);
if (!$sValue) {
return false;
}
$this->aStructuredQuery[$sKey] = $sValue;
if ($this->iMinAddressRank == 0 && $this->iMaxAddressRank == 30) {
$this->iMinAddressRank = $iNewMinAddressRank;
$this->iMaxAddressRank = $iNewMaxAddressRank;
}
if ($aItemListValues) {
$this->aAddressRankList = array_merge($this->aAddressRankList, $aItemListValues);
}
return true;
}
public function setStructuredQuery($sAmenity = false, $sStreet = false, $sCity = false, $sCounty = false, $sState = false, $sCountry = false, $sPostalCode = false)
{
$this->sQuery = false;
// Reset
$this->iMinAddressRank = 0;
$this->iMaxAddressRank = 30;
$this->aAddressRankList = array();
$this->aStructuredQuery = array();
$this->sAllowedTypesSQLList = false;
$this->loadStructuredAddressElement($sAmenity, 'amenity', 26, 30, false);
$this->loadStructuredAddressElement($sStreet, 'street', 26, 30, false);
$this->loadStructuredAddressElement($sCity, 'city', 14, 24, false);
$this->loadStructuredAddressElement($sCounty, 'county', 9, 13, false);
$this->loadStructuredAddressElement($sState, 'state', 8, 8, false);
$this->loadStructuredAddressElement($sPostalCode, 'postalcode', 5, 11, array(5, 11));
$this->loadStructuredAddressElement($sCountry, 'country', 4, 4, false);
if (!empty($this->aStructuredQuery)) {
$this->sQuery = join(', ', $this->aStructuredQuery);
if ($this->iMaxAddressRank < 30) {
$this->sAllowedTypesSQLList = '(\'place\',\'boundary\')';
}
}
}
public function fallbackStructuredQuery()
{
$aParams = $this->aStructuredQuery;
if (!$aParams || count($aParams) == 1) {
return false;
}
$aOrderToFallback = array('postalcode', 'street', 'city', 'county', 'state');
foreach ($aOrderToFallback as $sType) {
if (isset($aParams[$sType])) {
unset($aParams[$sType]);
$this->setStructuredQuery(@$aParams['amenity'], @$aParams['street'], @$aParams['city'], @$aParams['county'], @$aParams['state'], @$aParams['country'], @$aParams['postalcode']);
return true;
}
}
return false;
}
public function getGroupedSearches($aSearches, $aPhrases, $oValidTokens)
{
/*
Calculate all searches using oValidTokens i.e.
'Wodsworth Road, Sheffield' =>
Phrase Wordset
0 0 (wodsworth road)
0 1 (wodsworth)(road)
1 0 (sheffield)
Score how good the search is so they can be ordered
*/
foreach ($aPhrases as $iPhrase => $oPhrase) {
$aNewPhraseSearches = array();
$sPhraseType = $oPhrase->getPhraseType();
foreach ($oPhrase->getWordSets() as $aWordset) {
$aWordsetSearches = $aSearches;
// Add all words from this wordset
foreach ($aWordset as $iToken => $sToken) {
//echo "
$sToken";
$aNewWordsetSearches = array();
foreach ($aWordsetSearches as $oCurrentSearch) {
//echo "";
//var_dump($oCurrentSearch);
//echo "";
// Tokens with full name matches.
foreach ($oValidTokens->get(' '.$sToken) as $oSearchTerm) {
$aNewSearches = $oCurrentSearch->extendWithFullTerm(
$oSearchTerm,
$sPhraseType,
$iToken == 0 && $iPhrase == 0,
$iPhrase == 0,
$iToken + 1 == count($aWordset)
&& $iPhrase + 1 == count($aPhrases)
);
foreach ($aNewSearches as $oSearch) {
if ($oSearch->getRank() < $this->iMaxRank) {
$aNewWordsetSearches[] = $oSearch;
}
}
}
// Look for partial matches.
// Note that there is no point in adding country terms here
// because country is omitted in the address.
if ($sPhraseType != 'country') {
// Allow searching for a word - but at extra cost
foreach ($oValidTokens->get($sToken) as $oSearchTerm) {
$aNewSearches = $oCurrentSearch->extendWithPartialTerm(
$sToken,
$oSearchTerm,
(bool) $sPhraseType,
$iPhrase,
$oValidTokens->get(' '.$sToken)
);
foreach ($aNewSearches as $oSearch) {
if ($oSearch->getRank() < $this->iMaxRank) {
$aNewWordsetSearches[] = $oSearch;
}
}
}
}
}
// Sort and cut
usort($aNewWordsetSearches, array('Nominatim\SearchDescription', 'bySearchRank'));
$aWordsetSearches = array_slice($aNewWordsetSearches, 0, 50);
}
//var_Dump('