From 10560d6fdae59a2f31e9434f1591d9be69eeb4cf Mon Sep 17 00:00:00 2001 From: NouddeBrouwer Date: Wed, 26 Nov 2025 09:25:57 +0100 Subject: [PATCH 1/2] ZipCodeCheck --- src/Request/Enum/Portfolio.php | 10 + src/Request/Enum/Supplier.php | 13 ++ src/Request/ZipCodeCheckRequest.php | 217 +++++++++++++++++++ src/Response/AvailableSpeed.php | 294 ++++++++++++++++++++++++++ src/Response/AvailableSupplier.php | 105 +++++++++ src/Response/ZipCodeCheckResponse.php | 35 +++ src/RoutITAPIClient.php | 15 ++ 7 files changed, 689 insertions(+) create mode 100644 src/Request/Enum/Portfolio.php create mode 100644 src/Request/Enum/Supplier.php create mode 100644 src/Request/ZipCodeCheckRequest.php create mode 100644 src/Response/AvailableSpeed.php create mode 100644 src/Response/AvailableSupplier.php create mode 100644 src/Response/ZipCodeCheckResponse.php diff --git a/src/Request/Enum/Portfolio.php b/src/Request/Enum/Portfolio.php new file mode 100644 index 0000000..20d67ce --- /dev/null +++ b/src/Request/Enum/Portfolio.php @@ -0,0 +1,10 @@ + ['KPN', 'Tele2']] + + /** + * @return string|null + */ + public function getPortfolio(): ?string + { + return $this->portfolio; + } + + /** + * @param Portfolio|string|null $portfolio + */ + public function setPortfolio(Portfolio|string|null $portfolio): self + { + if ($portfolio instanceof Portfolio) { + $this->portfolio = $portfolio->value; + } else { + $this->portfolio = $portfolio; + } + + return $this; + } + + /** + * @return string|null + */ + public function getZipCode(): ?string + { + return $this->zipCode; + } + + /** + * @param string|null $zipCode + * + * @return $this + */ + public function setZipCode(?string $zipCode): self + { + $this->zipCode = $zipCode; + + return $this; + } + + /** + * @return int|null + */ + public function getHouseNr(): ?int + { + return $this->houseNr; + } + + /** + * @param int|null $houseNr + * + * @return $this + */ + public function setHouseNr(?int $houseNr): self + { + $this->houseNr = $houseNr; + + return $this; + } + + /** + * @return string|null + */ + public function getHouseNrExtension(): ?string + { + return $this->houseNrExtension; + } + + /** + * @param string|null $houseNrExtension + * + * @return $this + */ + public function setHouseNrExtension(?string $houseNrExtension): self + { + $this->houseNrExtension = $houseNrExtension; + + return $this; + } + + /** + * @return string|null + */ + public function getServiceId(): ?string + { + return $this->serviceId; + } + + /** + * @param string|null $serviceId + * + * @return $this + */ + public function setServiceId(?string $serviceId): self + { + $this->serviceId = $serviceId; + + return $this; + } + + /** + * @return string|null + */ + public function getRoomNumber(): ?string + { + return $this->roomNumber; + } + + /** + * @param string|null $roomNumber + * + * @return $this + */ + public function setRoomNumber(?string $roomNumber): self + { + $this->roomNumber = $roomNumber; + + return $this; + } + + /** + * @return bool|null + */ + public function getIsRoomNumberKnown(): ?bool + { + return $this->isRoomNumberKnown; + } + + /** + * @param bool|null $isRoomNumberKnown + * + * @return $this + */ + public function setIsRoomNumberKnown(?bool $isRoomNumberKnown): self + { + $this->isRoomNumberKnown = $isRoomNumberKnown; + + return $this; + } + + /** + * @return array>|null + */ + public function getSuppliers(): ?array + { + return $this->suppliers; // ✅ return the nested structure + } + + /** + * @param array|null $suppliers + */ + public function setSuppliers(?array $suppliers): self + { + if ($suppliers === null) { + $this->suppliers = null; + return $this; + } + + $normalized = []; + + foreach ($suppliers as $supplier) { + if ($supplier instanceof Supplier) { + $normalized[] = $supplier->value; + } elseif ($supplier !== null) { + $normalized[] = (string) $supplier; + } + } + + // This shape matches ArrayOfString → ... + $this->suppliers = [ + 'string' => $normalized, + ]; + + return $this; + } +} diff --git a/src/Response/AvailableSpeed.php b/src/Response/AvailableSpeed.php new file mode 100644 index 0000000..be7df46 --- /dev/null +++ b/src/Response/AvailableSpeed.php @@ -0,0 +1,294 @@ +availability; + } + + /** + * @param string|null $availability + * + * @return $this + */ + public function setAvailability(?string $availability): self + { + $this->availability = $availability; + + return $this; + } + + /** + * @return string|null + */ + public function getDescription(): ?string + { + return $this->description; + } + + /** + * @param string|null $description + * + * @return $this + */ + public function setDescription(?string $description): self + { + $this->description = $description; + + return $this; + } + + /** + * @return string|null + */ + public function getNlsType(): ?string + { + // if we already normalized to string/null, just return it + if ($this->nlsType === null || $this->nlsType === '') { + return null; + } + + if (is_string($this->nlsType)) { + return $this->nlsType; + } + + // if somehow it's still an array or something weird → treat as null + return null; + } + + /** + * @param mixed $nlsType + * + * @return $this + */ + public function setNlsType(mixed $nlsType): self + { + // Case: + if (is_array($nlsType)) { + $flat = array_change_key_case($nlsType, CASE_LOWER); + $nil = $flat['@xsi:nil'] ?? $flat['@nil'] ?? $flat['nil'] ?? null; + + if ($nil === 'true' || $nil === true || $nil === '1') { + $this->nlsType = null; + return $this; + } + + // Unknown array shape → safest is null + $this->nlsType = null; + return $this; + } + + // Normal string like "Nls1", "Nls6", ... + if (is_string($nlsType)) { + $this->nlsType = $nlsType; + return $this; + } + + // null or anything else + $this->nlsType = null; + return $this; + } + + /** + * Always return a flat list of non-empty strings. + * + * @return string[] + */ + public function getRemarks(): array + { + $raw = $this->remarks; + + if ($raw === null || $raw === '') { + return []; + } + + // Single scalar → one remark (if non-empty) + if (is_scalar($raw) || $raw instanceof \Stringable) { + $s = trim((string) $raw); + return $s === '' ? [] : [$s]; + } + + // Traversable → turn into array + if ($raw instanceof \Traversable) { + $raw = iterator_to_array($raw); + } + + // Any array shape → flatten all scalar values + if (is_array($raw)) { + $out = []; + + $it = new \RecursiveIteratorIterator( + new \RecursiveArrayIterator($raw) + ); + + foreach ($it as $v) { + if (is_scalar($v) || $v instanceof \Stringable) { + $s = trim((string) $v); + if ($s !== '') { + $out[] = $s; + } + } + } + + return $out; + } + + // Anything else → no remarks + return []; + } + + /** + * @param mixed $remarks + */ + public function setRemarks(mixed $remarks): self + { + // Possible shapes: + // - null + // - '' + // - 'some text' + // - ['string' => ['Nls6', 'Bestel de ...']] + // - ['string' => 'Nls6'] + // - [] + $this->remarks = $remarks; + return $this; + } + + /** + * @return string|null + */ + public function getTechnology(): ?string + { + return $this->technology; + } + + /** + * @param string|null $technology + * + * @return $this + */ + public function setTechnology(?string $technology): self + { + $this->technology = $technology; + + return $this; + } + + /** + * @return string|null + */ + public function getTariffCluster(): ?string + { + return $this->tariffCluster; + } + + /** + * @param string|null $tariffCluster + * + * @return $this + */ + public function setTariffCluster(?string $tariffCluster): self + { + $this->tariffCluster = $tariffCluster; + + return $this; + } + + /** + * @return DateTimeInterface|null + */ + public function getPlanDate(): ?DateTimeInterface + { + return $this->planDate; + } + + /** + * @param mixed $planDate + * + * @return $this + */ + public function setPlanDate(mixed $planDate): self + { + // Case 1: explicit null or empty string + if ($planDate === null || $planDate === '') { + $this->planDate = null; + return $this; + } + + // Case 2: XML decoder gave an array for xsi:nil / attributes + if (is_array($planDate)) { + $flat = array_change_key_case($planDate, CASE_LOWER); + + // Try to detect any kind of nil="true" + $nil = + $flat['@xsi:nil'] ?? + $flat['@nil'] ?? + $flat['nil'] ?? + null; + + if ($nil === 'true' || $nil === true || $nil === '1') { + $this->planDate = null; + return $this; + } + + // Unknown array shape → be safe and treat as null + $this->planDate = null; + return $this; + } + + // Case 3: normal date string "2024-02-15T13:45:00" + if (is_string($planDate)) { + try { + $this->planDate = new DateTimeImmutable($planDate); + } catch (\Throwable $e) { + // Invalid date format → store null, don't kill deserialization + $this->planDate = null; + } + + return $this; + } + + // Case 4: Already a DateTimeInterface (unlikely, but fine) + if ($planDate instanceof DateTimeInterface) { + $this->planDate = $planDate; + return $this; + } + + // Fallback: unknown type → null + $this->planDate = null; + return $this; + } +} diff --git a/src/Response/AvailableSupplier.php b/src/Response/AvailableSupplier.php new file mode 100644 index 0000000..02792b0 --- /dev/null +++ b/src/Response/AvailableSupplier.php @@ -0,0 +1,105 @@ +name; + } + + /** + * @param string|null $name + * + * @return $this + */ + public function setName(?string $name): self + { + $this->name = $name; + + return $this; + } + + /** + * @return string|null + */ + public function getErrorMessage(): ?string + { + return $this->errorMessage; + } + + /** + * @param string|null $errorMessage + * + * @return $this + */ + public function setErrorMessage(?string $errorMessage): self + { + $this->errorMessage = $errorMessage; + + return $this; + } + + /** + * @return string|null + */ + public function getLocationInfo(): ?string + { + return $this->locationInfo; + } + + /** + * @param string|null $locationInfo + * + * @return $this + */ + public function setLocationInfo(?string $locationInfo): self + { + $this->locationInfo = $locationInfo; + + return $this; + } + + /** + * @param AvailableSpeed[] $availableSpeed + * + * @return $this + */ + public function setAvailableSpeed(array $availableSpeed): self + { + $this->availableSpeed = $availableSpeed; + + return $this; + } + + /** + * @return AvailableSpeed[]|null + */ + public function getAvailableSpeed(): ?array + { + return $this->availableSpeed; + } +} diff --git a/src/Response/ZipCodeCheckResponse.php b/src/Response/ZipCodeCheckResponse.php new file mode 100644 index 0000000..9bc914b --- /dev/null +++ b/src/Response/ZipCodeCheckResponse.php @@ -0,0 +1,35 @@ +availableSupplier = $availableSupplier; + + return $this; + } + + /** + * @return AvailableSupplier[]|null + */ + public function getAvailableSupplier(): ?array + { + return $this->availableSupplier; + } +} diff --git a/src/RoutITAPIClient.php b/src/RoutITAPIClient.php index b5b15aa..fb3e77e 100644 --- a/src/RoutITAPIClient.php +++ b/src/RoutITAPIClient.php @@ -9,9 +9,11 @@ use Inserve\RoutITAPI\Request\OrderSummaryRequest; use Inserve\RoutITAPI\Request\ProductPriceDetailsRequest; use Inserve\RoutITAPI\Request\RoutITRequestInterface; +use Inserve\RoutITAPI\Request\ZipCodeCheckRequest; use Inserve\RoutITAPI\Response\CustomerDataResponse; use Inserve\RoutITAPI\Response\OrderSummaryResponse; use Inserve\RoutITAPI\Response\ProductPriceDetailsResponse; +use Inserve\RoutITAPI\Response\ZipCodeCheckResponse; use Psr\Log\LoggerInterface; use SensitiveParameter; @@ -89,6 +91,19 @@ public function getProductPriceDetails(): ?ProductPriceDetailsResponse /** @var ProductPriceDetailsResponse|null */ return $this->apiCall(new ProductPriceDetailsRequest(), ProductPriceDetailsResponse::class); } + + /** + * @param ZipCodeCheckRequest|null $request + * + * @return ZipCodeCheckResponse|null + * @throws RoutITAPIException + */ + public function zipCodeCheck(?ZipCodeCheckRequest $request = null): ?ZipCodeCheckResponse + { + /** @var ZipCodeCheckResponse|null */ + return $this->apiCall($request ?? new ZipCodeCheckRequest(), ZipCodeCheckResponse::class); + } + /** * @param RoutITRequestInterface $request * @param string $responseClass From 44c158a4c7a486b077a9b03623004c280846508f Mon Sep 17 00:00:00 2001 From: NouddeBrouwer Date: Wed, 26 Nov 2025 09:56:48 +0100 Subject: [PATCH 2/2] ZipCodeCheck NlsType enum --- src/Response/AvailableSpeed.php | 59 ++++++++++++++------------------- src/Response/Enum/NlsType.php | 31 +++++++++++++++++ 2 files changed, 56 insertions(+), 34 deletions(-) create mode 100644 src/Response/Enum/NlsType.php diff --git a/src/Response/AvailableSpeed.php b/src/Response/AvailableSpeed.php index be7df46..7f8595d 100644 --- a/src/Response/AvailableSpeed.php +++ b/src/Response/AvailableSpeed.php @@ -4,6 +4,7 @@ use DateTimeImmutable; use DateTimeInterface; +use Inserve\RoutITAPI\Response\Enum\NlsType; use Symfony\Component\Serializer\Attribute\SerializedName; /** @@ -73,53 +74,43 @@ public function setDescription(?string $description): self } /** - * @return string|null + * @return NlsType|null */ - public function getNlsType(): ?string + public function getNlsTypeEnum(): ?NlsType { - // if we already normalized to string/null, just return it - if ($this->nlsType === null || $this->nlsType === '') { - return null; - } - - if (is_string($this->nlsType)) { - return $this->nlsType; - } + return NlsType::fromNullable($this->getNlsTypeRaw()); + } - // if somehow it's still an array or something weird → treat as null - return null; + /** + * @return string|null + */ + public function getNlsTypeRaw(): ?string + { + return is_string($this->nlsType) && $this->nlsType !== '' + ? $this->nlsType + : null; } /** - * @param mixed $nlsType + * @param mixed $value * * @return $this */ - public function setNlsType(mixed $nlsType): self + public function setNlsType(mixed $value): self { - // Case: - if (is_array($nlsType)) { - $flat = array_change_key_case($nlsType, CASE_LOWER); - $nil = $flat['@xsi:nil'] ?? $flat['@nil'] ?? $flat['nil'] ?? null; - - if ($nil === 'true' || $nil === true || $nil === '1') { - $this->nlsType = null; - return $this; - } - - // Unknown array shape → safest is null + // Possible shapes: + // - 'Nls6' + // - 'Nls1' + // - null + // - '' + // - array with nil metadata (for p6:nil="true") + // We only keep it if it's a non-empty string. + if (is_string($value) && $value !== '') { + $this->nlsType = $value; + } else { $this->nlsType = null; - return $this; - } - - // Normal string like "Nls1", "Nls6", ... - if (is_string($nlsType)) { - $this->nlsType = $nlsType; - return $this; } - // null or anything else - $this->nlsType = null; return $this; } diff --git a/src/Response/Enum/NlsType.php b/src/Response/Enum/NlsType.php new file mode 100644 index 0000000..c5f9d37 --- /dev/null +++ b/src/Response/Enum/NlsType.php @@ -0,0 +1,31 @@ +