From 8343083ac870cae8a6f0874e6e1f1a13071c0905 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 23 Sep 2019 10:07:55 +0200 Subject: [PATCH 01/11] =?UTF-8?q?[CHANGE]=20Abstraktion=20der=20Services.?= =?UTF-8?q?=20Nominatem&Google=20Service=20hinzugef=C3=BCgt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Classes/Aspect/LoggingAspect.php | 28 +++ Classes/Domain/LocationData.php | 50 +++++ Classes/Domain/LocationDataDetails.php | 18 ++ .../Service/AbstractGeoIndexingService.php | 65 +++++++ Classes/GoogleGeoIndexableService.php | 107 +++++++++++ Classes/NominatimGeoIndexableService.php | 104 +++++++++++ Classes/Service/GeoIndexService.php | 173 +++++------------- Configuration/Settings.yaml | 22 ++- 8 files changed, 435 insertions(+), 132 deletions(-) create mode 100644 Classes/Aspect/LoggingAspect.php create mode 100644 Classes/Domain/LocationData.php create mode 100644 Classes/Domain/LocationDataDetails.php create mode 100644 Classes/Domain/Service/AbstractGeoIndexingService.php create mode 100644 Classes/GoogleGeoIndexableService.php create mode 100644 Classes/NominatimGeoIndexableService.php diff --git a/Classes/Aspect/LoggingAspect.php b/Classes/Aspect/LoggingAspect.php new file mode 100644 index 0000000..f66c884 --- /dev/null +++ b/Classes/Aspect/LoggingAspect.php @@ -0,0 +1,28 @@ +indexByAddress(.*)) && within(FormatD\GeoIndexable\Domain\Service\AbstractGeoIndexingService)") + * @return void + */ + public function logIndexByAddress(JoinPointInterface $joinPoint) { + $className = $joinPoint->getClassName(); + echo 'Indexing by address with class: '.$className."\n"; + } +} diff --git a/Classes/Domain/LocationData.php b/Classes/Domain/LocationData.php new file mode 100644 index 0000000..5fe1cd5 --- /dev/null +++ b/Classes/Domain/LocationData.php @@ -0,0 +1,50 @@ +details = $requiredDetails; + } + + /** + * @return array + */ + public function getDetails(): array { + return $this->details; + } + + /** + * @param $name + * @return mixed + */ + public function getDetail($name){ + if(!in_array($name, $this->getDetails())){ + throw new Exception('detail "'.$name.'" not available'); + } + return $this->$name; + } + + /** + * @param $name + * @param $value + */ + public function __set($name, $value) { + if(!in_array($name, $this->getDetails())){ + throw new Exception('detail "'.$name.'" not available'); + } + $this->$name = $value; + } +} diff --git a/Classes/Domain/LocationDataDetails.php b/Classes/Domain/LocationDataDetails.php new file mode 100644 index 0000000..67db16a --- /dev/null +++ b/Classes/Domain/LocationDataDetails.php @@ -0,0 +1,18 @@ +options = $options; + } + + /** + * @param LocationData $locationData + * @param string $address + * @return LocationData|null + */ + abstract public function indexByAddress(LocationData $locationData, string $address): ?LocationData; + + /** + * @param $detail string + * @return bool + */ + public function providesDetail($detail) { + return in_array($detail, $this->getDetails()); + } + + /** + * @param $details array + * @return bool + */ + public function providesDetails($details) { + return $details == array_intersect($details, $this->getDetails()) ; + } + + /** + * @return array + */ + public function getDetails(): array { + return $this->details; + } +} diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php new file mode 100644 index 0000000..1845258 --- /dev/null +++ b/Classes/GoogleGeoIndexableService.php @@ -0,0 +1,107 @@ +requestEngine->setOption(CURLOPT_TIMEOUT, 15); + $this->browser->setRequestEngine($this->requestEngine); + } + + /** + * @param LocationData $locationData + * @param string $address + * @return LocationData|null + * @throws Exception + * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException + */ + public function indexByAddress(LocationData $locationData, string $address): ?LocationData { + $apiKey = $this->options['apiKey']; + + if(!$apiKey){ + throw new Exception('Please specify your Google Api Key!', 1567771297); + } + $formattedAddr = str_replace(' ','+', $address); + $uri = $this->options['baseUri'].'geocode/json?address='.$formattedAddr.'&key='.$apiKey; + $geoData = json_decode($this->browser->request($uri)->getContent()); + + if ($geoData && array_key_exists(0, $geoData->results)) { + $ret = $geoData->results[0]; + + $addressData = $this->getAdressDataFromAddressComponents($ret->address_components); + + foreach($locationData->getDetails() as $detailName){ + switch ($detailName){ + case LocationDataDetails::LATITUDE: + $locationData->latitude = $ret->geometry->location->lat; + break; + case LocationDataDetails::LONGITUDE: + $locationData->longitude = $ret->geometry->location->lng; + break; + case LocationDataDetails::CITY: + $locationData->city = $addressData['city']; + break; + case LocationDataDetails::LABEL: + $locationData->label = $ret->formatted_address; + break; + case LocationDataDetails::COUNTRY: + $locationData->country = $addressData['country']; + break; + default: + throw new Exception('detail not supported'); + break; + } + } + return $locationData; + } + return NULL; + } + + protected function getAdressDataFromAddressComponents($components){ + $address = []; + foreach($components as $component){ + if(in_array('country', $component['types'])){ + $address['country'] = $component['long_name']; + } + } + return $address; + } +} diff --git a/Classes/NominatimGeoIndexableService.php b/Classes/NominatimGeoIndexableService.php new file mode 100644 index 0000000..9234d78 --- /dev/null +++ b/Classes/NominatimGeoIndexableService.php @@ -0,0 +1,104 @@ +requestEngine->setOption(CURLOPT_TIMEOUT, 15); + $this->browser->setRequestEngine($this->requestEngine); + } + + /** + * @param $uri + * @return string + * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException + */ + protected function sendRequest($uri){ + $response = $this->browser->request($uri); + return $response->getContent(); + } + + + /** + * @param LocationData $locationData + * @param string $address + * @return LocationData|null + */ + public function indexByAddress(LocationData $locationData, string $address): ?LocationData { + $uri = $this->options['baseUri'] . 'search?format=json&addressdetails=1&accept-language=en&q=' . urlencode($address); + $geoData = json_decode($this->sendRequest($uri), true); + if ($geoData && array_key_exists(0, $geoData)) { + $ret = $geoData[0]; + + foreach($locationData->getDetails() as $detailName){ + switch ($detailName){ + case LocationDataDetails::LATITUDE: + $locationData->latitude = $ret['lat']; + break; + case LocationDataDetails::LONGITUDE: + $locationData->longitude = $ret['lon']; + break; + case LocationDataDetails::CITY: + $locationData->city = isset($ret['address']['city']) ? $ret['address']['city'] : $ret['address']['county']; + break; + case LocationDataDetails::LABEL: + $locationData->label = $ret['display_name']; + break; + case LocationDataDetails::COUNTRY: + $locationData->country = $ret['address']['country']; + break; + case LocationDataDetails::BOUNDINGBOX: + $locationData->boundingbox = $ret['boundingbox']; + break; + default: + throw new Exception('detail not supported'); + break; + } + } + + return $locationData; + } + return NULL; + } +} diff --git a/Classes/Service/GeoIndexService.php b/Classes/Service/GeoIndexService.php index fb1957b..506998d 100755 --- a/Classes/Service/GeoIndexService.php +++ b/Classes/Service/GeoIndexService.php @@ -5,6 +5,8 @@ * This file is part of the FormatD.GeoIndexable package. */ +use FormatD\GeoIndexable\Domain\LocationData; +use FormatD\GeoIndexable\Domain\Service\AbstractGeoIndexingService; use Neos\Flow\Annotations as Flow; use Neos\Neos\Exception; @@ -21,36 +23,6 @@ class GeoIndexService { */ protected $configurationManager; - /** - * @var string - */ - protected $nominatimBaseUri; - - /** - * @var boolean - */ - protected $geonamesEnable; - - /** - * @var string - */ - protected $geonamesBaseUri; - - /** - * @var string - */ - protected $geonamesUsername; - - /** - * @var string - */ - protected $googleBaseUri; - - /** - * @var string - */ - protected $googleApiKey; - /** * @Flow\Inject * @var \Neos\Flow\Http\Client\Browser @@ -71,95 +43,76 @@ class GeoIndexService { protected $resultData = NULL; /** - * init node context + * @var array */ - public function initializeObject() { - $this->requestEngine->setOption(CURLOPT_TIMEOUT, 15); - $this->browser->setRequestEngine($this->requestEngine); + protected $services = []; - $conf = $this->configurationManager->getConfiguration(\Neos\Flow\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'FormatD.GeoIndexable.geoIndexService'); - $this->nominatimBaseUri = $conf['nominatimBaseUri']; - $this->geonamesEnable = $conf['geonamesEnable']; - $this->geonamesBaseUri = $conf['geonamesBaseUri']; - $this->geonamesUsername = $conf['geonamesUsername']; - $this->googleBaseUri = $conf['googleBaseUri']; - $this->googleApiKey = $conf['googleApiKey']; - } + /** + * @var \Neos\Flow\ObjectManagement\ObjectManagerInterface + */ + protected $objectManager; /** - * @param $address - * @param string $serviceToUse - * @return bool - * @throws Exception - * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException + * GeoIndexService constructor. + * @param \Neos\Flow\ObjectManagement\ObjectManagerInterface $objectManager */ - public function indexAddress($address, $serviceToUse = 'nominatim') { - switch ($serviceToUse) { - case 'google': - $indexedAddress = $this->indexWithGoogle($address); - break; - default: - $indexedAddress = $this->indexWithNomination($address); - } - return $indexedAddress; + public function __construct(\Neos\Flow\ObjectManagement\ObjectManagerInterface $objectManager) { + $this->objectManager = $objectManager; } /** - * @param $address - * @return bool - * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException + * init node context */ - public function indexWithNomination($address) - { - $uri = $this->nominatimBaseUri . 'search?format=json&addressdetails=1&accept-language=en&q=' . urlencode($address); - $geoData = json_decode($this->sendRequest($uri)); - if ($geoData && array_key_exists(0, $geoData)) { - if ($this->geonamesEnable && isset($geoData[0]->lon)) { - $timeZoneServiceUrl = $this->geonamesBaseUri . "timezoneJSON?lat=" . $geoData[0]->lat . "&lng=".$geoData[0]->lon . "&username=" . $this->geonamesUsername; - $timeZone = json_decode($this->sendRequest($timeZoneServiceUrl), true); - $geoData[0]->timezone = $timeZone['timezoneId']; + public function initializeObject() { + $this->requestEngine->setOption(CURLOPT_TIMEOUT, 15); + $this->browser->setRequestEngine($this->requestEngine); + + $conf = $this->configurationManager->getConfiguration(\Neos\Flow\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'FormatD.GeoIndexable'); + //TODO: check yaml felder if NULL etc. + + foreach($conf['services'] as $serviceName=>$serviceConf){ + $serviceClass = $serviceConf['serviceClass']; + if(class_exists($serviceClass)){ + $this->services[$serviceName] = $this->objectManager->get($serviceClass); + $this->services[$serviceName]->setOptions($serviceConf['options']); + }else{ + //TODO: Errormeldung } - $this->resultData = $geoData[0]; - return TRUE; } - return FALSE; } /** + * @param LocationData $locationData * @param $address - * @return bool - * @throws Exception - * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException + * @return LocationData|null */ - public function indexWithGoogle($address) - { - if(!$this->googleApiKey){ - throw new Exception('Please specify your Google Api Key!', 1567771297); + public function indexByAddress(LocationData $locationData, $address){ + $geoService = $this->getServiceWithDetails($locationData->getDetails()); + if(!$geoService){ + return NULL; } - $formattedAddr = str_replace(' ','+', $address); - $uri = $this->googleBaseUri . 'geocode/json?address='.$formattedAddr.'&key='.$this->googleApiKey; - $geoData = json_decode($this->browser->request($uri)->getContent()); - - if ($geoData && array_key_exists(0, $geoData->results)) { - $this->resultData = $geoData->results[0]->geometry; - return TRUE; - } - return FALSE; + return $geoService->indexByAddress($locationData, $address); } /** - * @param $uri - * @return string - * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException + * @param $details + * @return AbstractGeoIndexingService|null */ - protected function sendRequest($uri) { - $response = $this->browser->request($uri); - return $response->getContent(); + protected function getServiceWithDetails($details){ + $geoService = NULL; + foreach($this->services as $service){ + if($service->providesDetails($details)){ + $geoService = $service; + break; + } + } + return $geoService; } /** * @param $object */ + /* public function setLocationDataOnObject($object) { if (isset($this->resultData->location->lng)) { $object->setLocationLatitude($this->resultData->location->lat); @@ -185,35 +138,5 @@ public function setLocationDataOnObject($object) { $object->setLocationLabel(''); } } - - /** - * @return float - */ - public function getLongitude() { - if (isset($this->resultData->location->lng)) { - return $this->resultData->location->lng; - } elseif (isset($this->resultData->lon)) { - return $this->resultData->lon; - } - return NULL; - } - - /** - * @return float - */ - public function getLatitude() { - if (isset($this->resultData->location->lat)) { - return $this->resultData->location->lat; - } elseif (isset($this->resultData->lat)) { - return $this->resultData->lat; - } - return NULL; - } - - /** - * @return array - */ - public function getResultData(){ - return $this->resultData; - } -} \ No newline at end of file + */ +} diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 24a4b23..75318ad 100755 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -1,10 +1,18 @@ FormatD: GeoIndexable: - geoIndexService: - nominatimBaseUri: 'http://nominatim.openstreetmap.org/' - geonamesEnable: true - geonamesBaseUri: 'http://api.geonames.org/' - geonamesUsername: '' - googleBaseUri: 'https://maps.googleapis.com/maps/api/' - googleApiKey: '' \ No newline at end of file + services: + google: + serviceClass: 'FormatD\GeoIndexable\GoogleGeoIndexableService' + options: + baseUri: 'https://maps.googleapis.com/maps/api/' + apiKey: 'ichbineinapikey' + nominatim: + serviceClass: 'FormatD\GeoIndexable\NominatimGeoIndexableService' + options: + baseUri: 'http://nominatim.openstreetmap.org/' + geonames: + serviceClass: '' + options: + baseUri: 'http://api.geonames.org/' + username: '' From 8c7b34ad4ea08557847ad65dd64e09e50dc92a08 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 23 Sep 2019 15:43:06 +0200 Subject: [PATCH 02/11] [CHANGE] Caching von $address und $result. --- Classes/Aspect/LoggingAspect.php | 2 +- Classes/Aspect/RequestCachingAspect.php | 9 +- Classes/Domain/LocationData.php | 4 +- .../Service/AbstractGeoIndexingService.php | 23 +++++- Classes/GoogleGeoIndexableService.php | 82 ++++++++++--------- Classes/NominatimGeoIndexableService.php | 77 +++++++++-------- 6 files changed, 117 insertions(+), 80 deletions(-) diff --git a/Classes/Aspect/LoggingAspect.php b/Classes/Aspect/LoggingAspect.php index f66c884..75ae83c 100644 --- a/Classes/Aspect/LoggingAspect.php +++ b/Classes/Aspect/LoggingAspect.php @@ -23,6 +23,6 @@ class LoggingAspect */ public function logIndexByAddress(JoinPointInterface $joinPoint) { $className = $joinPoint->getClassName(); - echo 'Indexing by address with class: '.$className."\n"; + // echo 'Indexing by address with class: '.$className."\n"; } } diff --git a/Classes/Aspect/RequestCachingAspect.php b/Classes/Aspect/RequestCachingAspect.php index 08d463c..7b8a520 100755 --- a/Classes/Aspect/RequestCachingAspect.php +++ b/Classes/Aspect/RequestCachingAspect.php @@ -19,13 +19,14 @@ class RequestCachingAspect { protected $requestCache; /** - * @Flow\Around("method(FormatD\GeoIndexable\Service\GeoIndexService->sendRequest(.*))") + * @Flow\Around("method(.*->getResultFromAddress(.*)) && within(FormatD\GeoIndexable\Domain\Service\AbstractGeoIndexingService)") * @param JoinPointInterface $joinPoint The current joinpoint * @return string */ - public function cacheRequests(JoinPointInterface $joinPoint) { - - $cacheIdentifier = md5($joinPoint->getMethodArgument('uri')); + public function cacheResultFromAddress(JoinPointInterface $joinPoint){ + $address = $joinPoint->getMethodArgument('address'); + $className = $joinPoint->getClassName(); + $cacheIdentifier = md5($className.'-'.$address); if ($this->requestCache->has($cacheIdentifier)) { $response = $this->requestCache->get($cacheIdentifier); diff --git a/Classes/Domain/LocationData.php b/Classes/Domain/LocationData.php index 5fe1cd5..f292845 100644 --- a/Classes/Domain/LocationData.php +++ b/Classes/Domain/LocationData.php @@ -32,7 +32,7 @@ public function getDetails(): array { */ public function getDetail($name){ if(!in_array($name, $this->getDetails())){ - throw new Exception('detail "'.$name.'" not available'); + throw new \Exception('detail "'.$name.'" not available'); } return $this->$name; } @@ -43,7 +43,7 @@ public function getDetail($name){ */ public function __set($name, $value) { if(!in_array($name, $this->getDetails())){ - throw new Exception('detail "'.$name.'" not available'); + throw new \Exception('detail "'.$name.'" not available'); } $this->$name = $value; } diff --git a/Classes/Domain/Service/AbstractGeoIndexingService.php b/Classes/Domain/Service/AbstractGeoIndexingService.php index 888048d..b427111 100644 --- a/Classes/Domain/Service/AbstractGeoIndexingService.php +++ b/Classes/Domain/Service/AbstractGeoIndexingService.php @@ -6,6 +6,7 @@ use FormatD\GeoIndexable\Domain\LocationDataDepr; use FormatD\GeoIndexable\Domain\LocationDataDetails; use FormatD\GeoIndexable\Domain\LocationDataInterface; +use FormatD\NeosUtilities\Eel\Helper\StringHelper; use Neos\Flow\Annotations as Flow; /** @@ -38,7 +39,27 @@ public function setOptions(array $options): void { * @param string $address * @return LocationData|null */ - abstract public function indexByAddress(LocationData $locationData, string $address): ?LocationData; + public function indexByAddress(LocationData $locationData, string $address): ?LocationData{ + $result = $this->getResultFromAddress($address); + return $this->setResultToLocationData($locationData, $result); + } + + /** + * Get the raw result as string for the address + * + * @param $address + * @return String + */ + abstract protected function getResultFromAddress($address): String; + + /** + * Maps the processed result to the provided LocationData-Object. Return NULL on invalid data + * + * @param $locationData + * @param $result + * @return LocationData|null + */ + abstract protected function setResultToLocationData($locationData, $result): ?LocationData; /** * @param $detail string diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php index 1845258..35f1373 100644 --- a/Classes/GoogleGeoIndexableService.php +++ b/Classes/GoogleGeoIndexableService.php @@ -11,6 +11,7 @@ use FormatD\GeoIndexable\Domain\Service\AbstractGeoIndexingService; use Neos\Flow\Http\Client\Browser; use Neos\Flow\Http\Client\CurlEngine; +use Neos\FluidAdaptor\Tests\Functional\Form\Fixtures\Domain\Model\Location; use Neos\Neos\Exception; /** @@ -47,13 +48,51 @@ public function initializeObject() { } /** - * @param LocationData $locationData - * @param string $address - * @return LocationData|null + * @param $locationData + * @param $result + * @return mixed + * @throws Exception + */ + protected function setResultToLocationData($locationData, $result): ?LocationData { + $geoData = json_decode($result); + if (!$geoData || !array_key_exists(0, $geoData)) { + return NULL; + } + $data = $geoData->results[0]; + $addressData = $this->getAddressDataFromAddressComponents($data->address_components); + + foreach($locationData->getDetails() as $detailName){ + switch ($detailName){ + case LocationDataDetails::LATITUDE: + $locationData->latitude = $data->geometry->location->lat; + break; + case LocationDataDetails::LONGITUDE: + $locationData->longitude = $data->geometry->location->lng; + break; + case LocationDataDetails::CITY: + $locationData->city = $addressData['city']; + break; + case LocationDataDetails::LABEL: + $locationData->label = $data->formatted_address; + break; + case LocationDataDetails::COUNTRY: + $locationData->country = $addressData['country']; + break; + default: + throw new Exception('detail not supported'); + break; + } + } + return $locationData; + } + + /** + * @param $address + * @return |null * @throws Exception * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException */ - public function indexByAddress(LocationData $locationData, string $address): ?LocationData { + protected function getResultFromAddress($address): String { $apiKey = $this->options['apiKey']; if(!$apiKey){ @@ -61,41 +100,10 @@ public function indexByAddress(LocationData $locationData, string $address): ?Lo } $formattedAddr = str_replace(' ','+', $address); $uri = $this->options['baseUri'].'geocode/json?address='.$formattedAddr.'&key='.$apiKey; - $geoData = json_decode($this->browser->request($uri)->getContent()); - - if ($geoData && array_key_exists(0, $geoData->results)) { - $ret = $geoData->results[0]; - - $addressData = $this->getAdressDataFromAddressComponents($ret->address_components); - - foreach($locationData->getDetails() as $detailName){ - switch ($detailName){ - case LocationDataDetails::LATITUDE: - $locationData->latitude = $ret->geometry->location->lat; - break; - case LocationDataDetails::LONGITUDE: - $locationData->longitude = $ret->geometry->location->lng; - break; - case LocationDataDetails::CITY: - $locationData->city = $addressData['city']; - break; - case LocationDataDetails::LABEL: - $locationData->label = $ret->formatted_address; - break; - case LocationDataDetails::COUNTRY: - $locationData->country = $addressData['country']; - break; - default: - throw new Exception('detail not supported'); - break; - } - } - return $locationData; - } - return NULL; + return $this->browser->request($uri)->getContent(); } - protected function getAdressDataFromAddressComponents($components){ + protected function getAddressDataFromAddressComponents($components){ $address = []; foreach($components as $component){ if(in_array('country', $component['types'])){ diff --git a/Classes/NominatimGeoIndexableService.php b/Classes/NominatimGeoIndexableService.php index 9234d78..9d77b4c 100644 --- a/Classes/NominatimGeoIndexableService.php +++ b/Classes/NominatimGeoIndexableService.php @@ -59,46 +59,53 @@ protected function sendRequest($uri){ return $response->getContent(); } - /** - * @param LocationData $locationData - * @param string $address - * @return LocationData|null + * @param $address + * @return String + * @throws \Neos\Flow\Http\Client\InfiniteRedirectionException */ - public function indexByAddress(LocationData $locationData, string $address): ?LocationData { + protected function getResultFromAddress($address): String { $uri = $this->options['baseUri'] . 'search?format=json&addressdetails=1&accept-language=en&q=' . urlencode($address); - $geoData = json_decode($this->sendRequest($uri), true); - if ($geoData && array_key_exists(0, $geoData)) { - $ret = $geoData[0]; + return $this->sendRequest($uri); + } - foreach($locationData->getDetails() as $detailName){ - switch ($detailName){ - case LocationDataDetails::LATITUDE: - $locationData->latitude = $ret['lat']; - break; - case LocationDataDetails::LONGITUDE: - $locationData->longitude = $ret['lon']; - break; - case LocationDataDetails::CITY: - $locationData->city = isset($ret['address']['city']) ? $ret['address']['city'] : $ret['address']['county']; - break; - case LocationDataDetails::LABEL: - $locationData->label = $ret['display_name']; - break; - case LocationDataDetails::COUNTRY: - $locationData->country = $ret['address']['country']; - break; - case LocationDataDetails::BOUNDINGBOX: - $locationData->boundingbox = $ret['boundingbox']; - break; - default: - throw new Exception('detail not supported'); - break; - } + /** + * @param $locationData + * @param $result + * @return LocationData|null + */ + protected function setResultToLocationData($locationData, $result): ?LocationData { + $geoData = json_decode($result, true); + if (!$geoData || !array_key_exists(0, $geoData)) { + return NULL; + } + $data = $geoData[0]; + foreach($locationData->getDetails() as $detailName){ + switch ($detailName){ + case LocationDataDetails::LATITUDE: + $locationData->latitude = $data['lat']; + break; + case LocationDataDetails::LONGITUDE: + $locationData->longitude = $data['lon']; + break; + case LocationDataDetails::CITY: + $locationData->city = isset($data['address']['city']) ? $data['address']['city'] : $data['address']['county']; + break; + case LocationDataDetails::LABEL: + $locationData->label = $data['display_name']; + break; + case LocationDataDetails::COUNTRY: + $locationData->country = $data['address']['country']; + break; + case LocationDataDetails::BOUNDINGBOX: + $locationData->boundingbox = $data['boundingbox']; + break; + default: + throw new Exception('detail not supported'); + break; } - - return $locationData; } - return NULL; + return $locationData; } + } From f968b32d9261b7c6e6bd6a513a6e4d99faf8bea8 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 24 Sep 2019 10:59:39 +0200 Subject: [PATCH 03/11] [CHANGE] LocationData Details als Array. Traits. --- Classes/Domain/LocationData.php | 37 +++-- .../Model/GeoIndexableElasticSearchTrait.php | 52 +++++++ Classes/Domain/Model/GeoIndexableTrait.php | 142 +++--------------- .../Service/AbstractGeoIndexingService.php | 2 +- Classes/GoogleGeoIndexableService.php | 17 ++- Classes/NominatimGeoIndexableService.php | 20 +-- Classes/Service/GeoIndexService.php | 54 +------ 7 files changed, 118 insertions(+), 206 deletions(-) create mode 100644 Classes/Domain/Model/GeoIndexableElasticSearchTrait.php diff --git a/Classes/Domain/LocationData.php b/Classes/Domain/LocationData.php index f292845..b975866 100644 --- a/Classes/Domain/LocationData.php +++ b/Classes/Domain/LocationData.php @@ -2,7 +2,8 @@ namespace FormatD\GeoIndexable\Domain; - +use Doctrine\ORM\Mapping as ORM; +use Neos\Flow\Annotations as Flow; class LocationData implements LocationDataDetails { @@ -16,7 +17,12 @@ class LocationData implements LocationDataDetails * @param $requiredDetails */ public function __construct($requiredDetails) { - $this->details = $requiredDetails; + //$this->details = $requiredDetails; + $this->details = array_combine($requiredDetails, array_pad([], count($requiredDetails), '')); + } + + public function getRequiredDetails(){ + return array_keys($this->getDetails()); } /** @@ -28,23 +34,28 @@ public function getDetails(): array { /** * @param $name - * @return mixed + * @return bool */ - public function getDetail($name){ - if(!in_array($name, $this->getDetails())){ - throw new \Exception('detail "'.$name.'" not available'); - } - return $this->$name; + public function hasDetail($name){ + return array_key_exists($name, $this->getDetails()); } /** * @param $name - * @param $value + * @return mixed */ - public function __set($name, $value) { - if(!in_array($name, $this->getDetails())){ - throw new \Exception('detail "'.$name.'" not available'); + public function getDetail($name){ + if(!$this->hasDetail($name)){ + return NULL; + } + return $this->details[$name]; + } + + public function setDetail($name, $value){ + if(!$this->hasDetail($name)){ + return false; } - $this->$name = $value; + $this->details[$name] = $value; + return true; } } diff --git a/Classes/Domain/Model/GeoIndexableElasticSearchTrait.php b/Classes/Domain/Model/GeoIndexableElasticSearchTrait.php new file mode 100644 index 0000000..8388505 --- /dev/null +++ b/Classes/Domain/Model/GeoIndexableElasticSearchTrait.php @@ -0,0 +1,52 @@ + xx.xxx, lon => xx.xxx] + * Be aware! After DB-Persist lat and lon are strings! + * + * @var array + * @ElasticSearch\Indexable + * @ElasticSearch\Mapping(type="geo_point") + */ + protected $locationGeoPoint = []; + + /** + * @return array + */ + public function getLocationGeoPoint() { + if (isset($this->locationGeoPoint['lat']) && $this->locationGeoPoint['lat']) { + $this->locationGeoPoint['lat'] = (float) $this->locationGeoPoint['lat']; + } + if (isset($this->locationGeoPoint['lon']) && $this->locationGeoPoint['lon']) { + $this->locationGeoPoint['lon'] = (float) $this->locationGeoPoint['lon']; + } + return $this->locationGeoPoint; + } + + /** + * @param string $locationAddress + */ + protected function onLocationChange($locationAddress){ + if (strlen($locationAddress) > 1) { + $this->geoIndexService->indexByAddress($this->locationData, $locationAddress); + if( + $this->locationData->hasDetail(LocationDataDetails::LONGITUDE) + && $this->locationData->hasDetail(LocationDataDetails::LATITUDE) + ){ + $this->locationGeoPoint['lat'] = $this->locationData->getDetail(LocationDataDetails::LATITUDE); + $this->locationGeoPoint['lon'] = $this->locationData->getDetail(LocationDataDetails::LONGITUDE); + } + } + } +} diff --git a/Classes/Domain/Model/GeoIndexableTrait.php b/Classes/Domain/Model/GeoIndexableTrait.php index abf3494..d950ca7 100755 --- a/Classes/Domain/Model/GeoIndexableTrait.php +++ b/Classes/Domain/Model/GeoIndexableTrait.php @@ -3,6 +3,8 @@ namespace FormatD\GeoIndexable\Domain\Model; use Doctrine\ORM\Mapping as ORM; +use FormatD\GeoIndexable\Domain\LocationData; +use FormatD\GeoIndexable\Domain\LocationDataDetails; use Neos\Flow\Annotations as Flow; use Flowpack\ElasticSearch\Annotations as ElasticSearch; @@ -11,50 +13,6 @@ */ trait GeoIndexableTrait { - /** - * Lat and Lon as array for elasticsearch indexing [lat => xx.xxx, lon => xx.xxx] - * Be aware! After DB-Persist lat and lon are strings! - * - * @var array - * @ElasticSearch\Indexable - * @ElasticSearch\Mapping(type="geo_point") - */ - protected $locationGeoPoint = []; - - /** - * @var string - * @ElasticSearch\Indexable - */ - protected $locationAddress = ''; - - /** - * @var float - * @ORM\Column(nullable=true) - * @ElasticSearch\Indexable - */ - protected $locationLatitude = NULL; - - /** - * @var float - * @ORM\Column(nullable=true) - * @ElasticSearch\Indexable - */ - protected $locationLongitude = NULL; - - /** - * @var string - * @ElasticSearch\Indexable - */ - protected $locationLabel = ''; - - /** - * @var string - * @ORM\Column(nullable=true) - * @ElasticSearch\Indexable - */ - protected $locationTimezone = NULL; - - /** * @Flow\Inject * @var \FormatD\GeoIndexable\Service\GeoIndexService @@ -62,107 +20,47 @@ trait GeoIndexableTrait { protected $geoIndexService; /** - * @return array - */ - public function getLocationGeoPoint() { - if (isset($this->locationGeoPoint['lat']) && $this->locationGeoPoint['lat']) { - $this->locationGeoPoint['lat'] = (float) $this->locationGeoPoint['lat']; - } - if (isset($this->locationGeoPoint['lon']) && $this->locationGeoPoint['lon']) { - $this->locationGeoPoint['lon'] = (float) $this->locationGeoPoint['lon']; - } - return $this->locationGeoPoint; - } - - /** - * @return string - */ - public function getLocationAddress() { - return $this->locationAddress; - } - - /** - * @param string $locationAddress + * @var LocationData + * @ORM\Column(type="object") */ - public function setLocationAddress($locationAddress) { - $this->onLocationChange($locationAddress); - $this->locationAddress = $locationAddress; - } + protected $locationData; /** - * @return float - */ - public function getLocationLatitude() { - return $this->locationLatitude; - } - - /** - * @param float $locationLatitude - */ - public function setLocationLatitude($locationLatitude) { - $this->locationGeoPoint['lat'] = $locationLatitude; - $this->locationLatitude = $locationLatitude; - } - - /** - * @return float - */ - public function getLocationLongitude() { - return $this->locationLongitude; - } - - /** - * @param float $locationLongitude + * @var string */ - public function setLocationLongitude($locationLongitude) { - $this->locationGeoPoint['lon'] = $locationLongitude; - $this->locationLongitude = $locationLongitude; - } + protected $locationAddress = ''; /** * @return string */ - public function getLocationLabel() { - return $this->locationLabel; - } - - /** - * @param string $locationLabel - */ - public function setLocationLabel($locationLabel) { - $this->locationLabel = $locationLabel; + public function getLocationAddress() { + return $this->locationAddress; } - /** - * @return string - */ - public function getLocationTimezone() { - return $this->locationTimezone; + public function setLocationDataDetails($details){ + $this->locationData = new LocationData($details); } /** - * @param string $locationTimezone + * @param $locationAddress + * @param bool $skipIndexing */ - public function setLocationTimezone($locationTimezone) { - $this->locationTimezone = $locationTimezone; + public function setLocationAddress($locationAddress, $skipIndexing = false) { + $this->locationAddress = $locationAddress; + if(!$skipIndexing){ + $this->onLocationChange($locationAddress); + } } - /** * @param string $locationAddress */ protected function onLocationChange($locationAddress){ if (strlen($locationAddress) > 1) { - $this->geoIndexService->indexAddress($locationAddress); - $this->geoIndexService->setLocationDataOnObject($this); - } else { - $this->setLocationLabel(''); - $this->setLocationLatitude(NULL); - $this->setLocationLongitude(NULL); - $this->setLocationTimezone(NULL); + $this->geoIndexService->indexByAddress($this->locationData, $locationAddress); } } } -?> \ No newline at end of file +?> diff --git a/Classes/Domain/Service/AbstractGeoIndexingService.php b/Classes/Domain/Service/AbstractGeoIndexingService.php index b427111..0192306 100644 --- a/Classes/Domain/Service/AbstractGeoIndexingService.php +++ b/Classes/Domain/Service/AbstractGeoIndexingService.php @@ -59,7 +59,7 @@ abstract protected function getResultFromAddress($address): String; * @param $result * @return LocationData|null */ - abstract protected function setResultToLocationData($locationData, $result): ?LocationData; + abstract protected function setResultToLocationData(LocationData $locationData, $result): ?LocationData; /** * @param $detail string diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php index 35f1373..fcabdf1 100644 --- a/Classes/GoogleGeoIndexableService.php +++ b/Classes/GoogleGeoIndexableService.php @@ -53,7 +53,7 @@ public function initializeObject() { * @return mixed * @throws Exception */ - protected function setResultToLocationData($locationData, $result): ?LocationData { + protected function setResultToLocationData(LocationData $locationData, $result): ?LocationData { $geoData = json_decode($result); if (!$geoData || !array_key_exists(0, $geoData)) { return NULL; @@ -61,25 +61,26 @@ protected function setResultToLocationData($locationData, $result): ?LocationDat $data = $geoData->results[0]; $addressData = $this->getAddressDataFromAddressComponents($data->address_components); - foreach($locationData->getDetails() as $detailName){ + foreach($locationData->getRequiredDetails() as $detailName){ switch ($detailName){ case LocationDataDetails::LATITUDE: - $locationData->latitude = $data->geometry->location->lat; + $locationData->setDetail($detailName, $data->geometry->location->lat); break; case LocationDataDetails::LONGITUDE: - $locationData->longitude = $data->geometry->location->lng; + $locationData->setDetail($detailName, $data->geometry->location->lng); break; case LocationDataDetails::CITY: - $locationData->city = $addressData['city']; + $locationData->setDetail($detailName, $addressData['city']); break; case LocationDataDetails::LABEL: - $locationData->label = $data->formatted_address; + $locationData->setDetail($detailName, $data->formatted_address); break; case LocationDataDetails::COUNTRY: - $locationData->country = $addressData['country']; + $locationData->setDetail($detailName, $addressData['country']); break; default: - throw new Exception('detail not supported'); + echo "Detail '".$detailName."' not supported\n"; + return NULL; break; } } diff --git a/Classes/NominatimGeoIndexableService.php b/Classes/NominatimGeoIndexableService.php index 9d77b4c..e948201 100644 --- a/Classes/NominatimGeoIndexableService.php +++ b/Classes/NominatimGeoIndexableService.php @@ -74,34 +74,36 @@ protected function getResultFromAddress($address): String { * @param $result * @return LocationData|null */ - protected function setResultToLocationData($locationData, $result): ?LocationData { + protected function setResultToLocationData(LocationData $locationData, $result): ?LocationData { $geoData = json_decode($result, true); if (!$geoData || !array_key_exists(0, $geoData)) { return NULL; } $data = $geoData[0]; - foreach($locationData->getDetails() as $detailName){ + foreach($locationData->getRequiredDetails() as $detailName){ switch ($detailName){ case LocationDataDetails::LATITUDE: - $locationData->latitude = $data['lat']; + $locationData->setDetail($detailName, $data['lat']); break; case LocationDataDetails::LONGITUDE: - $locationData->longitude = $data['lon']; + $locationData->setDetail($detailName, $data['lon']); break; case LocationDataDetails::CITY: - $locationData->city = isset($data['address']['city']) ? $data['address']['city'] : $data['address']['county']; + $value = isset($data['address']['city']) ? $data['address']['city'] : $data['address']['county']; + $locationData->setDetail($detailName, $value); break; case LocationDataDetails::LABEL: - $locationData->label = $data['display_name']; + $locationData->setDetail($detailName, $data['display_name']); break; case LocationDataDetails::COUNTRY: - $locationData->country = $data['address']['country']; + $locationData->setDetail($detailName, $data['address']['country']); break; case LocationDataDetails::BOUNDINGBOX: - $locationData->boundingbox = $data['boundingbox']; + $locationData->setDetail($detailName, $data['boundingbox']); break; default: - throw new Exception('detail not supported'); + echo "Detail '".$detailName."' not supported\n"; + return NULL; break; } } diff --git a/Classes/Service/GeoIndexService.php b/Classes/Service/GeoIndexService.php index 506998d..c85e298 100755 --- a/Classes/Service/GeoIndexService.php +++ b/Classes/Service/GeoIndexService.php @@ -23,25 +23,6 @@ class GeoIndexService { */ protected $configurationManager; - /** - * @Flow\Inject - * @var \Neos\Flow\Http\Client\Browser - */ - protected $browser; - - /** - * @Flow\Inject - * @var \Neos\Flow\Http\Client\CurlEngine - */ - protected $requestEngine; - - /** - * The result of last index-call - * - * @var array - */ - protected $resultData = NULL; - /** * @var array */ @@ -64,9 +45,6 @@ public function __construct(\Neos\Flow\ObjectManagement\ObjectManagerInterface $ * init node context */ public function initializeObject() { - $this->requestEngine->setOption(CURLOPT_TIMEOUT, 15); - $this->browser->setRequestEngine($this->requestEngine); - $conf = $this->configurationManager->getConfiguration(\Neos\Flow\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'FormatD.GeoIndexable'); //TODO: check yaml felder if NULL etc. @@ -87,7 +65,7 @@ public function initializeObject() { * @return LocationData|null */ public function indexByAddress(LocationData $locationData, $address){ - $geoService = $this->getServiceWithDetails($locationData->getDetails()); + $geoService = $this->getServiceWithDetails($locationData->getRequiredDetails()); if(!$geoService){ return NULL; } @@ -109,34 +87,4 @@ protected function getServiceWithDetails($details){ return $geoService; } - /** - * @param $object - */ - /* - public function setLocationDataOnObject($object) { - if (isset($this->resultData->location->lng)) { - $object->setLocationLatitude($this->resultData->location->lat); - $object->setLocationLongitude($this->resultData->location->lng); - } - - // Nominatim - if (isset($this->resultData->lon)) { - $object->setLocationLatitude($this->resultData->lat); - $object->setLocationLongitude($this->resultData->lon); - if (isset($this->resultData->timezone) && $this->resultData->timezone) { - $object->setLocationTimezone($this->resultData->timezone); - } - } - if (isset($this->resultData->address)) { - $object->setLocationLabel( - (isset($this->resultData->address->city) ? $this->resultData->address->city . ', ' : - (isset($this->resultData->address->town) ? $this->resultData->address->town . ', ' : - (isset($this->resultData->address->village) ? $this->resultData->address->village . ', ' : ''))) - . $this->resultData->address->country - ); - } else { - $object->setLocationLabel(''); - } - } - */ } From 7ed1af849103ad0836e8d7f01fb87c5db34b1323 Mon Sep 17 00:00:00 2001 From: Benno Weinzierl Date: Fri, 8 Nov 2019 15:38:05 +0100 Subject: [PATCH 04/11] [FEATURE] Enable potentially used services via configuration --- Classes/Domain/Model/GeoIndexableTrait.php | 32 ++++++++++++++++------ Classes/Service/GeoIndexService.php | 2 +- Configuration/Settings.yaml | 3 ++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Classes/Domain/Model/GeoIndexableTrait.php b/Classes/Domain/Model/GeoIndexableTrait.php index d950ca7..88f5140 100755 --- a/Classes/Domain/Model/GeoIndexableTrait.php +++ b/Classes/Domain/Model/GeoIndexableTrait.php @@ -30,6 +30,13 @@ trait GeoIndexableTrait { */ protected $locationAddress = ''; + /** + * @param array $details + */ + public function setLocationDataDetails($details) { + $this->locationData = new LocationData($details); + } + /** * @return string */ @@ -37,25 +44,34 @@ public function getLocationAddress() { return $this->locationAddress; } - public function setLocationDataDetails($details){ - $this->locationData = new LocationData($details); - } - /** - * @param $locationAddress + * @param string $locationAddress * @param bool $skipIndexing */ public function setLocationAddress($locationAddress, $skipIndexing = false) { - $this->locationAddress = $locationAddress; - if(!$skipIndexing){ + $this->setLocationDataDetails([LocationDataDetails::LATITUDE, LocationDataDetails::LONGITUDE]); + + if ($this->locationAddress === $locationAddress) { + $skipIndexing = true; + } else { + $this->locationAddress = $locationAddress; + } + if (!$skipIndexing) { $this->onLocationChange($locationAddress); } } + /** + * @return LocationData + */ + public function getLocationData() { + return $this->locationData; + } + /** * @param string $locationAddress */ - protected function onLocationChange($locationAddress){ + protected function onLocationChange($locationAddress) { if (strlen($locationAddress) > 1) { $this->geoIndexService->indexByAddress($this->locationData, $locationAddress); } diff --git a/Classes/Service/GeoIndexService.php b/Classes/Service/GeoIndexService.php index c85e298..bb291fa 100755 --- a/Classes/Service/GeoIndexService.php +++ b/Classes/Service/GeoIndexService.php @@ -50,7 +50,7 @@ public function initializeObject() { foreach($conf['services'] as $serviceName=>$serviceConf){ $serviceClass = $serviceConf['serviceClass']; - if(class_exists($serviceClass)){ + if($serviceConf['enabled'] && class_exists($serviceClass)){ $this->services[$serviceName] = $this->objectManager->get($serviceClass); $this->services[$serviceName]->setOptions($serviceConf['options']); }else{ diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 75318ad..abd5bf1 100755 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -3,15 +3,18 @@ FormatD: GeoIndexable: services: google: + enabled: false serviceClass: 'FormatD\GeoIndexable\GoogleGeoIndexableService' options: baseUri: 'https://maps.googleapis.com/maps/api/' apiKey: 'ichbineinapikey' nominatim: + enabled: true serviceClass: 'FormatD\GeoIndexable\NominatimGeoIndexableService' options: baseUri: 'http://nominatim.openstreetmap.org/' geonames: + enabled: false serviceClass: '' options: baseUri: 'http://api.geonames.org/' From cc85c749a2d62706dca1580eb1c3e13fda9d9e48 Mon Sep 17 00:00:00 2001 From: Sabrina Sauter Date: Fri, 29 Nov 2019 19:59:21 +0100 Subject: [PATCH 05/11] [BUGFIX] Method for retrieving response body changed. --- Classes/GoogleGeoIndexableService.php | 2 +- Classes/NominatimGeoIndexableService.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php index fcabdf1..8d29b21 100644 --- a/Classes/GoogleGeoIndexableService.php +++ b/Classes/GoogleGeoIndexableService.php @@ -101,7 +101,7 @@ protected function getResultFromAddress($address): String { } $formattedAddr = str_replace(' ','+', $address); $uri = $this->options['baseUri'].'geocode/json?address='.$formattedAddr.'&key='.$apiKey; - return $this->browser->request($uri)->getContent(); + return $this->browser->request($uri)->getBody()->getContents(); } protected function getAddressDataFromAddressComponents($components){ diff --git a/Classes/NominatimGeoIndexableService.php b/Classes/NominatimGeoIndexableService.php index e948201..ac76678 100644 --- a/Classes/NominatimGeoIndexableService.php +++ b/Classes/NominatimGeoIndexableService.php @@ -56,7 +56,7 @@ public function initializeObject() { */ protected function sendRequest($uri){ $response = $this->browser->request($uri); - return $response->getContent(); + return $response->getBody()->getContents(); } /** From e130dba2e16f780e912a0d2677d16bca2724deaf Mon Sep 17 00:00:00 2001 From: Benno Weinzierl Date: Thu, 15 Oct 2020 15:28:21 +0200 Subject: [PATCH 06/11] [FIX] A bit of cleanup --- Classes/Domain/LocationData.php | 17 +++++++++++++---- Classes/Domain/LocationDataDetails.php | 6 +++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Classes/Domain/LocationData.php b/Classes/Domain/LocationData.php index b975866..53fe22e 100644 --- a/Classes/Domain/LocationData.php +++ b/Classes/Domain/LocationData.php @@ -5,6 +5,9 @@ use Doctrine\ORM\Mapping as ORM; use Neos\Flow\Annotations as Flow; +/** + * @Flow\Scope("prototype") + */ class LocationData implements LocationDataDetails { /** @@ -13,14 +16,15 @@ class LocationData implements LocationDataDetails protected $details; /** - * LocationData constructor. - * @param $requiredDetails + * @param array $requiredDetails */ public function __construct($requiredDetails) { - //$this->details = $requiredDetails; $this->details = array_combine($requiredDetails, array_pad([], count($requiredDetails), '')); } + /** + * @return array + */ public function getRequiredDetails(){ return array_keys($this->getDetails()); } @@ -33,7 +37,7 @@ public function getDetails(): array { } /** - * @param $name + * @param string $name * @return bool */ public function hasDetail($name){ @@ -51,6 +55,11 @@ public function getDetail($name){ return $this->details[$name]; } + /** + * @param string $name + * @param mixed $value + * @return bool (true if successful and false if no detail was found) + */ public function setDetail($name, $value){ if(!$this->hasDetail($name)){ return false; diff --git a/Classes/Domain/LocationDataDetails.php b/Classes/Domain/LocationDataDetails.php index 67db16a..0b697e7 100644 --- a/Classes/Domain/LocationDataDetails.php +++ b/Classes/Domain/LocationDataDetails.php @@ -1,9 +1,9 @@ Date: Fri, 6 May 2022 09:04:46 +0200 Subject: [PATCH 07/11] [CHANGE] Make sure Google geo data result gets processed as an array. --- Classes/GoogleGeoIndexableService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php index 8d29b21..566f390 100644 --- a/Classes/GoogleGeoIndexableService.php +++ b/Classes/GoogleGeoIndexableService.php @@ -54,7 +54,7 @@ public function initializeObject() { * @throws Exception */ protected function setResultToLocationData(LocationData $locationData, $result): ?LocationData { - $geoData = json_decode($result); + $geoData = json_decode($result, true); if (!$geoData || !array_key_exists(0, $geoData)) { return NULL; } From 66f39d3fbfc655e56200879de2397d37e82bd5ea Mon Sep 17 00:00:00 2001 From: Benno Weinzierl Date: Tue, 28 Feb 2023 14:56:08 +0100 Subject: [PATCH 08/11] fix: bug in google geoindex response parsing google does not respond with a numeric array like nominatim does. Why this worked in the past may be due to the behaviour of array_key_exists pre 8.1 --- Classes/GoogleGeoIndexableService.php | 6 +++--- Classes/NominatimGeoIndexableService.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php index 566f390..33b9738 100644 --- a/Classes/GoogleGeoIndexableService.php +++ b/Classes/GoogleGeoIndexableService.php @@ -55,13 +55,13 @@ public function initializeObject() { */ protected function setResultToLocationData(LocationData $locationData, $result): ?LocationData { $geoData = json_decode($result, true); - if (!$geoData || !array_key_exists(0, $geoData)) { + if (!$geoData || !array_key_exists('status', $geoData) || $geoData['status'] !== 'OK') { return NULL; } $data = $geoData->results[0]; $addressData = $this->getAddressDataFromAddressComponents($data->address_components); - foreach($locationData->getRequiredDetails() as $detailName){ + foreach($locationData->getRequiredDetails() as $detailName) { switch ($detailName){ case LocationDataDetails::LATITUDE: $locationData->setDetail($detailName, $data->geometry->location->lat); @@ -104,7 +104,7 @@ protected function getResultFromAddress($address): String { return $this->browser->request($uri)->getBody()->getContents(); } - protected function getAddressDataFromAddressComponents($components){ + protected function getAddressDataFromAddressComponents($components) { $address = []; foreach($components as $component){ if(in_array('country', $component['types'])){ diff --git a/Classes/NominatimGeoIndexableService.php b/Classes/NominatimGeoIndexableService.php index ac76678..c6f1a4c 100644 --- a/Classes/NominatimGeoIndexableService.php +++ b/Classes/NominatimGeoIndexableService.php @@ -80,7 +80,7 @@ protected function setResultToLocationData(LocationData $locationData, $result): return NULL; } $data = $geoData[0]; - foreach($locationData->getRequiredDetails() as $detailName){ + foreach($locationData->getRequiredDetails() as $detailName) { switch ($detailName){ case LocationDataDetails::LATITUDE: $locationData->setDetail($detailName, $data['lat']); From 7e6661e1f90aec9379be7faf8fde0609f441b9f2 Mon Sep 17 00:00:00 2001 From: Benno Weinzierl Date: Tue, 28 Feb 2023 15:59:58 +0100 Subject: [PATCH 09/11] fix: additional incompatibilities in google api response structure --- Classes/GoogleGeoIndexableService.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Classes/GoogleGeoIndexableService.php b/Classes/GoogleGeoIndexableService.php index 33b9738..27ae0d7 100644 --- a/Classes/GoogleGeoIndexableService.php +++ b/Classes/GoogleGeoIndexableService.php @@ -54,13 +54,12 @@ public function initializeObject() { * @throws Exception */ protected function setResultToLocationData(LocationData $locationData, $result): ?LocationData { - $geoData = json_decode($result, true); - if (!$geoData || !array_key_exists('status', $geoData) || $geoData['status'] !== 'OK') { + $geoData = json_decode($result); + if (!$geoData || !isset($geoData->status) || $geoData->status !== 'OK') { return NULL; } $data = $geoData->results[0]; $addressData = $this->getAddressDataFromAddressComponents($data->address_components); - foreach($locationData->getRequiredDetails() as $detailName) { switch ($detailName){ case LocationDataDetails::LATITUDE: @@ -106,9 +105,9 @@ protected function getResultFromAddress($address): String { protected function getAddressDataFromAddressComponents($components) { $address = []; - foreach($components as $component){ - if(in_array('country', $component['types'])){ - $address['country'] = $component['long_name']; + foreach ($components as $component) { + if (in_array('country', $component->types)) { + $address['country'] = $component->long_name; } } return $address; From 398e25271a28338fdb8b8f54e8c1d786ebe647b4 Mon Sep 17 00:00:00 2001 From: Benno Weinzierl Date: Tue, 28 Feb 2023 16:24:29 +0100 Subject: [PATCH 10/11] chore: added neos flow requirements to composer.json --- README.md | 19 +++++++++++++++++++ composer.json | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ada76b..32f02b7 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,25 @@ This package provides a service class for geo-indexing addresses. Also a php tra This trait can be used to create a domain model that automatically fetches the geo location when the address is changed. +## Compatibility + +Versioning scheme: + + 1.0.0 + | | | + | | Bugfix Releases (non breaking) + | Neos Compatibility Releases (non breaking except framework dependencies) + Feature Releases (breaking) + +Releases und compatibility: + +| Package-Version | Neos Framework Version | +|-----------------|------------------------| +| 1.0.x | deprecated | +| 1.1.x | deprecated | +| 2.0.x | 5.x, 6.x, 7.x, 8.x | + + ## Configuration Provide the geonames username (that you have to create on the geonames website) or deactivate the geonames api diff --git a/composer.json b/composer.json index 62e4bb3..e87921d 100755 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "neos-package", "license": "MIT", "require": { - "neos/flow": "*", + "neos/flow": "^5.0 || ^6.0 || ^7.0 || ^8.0", "flowpack/elasticsearch": ">=2.0" }, "suggest": { From d560912f2546f59acee8b64991e7e0fc2cb31382 Mon Sep 17 00:00:00 2001 From: Benno Weinzierl Date: Tue, 28 Feb 2023 16:42:15 +0100 Subject: [PATCH 11/11] docu: changed documentation to reflect new settings structure --- README.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 32f02b7..cc85e62 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ but you can use Google API, too. ## What does it do? -This package provides a service class for geo-indexing addresses. Also a php trait to use in domain models is contained. +This package provides a service class for geo-indexing addresses. Also a php trait to use in domain models is provided. This trait can be used to create a domain model that automatically fetches the geo location when the address is changed. @@ -37,15 +37,23 @@ Provide the geonames username (that you have to create on the geonames website) ``` FormatD: GeoIndexable: - geoIndexService: - geonamesEnable: true - geonamesUsername: '' + services: + geonames: + enabled: true + options: + username: '' ``` In case you want to use the Google API, you have to provide your API Key ``` FormatD: GeoIndexable: - geoIndexService: - googleApiKey: '' -``` \ No newline at end of file + services: + google: + enabled: false + options: + apiKey: 'ichbineinapikey' +``` + + +