From: Sarah Hoffmann Date: Thu, 8 Mar 2018 20:37:24 +0000 (+0100) Subject: Merge branch 'vagrant-centos-with-selinux' of https://github.com/mtmail/Nominatim X-Git-Tag: v3.2.0~112 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/8d4a86635fe661717a17fe3bb7ff2cde8a784158?hp=2dc6ee7e1c2d6a62abeef8b8e4abd3d7c126f475 Merge branch 'vagrant-centos-with-selinux' of https://github.com/mtmail/Nominatim --- diff --git a/.travis.yml b/.travis.yml index 5efc9f08..c67f155e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ script: - if [[ $TEST_SUITE == "monaco" ]]; then ./utils/specialphrases.php --wiki-import | psql -d test_api_nominatim >/dev/null; fi - cd $TRAVIS_BUILD_DIR/test/php - if [[ $TEST_SUITE == "tests" ]]; then phpunit ./ ; fi - - if [[ $TEST_SUITE == "tests" ]]; then phpcs --report-width=120 */**.php ; fi + - if [[ $TEST_SUITE == "tests" ]]; then phpcs --report-width=120 . ; fi - cd $TRAVIS_BUILD_DIR/test/bdd - # behave --format=progress3 api - if [[ $TEST_SUITE == "tests" ]]; then behave --format=progress3 db ; fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a00d0ed3..242a9d6f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,7 +41,7 @@ Please add the following information to your issue: ## Workflow for Pull Requests -We love to get pull reuqests from you. We operate the "Fork & Pull" model +We love to get pull requests from you. We operate the "Fork & Pull" model explained at https://help.github.com/articles/using-pull-requests @@ -65,7 +65,7 @@ that duplicate work can be avoided. ## Coding style Nominatim historically hasn't followed a particular coding style but we -are in process of consolodating the style. The following rules apply: +are in process of consolidating the style. The following rules apply: * Python code uses the official Python style * indention @@ -82,7 +82,7 @@ are in process of consolodating the style. The following rules apply: The coding style is enforced with PHPCS and can be tested with: ``` - phpcs --report-width=120 --colors */**.php + phpcs --report-width=120 --colors . ``` ## Testing diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index e8596e49..d2fe03d0 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -8,6 +8,7 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/appendix) ADD_CUSTOM_TARGET(doc COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/admin ${CMAKE_CURRENT_BINARY_DIR}/admin + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/develop ${CMAKE_CURRENT_BINARY_DIR}/develop COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/index.md ${CMAKE_CURRENT_BINARY_DIR}/index.md COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-7.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-7.md COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-16.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-16.md diff --git a/docs/admin/Installation.md b/docs/admin/Installation.md index ce7fb412..67c4fe3c 100644 --- a/docs/admin/Installation.md +++ b/docs/admin/Installation.md @@ -8,6 +8,13 @@ the following operating systems: These OS-specific instructions can also be found in executable form in the `vagrant/` directory. +Users have created instructions for other frameworks. We haven't tested those +and can't offer support. + + * [Docker](https://github.com/mediagis/nominatim-docker) + * [Docker on Kubernetes](https://github.com/peter-evans/nominatim-k8s) + * [Ansible](https://github.com/synthesio/infra-ansible-nominatim) + # Prerequisites ## Software diff --git a/docs/develop/overview.md b/docs/develop/overview.md new file mode 100644 index 00000000..179eeb0b --- /dev/null +++ b/docs/develop/overview.md @@ -0,0 +1,24 @@ +# Basic Architecture + +Nominatim provides geocoding based on OpenStreetMap data. It uses a Postgresql +database as a backend for storing the data. + +There are three basic parts to Nominatim's architecture: the data import, +the address computation and the search frontend. + +The __data import__ stage reads the raw OSM data and extracts all information +that is useful for geocoding. This part is done by osm2pgsql, the same tool +that can also be used to import a rendering database. It uses the special +gazetteer output plugin in `osm2pgsql/output-gazetter.[ch]pp`. The result of +the import can be found in the database table `place`. + +The __address computation__ or __indexing__ stage takes the data from `place` +and adds additional information needed for geocoding. It ranks the places by +importance, links objects that belong together and computes addresses and +the search index. Most of this work is done in Pl/pqSQL via database triggers +and can be found in the file `sql/functions.sql`. + +The __search frontend__ implements the actual API. It takes queries for +search and reverse geocoding queries from the user, looks up the data and +returns the results in the requested format. This part is written in PHP +and can be found in the `lib/` and `website/` directories. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index d647dd87..b0aee5d0 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -10,6 +10,8 @@ pages: - 'Importing and Updating' : 'admin/Import-and-Update.md' - 'Migration from older Versions' : 'admin/Migration.md' - 'Troubleshooting' : 'admin/Faq.md' + - 'Developers Guide': + - 'Overview' : 'develop/overview.md' - 'Appendix': - 'Installation on CentOS 7' : 'appendix/Install-on-Centos-7.md' - 'Installation on Ubuntu 16' : 'appendix/Install-on-Ubuntu-16.md' diff --git a/lib/Geocode.php b/lib/Geocode.php index d5647c76..26fafb73 100644 --- a/lib/Geocode.php +++ b/lib/Geocode.php @@ -921,12 +921,12 @@ class Geocode $aResult['importance'] = 0.001; $aResult['foundorder'] = $aResult['addressimportance']; } else { - // Adjust importance for the number of exact string matches in the result + $aResult['importance'] = max(0.001, $aResult['importance']); $aResult['importance'] *= $this->viewboxImportanceFactor( $aResult['lon'], $aResult['lat'] ); - $aResult['importance'] = max(0.001, $aResult['importance']); + // Adjust importance for the number of exact string matches in the result $iCountWords = 0; $sAddress = $aResult['langaddress']; foreach ($aRecheckWords as $i => $sWord) { diff --git a/lib/ParameterParser.php b/lib/ParameterParser.php index 2eed1629..c9a97c25 100644 --- a/lib/ParameterParser.php +++ b/lib/ParameterParser.php @@ -23,7 +23,7 @@ class ParameterParser public function getInt($sName, $bDefault = false) { - if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) { + if (!isset($this->aParams[$sName])) { return $bDefault; } @@ -36,7 +36,7 @@ class ParameterParser public function getFloat($sName, $bDefault = false) { - if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) { + if (!isset($this->aParams[$sName])) { return $bDefault; } @@ -74,7 +74,8 @@ class ParameterParser $sValue = $this->getString($sName); if ($sValue) { - return explode(',', $sValue); + // removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values + return array_values(array_filter(explode(',', $sValue), 'strlen')); } return $aDefault; diff --git a/lib/SearchDescription.php b/lib/SearchDescription.php index 4ba28e35..2e72decc 100644 --- a/lib/SearchDescription.php +++ b/lib/SearchDescription.php @@ -276,11 +276,12 @@ class SearchDescription && $sPhraseType != 'country' ) { $iWordID = $aSearchTerm['word_id']; - if (sizeof($this->aName)) { - if (($sPhraseType == '' || !$bFirstPhrase) - && $sPhraseType != 'country' - && !$bHasPartial - ) { + // Full words can only be a name if they appear at the beginning + // of the phrase. In structured search the name must forcably in + // the first phrase. In unstructured search it may be in a later + // phrase when the first phrase is a house number. + if (sizeof($this->aName) || !($bFirstPhrase || $sPhraseType == '')) { + if (($sPhraseType == '' || !$bFirstPhrase) && !$bHasPartial) { $oSearch = clone $this; $oSearch->iSearchRank++; $oSearch->aAddress[$iWordID] = $iWordID; @@ -675,7 +676,7 @@ class SearchDescription if ($this->sHouseNumber) { $sImportanceSQL = '- abs(26 - address_rank) + 3'; } else { - $sImportanceSQL = '(CASE WHEN importance = 0 OR importance IS NULL THEN 0.75-(search_rank::float/40) ELSE importance END)'; + $sImportanceSQL = '(CASE WHEN importance = 0 OR importance IS NULL THEN 0.75001-(search_rank::float/40) ELSE importance END)'; } $sImportanceSQL .= $this->oContext->viewboxImportanceSQL('centroid'); $aOrder[] = "$sImportanceSQL DESC"; diff --git a/lib/template/address-json.php b/lib/template/address-json.php index 93abb601..cea87745 100644 --- a/lib/template/address-json.php +++ b/lib/template/address-json.php @@ -2,20 +2,15 @@ $aFilteredPlaces = array(); -if (!sizeof($aPlace)) -{ +if (!sizeof($aPlace)) { if (isset($sError)) $aFilteredPlaces['error'] = $sError; - else - $aFilteredPlaces['error'] = 'Unable to geocode'; -} -else -{ + else $aFilteredPlaces['error'] = 'Unable to geocode'; +} else { if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id']; - $aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright"; + $aFilteredPlaces['licence'] = 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright'; $sOSMType = formatOSMType($aPlace['osm_type']); - if ($sOSMType) - { + if ($sOSMType) { $aFilteredPlaces['osm_type'] = $sOSMType; $aFilteredPlaces['osm_id'] = $aPlace['osm_id']; } @@ -26,31 +21,25 @@ else if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags']; if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails']; - if (isset($aPlace['aBoundingBox'])) - { + if (isset($aPlace['aBoundingBox'])) { $aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox']; } - if (isset($aPlace['asgeojson'])) - { + if (isset($aPlace['asgeojson'])) { $aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']); } - if (isset($aPlace['assvg'])) - { + if (isset($aPlace['assvg'])) { $aFilteredPlaces['svg'] = $aPlace['assvg']; } - if (isset($aPlace['astext'])) - { + if (isset($aPlace['astext'])) { $aFilteredPlaces['geotext'] = $aPlace['astext']; } - if (isset($aPlace['askml'])) - { + if (isset($aPlace['askml'])) { $aFilteredPlaces['geokml'] = $aPlace['askml']; } } javascript_renderData($aFilteredPlaces); - diff --git a/lib/template/address-jsonv2.php b/lib/template/address-jsonv2.php index 229303be..399c978f 100644 --- a/lib/template/address-jsonv2.php +++ b/lib/template/address-jsonv2.php @@ -2,20 +2,15 @@ $aFilteredPlaces = array(); -if (!sizeof($aPlace)) -{ +if (!sizeof($aPlace)) { if (isset($sError)) $aFilteredPlaces['error'] = $sError; - else - $aFilteredPlaces['error'] = 'Unable to geocode'; -} -else -{ + else $aFilteredPlaces['error'] = 'Unable to geocode'; +} else { if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id']; - $aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright"; + $aFilteredPlaces['licence'] = 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright'; $sOSMType = formatOSMType($aPlace['osm_type']); - if ($sOSMType) - { + if ($sOSMType) { $aFilteredPlaces['osm_type'] = $sOSMType; $aFilteredPlaces['osm_id'] = $aPlace['osm_id']; } @@ -38,31 +33,25 @@ else if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags']; if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails']; - if (isset($aPlace['aBoundingBox'])) - { + if (isset($aPlace['aBoundingBox'])) { $aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox']; } - if (isset($aPlace['asgeojson'])) - { + if (isset($aPlace['asgeojson'])) { $aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']); } - if (isset($aPlace['assvg'])) - { + if (isset($aPlace['assvg'])) { $aFilteredPlaces['svg'] = $aPlace['assvg']; } - if (isset($aPlace['astext'])) - { + if (isset($aPlace['astext'])) { $aFilteredPlaces['geotext'] = $aPlace['astext']; } - if (isset($aPlace['askml'])) - { + if (isset($aPlace['askml'])) { $aFilteredPlaces['geokml'] = $aPlace['askml']; } - } javascript_renderData($aFilteredPlaces); diff --git a/lib/template/address-xml.php b/lib/template/address-xml.php index d3db2edd..6183b284 100644 --- a/lib/template/address-xml.php +++ b/lib/template/address-xml.php @@ -1,103 +1,87 @@ \n"; -echo "\n"; -if (!sizeof($aPlace)) -{ +if (!sizeof($aPlace)) { if (isset($sError)) echo "$sError"; - else - echo "Unable to geocode"; -} -else -{ - echo "Unable to geocode'; +} else { + echo '".htmlspecialchars($aPlace['langaddress']).""; + echo '>'.htmlspecialchars($aPlace['langaddress']).''; - if (isset($aPlace['aAddress'])) - { - echo ""; - foreach($aPlace['aAddress'] as $sKey => $sValue) - { - $sKey = str_replace(' ','_',$sKey); + if (isset($aPlace['aAddress'])) { + echo ''; + foreach ($aPlace['aAddress'] as $sKey => $sValue) { + $sKey = str_replace(' ', '_', $sKey); echo "<$sKey>"; echo htmlspecialchars($sValue); echo ""; } - echo ""; + echo ''; } - if (isset($aPlace['sExtraTags'])) - { - echo ""; - foreach ($aPlace['sExtraTags'] as $sKey => $sValue) - { + if (isset($aPlace['sExtraTags'])) { + echo ''; + foreach ($aPlace['sExtraTags'] as $sKey => $sValue) { echo ''; } - echo ""; + echo ''; } - if (isset($aPlace['sNameDetails'])) - { - echo ""; - foreach ($aPlace['sNameDetails'] as $sKey => $sValue) - { + if (isset($aPlace['sNameDetails'])) { + echo ''; + foreach ($aPlace['sNameDetails'] as $sKey => $sValue) { echo ''; echo htmlspecialchars($sValue); - echo ""; + echo ''; } - echo ""; + echo ''; } - if (isset($aPlace['askml'])) - { + if (isset($aPlace['askml'])) { echo "\n"; echo $aPlace['askml']; - echo ""; + echo ''; } - } -echo ""; +echo ''; diff --git a/lib/template/search-batch-json.php b/lib/template/search-batch-json.php index a3ced45b..09ea48b6 100644 --- a/lib/template/search-batch-json.php +++ b/lib/template/search-batch-json.php @@ -1,42 +1,37 @@ $aPointDetails) - { + foreach ($aSearchResults as $iResNum => $aPointDetails) { $aPlace = array( - 'place_id'=>$aPointDetails['place_id'], - ); + 'place_id'=>$aPointDetails['place_id'], + ); $sOSMType = formatOSMType($aPointDetails['osm_type']); - if ($sOSMType) - { + if ($sOSMType) { $aPlace['osm_type'] = $sOSMType; $aPlace['osm_id'] = $aPointDetails['osm_id']; } - if (isset($aPointDetails['aBoundingBox'])) - { + if (isset($aPointDetails['aBoundingBox'])) { $aPlace['boundingbox'] = array( - $aPointDetails['aBoundingBox'][0], - $aPointDetails['aBoundingBox'][1], - $aPointDetails['aBoundingBox'][2], - $aPointDetails['aBoundingBox'][3]); + $aPointDetails['aBoundingBox'][0], + $aPointDetails['aBoundingBox'][1], + $aPointDetails['aBoundingBox'][2], + $aPointDetails['aBoundingBox'][3] + ); - if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons) - { + if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons) { $aPlace['polygonpoints'] = $aPointDetails['aPolyPoints']; } } - if (isset($aPointDetails['zoom'])) - { + if (isset($aPointDetails['zoom'])) { $aPlace['zoom'] = $aPointDetails['zoom']; } @@ -50,33 +45,27 @@ foreach($aBatchResults as $aSearchResults) $aPlace['importance'] = $aPointDetails['importance']; - if (isset($aPointDetails['icon'])) - { + if (isset($aPointDetails['icon'])) { $aPlace['icon'] = $aPointDetails['icon']; } - if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0) - { + if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0) { $aPlace['address'] = $aPointDetails['address']; } - if (isset($aPointDetails['asgeojson'])) - { + if (isset($aPointDetails['asgeojson'])) { $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']); } - if (isset($aPointDetails['assvg'])) - { + if (isset($aPointDetails['assvg'])) { $aPlace['svg'] = $aPointDetails['assvg']; } - if (isset($aPointDetails['astext'])) - { + if (isset($aPointDetails['astext'])) { $aPlace['geotext'] = $aPointDetails['astext']; } - if (isset($aPointDetails['askml'])) - { + if (isset($aPointDetails['askml'])) { $aPlace['geokml'] = $aPointDetails['askml']; } diff --git a/lib/template/search-json.php b/lib/template/search-json.php index 846d654c..b997f6d9 100644 --- a/lib/template/search-json.php +++ b/lib/template/search-json.php @@ -1,33 +1,28 @@ $aPointDetails) -{ +foreach ($aSearchResults as $iResNum => $aPointDetails) { $aPlace = array( - 'place_id'=>$aPointDetails['place_id'], - 'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright", - ); + 'place_id'=>$aPointDetails['place_id'], + 'licence'=>'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright', + ); $sOSMType = formatOSMType($aPointDetails['osm_type']); - if ($sOSMType) - { + if ($sOSMType) { $aPlace['osm_type'] = $sOSMType; $aPlace['osm_id'] = $aPointDetails['osm_id']; } - if (isset($aPointDetails['aBoundingBox'])) - { + if (isset($aPointDetails['aBoundingBox'])) { $aPlace['boundingbox'] = $aPointDetails['aBoundingBox']; - if (isset($aPointDetails['aPolyPoints'])) - { + if (isset($aPointDetails['aPolyPoints'])) { $aPlace['polygonpoints'] = $aPointDetails['aPolyPoints']; } } - if (isset($aPointDetails['zoom'])) - { + if (isset($aPointDetails['zoom'])) { $aPlace['zoom'] = $aPointDetails['zoom']; } @@ -40,33 +35,27 @@ foreach($aSearchResults as $iResNum => $aPointDetails) $aPlace['importance'] = $aPointDetails['importance']; - if (isset($aPointDetails['icon']) && $aPointDetails['icon']) - { + if (isset($aPointDetails['icon']) && $aPointDetails['icon']) { $aPlace['icon'] = $aPointDetails['icon']; } - if (isset($aPointDetails['address'])) - { + if (isset($aPointDetails['address'])) { $aPlace['address'] = $aPointDetails['address']; } - if (isset($aPointDetails['asgeojson'])) - { + if (isset($aPointDetails['asgeojson'])) { $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']); } - if (isset($aPointDetails['assvg'])) - { + if (isset($aPointDetails['assvg'])) { $aPlace['svg'] = $aPointDetails['assvg']; } - if (isset($aPointDetails['astext'])) - { + if (isset($aPointDetails['astext'])) { $aPlace['geotext'] = $aPointDetails['astext']; } - if (isset($aPointDetails['askml'])) - { + if (isset($aPointDetails['askml'])) { $aPlace['geokml'] = $aPointDetails['askml']; } diff --git a/lib/template/search-jsonv2.php b/lib/template/search-jsonv2.php index 5d2802af..76103304 100644 --- a/lib/template/search-jsonv2.php +++ b/lib/template/search-jsonv2.php @@ -1,32 +1,27 @@ $aPointDetails) -{ +foreach ($aSearchResults as $iResNum => $aPointDetails) { $aPlace = array( - 'place_id'=>$aPointDetails['place_id'], - 'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright", - ); + 'place_id'=>$aPointDetails['place_id'], + 'licence'=>'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', + ); $sOSMType = formatOSMType($aPointDetails['osm_type']); - if ($sOSMType) - { + if ($sOSMType) { $aPlace['osm_type'] = $sOSMType; $aPlace['osm_id'] = $aPointDetails['osm_id']; } - if (isset($aPointDetails['aBoundingBox'])) - { + if (isset($aPointDetails['aBoundingBox'])) { $aPlace['boundingbox'] = $aPointDetails['aBoundingBox']; - if (isset($aPointDetails['aPolyPoints'])) - { + if (isset($aPointDetails['aPolyPoints'])) { $aPlace['polygonpoints'] = $aPointDetails['aPolyPoints']; } } - if (isset($aPointDetails['zoom'])) - { + if (isset($aPointDetails['zoom'])) { $aPlace['zoom'] = $aPointDetails['zoom']; } @@ -40,33 +35,27 @@ foreach($aSearchResults as $iResNum => $aPointDetails) $aPlace['importance'] = $aPointDetails['importance']; - if (isset($aPointDetails['icon'])) - { + if (isset($aPointDetails['icon'])) { $aPlace['icon'] = $aPointDetails['icon']; } - if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0) - { + if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0) { $aPlace['address'] = $aPointDetails['address']; } - if (isset($aPointDetails['asgeojson'])) - { + if (isset($aPointDetails['asgeojson'])) { $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']); } - if (isset($aPointDetails['assvg'])) - { + if (isset($aPointDetails['assvg'])) { $aPlace['svg'] = $aPointDetails['assvg']; } - if (isset($aPointDetails['astext'])) - { + if (isset($aPointDetails['astext'])) { $aPlace['geotext'] = $aPointDetails['astext']; } - if (isset($aPointDetails['askml'])) - { + if (isset($aPointDetails['askml'])) { $aPlace['geokml'] = $aPointDetails['askml']; } diff --git a/lib/template/search-xml.php b/lib/template/search-xml.php index 80414fce..94bb7ec9 100644 --- a/lib/template/search-xml.php +++ b/lib/template/search-xml.php @@ -1,72 +1,63 @@ \n"; -echo "<"; +echo '<'; echo (isset($sXmlRootTag)?$sXmlRootTag:'searchresults'); echo " timestamp='".date(DATE_RFC822)."'"; echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'"; echo " querystring='".htmlspecialchars($sQuery, ENT_QUOTES)."'"; if (isset($aMoreParams['viewbox'])) echo " viewbox='".htmlspecialchars($aMoreParams['viewbox'], ENT_QUOTES)."'"; echo " polygon='".(isset($aMoreParams['polygon'])?'true':'false')."'"; -if (isset($aMoreParams['exclude_place_ids'])) -{ +if (isset($aMoreParams['exclude_place_ids'])) { echo " exclude_place_ids='".htmlspecialchars($aMoreParams['exclude_place_ids'])."'"; } echo " more_url='".htmlspecialchars($sMoreURL)."'"; echo ">\n"; -foreach($aSearchResults as $iResNum => $aResult) -{ +foreach ($aSearchResults as $iResNum => $aResult) { echo " $aResult) echo " class='".htmlspecialchars($aResult['class'])."'"; echo " type='".htmlspecialchars($aResult['type'], ENT_QUOTES)."'"; echo " importance='".htmlspecialchars($aResult['importance'])."'"; - if (isset($aResult['icon']) && $aResult['icon']) - { + if (isset($aResult['icon']) && $aResult['icon']) { echo " icon='".htmlspecialchars($aResult['icon'], ENT_QUOTES)."'"; } $bHasDelim = false; - if (isset($aResult['askml'])) - { - if (!$bHasDelim) - { + if (isset($aResult['askml'])) { + if (!$bHasDelim) { $bHasDelim = true; - echo ">"; + echo '>'; } echo "\n"; echo $aResult['askml']; - echo ""; + echo ''; } - if (isset($aResult['sExtraTags'])) - { - if (!$bHasDelim) - { + if (isset($aResult['sExtraTags'])) { + if (!$bHasDelim) { $bHasDelim = true; - echo ">"; + echo '>'; } echo "\n"; - foreach ($aResult['sExtraTags'] as $sKey => $sValue) - { + foreach ($aResult['sExtraTags'] as $sKey => $sValue) { echo ''; } - echo ""; + echo ''; } - if (isset($aResult['sNameDetails'])) - { - if (!$bHasDelim) - { + if (isset($aResult['sNameDetails'])) { + if (!$bHasDelim) { $bHasDelim = true; - echo ">"; + echo '>'; } echo "\n"; - foreach ($aResult['sNameDetails'] as $sKey => $sValue) - { + foreach ($aResult['sNameDetails'] as $sKey => $sValue) { echo ''; echo htmlspecialchars($sValue); - echo ""; + echo ''; } - echo ""; + echo ''; } - if (isset($aResult['address'])) - { - if (!$bHasDelim) - { + if (isset($aResult['address'])) { + if (!$bHasDelim) { $bHasDelim = true; - echo ">"; + echo '>'; } echo "\n"; - foreach($aResult['address'] as $sKey => $sValue) - { - $sKey = str_replace(' ','_',$sKey); + foreach ($aResult['address'] as $sKey => $sValue) { + $sKey = str_replace(' ', '_', $sKey); echo "<$sKey>"; echo htmlspecialchars($sValue); echo ""; } } - if ($bHasDelim) - { - echo ""; - } - else - { - echo "/>"; + if ($bHasDelim) { + echo ''; + } else { + echo '/>'; } } -echo ""; +echo ''; diff --git a/module/nominatim.c b/module/nominatim.c index 75238e22..73bf16c8 100644 --- a/module/nominatim.c +++ b/module/nominatim.c @@ -157,17 +157,18 @@ transliteration( PG_FUNCTION_ARGS ) PG_RETURN_TEXT_P(result); } +// Set isspace=1 if the replacement _only_ adds a space before the search string. I.e. to == " " + from void str_replace(char* buffer, int* len, int* changes, char* from, int fromlen, char* to, int tolen, int isspace) { char *p; - // Search string is too long to be pressent + // Search string is too long to be present if (fromlen > *len) return; p = strstr(buffer, from); while(p) { - if (!isspace || *(p-1) != ' ') + if (!isspace || (p > buffer && *(p-1) != ' ')) { (*changes)++; if (tolen != fromlen) memmove(p+tolen, p+fromlen, *len-(p-buffer)+1); @@ -230,7 +231,7 @@ gettokenstring( PG_FUNCTION_ARGS ) sourcedata = (unsigned char *)VARDATA(source); sourcedatalength = VARSIZE(source) - VARHDRSZ; - // Buffer for doing the replace in - string could get slightly longer (double is mastive overkill) + // Buffer for doing the replace in - string could get slightly longer (double is massive overkill) buffer = (char *)palloc((sourcedatalength*2)*sizeof(char)); memcpy(buffer+1, sourcedata, sourcedatalength); buffer[0] = 32; diff --git a/phpcs.xml b/phpcs.xml index 8f92f7c9..a48b5c3e 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -8,6 +8,12 @@ + ./lib/template/*html* + ./lib/template/includes/ + ./module/ + ./website/css + ./website/js + @@ -80,19 +86,6 @@ INDENTATION, SPACING ************************************************************** --> - - - 0 - - - - - 0 - - - 0 - - 0 diff --git a/test/bdd/db/import/parenting.feature b/test/bdd/db/import/parenting.feature index 401a58f1..87467fd2 100644 --- a/test/bdd/db/import/parenting.feature +++ b/test/bdd/db/import/parenting.feature @@ -20,12 +20,12 @@ Feature: Parenting of objects | N2 | W1 | When searching for "4 galoo" Then results contain - | ID | osm_type | osm_id | langaddress - | 0 | N | 1 | 4, galoo, 12345 + | ID | osm_type | osm_id | langaddress | + | 0 | N | 1 | 4, galoo, 12345 | When searching for "5 galoo" Then results contain - | ID | osm_type | osm_id | langaddress - | 0 | N | 2 | 5, galoo, 99999 + | ID | osm_type | osm_id | langaddress | + | 0 | N | 2 | 5, galoo, 99999 | Scenario: Address without tags, closest street Given the scene roads-with-pois diff --git a/test/bdd/osm2pgsql/update/relation.feature b/test/bdd/osm2pgsql/update/relation.feature index 83ce9129..fd8b83e3 100644 --- a/test/bdd/osm2pgsql/update/relation.feature +++ b/test/bdd/osm2pgsql/update/relation.feature @@ -11,11 +11,11 @@ Feature: Update of relations by osm2pgsql n202 x0.0001 y0.0001 n203 x0.0001 y0 w2 Tref=45' Nn200,n201,n202,n203,n200 - r1 Ttype=multipolygon,tourism=hotel,name=XZ' Mw2@ + r1 Ttype=multipolygon,tourism=hotel,name=XZ Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'XZ' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'XZ' | When updating osm data """ r1 Ttype=multipolygon,tourism=hotel,name=XZ Mn1@ @@ -34,16 +34,16 @@ Feature: Update of relations by osm2pgsql r1 Ttype=multipolygon,tourism=hotel,name=XZ Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'XZ' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'XZ' | When updating osm data """ r1 Ttype=multipolygon,amenity=prison,name=XZ Mw2@ """ Then place has no entry for R1:tourism And place contains - | object | class | type | name - | R1 | amenity | prison | 'name' : 'XZ' + | object | class | type | name | + | R1 | amenity | prison | 'name' : 'XZ' | Scenario: Change name of a relation When loading osm data @@ -56,15 +56,15 @@ Feature: Update of relations by osm2pgsql r1 Ttype=multipolygon,tourism=hotel,name=AB Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'AB' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'AB' | When updating osm data """ r1 Ttype=multipolygon,tourism=hotel,name=XY Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'XZ' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'XY' | Scenario: Change type of a relation into something unknown When loading osm data @@ -77,8 +77,8 @@ Feature: Update of relations by osm2pgsql r1 Ttype=multipolygon,tourism=hotel,name=XY Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'XZ' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'XY' | When updating osm data """ r1 Ttype=multipolygon,amenities=prison,name=XY Mw2@ @@ -96,8 +96,8 @@ Feature: Update of relations by osm2pgsql r1 Ttype=multipolygon,tourism=hotel,name=XY Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'XZ' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'XY' | When updating osm data """ r1 Ttourism=hotel,name=XY Mw2@ @@ -115,8 +115,8 @@ Feature: Update of relations by osm2pgsql r1 Ttype=multipolygon,tourism=hotel,name=XY Mw2@ """ Then place contains - | object | class | type | name - | R1 | tourism | hotel | 'name' : 'XZ' + | object | class | type | name | + | R1 | tourism | hotel | 'name' : 'XY' | When updating osm data """ r1 Ttype=multipolygonn,tourism=hotel,name=XY Mw2@ diff --git a/test/bdd/osm2pgsql/update/simple.feature b/test/bdd/osm2pgsql/update/simple.feature index 33c21039..e8d96d44 100644 --- a/test/bdd/osm2pgsql/update/simple.feature +++ b/test/bdd/osm2pgsql/update/simple.feature @@ -9,10 +9,10 @@ Feature: Update of simple objects by osm2pgsql n2 Tplace=locality,name=spotty """ Then place contains - | object | type | name - | N1:tourism | hotel | 'name' : 'foo' - | N1:amenity | restaurant | 'name' : 'foo' - | N2:place | locality | 'name' : 'spotty' + | object | type | name+name | + | N1:tourism | hotel | foo | + | N1:amenity | restaurant | foo | + | N2:place | locality | spotty | When updating osm data """ n1 dV Ttourism=hotel,name=foo @@ -21,6 +21,6 @@ Feature: Update of simple objects by osm2pgsql Then place has no entry for N1:amenity And place has no entry for N2 And place contains - | object | class | type | name - | N1:tourism | tourism | hotel | 'name' : 'foo' + | object | class | type | name | + | N1:tourism | tourism | hotel | 'name' : 'foo' | diff --git a/test/bdd/steps/cgi-with-coverage.php b/test/bdd/steps/cgi-with-coverage.php index 165a1b0c..47d3cc9a 100644 --- a/test/bdd/steps/cgi-with-coverage.php +++ b/test/bdd/steps/cgi-with-coverage.php @@ -1,6 +1,7 @@ stop(); @@ -16,5 +17,3 @@ $coverage->start($_SERVER['COV_TEST_NAME']); register_shutdown_function('coverage_shutdown', $coverage); include $_SERVER['COV_SCRIPT_FILENAME']; - - diff --git a/test/php/Nominatim/ParameterParserTest.php b/test/php/Nominatim/ParameterParserTest.php new file mode 100644 index 00000000..4265cffb --- /dev/null +++ b/test/php/Nominatim/ParameterParserTest.php @@ -0,0 +1,217 @@ + '1', + 'bool2' => '0', + 'bool3' => 'true', + 'bool4' => 'false', + 'bool5' => '' + ]); + + $this->assertSame(false, $oParams->getBool('non-exists')); + $this->assertSame(true, $oParams->getBool('non-exists', true)); + $this->assertSame(true, $oParams->getBool('bool1')); + $this->assertSame(false, $oParams->getBool('bool2')); + $this->assertSame(true, $oParams->getBool('bool3')); + $this->assertSame(true, $oParams->getBool('bool4')); + $this->assertSame(false, $oParams->getBool('bool5')); + } + + + public function testGetInt() + { + $oParams = new ParameterParser([ + 'int1' => '5', + 'int2' => '-1', + 'int3' => 0 + ]); + + $this->assertSame(false, $oParams->getInt('non-exists')); + $this->assertSame(999, $oParams->getInt('non-exists', 999)); + $this->assertSame(5, $oParams->getInt('int1')); + + $this->assertSame(-1, $oParams->getInt('int2')); + $this->assertSame(0, $oParams->getInt('int3')); + } + + + public function testGetIntWithNonNumber() + { + $this->setExpectedException(Exception::class, "Integer number expected for parameter 'int4'"); + (new ParameterParser(['int4' => 'a']))->getInt('int4'); + } + + + public function testGetIntWithEmpytString() + { + $this->setExpectedException(Exception::class, "Integer number expected for parameter 'int5'"); + (new ParameterParser(['int5' => '']))->getInt('int5'); + } + + + public function testGetFloat() + { + + $oParams = new ParameterParser([ + 'float1' => '1.0', + 'float2' => '-5', + 'float3' => 0 + ]); + + $this->assertSame(false, $oParams->getFloat('non-exists')); + $this->assertSame(999, $oParams->getFloat('non-exists', 999)); + $this->assertSame(1.0, $oParams->getFloat('float1')); + $this->assertSame(-5.0, $oParams->getFloat('float2')); + $this->assertSame(0.0, $oParams->getFloat('float3')); + } + + public function testGetFloatWithEmptyString() + { + $this->setExpectedException(Exception::class, "Floating-point number expected for parameter 'float4'"); + (new ParameterParser(['float4' => '']))->getFloat('float4'); + } + + public function testGetFloatWithTextString() + { + $this->setExpectedException(Exception::class, "Floating-point number expected for parameter 'float5'"); + (new ParameterParser(['float5' => 'a']))->getFloat('float5'); + } + + + public function testGetFloatWithInvalidNumber() + { + $this->setExpectedException(Exception::class, "Floating-point number expected for parameter 'float6'"); + (new ParameterParser(['float6' => '-55.']))->getFloat('float6'); + } + + + public function testGetString() + { + $oParams = new ParameterParser([ + 'str1' => 'abc', + 'str2' => '', + 'str3' => '0' + ]); + + $this->assertSame(false, $oParams->getString('non-exists')); + $this->assertSame('default', $oParams->getString('non-exists', 'default')); + $this->assertSame('abc', $oParams->getString('str1')); + $this->assertSame(false, $oParams->getStringList('str2')); + $this->assertSame(false, $oParams->getStringList('str3')); // sadly PHP magic treats 0 as false when returned + } + + + public function testGetSet() + { + $oParams = new ParameterParser([ + 'val1' => 'foo', + 'val2' => '', + 'val3' => 0 + ]); + + $this->assertSame(false, $oParams->getSet('non-exists', ['foo', 'bar'])); + $this->assertSame('default', $oParams->getSet('non-exists', ['foo', 'bar'], 'default')); + $this->assertSame('foo', $oParams->getSet('val1', ['foo', 'bar'])); + + $this->assertSame(false, $oParams->getSet('val2', ['foo', 'bar'])); + $this->assertSame(0, $oParams->getSet('val3', ['foo', 'bar'])); + } + + + public function testGetSetWithValueNotInSet() + { + $this->setExpectedException(Exception::class, "Parameter 'val4' must be one of: foo, bar"); + (new ParameterParser(['val4' => 'faz']))->getSet('val4', ['foo', 'bar']); + } + + + public function testGetStringList() + { + $oParams = new ParameterParser([ + 'list1' => ',a,b,c,,c,d', + 'list2' => 'a', + 'list3' => '', + 'list4' => '0' + ]); + + $this->assertSame(false, $oParams->getStringList('non-exists')); + $this->assertSame(['a', 'b'], $oParams->getStringList('non-exists', ['a', 'b'])); + $this->assertSame(['a', 'b', 'c', 'c', 'd'], $oParams->getStringList('list1')); + $this->assertSame(['a'], $oParams->getStringList('list2')); + $this->assertSame(false, $oParams->getStringList('list3')); + $this->assertSame(false, $oParams->getStringList('list4')); + } + + + public function testGetPreferredLanguages() + { + $oParams = new ParameterParser(['accept-language' => '']); + $this->assertSame([ + 'short_name:default' => 'short_name:default', + 'name:default' => 'name:default', + 'short_name' => 'short_name', + 'name' => 'name', + 'brand' => 'brand', + 'official_name:default' => 'official_name:default', + 'official_name' => 'official_name', + 'ref' => 'ref', + 'type' => 'type' + ], $oParams->getPreferredLanguages('default')); + + $oParams = new ParameterParser(['accept-language' => 'de,en']); + $this->assertSame([ + 'short_name:de' => 'short_name:de', + 'name:de' => 'name:de', + 'short_name:en' => 'short_name:en', + 'name:en' => 'name:en', + 'short_name' => 'short_name', + 'name' => 'name', + 'brand' => 'brand', + 'official_name:de' => 'official_name:de', + 'official_name:en' => 'official_name:en', + 'official_name' => 'official_name', + 'ref' => 'ref', + 'type' => 'type' + ], $oParams->getPreferredLanguages('default')); + + $oParams = new ParameterParser(['accept-language' => 'fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3']); + $this->assertSame([ + 'short_name:fr-ca' => 'short_name:fr-ca', + 'name:fr-ca' => 'name:fr-ca', + 'short_name:fr' => 'short_name:fr', + 'name:fr' => 'name:fr', + 'short_name:en-ca' => 'short_name:en-ca', + 'name:en-ca' => 'name:en-ca', + 'short_name:en' => 'short_name:en', + 'name:en' => 'name:en', + 'short_name' => 'short_name', + 'name' => 'name', + 'brand' => 'brand', + 'official_name:fr-ca' => 'official_name:fr-ca', + 'official_name:fr' => 'official_name:fr', + 'official_name:en-ca' => 'official_name:en-ca', + 'official_name:en' => 'official_name:en', + 'official_name' => 'official_name', + 'ref' => 'ref', + 'type' => 'type', + ], $oParams->getPreferredLanguages('default')); + } +} diff --git a/test/php/Nominatim/PhraseTest.php b/test/php/Nominatim/PhraseTest.php index db8d8b50..b5e6c1bf 100644 --- a/test/php/Nominatim/PhraseTest.php +++ b/test/php/Nominatim/PhraseTest.php @@ -6,6 +6,8 @@ require_once '../../lib/Phrase.php'; class PhraseTest extends \PHPUnit_Framework_TestCase { + + private function serializeSets($aSets) { $aParts = array(); diff --git a/test/php/Nominatim/SearchContextTest.php b/test/php/Nominatim/SearchContextTest.php index a40d0716..2a74dc41 100644 --- a/test/php/Nominatim/SearchContextTest.php +++ b/test/php/Nominatim/SearchContextTest.php @@ -10,6 +10,7 @@ class SearchContextTest extends \PHPUnit_Framework_TestCase { private $oCtx; + protected function setUp() { $this->oCtx = new SearchContext();