From 5eb36e697705b38a6951f2012ccaa0f3889f23fc Mon Sep 17 00:00:00 2001 From: Tjardo Date: Thu, 8 Jan 2026 11:11:39 +0100 Subject: [PATCH 1/2] Add energy labels endpoint --- README.md | 76 ++++------------ src/DTO/EnergyLabel.php | 24 +++++ src/DTO/EnergyLabelCollection.php | 42 +++++++++ .../EnergyLabelCollectionFactory.php | 60 +++++++++++++ src/NederlandPostcodeClient.php | 7 ++ src/Resources/EnergyLabelResource.php | 26 ++++++ tests/Resources/EnergyLabelResourceTest.php | 37 ++++++++ tests/TestCase.php | 87 +++++++++++++++++-- 8 files changed, 297 insertions(+), 62 deletions(-) create mode 100644 src/DTO/EnergyLabel.php create mode 100644 src/DTO/EnergyLabelCollection.php create mode 100644 src/Factories/EnergyLabelCollectionFactory.php create mode 100644 src/Resources/EnergyLabelResource.php create mode 100644 tests/Resources/EnergyLabelResourceTest.php diff --git a/README.md b/README.md index d4b06a9..995917b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Register for free to obtain a **test API key** at [nederlandpostcode.nl](https:/ - [Address Endpoint](#address-endpoint) - [Single Address](#single-address) - [Multiple Addresses](#multiple-addresses) + - [Energy Label Endpoint](#energy-label-endpoint) - [Quota Endpoint](#quota-endpoint) - [Error Handling](#error-handling) @@ -124,67 +125,28 @@ $address = $client->list( ); ``` -This will return an `AddressCollection` object like this: +This will return an `AddressCollection`, which is a collection of `Address` objects. + +### Energy Label Endpoint + +The energy label endpoint allows you to fetch energy label information for a given postcode and house number. ```php -AddressCollection { - items: [ - Address { - postcode: "1015CN", - number: 10, - addition: 'A', - street: "Keizersgracht", - city: "Amsterdam", - municipality: "Amsterdam", - province: "Noord-Holland", - coordinates: Coordinates { - latitude: 52.379401496779124, - longitude: 4.889216673725493 - } - }, - Address { - postcode: "1015CN", - number: 10, - addition: 'B', - street: "Keizersgracht", - city: "Amsterdam", - municipality: "Amsterdam", - province: "Noord-Holland", - coordinates: Coordinates { - latitude: 52.379401496779124, - longitude: 4.889216673725493 - } - }, - Address { - postcode: "1015CN", - number: 10, - addition: 'C', - street: "Keizersgracht", - city: "Amsterdam", - municipality: "Amsterdam", - province: "Noord-Holland", - coordinates: Coordinates { - latitude: 52.379401496779124, - longitude: 4.889216673725493 - } - }, - Address { - postcode: "1015CN", - number: 10, - addition: 'D', - street: "Keizersgracht", - city: "Amsterdam", - municipality: "Amsterdam", - province: "Noord-Holland", - coordinates: Coordinates { - latitude: 52.379401496779124, - longitude: 4.889216673725493 - } - }, - ] -} +use Label84\NederlandPostcode\NederlandPostcodeClient; + +$client = new NederlandPostcodeClient( + key: 'npa_live_XXX' +); + +$energyLabels = $client->energyLabels()->get( + postcode: '1118BN', + number: 800, + addition: null, +); ``` +This will return an `EnergyLabelCollection` object, which is a collection of `EnergyLabel` objects. + ### Quota Endpoint The quota endpoint allows you to check your current API usage and limits. This endpoint does not increment your usage count. diff --git a/src/DTO/EnergyLabel.php b/src/DTO/EnergyLabel.php new file mode 100644 index 0000000..056d539 --- /dev/null +++ b/src/DTO/EnergyLabel.php @@ -0,0 +1,24 @@ + */ +class EnergyLabelCollection implements IteratorAggregate, Countable +{ + /** @var EnergyLabel[] */ + protected array $items = []; + + /** @param EnergyLabel[] $items */ + public function __construct(array $items = []) + { + $this->items = $items; + } + + /** @return EnergyLabel[] */ + public function all(): array + { + return $this->items; + } + + public function count(): int + { + return count($this->items); + } + + /** @return ArrayIterator */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->items); + } + + public function isEmpty(): bool + { + return empty($this->items); + } +} diff --git a/src/Factories/EnergyLabelCollectionFactory.php b/src/Factories/EnergyLabelCollectionFactory.php new file mode 100644 index 0000000..75bd1ea --- /dev/null +++ b/src/Factories/EnergyLabelCollectionFactory.php @@ -0,0 +1,60 @@ +, + * }} $response + */ + public static function make(array $response): EnergyLabelCollection + { + $postcode = $response['data']['postcode']; + $number = $response['data']['number']; + $addition = $response['data']['addition'] ?? null; + $street = $response['data']['street']; + $city = $response['data']['city']; + + $energyLabels = array_map(function (array $attributes) use ($postcode, $number, $addition, $street, $city) { + return new EnergyLabel( + postcode: $postcode, + number: $number, + addition: $addition, + street: $street, + city: $city, + inspectionDate: new DateTime($attributes['inspection_date']), + validUntilDate: new DateTime($attributes['valid_until_date']), + constructionType: $attributes['construction_type'], + buildingType: $attributes['building_type'], + energyLabel: $attributes['energy_label'], + maxEnergyDemand: $attributes['max_energy_demand'], + maxFossilEnergyDemand: $attributes['max_fossil_energy_demand'], + minRenewableShare: $attributes['min_renewable_share'], + ); + }, $response['data']['energy_labels']); + + $energyLabels = array_values($energyLabels); + + return new EnergyLabelCollection($energyLabels); + } +} diff --git a/src/NederlandPostcodeClient.php b/src/NederlandPostcodeClient.php index 5acd23d..e5d2a40 100644 --- a/src/NederlandPostcodeClient.php +++ b/src/NederlandPostcodeClient.php @@ -10,11 +10,13 @@ use Label84\NederlandPostcode\Exceptions\AddressNotFoundException; use Label84\NederlandPostcode\Exceptions\MultipleAddressesFoundException; use Label84\NederlandPostcode\Resources\AddressesResource; +use Label84\NederlandPostcode\Resources\EnergyLabelResource; use Label84\NederlandPostcode\Resources\QuotaResource; /** * @method AddressesResource addresses() * @method QuotaResource quota() + * @method EnergyLabelResource energyLabels() * @method AddressCollection
list(string $postcode, int $number, ?string $addition = null, array $attributes = []) * @method Address find(string $postcode, int $number, ?string $addition = null, array $attributes = []) * @method Quota usage() @@ -62,6 +64,11 @@ public function addresses(): AddressesResource return new AddressesResource($this); } + public function energyLabels(): EnergyLabelResource + { + return new EnergyLabelResource($this); + } + public function quota(): QuotaResource { return new QuotaResource($this); diff --git a/src/Resources/EnergyLabelResource.php b/src/Resources/EnergyLabelResource.php new file mode 100644 index 0000000..6e0a4df --- /dev/null +++ b/src/Resources/EnergyLabelResource.php @@ -0,0 +1,26 @@ +request( + method: 'GET', + path: 'v1/energy-label', + query: [ + 'postcode' => $postcode, + 'number' => $number, + 'addition' => $addition, + ], + )); + } +} diff --git a/tests/Resources/EnergyLabelResourceTest.php b/tests/Resources/EnergyLabelResourceTest.php new file mode 100644 index 0000000..380d347 --- /dev/null +++ b/tests/Resources/EnergyLabelResourceTest.php @@ -0,0 +1,37 @@ +client + ->energyLabels() + ->get( + postcode: '1118BN', + number: 800, + addition: null, + ); + + $this->assertInstanceOf(EnergyLabelCollection::class, $result); + $this->assertCount(1, $result); + } + + public function test_get_multiple_results(): void + { + $result = $this->client + ->energyLabels() + ->get( + postcode: '1015CN', + number: 10, + addition: 'A', + ); + + $this->assertInstanceOf(EnergyLabelCollection::class, $result); + $this->assertCount(2, $result); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index c564c9e..1bf9853 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,14 +2,16 @@ namespace Label84\NederlandPostcode\Tests; +use DateTime; use Label84\NederlandPostcode\DTO\Address; use Label84\NederlandPostcode\DTO\AddressCollection; use Label84\NederlandPostcode\DTO\Coordinates; +use Label84\NederlandPostcode\DTO\EnergyLabel; +use Label84\NederlandPostcode\DTO\EnergyLabelCollection; use Label84\NederlandPostcode\DTO\Quota; -use Label84\NederlandPostcode\Exceptions\AddressNotFoundException; -use Label84\NederlandPostcode\Exceptions\MultipleAddressesFoundException; use Label84\NederlandPostcode\NederlandPostcodeClient; use Label84\NederlandPostcode\Resources\AddressesResource; +use Label84\NederlandPostcode\Resources\EnergyLabelResource; use Label84\NederlandPostcode\Resources\QuotaResource; use PHPUnit\Framework\TestCase as BaseTestCase; @@ -28,7 +30,7 @@ protected function mockNederlandPostcodeClient(): void { $mockAddresses = $this->createStub(AddressesResource::class); $mockAddresses->method('get') - ->willReturnCallback(function (string $postcode, int $number, ?array $addition, $attributes = []) { + ->willReturnCallback(function (string $postcode, int $number, ?string $addition, array $attributes = []) { return match (true) { $postcode === '1118BN' && $number === 800 => $this->singleAddressResponse(), $postcode === '1015CN' && $number === 10 => $this->multipleAddressesResponse(), @@ -36,16 +38,29 @@ protected function mockNederlandPostcodeClient(): void }; }); + $mockEnergyLabels = $this->createStub(EnergyLabelResource::class); + $mockEnergyLabels->method('get') + ->willReturnCallback(function (string $postcode, int $number, ?string $addition) { + return match (true) { + $postcode === '1118BN' && $number === 800 => $this->singleEnergyLabelsResponse(), + $postcode === '1015CN' && $number === 10 => $this->multipleEnergyLabelsResponse(), + default => new EnergyLabelCollection([]), + }; + }); + + $mockQuota = $this->createStub(QuotaResource::class); $mockQuota->method('get')->willReturn(new Quota(used: 1500, limit: 10000)); - $this->client = new class($mockAddresses, $mockQuota) extends NederlandPostcodeClient { + $this->client = new class($mockAddresses, $mockEnergyLabels, $mockQuota) extends NederlandPostcodeClient { public AddressesResource $addressesResource; + public EnergyLabelResource $energyLabelsResource; public QuotaResource $quotaResource; - public function __construct($addresses, $quota) + public function __construct($addresses, $energyLabels, $quota) { $this->addressesResource = $addresses; + $this->energyLabelsResource = $energyLabels; $this->quotaResource = $quota; } @@ -54,6 +69,11 @@ public function addresses(): AddressesResource return $this->addressesResource; } + public function energyLabels(): EnergyLabelResource + { + return $this->energyLabelsResource; + } + public function quota(): QuotaResource { return $this->quotaResource; @@ -142,4 +162,61 @@ private function multipleAddressesResponse(): AddressCollection ), ]); } + + private function singleEnergyLabelsResponse(): EnergyLabelCollection + { + return new EnergyLabelCollection([ + new EnergyLabel( + postcode: '1118BN', + number: 800, + addition: '', + street: 'Schiphol Boulevard', + city: 'Schiphol', + inspectionDate: new DateTime('2026-01-15'), + validUntilDate: new DateTime('2036-01-15'), + constructionType: 'utiliteitsbouw', + buildingType: null, + energyLabel: 'A+++', + maxEnergyDemand: 98.4, + maxFossilEnergyDemand: 55.48, + minRenewableShare: 55.3, + ), + ]); + } + + private function multipleEnergyLabelsResponse(): EnergyLabelCollection + { + return new EnergyLabelCollection([ + new EnergyLabel( + postcode: '1015CN', + number: 10, + addition: 'A', + street: 'Keizersgracht', + city: 'Amsterdam', + inspectionDate: new DateTime('2026-01-05'), + validUntilDate: new DateTime('2036-01-05'), + constructionType: 'woningbouw', + buildingType: 'vrijstaande woning', + energyLabel: 'B', + maxEnergyDemand: 99.57, + maxFossilEnergyDemand: 150, + minRenewableShare: 33.5, + ), + new EnergyLabel( + postcode: '1015CN', + number: 10, + addition: 'A', + street: 'Keizersgracht', + city: 'Amsterdam', + inspectionDate: new DateTime('2015-06-01'), + validUntilDate: new DateTime('2025-06-01'), + constructionType: 'woningbouw', + buildingType: 'vrijstaande woning', + energyLabel: 'G', + maxEnergyDemand: 177.57, + maxFossilEnergyDemand: 218.86, + minRenewableShare: 11, + ), + ]); + } } From 48b0eda21f5fc4589513fb7079738976d7f152c9 Mon Sep 17 00:00:00 2001 From: Tjardo Date: Tue, 3 Feb 2026 15:02:50 +0100 Subject: [PATCH 2/2] WIP --- README.md | 61 +++++++++++++++++++++++++++++---- src/NederlandPostcodeClient.php | 10 ++++-- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 995917b..0ff5752 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ try { $address = $client->find( postcode: '1118BN', number: 800, - addition: ['coordinates'], + attributes: ['coordinates'], ); } catch (NederlandPostcodeException $exception) { // handle exception @@ -80,7 +80,7 @@ $address = $client->find( postcode: '1118BN', number: 800, addition: null, - attributes: ['coordinates'] + attributes: ['coordinates'], ); ``` @@ -117,19 +117,44 @@ $client = new NederlandPostcodeClient( key: 'npa_live_XXX' ); -$address = $client->list( +$addresses = $client->list( postcode: '1015CN', number: 10, addition: null, - attributes: ['coordinates'] + attributes: ['coordinates'], ); ``` -This will return an `AddressCollection`, which is a collection of `Address` objects. +This will return an `AddressCollection` like this: + +```php +AddressCollection { + items: [ + Address { + postcode: "1015CN", + number: 10, + addition: "A", + street: "Keizersgracht", + city: "Amsterdam", + municipality: "Amsterdam", + province: "Noord-Holland", + country: "Nederland", + coordinates: Coordinates { ... } + }, + Address { + postcode: "1015CN", + number: 10, + addition: "B", + street: "Keizersgracht", + ... + } + ] +} +``` ### Energy Label Endpoint -The energy label endpoint allows you to fetch energy label information for a given postcode and house number. +The energy label endpoint allows you to fetch energy label information for a given postcode and house number (with optional addition). ```php use Label84\NederlandPostcode\NederlandPostcodeClient; @@ -145,7 +170,29 @@ $energyLabels = $client->energyLabels()->get( ); ``` -This will return an `EnergyLabelCollection` object, which is a collection of `EnergyLabel` objects. +This will return an `EnergyLabelCollection` like this: + +```php +EnergyLabelCollection { + items: [ + EnergyLabel { + postcode: "1118BN", + number: 800, + addition: null, + street: "Schiphol Boulevard", + city: "Schiphol", + inspectionDate: DateTime("2022-08-02"), + validUntilDate: DateTime("2032-08-02"), + constructionType: "utiliteitsbouw", + buildingType: null, + energyLabel: "A+++", + maxEnergyDemand: 98.4, + maxFossilEnergyDemand: 55.48, + minRenewableShare: 55.3 + } + ] +} +``` ### Quota Endpoint diff --git a/src/NederlandPostcodeClient.php b/src/NederlandPostcodeClient.php index e5d2a40..fb362b1 100644 --- a/src/NederlandPostcodeClient.php +++ b/src/NederlandPostcodeClient.php @@ -9,6 +9,7 @@ use Label84\NederlandPostcode\Enums\AddressAttributesEnum; use Label84\NederlandPostcode\Exceptions\AddressNotFoundException; use Label84\NederlandPostcode\Exceptions\MultipleAddressesFoundException; +use Label84\NederlandPostcode\Exceptions\NederlandPostcodeException; use Label84\NederlandPostcode\Resources\AddressesResource; use Label84\NederlandPostcode\Resources\EnergyLabelResource; use Label84\NederlandPostcode\Resources\QuotaResource; @@ -48,7 +49,7 @@ public function __construct( /** * @param array $options - * @return array + * @return array */ public function request(string $method, string $uri, array $options = []): array { @@ -56,7 +57,12 @@ public function request(string $method, string $uri, array $options = []): array $body = $response->getBody()->getContents(); - return json_decode($body, true); // @phpstan-ignore return.type + $decoded = json_decode($body, true); + + if (! is_array($decoded)) { + throw new NederlandPostcodeException('Invalid JSON response from API'); + } + return $decoded; } public function addresses(): AddressesResource