diff --git a/CHANGELOG.md b/CHANGELOG.md index ffbab9d..7400263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +* [PR-32](https://github.com/OS2web/os2web_datalookup/pull/32) + Adding Datafordeler address lookup + ## [3.1.0] - 2026-04-27 * [PR-29](https://github.com/OS2web/os2web_datalookup/pull/29) diff --git a/src/LookupResult/AddressLookupResult.php b/src/LookupResult/AddressLookupResult.php new file mode 100644 index 0000000..22ec355 --- /dev/null +++ b/src/LookupResult/AddressLookupResult.php @@ -0,0 +1,361 @@ +successful; + } + + /** + * Set state of successfulness. + * + * @param bool $successful + * The state. + */ + public function setSuccessful(bool $successful = TRUE): void { + $this->successful = $successful; + } + + /** + * Get an error message. + * + * @return string + * The message. + */ + public function getErrorMessage(): string { + return $this->errorMessage; + } + + /** + * Set error message. + * + * @param string $errorMessage + * The message. + */ + public function setErrorMessage(string $errorMessage): void { + $this->errorMessage = $errorMessage; + } + + /** + * Get ID. + * + * @return string + * The ID number. + */ + public function getId(): string { + return $this->id; + } + + /** + * Set ID. + * + * @param string $id + * ID number. + */ + public function setId(string $id): void { + $this->id = $id; + } + + /** + * Get house ID. + * + * @return string + * Access id number. + */ + public function getHouseId(): string { + return $this->houseId; + } + + /** + * Sets house ID. + * + * @param string $houseId + * Access id number. + */ + public function setHouseId(string $houseId): void { + $this->houseId = $houseId; + } + + /** + * Get full address. + * + * @return string + * The full address. + */ + public function getFullAddress(): string { + return $this->fullAddress; + } + + /** + * Set full address. + * + * @param string $fullAddress + * The full address. + */ + public function setFullAddress(string $fullAddress): void { + $this->fullAddress = $fullAddress; + } + + /** + * Get street. + * + * @return string + * The street. + */ + public function getStreet(): string { + return $this->street; + } + + /** + * Set street. + * + * @param string $street + * The street. + */ + public function setStreet(string $street): void { + $this->street = $street; + } + + /** + * Get house number. + * + * @return string + * The number. + */ + public function getHouseNr(): string { + return $this->houseNr; + } + + /** + * Set house number. + * + * @param string $houseNr + * The number. + */ + public function setHouseNr(string $houseNr): void { + $this->houseNr = $houseNr; + } + + /** + * Get floor. + * + * @return string + * The floor. + */ + public function getFloor(): string { + return $this->floor; + } + + /** + * Set floor. + * + * @param string $floor + * The floor. + */ + public function setFloor(string $floor): void { + $this->floor = $floor; + } + + /** + * Get apartment number. + * + * @return string + * The number. + */ + public function getApartmentNr(): string { + return $this->apartmentNr; + } + + /** + * Set apartment number. + * + * @param string $apartmentNr + * The number. + */ + public function setApartmentNr(string $apartmentNr): void { + $this->apartmentNr = $apartmentNr; + } + + /** + * Get postal code. + * + * @return string + * The code. + */ + public function getPostalCode(): string { + return $this->postalCode; + } + + /** + * Set postal code. + * + * @param string $postalCode + * The code. + */ + public function setPostalCode(string $postalCode): void { + $this->postalCode = $postalCode; + } + + /** + * Get city name. + * + * @return string + * The city name. + */ + public function getCity(): string { + return $this->city; + } + + /** + * Set city. + * + * @param string $city + * The city name. + */ + public function setCity(string $city): void { + $this->city = $city; + } + + /** + * Get municipality code. + * + * @return string + * The code. + */ + public function getMunicipalityCode(): string { + return $this->municipalityCode; + } + + /** + * Set municipality code. + * + * @param string $municipalityCode + * The municipality code. + */ + public function setMunicipalityCode(string $municipalityCode): void { + $this->municipalityCode = $municipalityCode; + } + + /** + * Set supplementary locality / village name. + * + * @param string $supplementaryCity + * Supplementary city name. + */ + public function setSupplementaryCity(string $supplementaryCity): void { + $this->supplementaryCity = $supplementaryCity; + } + + /** + * Get supplementary locality / village name. + * + * @return string + * Supplementary city name. + */ + public function getSupplementaryCity(): string { + return $this->supplementaryCity; + } + +} diff --git a/src/LookupResult/MatrikulaLookupResult.php b/src/LookupResult/MatrikulaLookupResult.php new file mode 100644 index 0000000..80b91d9 --- /dev/null +++ b/src/LookupResult/MatrikulaLookupResult.php @@ -0,0 +1,95 @@ +ownerLicenseCode = $ownerLicenseCode; + } + + /** + * Returns owner license code. + * + * @return string + * Owners license code. + */ + public function getOwnerLicenseCode(): string { + return $this->ownerLicenseCode; + } + + /** + * Sets ownership name. + * + * @param string $ownershipName + * Ownership name. + */ + public function setOwnershipName(string $ownershipName): void { + $this->ownershipName = $ownershipName; + } + + /** + * Returns ownership name. + * + * @return string + * Ownership name. + */ + public function getOwnershipName(): string { + return $this->ownershipName; + } + + /** + * Sets matrikula number. + * + * @param string $matrikulaNumber + * Matrikula number. + */ + public function setMatrikulaNumber(string $matrikulaNumber): void { + $this->matrikulaNumber = $matrikulaNumber; + } + + /** + * Returns matrikula number. + * + * @return string + * Matrikula number. + */ + public function getMatrikulaNumber(): string { + return $this->matrikulaNumber; + } + +} diff --git a/src/Plugin/os2web/DataLookup/DatafordelerAddressLookup.php b/src/Plugin/os2web/DataLookup/DatafordelerAddressLookup.php new file mode 100644 index 0000000..af222af --- /dev/null +++ b/src/Plugin/os2web/DataLookup/DatafordelerAddressLookup.php @@ -0,0 +1,227 @@ +get('os2web_audit.logger'); + /** @var \Drupal\key\KeyRepositoryInterface $keyRepository */ + $keyRepository = $container->get('key.repository'); + /** @var \Drupal\Core\File\FileSystem $fileSystem */ + $fileSystem = $container->get('file_system'); + + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('http_client'), + $auditLogger, + $keyRepository, + $fileSystem, + ); + } + + /** + * {@inheritdoc} + */ + public function getAddressMatches(ParameterBag $params, $fetchColumn = 'titel') : array { + $token = $this->getConfiguration()['token']; + $url = "https://adressevaelger.dk/adresser/soeg"; + + // Get autocomplete query. + $q = $params->get('q') ?: ''; + // Adding limit by municipality limit, if present. + $limitByMunicipality = $params->get('limit_by_municipality') ?: ''; + + $query = [ + 'token' => $token, + 'tekst' => $q, + ]; + + if (!empty($limitByMunicipality)) { + $query['kommunekode'] = $limitByMunicipality; + } + + try { + $json = $this->httpClient->request('GET', $url, [ + 'query' => $query, + ])->getBody(); + } + catch (GuzzleException $e) { + \Drupal::logger('os2web_datalookup')->warning('Request failed: @e', ['@e' => $e->getMessage()]); + return []; + } + + $jsonDecoded = json_decode($json, TRUE); + $addresses = []; + if (is_array($jsonDecoded) && !empty($jsonDecoded['fund'])) { + $addresses = $jsonDecoded['fund']; + } + + if ($fetchColumn) { + // Checking if remove_place_name is enabled. + $removePlaceName = $params->get('remove_place_name') ?: ''; + if ($removePlaceName) { + foreach ($addresses as &$entry) { + $addressId = $entry['id']; + + $address = $this->fetchAddressLookupResult($addressId); + if ($supplerendebynavn = $address->getSupplementaryCity()) { + $entry['titel'] = preg_replace("/$supplerendebynavn,/", '', $entry['titel']); + } + } + } + + $matches = array_column($addresses, $fetchColumn); + } + else { + $matches = $addresses; + } + + return $matches; + } + + /** + * {@inheritdoc} + */ + public function getSingleAddress(ParameterBag $params) : ?AddressLookupResult { + $address = NULL; + + // Getting address_id. + $matches = $this->getAddressMatches($params, NULL); + if (!empty($matches)) { + $addressSource = $matches[0]; + + // Fetching address. + $address = $this->fetchAddressLookupResult($addressSource['id']); + } + + return $address; + } + + /** + * Returns single address from address API. + * + * @param string $id + * ID of the address. + * + * @return \Drupal\os2web_datalookup\LookupResult\AddressLookupResult + * The found address. + */ + public function fetchAddressLookupResult($id) { + $token = $this->getConfiguration()['token']; + $url = "https://adressevaelger.dk/adresser/$id"; + + $address = new AddressLookupResult(); + $address->setSuccessful(FALSE); + + // Fetching address. + try { + $json = $this->httpClient->request('GET', $url, [ + 'query' => [ + 'token' => $token, + ], + ])->getBody(); + } + catch (GuzzleException $e) { + \Drupal::logger('os2web_datalookup')->warning('Request failed: @e', ['@e' => $e->getMessage()]); + return $address; + } + + $jsonDecoded = json_decode($json, TRUE); + if (is_array($jsonDecoded) && !empty($jsonDecoded)) { + if ($jsonDecoded['status'] === 'ok') { + $address->setSuccessful(); + + $address_raw = $jsonDecoded['adresse']; + $address->setId($address_raw['id_lokalid']); + $address->setHouseId($address_raw['husnummer']['id_lokalid']); + $address->setFullAddress($address_raw['adressebetegnelse']); + + $address->setStreet($address_raw['husnummer']['vejnavn'] ?? ''); + $address->setHouseNr($address_raw['husnummer']['husnummertekst'] ?? ''); + $address->setFloor($address_raw['etagebetegnelse'] ?? ''); + $address->setApartmentNr($address_raw['doerbetegnelse'] ?? ''); + $address->setPostalCode($address_raw['husnummer']['postnummer']['postnr'] ?? ''); + $address->setCity($address_raw['husnummer']['postnummer']['navn'] ?? ''); + $address->setMunicipalityCode($address_raw['husnummer']['navngivenvejkommunedel']['kommune'] ?? ''); + $address->setSupplementaryCity($address_raw['husnummer']['supplerendebynavn']['navn'] ?? ''); + } + } + + return $address; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration(): array { + return [ + 'token' => '', + ] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form['token'] = [ + '#type' => 'textfield', + '#title' => $this->t('Token for service calls'), + '#default_value' => $this->configuration['token'] ?? '', + '#required' => TRUE, + '#description' => $this->t('Token required for performing API requests'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $configuration = $this->getConfiguration(); + $configuration['token'] = $form_state->getValue('token'); + $this->setConfiguration($configuration); + } + +} diff --git a/src/Plugin/os2web/DataLookup/DatafordelerAddressLookupInterface.php b/src/Plugin/os2web/DataLookup/DatafordelerAddressLookupInterface.php new file mode 100644 index 0000000..c474f04 --- /dev/null +++ b/src/Plugin/os2web/DataLookup/DatafordelerAddressLookupInterface.php @@ -0,0 +1,41 @@ +logger = $logger; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + /** @var \Drupal\os2web_audit\Service\Logger $auditLogger */ + $auditLogger = $container->get('os2web_audit.logger'); + /** @var \Drupal\key\KeyRepositoryInterface $keyRepository */ + $keyRepository = $container->get('key.repository'); + /** @var \Drupal\Core\File\FileSystem $fileSystem */ + $fileSystem = $container->get('file_system'); + + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('http_client'), + $auditLogger, + $keyRepository, + $fileSystem, + $container->get('logger.factory')->get('os2web_datalookup') + ); + } + + /** + * {@inheritdoc} + */ + public function getMatrikulaId(string $addressAccessId) : ?string { + $url = "https://services.datafordeler.dk/DAR/DAR/3.0.0/rest/husnummerTilJordstykke"; + + try { + $json = $this->httpClient->request('GET', $url, [ + 'query' => [ + 'husnummerid' => $addressAccessId, + ], + ])->getBody(); + } + catch (GuzzleException $e) { + $this->logger->warning('Request failed: @e', ['@e' => $e->getMessage()]); + + return NULL; + } + + $jsonDecoded = json_decode($json, TRUE); + if (is_array($jsonDecoded)) { + if (NestedArray::keyExists($jsonDecoded, ['gældendeJordstykke', 'jordstykkeLokalId'])) { + return NestedArray::getValue($jsonDecoded, ['gældendeJordstykke', 'jordstykkeLokalId']); + } + } + + return NULL; + } + + /** + * {@inheritdoc} + */ + public function getMatrikulaEntries(string $matrikulaId) : array { + $matrikulaEntries = []; + $url = "https://services.datafordeler.dk/Matriklen2/Matrikel/2.0.0/rest/SamletFastEjendom"; + + $configuration = $this->getConfiguration(); + + try { + $json = $this->httpClient->request('GET', $url, [ + 'query' => [ + 'jordstykkeid' => $matrikulaId, + 'username' => $configuration['username'], + 'password' => $configuration['password'], + ], + ])->getBody(); + } + catch (GuzzleException $e) { + $this->logger->warning('Request failed: @e', ['@e' => $e->getMessage()]); + + return $matrikulaEntries; + } + + $jsonDecoded = json_decode($json, TRUE); + + if (is_array($jsonDecoded)) { + if (NestedArray::keyExists($jsonDecoded, ['features', 0, 'properties', 'jordstykke'])) { + $jordstykker = NestedArray::getValue($jsonDecoded, ['features', 0, 'properties', 'jordstykke']); + foreach ($jordstykker as $jordstyk) { + if (isset($jordstyk['properties']) && !empty($jordstyk['properties'])) { + $matrikula = new MatrikulaLookupResult(); + $matrikula->setOwnerLicenseCode($jordstyk['properties']['ejerlavskode']); + $matrikula->setOwnershipName($jordstyk['properties']['ejerlavsnavn']); + $matrikula->setMatrikulaNumber($jordstyk['properties']['matrikelnummer']); + + $matrikulaEntries[] = $matrikula; + } + } + } + } + + return $matrikulaEntries; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration(): array { + return [ + 'username' => '', + 'password' => '', + ] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form['username'] = [ + '#type' => 'textfield', + '#title' => $this->t('Username for service calls'), + '#default_value' => $this->configuration['username'], + '#required' => TRUE, + '#description' => $this->t('Username required for performing API requests'), + ]; + $form['password'] = [ + '#type' => 'textfield', + '#title' => $this->t('Password for service calls'), + '#default_value' => $this->configuration['password'], + '#required' => TRUE, + '#description' => $this->t('Password required for performing API requests'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $configuration = $this->getConfiguration(); + $configuration['username'] = $form_state->getValue('username'); + $configuration['password'] = $form_state->getValue('password'); + $this->setConfiguration($configuration); + } + +} diff --git a/src/Plugin/os2web/DataLookup/DatafordelerMatrikulaLookupInterface.php b/src/Plugin/os2web/DataLookup/DatafordelerMatrikulaLookupInterface.php new file mode 100644 index 0000000..4595062 --- /dev/null +++ b/src/Plugin/os2web/DataLookup/DatafordelerMatrikulaLookupInterface.php @@ -0,0 +1,36 @@ +