diff --git a/config/schema/geocoder.schema.yml b/config/schema/geocoder.schema.yml index f0b4ce6..6516759 100644 --- a/config/schema/geocoder.schema.yml +++ b/config/schema/geocoder.schema.yml @@ -106,6 +106,22 @@ geocoder_provider.configuration.arcgisonline: label: 'Source country for country biasing (optional)' nullable: true +geocoder_provider.configuration.arcgistoken: + type: geocoder_provider_configuration + label: 'ArcGIS Online token credentials' + mapping: + client_id: + type: string + label: 'Client ID' + description: 'Authenticate a request to the ArcGIS World Geocoding Service' + client_secret: + type: string + label: 'Client Secret' + sourceCountry: + type: string + label: 'Source country for country biasing (optional)' + nullable: true + geocoder_provider.configuration.bingmaps: type: geocoder_provider_configuration label: 'Bingmaps arguments' diff --git a/src/Plugin/Geocoder/Provider/ArcGISOnlineToken.php b/src/Plugin/Geocoder/Provider/ArcGISOnlineToken.php new file mode 100644 index 0000000..6d9dd60 --- /dev/null +++ b/src/Plugin/Geocoder/Provider/ArcGISOnlineToken.php @@ -0,0 +1,106 @@ +handler === NULL) { + $token = $this->getToken( + $this->configuration['client_id'], + $this->configuration['client_secret'] + ); + if (!$token) { + throw new InvalidCredentials('Token authentication failed.'); + } + $this->handler = ArcGISOnline::token( + $this->httpAdapter, + $token, + $this->configuration['sourceCountry'] + ); + } + return $this->handler; + } + + /** + * Get a new or stored token for authenticating to the ArcGIS service. + */ + private function getToken($client_id, $client_secret) { + // If the token is cached and not expired, return it. + $cache = \Drupal::cache()->get('arcgis-online-token'); + if ($cache && $cache->expire > time()) { + return $cache->data; + } + + // Get a new token. + + // Inform the user if the token requesting credentials are missing. + if (!$client_id || !$client_secret) { + $num = (!$client_id && !$client_secret) ? 'Both' : 'One of the'; + $errors = [ + "{$num} token authentication credentials are missing.", + 'Please contact a developer to have this addressed.' + ]; + \Drupal::messenger()->addError(implode(' ', $errors)); + return FALSE; + } + // Parameters for the authentication endpoint. + $query = http_build_query([ + 'client_id' => $client_id, + 'grant_type' => 'client_credentials', + 'client_secret' => $client_secret, + 'f' => 'json', + ]); + $url = "https://www.arcgis.com/sharing/oauth2/token?{$query}"; + try { + // Query the endpoint. + $response = \Drupal::httpClient() + ->get($url, ['headers' => ['Accept' => 'text/plain']]); + $data = (string) $response->getBody(); + if (empty($data)) { + \Drupal::messenger()->addError('No query response detected.'); + return FALSE; + } + // Decode the JSON response. + $json = \Drupal\Component\Serialization\Json::decode($data); + if (!isset($json['access_token']) || !isset($json['expires_in'])) { + \Drupal::messenger()->addError('Incomplete token received.'); + return FALSE; + } + // Set the cache. + \Drupal::cache()->set( + 'arcgis-online-token', + $json['access_token'], + REQUEST_TIME + intval($json['expires_in']) + ); + // Return the token. + return $json['access_token']; + } + catch (RequestException $e) { + \Drupal::messenger()->addError('An error occurred during the request.'); + return FALSE; + } + } + +}