├── LICENSE.md ├── src ├── Exception │ ├── ServiceNotSetException.php │ ├── ApiException.php │ ├── CifDownException.php │ ├── NotFoundException.php │ ├── InvalidMethodException.php │ ├── NotSupportedException.php │ ├── InvalidBarcodeException.php │ ├── NotImplementedException.php │ ├── InvalidConfigurationException.php │ ├── PostNLException.php │ ├── InvalidArgumentException.php │ ├── ShipmentNotFoundException.php │ ├── DeserializationException.php │ ├── HttpClientException.php │ ├── ResponseException.php │ ├── ApiConnectionException.php │ └── CifException.php ├── Entity │ ├── CoordinatesNorthWest.php │ ├── CoordinatesSouthEast.php │ ├── Response │ │ ├── GenerateBarcodeResponse.php │ │ ├── SignatureResponse.php │ │ ├── GetLocationsResult.php │ │ ├── ConfirmingResponseShipment.php │ │ ├── MergedLabel.php │ │ ├── SendShipmentResponse.php │ │ ├── GetSentDateResponse.php │ │ ├── GetLocationsInAreaResponse.php │ │ └── CurrentStatusResponse.php │ ├── Message │ │ └── LabellingMessage.php │ ├── Event.php │ ├── Coordinates.php │ ├── Sustainability.php │ ├── Request │ │ └── GenerateBarcode.php │ ├── CutOffTime.php │ ├── Area.php │ ├── Barcode.php │ ├── Signature.php │ └── ProductOption.php ├── Service │ ├── ResponseProcessor │ │ ├── ResponseProcessorSettersTrait.php │ │ ├── BarcodeServiceResponseProcessorInterface.php │ │ ├── ShippingServiceResponseProcessorInterface.php │ │ ├── LabellingServiceResponseProcessorInterface.php │ │ ├── ConfirmingServiceResponseProcessorInterface.php │ │ ├── TimeframeServiceResponseProcessorInterface.php │ │ ├── Rest │ │ │ ├── BarcodeServiceRestResponseProcessor.php │ │ │ ├── ShippingServiceRestResponseProcessor.php │ │ │ ├── LabellingServiceRestResponseProcessor.php │ │ │ └── ConfirmingServiceRestResponseProcessor.php │ │ ├── AbstractResponseProcessor.php │ │ ├── DeliveryDateServiceResponseProcessorInterface.php │ │ └── LocationServiceResponseProcessorInterface.php │ ├── ServiceInterface.php │ ├── RequestBuilder │ │ ├── Rest │ │ │ ├── AbstractRestRequestBuilder.php │ │ │ └── ConfirmingServiceRestRequestBuilder.php │ │ ├── ConfirmingServiceRequestBuilderInterface.php │ │ ├── TimeframeServiceRequestBuilderInterface.php │ │ ├── BarcodeServiceRequestBuilderInterface.php │ │ ├── LabellingServiceRequestBuilderInterface.php │ │ ├── ShippingServiceRequestBuilderInterface.php │ │ ├── DeliveryDateServiceRequestBuilderInterface.php │ │ ├── RequestBuilderSettersTrait.php │ │ └── LocationServiceRequestBuilderInterface.php │ ├── ShippingServiceInterface.php │ ├── BarcodeServiceInterface.php │ ├── TimeframeServiceInterface.php │ ├── ConfirmingServiceInterface.php │ ├── LabellingServiceInterface.php │ ├── DeliveryDateServiceInterface.php │ └── LocationServiceInterface.php ├── Enum │ └── LabelPosition.php ├── Cache │ ├── CacheableRequestEntityInterface.php │ └── CacheableServiceInterface.php ├── Clock │ ├── ClockAwareInterface.php │ └── ClockAwareTrait.php ├── Util │ ├── RFPdi.php │ └── UUID.php ├── Attribute │ └── SerializableProperty.php └── HttpClient │ └── HttpClientInterface.php └── composer.json /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT). 2 | 3 | Copyright (c) 2017-2023 Michael Dekker (https://github.com/firstred) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 8 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 15 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /src/Exception/ServiceNotSetException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | class ServiceNotSetException extends InvalidConfigurationException 33 | { 34 | } 35 | -------------------------------------------------------------------------------- /src/Entity/CoordinatesNorthWest.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | /** 33 | * @since 1.0.0 34 | */ 35 | class CoordinatesNorthWest extends Coordinates 36 | { 37 | } 38 | -------------------------------------------------------------------------------- /src/Entity/CoordinatesSouthEast.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | /** 33 | * @since 1.0.0 34 | */ 35 | class CoordinatesSouthEast extends Coordinates 36 | { 37 | } 38 | -------------------------------------------------------------------------------- /src/Exception/ApiException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class ApiException. 34 | * 35 | * Group of API exceptions. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class ApiException extends PostNLException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/ResponseProcessorSettersTrait.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | /** 33 | * @since 2.0.0 34 | * 35 | * @internal For future use 36 | */ 37 | trait ResponseProcessorSettersTrait 38 | { 39 | } 40 | -------------------------------------------------------------------------------- /src/Enum/LabelPosition.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Enum; 31 | 32 | /** 33 | * @since 2.0.0 34 | */ 35 | enum LabelPosition: int 36 | { 37 | case TopLeft = 2; 38 | case TopRight = 4; 39 | case BottomLeft = 1; 40 | case BottomRight = 3; 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/CifDownException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class CifDownException. 34 | * 35 | * Thrown when the CIF API is down. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class CifDownException extends ApiException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/NotFoundException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class NotFoundException. 34 | * 35 | * Thrown when (a) requested object(s) could not be found. 36 | * 37 | * @since 1.2.0 38 | */ 39 | class NotFoundException extends ApiException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/InvalidMethodException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class InvalidMethodException. 34 | * 35 | * Thrown when an invalid method is called. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class InvalidMethodException extends HttpClientException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/NotSupportedException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class NotSupportedException. 34 | * 35 | * Thrown when a feature is not supported (anymore). 36 | * 37 | * @since 1.0.0 38 | */ 39 | class NotSupportedException extends PostNLException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Service/ServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use DateInterval; 33 | use DateTimeInterface; 34 | use Psr\Cache\CacheItemInterface; 35 | use Psr\Cache\CacheItemPoolInterface; 36 | use Psr\Cache\InvalidArgumentException; 37 | 38 | interface ServiceInterface 39 | { 40 | } 41 | -------------------------------------------------------------------------------- /src/Exception/InvalidBarcodeException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class InvalidBarcodeException. 34 | * 35 | * Thrown when an invalid barcode has been passed. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class InvalidBarcodeException extends InvalidArgumentException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/NotImplementedException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class NotImplementedException. 34 | * 35 | * Thrown when a feature is not implemented (yet). 36 | * 37 | * @since 1.0.0 38 | */ 39 | class NotImplementedException extends InvalidArgumentException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/InvalidConfigurationException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class InvalidConfigurationException. 34 | * 35 | * Thrown when there is a configuration error. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class InvalidConfigurationException extends PostNLException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/PostNLException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | use Exception; 33 | 34 | /** 35 | * Class AbstractException. 36 | * 37 | * Group of exceptions that can be thrown by this library. 38 | * 39 | * @since 1.0.0 40 | */ 41 | abstract class PostNLException extends Exception 42 | { 43 | } 44 | -------------------------------------------------------------------------------- /src/Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class InvalidArgumentException. 34 | * 35 | * Group of exceptions that are the result of an invalid passed argument. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class InvalidArgumentException extends PostNLException 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/Rest/AbstractRestRequestBuilder.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder\Rest; 31 | 32 | use Firstred\PostNL\Service\RequestBuilder\AbstractRequestBuilder; 33 | 34 | /** 35 | * @since 2.0.0 36 | * 37 | * @internal 38 | */ 39 | abstract class AbstractRestRequestBuilder extends AbstractRequestBuilder 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/Exception/ShipmentNotFoundException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | use JetBrains\PhpStorm\Deprecated; 33 | 34 | /** 35 | * Class InvalidArgumentException. 36 | * 37 | * Thrown when a `Shipment` object could not be found. 38 | * 39 | * @since 1.2.0 40 | * @deprecated 1.4.0 Use `NotFoundException` 41 | */ 42 | #[Deprecated] 43 | class ShipmentNotFoundException extends NotFoundException 44 | { 45 | } 46 | -------------------------------------------------------------------------------- /src/Cache/CacheableRequestEntityInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Cache; 31 | 32 | interface CacheableRequestEntityInterface 33 | { 34 | /** 35 | * This method returns a unique cache key for every unique cacheable request as defined by PSR-6. 36 | * 37 | * @see https://www.php-fig.org/psr/psr-6/#definitions 38 | * 39 | * @return string 40 | */ 41 | public function getCacheKey(): string; 42 | } -------------------------------------------------------------------------------- /src/Clock/ClockAwareInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Clock; 31 | 32 | use Psr\Clock\ClockInterface; 33 | 34 | /** 35 | * @since 2.0.0 36 | */ 37 | interface ClockAwareInterface 38 | { 39 | /** 40 | * Get the current clock. 41 | * 42 | * @return ClockInterface 43 | * 44 | * @since 2.0.0 45 | */ 46 | public function getClock(): ClockInterface; 47 | 48 | /** 49 | * Set the current clock. 50 | * 51 | * @param ClockInterface $clock 52 | * 53 | * @return void 54 | * 55 | * @since 2.0.0 56 | */ 57 | public function setClock(ClockInterface $clock): void; 58 | } -------------------------------------------------------------------------------- /src/Exception/DeserializationException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | use Throwable; 33 | 34 | /** 35 | * @since 2.0.0 36 | */ 37 | class DeserializationException extends PostNLException 38 | { 39 | /** 40 | * @param string $message 41 | * @param int $code 42 | * @param Throwable|null $previous 43 | * @param mixed|null $value 44 | */ 45 | public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null, public mixed $value = null) 46 | { 47 | parent::__construct(message: $message, code: $code, previous: $previous); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/ConfirmingServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\Confirming; 33 | use Firstred\PostNL\Exception\InvalidArgumentException; 34 | use Firstred\PostNL\Exception\InvalidConfigurationException; 35 | use Psr\Http\Message\RequestInterface; 36 | 37 | /** 38 | * @since 2.0.0 39 | * 40 | * @internal 41 | */ 42 | interface ConfirmingServiceRequestBuilderInterface 43 | { 44 | /** 45 | * Build the 'confirm label' HTTP request. 46 | * 47 | * @throws InvalidArgumentException 48 | * @throws InvalidConfigurationException 49 | * 50 | * @since 2.0.0 51 | */ 52 | public function buildConfirmRequest(Confirming $confirming): RequestInterface; 53 | } 54 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/TimeframeServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\GetTimeframes; 33 | use Firstred\PostNL\Exception\InvalidArgumentException; 34 | use Firstred\PostNL\Exception\InvalidConfigurationException; 35 | use Psr\Http\Message\RequestInterface; 36 | 37 | /** 38 | * @since 2.0.0 39 | * 40 | * @internal 41 | */ 42 | interface TimeframeServiceRequestBuilderInterface 43 | { 44 | /** 45 | * Build the 'get timeframes' HTTP request. 46 | * 47 | * @param GetTimeframes $getTimeframes 48 | * 49 | * @return RequestInterface 50 | * 51 | * @throws InvalidArgumentException 52 | * @throws InvalidConfigurationException 53 | * 54 | * @since 2.0.0 55 | */ 56 | public function buildGetTimeframesRequest(GetTimeframes $getTimeframes): RequestInterface; 57 | } 58 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/BarcodeServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\GenerateBarcode; 33 | use Firstred\PostNL\Exception\InvalidArgumentException; 34 | use Firstred\PostNL\Exception\InvalidConfigurationException; 35 | use Psr\Http\Message\RequestInterface; 36 | 37 | /** 38 | * @since 2.0.0 39 | * 40 | * @internal 41 | */ 42 | interface BarcodeServiceRequestBuilderInterface 43 | { 44 | /** 45 | * Build the 'generate barcode' HTTP request. 46 | * 47 | * @param GenerateBarcode $generateBarcode 48 | * 49 | * @return RequestInterface 50 | * 51 | * @throws InvalidArgumentException 52 | * @throws InvalidConfigurationException 53 | * 54 | * @since 2.0.0 55 | */ 56 | public function buildGenerateBarcodeRequest(GenerateBarcode $generateBarcode): RequestInterface; 57 | } 58 | -------------------------------------------------------------------------------- /src/Exception/HttpClientException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | use Exception; 33 | use Psr\Http\Message\ResponseInterface; 34 | 35 | /** 36 | * Class HttpClientException. 37 | * 38 | * Thrown when the HTTP Client has an error. 39 | * 40 | * @since 1.0.0 41 | */ 42 | class HttpClientException extends PostNLException 43 | { 44 | private ?ResponseInterface $response; 45 | 46 | public function __construct(string $message = '', int $code = 0, ?Exception $previous = null, ?ResponseInterface $response = null) 47 | { 48 | parent::__construct(message: $message, code: $code, previous: $previous); 49 | 50 | $this->response = $response; 51 | } 52 | 53 | public function setResponse(?ResponseInterface $response) 54 | { 55 | $this->response = $response; 56 | } 57 | 58 | public function getResponse(): ?ResponseInterface 59 | { 60 | return $this->response; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/LabellingServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\GenerateLabel; 33 | use Firstred\PostNL\Exception\InvalidArgumentException; 34 | use Firstred\PostNL\Exception\InvalidConfigurationException; 35 | use Psr\Http\Message\RequestInterface; 36 | 37 | /** 38 | * @since 2.0.0 39 | * 40 | * @internal 41 | */ 42 | interface LabellingServiceRequestBuilderInterface 43 | { 44 | /** 45 | * Build the 'generate label' HTTP request. 46 | * 47 | * @param GenerateLabel $generateLabel 48 | * @param bool $confirm 49 | * 50 | * @return RequestInterface 51 | * 52 | * @throws InvalidArgumentException 53 | * @throws InvalidConfigurationException 54 | * @since 2.0.0 55 | */ 56 | public function buildGenerateLabelRequest(GenerateLabel $generateLabel, bool $confirm = true): RequestInterface; 57 | } 58 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/ShippingServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\SendShipment; 33 | use Firstred\PostNL\Exception\InvalidArgumentException; 34 | use Firstred\PostNL\Exception\InvalidConfigurationException; 35 | use Psr\Http\Message\RequestInterface; 36 | 37 | /** 38 | * @since 2.0.0 39 | * 40 | * @internal 41 | */ 42 | interface ShippingServiceRequestBuilderInterface 43 | { 44 | /** 45 | * Build the 'send shipment' HTTP request. 46 | * 47 | * @param SendShipment $sendShipment 48 | * @param bool $confirm 49 | * 50 | * @return RequestInterface 51 | * 52 | * @throws InvalidArgumentException 53 | * @throws InvalidConfigurationException 54 | * 55 | * @since 2.0.0 56 | */ 57 | public function buildSendShipmentRequest(SendShipment $sendShipment, bool $confirm = true): RequestInterface; 58 | } 59 | -------------------------------------------------------------------------------- /src/Clock/ClockAwareTrait.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Clock; 31 | 32 | use Psr\Clock\ClockInterface; 33 | use Symfony\Component\Clock\NativeClock; 34 | 35 | /** 36 | * @since 2.0.0 37 | */ 38 | trait ClockAwareTrait 39 | { 40 | private ClockInterface $clock; 41 | 42 | /** 43 | * Get the current clock. 44 | * 45 | * @return ClockInterface 46 | * 47 | * @since 2.0.0 48 | */ 49 | public function getClock(): ClockInterface 50 | { 51 | if (!isset($this->clock) && class_exists(class: NativeClock::class)) { 52 | $this->clock = new NativeClock(); 53 | } 54 | 55 | return $this->clock; 56 | } 57 | 58 | /** 59 | * Set the current clock. 60 | * 61 | * @param ClockInterface $clock 62 | * 63 | * @return void 64 | * 65 | * @since 2.0.0 66 | */ 67 | public function setClock(ClockInterface $clock): void 68 | { 69 | $this->clock = $clock; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/BarcodeServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Exception\CifDownException; 33 | use Firstred\PostNL\Exception\CifException; 34 | use Firstred\PostNL\Exception\HttpClientException; 35 | use Firstred\PostNL\Exception\InvalidConfigurationException; 36 | use Firstred\PostNL\Exception\ResponseException; 37 | use Psr\Http\Message\ResponseInterface; 38 | 39 | /** 40 | * @since 2.0.0 41 | * 42 | * @internal 43 | */ 44 | interface BarcodeServiceResponseProcessorInterface 45 | { 46 | /** 47 | * Process the 'generate barcode' server response. 48 | * 49 | * @param ResponseInterface $response 50 | * 51 | * @return string 52 | * 53 | * @throws CifDownException 54 | * @throws CifException 55 | * @throws HttpClientException 56 | * @throws ResponseException 57 | * @throws InvalidConfigurationException 58 | * 59 | * @since 2.0.0 60 | */ 61 | public function processGenerateBarcodeResponse(ResponseInterface $response): string; 62 | } 63 | -------------------------------------------------------------------------------- /src/Entity/Response/GenerateBarcodeResponse.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | 35 | /** 36 | * @since 1.0.0 37 | */ 38 | class GenerateBarcodeResponse extends AbstractEntity 39 | { 40 | /** @var string|null $Barcode */ 41 | #[SerializableProperty(type: 'string')] 42 | protected ?string $Barcode = null; 43 | 44 | /** 45 | * @param string|null $Barcode 46 | */ 47 | public function __construct(?string $Barcode = null) 48 | { 49 | parent::__construct(); 50 | 51 | $this->setBarcode(Barcode: $Barcode); 52 | } 53 | 54 | /** 55 | * @return string|null 56 | */ 57 | public function getBarcode(): ?string 58 | { 59 | return $this->Barcode; 60 | } 61 | 62 | /** 63 | * @param string|null $Barcode 64 | * 65 | * @return static 66 | */ 67 | public function setBarcode(?string $Barcode): static 68 | { 69 | $this->Barcode = $Barcode; 70 | 71 | return $this; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Service/ShippingServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Entity\Request\SendShipment; 33 | use Firstred\PostNL\Entity\Response\SendShipmentResponse; 34 | use Firstred\PostNL\Exception\HttpClientException; 35 | use Firstred\PostNL\Exception\InvalidArgumentException as PostNLInvalidArgumentException; 36 | use Firstred\PostNL\Exception\NotFoundException; 37 | use Firstred\PostNL\Exception\NotSupportedException; 38 | use Firstred\PostNL\Exception\ResponseException; 39 | use Psr\Cache\InvalidArgumentException as PsrCacheInvalidArgumentException; 40 | 41 | /** 42 | * @since 1.2.0 43 | */ 44 | interface ShippingServiceInterface extends ServiceInterface 45 | { 46 | /** 47 | * Generate a single Shipping vai REST. 48 | * 49 | * @throws HttpClientException 50 | * @throws NotFoundException 51 | * @throws NotSupportedException 52 | * @throws PostNLInvalidArgumentException 53 | * @throws PsrCacheInvalidArgumentException 54 | * @throws ResponseException 55 | * 56 | * @since 1.2.0 57 | */ 58 | public function sendShipment(SendShipment $sendShipment, bool $confirm = true): ?SendShipmentResponse; 59 | } 60 | -------------------------------------------------------------------------------- /src/Entity/Response/SignatureResponse.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | use Firstred\PostNL\Entity\Signature; 35 | 36 | /** 37 | * @since 1.0.0 38 | */ 39 | class SignatureResponse extends AbstractEntity 40 | { 41 | /** @var Signature|null $Signature */ 42 | #[SerializableProperty(type: Signature::class)] 43 | protected ?Signature $Signature = null; 44 | 45 | /** 46 | * @param Signature|null $Signature 47 | */ 48 | public function __construct(?Signature $Signature = null) 49 | { 50 | parent::__construct(); 51 | 52 | $this->setSignature(Signature: $Signature); 53 | } 54 | 55 | /** 56 | * @return Signature|null 57 | */ 58 | public function getSignature(): ?Signature 59 | { 60 | return $this->Signature; 61 | } 62 | 63 | /** 64 | * @param Signature|null $Signature 65 | * 66 | * @return static 67 | */ 68 | public function setSignature(?Signature $Signature): static 69 | { 70 | $this->Signature = $Signature; 71 | 72 | return $this; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/ShippingServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Entity\Response\SendShipmentResponse; 33 | use Firstred\PostNL\Exception\DeserializationException; 34 | use Firstred\PostNL\Exception\HttpClientException; 35 | use Firstred\PostNL\Exception\InvalidConfigurationException; 36 | use Firstred\PostNL\Exception\NotSupportedException; 37 | use Firstred\PostNL\Exception\ResponseException; 38 | use Psr\Http\Message\ResponseInterface; 39 | 40 | /** 41 | * @since 2.0.0 42 | * 43 | * @internal 44 | */ 45 | interface ShippingServiceResponseProcessorInterface 46 | { 47 | /** 48 | * Process the 'send shipment' server response. 49 | * 50 | * @param ResponseInterface $response 51 | * 52 | * @return SendShipmentResponse|null 53 | * 54 | * @throws HttpClientException 55 | * @throws NotSupportedException 56 | * @throws ResponseException 57 | * @throws DeserializationException 58 | * @throws InvalidConfigurationException 59 | * 60 | * @since 2.0.0 61 | */ 62 | public function processSendShipmentResponse(ResponseInterface $response): ?SendShipmentResponse; 63 | } 64 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/LabellingServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Entity\Response\GenerateLabelResponse; 33 | use Firstred\PostNL\Exception\ApiException; 34 | use Firstred\PostNL\Exception\DeserializationException; 35 | use Firstred\PostNL\Exception\HttpClientException; 36 | use Firstred\PostNL\Exception\InvalidConfigurationException; 37 | use Firstred\PostNL\Exception\NotSupportedException; 38 | use Firstred\PostNL\Exception\ResponseException; 39 | use Psr\Http\Message\ResponseInterface; 40 | 41 | /** 42 | * @since 2.0.0 43 | * 44 | * @internal 45 | */ 46 | interface LabellingServiceResponseProcessorInterface 47 | { 48 | /** 49 | * Process the 'generate label' server response. 50 | * 51 | * @param ResponseInterface $response 52 | * 53 | * @return GenerateLabelResponse 54 | * 55 | * @throws HttpClientException 56 | * @throws NotSupportedException 57 | * @throws ResponseException 58 | * @throws DeserializationException 59 | * @throws ApiException 60 | * @throws InvalidConfigurationException 61 | * 62 | * @since 2.0.0 63 | */ 64 | public function processGenerateLabelResponse(ResponseInterface $response): GenerateLabelResponse; 65 | } 66 | -------------------------------------------------------------------------------- /src/Entity/Message/LabellingMessage.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Message; 31 | 32 | use DateTimeInterface; 33 | use Firstred\PostNL\Attribute\SerializableProperty; 34 | use Firstred\PostNL\Exception\InvalidArgumentException; 35 | 36 | /** 37 | * @since 1.0.0 38 | */ 39 | class LabellingMessage extends Message 40 | { 41 | /** @var string|null $Printertype */ 42 | #[SerializableProperty(type: 'string')] 43 | protected ?string $Printertype = null; 44 | 45 | /** 46 | * @throws InvalidArgumentException 47 | */ 48 | public function __construct( 49 | ?string $Printertype = 'GraphicFile|PDF', 50 | ?string $MessageID = null, 51 | string|DateTimeInterface|null $MessageTimeStamp = null 52 | ) { 53 | parent::__construct(MessageID: $MessageID, MessageTimeStamp: $MessageTimeStamp); 54 | 55 | $this->setPrintertype(Printertype: $Printertype); 56 | } 57 | 58 | /** 59 | * @return string|null 60 | */ 61 | public function getPrintertype(): ?string 62 | { 63 | return $this->Printertype; 64 | } 65 | 66 | /** 67 | * @param string|null $Printertype 68 | * 69 | * @return static 70 | */ 71 | public function setPrintertype(?string $Printertype): static 72 | { 73 | $this->Printertype = $Printertype; 74 | 75 | return $this; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/ConfirmingServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Entity\Response\ConfirmingResponseShipment; 33 | use Firstred\PostNL\Exception\CifDownException; 34 | use Firstred\PostNL\Exception\CifException; 35 | use Firstred\PostNL\Exception\DeserializationException; 36 | use Firstred\PostNL\Exception\HttpClientException; 37 | use Firstred\PostNL\Exception\InvalidConfigurationException; 38 | use Firstred\PostNL\Exception\NotSupportedException; 39 | use Firstred\PostNL\Exception\ResponseException; 40 | use Psr\Http\Message\ResponseInterface; 41 | 42 | /** 43 | * @since 2.0.0 44 | * 45 | * @internal 46 | */ 47 | interface ConfirmingServiceResponseProcessorInterface 48 | { 49 | /** 50 | * Process the 'confirm label' server response. 51 | * 52 | * @param ResponseInterface $response 53 | * 54 | * @return ConfirmingResponseShipment[] 55 | * 56 | * @throws CifDownException 57 | * @throws CifException 58 | * @throws DeserializationException 59 | * @throws HttpClientException 60 | * @throws NotSupportedException 61 | * @throws ResponseException 62 | * @throws InvalidConfigurationException 63 | * 64 | * @since 2.0.0 65 | */ 66 | public function processConfirmResponse(ResponseInterface $response): array; 67 | } 68 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/TimeframeServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Entity\Response\ResponseTimeframes; 33 | use Firstred\PostNL\Exception\CifDownException; 34 | use Firstred\PostNL\Exception\CifException; 35 | use Firstred\PostNL\Exception\DeserializationException; 36 | use Firstred\PostNL\Exception\HttpClientException; 37 | use Firstred\PostNL\Exception\InvalidConfigurationException; 38 | use Firstred\PostNL\Exception\NotSupportedException; 39 | use Firstred\PostNL\Exception\ResponseException; 40 | use Psr\Http\Message\ResponseInterface; 41 | 42 | /** 43 | * @since 2.0.0 44 | * 45 | * @internal 46 | */ 47 | interface TimeframeServiceResponseProcessorInterface 48 | { 49 | /** 50 | * Process the 'get timeframes' server response. 51 | * 52 | * @param ResponseInterface $response 53 | * 54 | * @return ResponseTimeframes 55 | * 56 | * @throws CifDownException 57 | * @throws CifException 58 | * @throws DeserializationException 59 | * @throws HttpClientException 60 | * @throws InvalidConfigurationException 61 | * @throws NotSupportedException 62 | * @throws ResponseException 63 | * 64 | * @since 2.0.0 65 | */ 66 | public function processGetTimeframesResponse(ResponseInterface $response): ResponseTimeframes; 67 | } 68 | -------------------------------------------------------------------------------- /src/Exception/ResponseException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | use Exception; 33 | use Psr\Http\Message\ResponseInterface; 34 | 35 | /** 36 | * Class ResponseException. 37 | * 38 | * Thrown when there was a problem with the response returned by the CIF API. 39 | * 40 | * @since 1.0.0 41 | */ 42 | class ResponseException extends ApiException 43 | { 44 | /** @var ResponseInterface */ 45 | private ?ResponseInterface $response; 46 | 47 | /** 48 | * ResponseException constructor. 49 | * 50 | * @param string $message 51 | * @param int $code 52 | * @param Exception|null $previous 53 | * @param ResponseInterface|null $response 54 | */ 55 | public function __construct(string $message = '', int $code = 0, $previous = null, ?ResponseInterface $response = null) 56 | { 57 | parent::__construct(message: $message, code: $code, previous: $previous); 58 | 59 | $this->response = $response; 60 | } 61 | 62 | /** 63 | * @param ResponseInterface $response 64 | */ 65 | public function setResponse(ResponseInterface $response) 66 | { 67 | $this->response = $response; 68 | } 69 | 70 | /** 71 | * @return ResponseInterface 72 | */ 73 | public function getResponse(): ?ResponseInterface 74 | { 75 | return $this->response; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/DeliveryDateServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\GetDeliveryDate; 33 | use Firstred\PostNL\Entity\Request\GetSentDateRequest; 34 | use Firstred\PostNL\Exception\InvalidArgumentException; 35 | use Firstred\PostNL\Exception\InvalidConfigurationException; 36 | use Psr\Http\Message\RequestInterface; 37 | 38 | /** 39 | * @since 2.0.0 40 | * 41 | * @internal 42 | */ 43 | interface DeliveryDateServiceRequestBuilderInterface 44 | { 45 | /** 46 | * Build the 'get delivery date' HTTP request. 47 | * 48 | * @param GetDeliveryDate $getDeliveryDate 49 | * 50 | * @return RequestInterface 51 | * 52 | * @throws InvalidArgumentException 53 | * @throws InvalidConfigurationException 54 | * 55 | * @since 2.0.0 56 | */ 57 | public function buildGetDeliveryDateRequest(GetDeliveryDate $getDeliveryDate): RequestInterface; 58 | 59 | /** 60 | * Build the 'get sent date' HTTP request. 61 | * 62 | * @param GetSentDateRequest $getSentDate 63 | * 64 | * @return RequestInterface 65 | * 66 | * @throws InvalidArgumentException 67 | * @throws InvalidConfigurationException 68 | * 69 | * @since 2.0.0 70 | */ 71 | public function buildGetSentDateRequest(GetSentDateRequest $getSentDate): RequestInterface; 72 | } 73 | -------------------------------------------------------------------------------- /src/Service/BarcodeServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Entity\Request\GenerateBarcode; 33 | use Firstred\PostNL\Exception\CifDownException; 34 | use Firstred\PostNL\Exception\CifException; 35 | use Firstred\PostNL\Exception\HttpClientException; 36 | use Firstred\PostNL\Exception\InvalidConfigurationException; 37 | use Firstred\PostNL\Exception\ResponseException; 38 | 39 | /** 40 | * @since 1.2.0 41 | */ 42 | interface BarcodeServiceInterface extends ServiceInterface 43 | { 44 | /** 45 | * Generate a single barcode. 46 | * 47 | * @throws CifDownException 48 | * @throws CifException 49 | * @throws HttpClientException 50 | * @throws ResponseException 51 | * @throws InvalidConfigurationException 52 | * 53 | * @since 1.0.0 54 | */ 55 | public function generateBarcode(GenerateBarcode $generateBarcode): string; 56 | 57 | /** 58 | * Generate multiple barcodes at once. 59 | * 60 | * @param GenerateBarcode[] $generateBarcodes 61 | * 62 | * @return string[] Barcodes 63 | * 64 | * @throws CifDownException 65 | * @throws CifException 66 | * @throws HttpClientException 67 | * @throws ResponseException 68 | * @throws InvalidConfigurationException 69 | * 70 | * @since 1.0.0 71 | */ 72 | public function generateBarcodes(array $generateBarcodes): array; 73 | } 74 | -------------------------------------------------------------------------------- /src/Service/TimeframeServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Cache\CacheableServiceInterface; 33 | use Firstred\PostNL\Entity\Request\GetTimeframes; 34 | use Firstred\PostNL\Entity\Response\ResponseTimeframes; 35 | use Firstred\PostNL\Exception\CifDownException; 36 | use Firstred\PostNL\Exception\CifException; 37 | use Firstred\PostNL\Exception\HttpClientException; 38 | use Firstred\PostNL\Exception\InvalidArgumentException as PostNLInvalidArgumentException; 39 | use Firstred\PostNL\Exception\NotFoundException; 40 | use Firstred\PostNL\Exception\NotSupportedException; 41 | use Firstred\PostNL\Exception\ResponseException; 42 | use Psr\Cache\InvalidArgumentException as PsrCacheInvalidArgumentException; 43 | 44 | /** 45 | * @since 1.2.0 46 | */ 47 | interface TimeframeServiceInterface extends ServiceInterface, CacheableServiceInterface 48 | { 49 | /** 50 | * Get timeframes via REST. 51 | * 52 | * @param GetTimeframes $getTimeframes 53 | * 54 | * @return ResponseTimeframes 55 | * 56 | * @throws CifDownException 57 | * @throws CifException 58 | * @throws HttpClientException 59 | * @throws PsrCacheInvalidArgumentException 60 | * @throws NotSupportedException 61 | * @throws PostNLInvalidArgumentException 62 | * @throws ResponseException 63 | * @throws NotFoundException 64 | * 65 | * @since 1.0.0 66 | */ 67 | public function getTimeframes(GetTimeframes $getTimeframes): ResponseTimeframes; 68 | } 69 | -------------------------------------------------------------------------------- /src/Entity/Event.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\Response\CompleteStatusResponseEvent; 34 | 35 | /** 36 | * @since 1.0.0 37 | */ 38 | class Event extends AbstractEntity 39 | { 40 | /** @var CompleteStatusResponseEvent|null $CompleteStatusResponseEvent */ 41 | #[SerializableProperty(type: CompleteStatusResponseEvent::class)] 42 | protected ?CompleteStatusResponseEvent $CompleteStatusResponseEvent = null; 43 | 44 | /** 45 | * @param CompleteStatusResponseEvent|null $CompleteStatusResponseEvent 46 | */ 47 | public function __construct(?CompleteStatusResponseEvent $CompleteStatusResponseEvent = null) 48 | { 49 | parent::__construct(); 50 | 51 | $this->setCompleteStatusResponseEvent(CompleteStatusResponseEvent: $CompleteStatusResponseEvent); 52 | } 53 | 54 | /** 55 | * @return CompleteStatusResponseEvent|null 56 | */ 57 | public function getCompleteStatusResponseEvent(): ?CompleteStatusResponseEvent 58 | { 59 | return $this->CompleteStatusResponseEvent; 60 | } 61 | 62 | /** 63 | * @param CompleteStatusResponseEvent|null $CompleteStatusResponseEvent 64 | * 65 | * @return static 66 | */ 67 | public function setCompleteStatusResponseEvent(?CompleteStatusResponseEvent $CompleteStatusResponseEvent): static 68 | { 69 | $this->CompleteStatusResponseEvent = $CompleteStatusResponseEvent; 70 | 71 | return $this; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Exception/ApiConnectionException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class ApiConnectionException. 34 | * 35 | * Thrown when there is a problem connecting to the CIF API. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class ApiConnectionException extends ApiException 40 | { 41 | /** @var string */ 42 | protected ?string $body; 43 | /** @var object */ 44 | protected ?object $jsonBody; 45 | /** @var array */ 46 | protected ?array $headers; 47 | 48 | /** 49 | * ApiConnectionException constructor. 50 | * 51 | * @param string $message 52 | * @param int $code 53 | * @param string|null $body 54 | * @param object|null $jsonBody 55 | * @param array|null $headers 56 | */ 57 | public function __construct(string $message = '', int $code = 0, $body = null, object $jsonBody = null, array $headers = null) 58 | { 59 | parent::__construct(message: $message, code: $code, previous: null); 60 | 61 | $this->body = $body; 62 | $this->jsonBody = $jsonBody; 63 | $this->headers = $headers; 64 | } 65 | 66 | /** 67 | * @return string 68 | */ 69 | public function getBody(): ?string 70 | { 71 | return $this->body; 72 | } 73 | 74 | /** 75 | * @return object 76 | */ 77 | public function getJsonBody(): ?object 78 | { 79 | return $this->jsonBody; 80 | } 81 | 82 | /** 83 | * @return array 84 | */ 85 | public function getHeaders(): ?array 86 | { 87 | return $this->headers; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Util/RFPdi.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Util; 31 | 32 | use setasign\Fpdi\Fpdi; 33 | 34 | /** 35 | * Class RFPdi. 36 | * 37 | * @credits to haakym on Stack Overflow: https://stackoverflow.com/a/40526456 38 | * 39 | * @codeCoverageIgnore 40 | * 41 | * @internal 42 | */ 43 | class RFPdi extends Fpdi 44 | { 45 | public int $angle = 0; 46 | 47 | public function rotate($angle, $x = -1, $y = -1) 48 | { 49 | if (-1 == $x) { 50 | $x = $this->x; 51 | } 52 | 53 | if (-1 == $y) { 54 | $y = $this->y; 55 | } 56 | 57 | if (0 != $this->angle) { 58 | $this->_out(s: 'Q'); 59 | } 60 | 61 | $this->angle = $angle; 62 | 63 | if (0 != $angle) { 64 | $angle *= M_PI / 180; 65 | $c = cos(num: $angle); 66 | $s = sin(num: $angle); 67 | $cx = $x * $this->k; 68 | $cy = ($this->h - $y) * $this->k; 69 | $this->_out( 70 | s: sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy) 71 | ); 72 | } 73 | } 74 | 75 | public function rotateClockWise() 76 | { 77 | $this->rotate(angle: 270); 78 | } 79 | 80 | public function rotateCounterClockWise() 81 | { 82 | $this->rotate(angle: 90); 83 | } 84 | 85 | public function _endpage() 86 | { 87 | if (0 != $this->angle) { 88 | $this->angle = 0; 89 | $this->_out(s: 'Q'); 90 | } 91 | parent::_endpage(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/Rest/BarcodeServiceRestResponseProcessor.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor\Rest; 31 | 32 | use Firstred\PostNL\Exception\CifDownException; 33 | use Firstred\PostNL\Exception\CifException; 34 | use Firstred\PostNL\Exception\HttpClientException; 35 | use Firstred\PostNL\Exception\InvalidConfigurationException; 36 | use Firstred\PostNL\Exception\ResponseException; 37 | use Firstred\PostNL\Service\ResponseProcessor\BarcodeServiceResponseProcessorInterface; 38 | use JsonException; 39 | use Psr\Http\Message\ResponseInterface; 40 | 41 | /** 42 | * @since 2.0.0 43 | * 44 | * @internal 45 | */ 46 | class BarcodeServiceRestResponseProcessor extends AbstractRestResponseProcessor implements BarcodeServiceResponseProcessorInterface 47 | { 48 | /** 49 | * Process the 'generate barcode' server response. 50 | * 51 | * @param ResponseInterface $response 52 | * 53 | * @return string 54 | * 55 | * @throws CifDownException 56 | * @throws CifException 57 | * @throws HttpClientException 58 | * @throws ResponseException 59 | * @throws InvalidConfigurationException 60 | * 61 | * @since 2.0.0 62 | */ 63 | public function processGenerateBarcodeResponse(ResponseInterface $response): string 64 | { 65 | $this->validateResponse(response: $response); 66 | $body = json_decode(json: static::getResponseText(response: $response)); 67 | 68 | if (!isset($body->Barcode)) { 69 | throw new ResponseException(message: 'Invalid API Response', response: $response); 70 | } 71 | 72 | return $body->Barcode; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Entity/Response/GetLocationsResult.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | 35 | /** 36 | * @since 1.0.0 37 | */ 38 | class GetLocationsResult extends AbstractEntity 39 | { 40 | /** @var ResponseLocation[]|null $ResponseLocation */ 41 | #[SerializableProperty(type: ResponseLocation::class, isArray: true)] 42 | protected ?array $ResponseLocation = null; 43 | 44 | /** 45 | * @param array|null $ResponseLocation 46 | */ 47 | public function __construct( 48 | /* @param ResponseLocation[]|null $ResponseLocation */ 49 | ?array $ResponseLocation = null, 50 | ) { 51 | parent::__construct(); 52 | 53 | $this->setResponseLocation(ResponseLocation: $ResponseLocation); 54 | } 55 | 56 | /** 57 | * @return ResponseLocation[]|null 58 | */ 59 | public function getResponseLocation(): ?array 60 | { 61 | return $this->ResponseLocation; 62 | } 63 | 64 | /** 65 | * @param ResponseLocation[]|null $ResponseLocation 66 | * 67 | * @return static 68 | */ 69 | public function setResponseLocation(?array $ResponseLocation): static 70 | { 71 | if (is_array(value: $ResponseLocation)) { 72 | foreach ($ResponseLocation as $location) { 73 | if (!$location instanceof ResponseLocation) { 74 | throw new \TypeError(message: 'Expected instance of `ResponseLocation`'); 75 | } 76 | } 77 | } 78 | 79 | $this->ResponseLocation = $ResponseLocation; 80 | 81 | return $this; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Entity/Coordinates.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | 34 | /** 35 | * @since 1.0.0 36 | */ 37 | class Coordinates extends AbstractEntity 38 | { 39 | /** @var string|null $Latitude */ 40 | #[SerializableProperty(type: 'string')] 41 | protected ?string $Latitude = null; 42 | 43 | /** @var string|null $Longitude */ 44 | #[SerializableProperty(type: 'string')] 45 | protected ?string $Longitude = null; 46 | 47 | /** 48 | * @param string|null $Latitude 49 | * @param string|null $Longitude 50 | */ 51 | public function __construct(?string $Latitude = null, ?string $Longitude = null) 52 | { 53 | parent::__construct(); 54 | 55 | $this->setLatitude(Latitude: $Latitude); 56 | $this->setLongitude(Longitude: $Longitude); 57 | } 58 | 59 | /** 60 | * @return string|null 61 | */ 62 | public function getLatitude(): ?string 63 | { 64 | return $this->Latitude; 65 | } 66 | 67 | /** 68 | * @param string|null $Latitude 69 | * 70 | * @return static 71 | */ 72 | public function setLatitude(?string $Latitude): static 73 | { 74 | $this->Latitude = $Latitude; 75 | 76 | return $this; 77 | } 78 | 79 | /** 80 | * @return string|null 81 | */ 82 | public function getLongitude(): ?string 83 | { 84 | return $this->Longitude; 85 | } 86 | 87 | /** 88 | * @param string|null $Longitude 89 | * 90 | * @return static 91 | */ 92 | public function setLongitude(?string $Longitude): static 93 | { 94 | $this->Longitude = $Longitude; 95 | 96 | return $this; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Util/UUID.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Util; 31 | 32 | use Ramsey\Uuid\Uuid as RamseyUuid; 33 | use Symfony\Component\Uid\Uuid as SymfonyUuid; 34 | 35 | /** 36 | * Class UUID. 37 | * 38 | * @since 1.0.0 39 | */ 40 | class UUID 41 | { 42 | /** 43 | * Generate a v4 UUID in RFC 4122 format. 44 | * 45 | * @return string 46 | */ 47 | public static function generate(): string 48 | { 49 | if (class_exists(class: SymfonyUuid::class) && method_exists(object_or_class: SymfonyUuid::class, method: 'v4')) { 50 | return SymfonyUuid::v4()->toRfc4122(); 51 | } 52 | 53 | if (class_exists(class: RamseyUuid::class) && method_exists(object_or_class: RamseyUuid::class, method: 'uuid4')) { 54 | return RamseyUuid::uuid4()->toString(); 55 | } 56 | 57 | return sprintf( 58 | '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', 59 | // 32 bits for "time_low" 60 | mt_rand(min: 0, max: 0xFFFF), 61 | mt_rand(min: 0, max: 0xFFFF), 62 | // 16 bits for "time_mid" 63 | mt_rand(min: 0, max: 0xFFFF), 64 | // 16 bits for "time_hi_and_version", 65 | // four most significant bits holds version number 4 66 | mt_rand(min: 0, max: 0x0FFF) | 0x4000, 67 | // 16 bits, 8 bits for "clk_seq_hi_res", 68 | // 8 bits for "clk_seq_low", 69 | // two most significant bits holds zero and one for variant DCE1.1 70 | mt_rand(min: 0, max: 0x3FFF) | 0x8000, 71 | // 48 bits for "node" 72 | mt_rand(min: 0, max: 0xFFFF), 73 | mt_rand(min: 0, max: 0xFFFF), 74 | mt_rand(min: 0, max: 0xFFFF) 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/Rest/ShippingServiceRestResponseProcessor.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor\Rest; 31 | 32 | use Firstred\PostNL\Entity\Response\SendShipmentResponse; 33 | use Firstred\PostNL\Exception\DeserializationException; 34 | use Firstred\PostNL\Exception\HttpClientException; 35 | use Firstred\PostNL\Exception\InvalidConfigurationException; 36 | use Firstred\PostNL\Exception\NotSupportedException; 37 | use Firstred\PostNL\Exception\ResponseException; 38 | use Firstred\PostNL\Service\ResponseProcessor\ShippingServiceResponseProcessorInterface; 39 | use Psr\Http\Message\ResponseInterface; 40 | 41 | /** 42 | * @since 2.0.0 43 | * 44 | * @internal 45 | */ 46 | class ShippingServiceRestResponseProcessor extends AbstractRestResponseProcessor implements ShippingServiceResponseProcessorInterface 47 | { 48 | /** 49 | * Process the 'send shipment' server response. 50 | * 51 | * @param ResponseInterface $response 52 | * 53 | * @return SendShipmentResponse|null 54 | * 55 | * @throws HttpClientException 56 | * @throws NotSupportedException 57 | * @throws ResponseException 58 | * @throws DeserializationException 59 | * @throws InvalidConfigurationException 60 | * 61 | * @since 2.0.0 62 | */ 63 | public function processSendShipmentResponse(ResponseInterface $response): ?SendShipmentResponse 64 | { 65 | $this->validateResponse(response: $response); 66 | $body = json_decode(json: static::getResponseText(response: $response)); 67 | if (isset($body->ResponseShipments)) { 68 | return SendShipmentResponse::JsonDeserialize(json: (object) ['SendShipmentResponse' => $body]); 69 | } 70 | 71 | return null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/RequestBuilderSettersTrait.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use ParagonIE\HiddenString\HiddenString; 33 | use Psr\Http\Message\RequestFactoryInterface; 34 | use Psr\Http\Message\StreamFactoryInterface; 35 | 36 | /** 37 | * @since 2.0.0 38 | * 39 | * @internal 40 | */ 41 | trait RequestBuilderSettersTrait 42 | { 43 | /** 44 | * @since 2.0.0 45 | */ 46 | public function setApiKey(HiddenString $apiKey): static 47 | { 48 | if (isset($this->adapter)) { 49 | $this->adapter->setApiKey(apiKey: $apiKey); 50 | } 51 | 52 | return parent::setApiKey(apiKey: $apiKey); 53 | } 54 | 55 | /** 56 | * @since 2.0.0 57 | */ 58 | public function setSandbox(bool $sandbox): static 59 | { 60 | if (isset($this->adapter)) { 61 | $this->adapter->setSandbox(sandbox: $sandbox); 62 | } 63 | 64 | return parent::setSandbox(sandbox: $sandbox); 65 | } 66 | 67 | /** 68 | * @since 2.0.0 69 | */ 70 | public function setRequestFactory(RequestFactoryInterface $requestFactory): static 71 | { 72 | if (isset($this->adapter)) { 73 | $this->adapter->setRequestFactory(requestFactory: $requestFactory); 74 | } 75 | 76 | return parent::setRequestFactory(requestFactory: $requestFactory); 77 | } 78 | 79 | /** 80 | * @since 2.0.0 81 | */ 82 | public function setStreamFactory(StreamFactoryInterface $streamFactory): static 83 | { 84 | if (isset($this->adapter)) { 85 | $this->adapter->setStreamFactory(streamFactory: $streamFactory); 86 | } 87 | 88 | return parent::setStreamFactory(streamFactory: $streamFactory); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/AbstractResponseProcessor.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Exception\HttpClientException; 33 | use Firstred\PostNL\Exception\ResponseException; 34 | use GuzzleHttp\Psr7\Response; 35 | use Psr\Http\Message\ResponseInterface; 36 | 37 | /** 38 | * @since 2.0.0 39 | * 40 | * @internal 41 | */ 42 | abstract class AbstractResponseProcessor 43 | { 44 | /** 45 | * Get the response. 46 | * 47 | * @throws ResponseException 48 | * @throws HttpClientException 49 | * 50 | * @since 2.0.0 51 | */ 52 | protected static function getResponseText(array|ResponseInterface|HttpClientException $response): string 53 | { 54 | // Guzzle returned promises 55 | if (is_array(value: $response)) { 56 | if (isset($response['reason'])) { 57 | $response = $response['reason']; 58 | } elseif (isset($response['value'])) { 59 | $response = $response['value']; 60 | } 61 | } 62 | 63 | if ($response instanceof ResponseInterface) { 64 | return (string) $response->getBody(); 65 | } elseif (is_a(object_or_class: $response, class: HttpClientException::class)) { 66 | $exception = $response; 67 | if (method_exists(object_or_class: $response, method: 'getResponse')) { 68 | $response = $response->getResponse(); 69 | } 70 | if (!$response || $response instanceof $exception) { 71 | throw $exception; 72 | } 73 | 74 | /* @var Response $response */ 75 | return (string) $response->getBody(); 76 | } else { 77 | throw new ResponseException(message: 'Unknown response type'); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Service/ConfirmingServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Entity\Request\Confirming; 33 | use Firstred\PostNL\Entity\Response\ConfirmingResponseShipment; 34 | use Firstred\PostNL\Exception\CifDownException; 35 | use Firstred\PostNL\Exception\CifException; 36 | use Firstred\PostNL\Exception\HttpClientException; 37 | use Firstred\PostNL\Exception\InvalidArgumentException; 38 | use Firstred\PostNL\Exception\NotFoundException; 39 | use Firstred\PostNL\Exception\NotSupportedException; 40 | use Firstred\PostNL\Exception\ResponseException; 41 | 42 | /** 43 | * @since 1.2.0 44 | */ 45 | interface ConfirmingServiceInterface extends ServiceInterface 46 | { 47 | /** 48 | * Generate a single barcode via REST. 49 | * 50 | * @param Confirming $confirming 51 | * 52 | * @return ConfirmingResponseShipment 53 | * 54 | * @throws CifDownException 55 | * @throws CifException 56 | * @throws ResponseException 57 | * @throws HttpClientException 58 | * @throws NotSupportedException 59 | * @throws InvalidArgumentException 60 | * @throws NotFoundException 61 | * 62 | * @since 1.0.0 63 | */ 64 | public function confirmShipment(Confirming $confirming): ConfirmingResponseShipment; 65 | 66 | /** 67 | * Confirm multiple shipments. 68 | * 69 | * @param Confirming[] $confirms ['uuid' => Confirming, ...] 70 | * 71 | * @return ConfirmingResponseShipment[] 72 | * 73 | * @throws CifDownException 74 | * @throws CifException 75 | * @throws HttpClientException 76 | * @throws InvalidArgumentException 77 | * @throws NotSupportedException 78 | * @throws ResponseException 79 | * 80 | * @since 1.0.0 81 | */ 82 | public function confirmShipments(array $confirms): array; 83 | } 84 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/LocationServiceRequestBuilderInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder; 31 | 32 | use Firstred\PostNL\Entity\Request\GetLocation; 33 | use Firstred\PostNL\Entity\Request\GetLocationsInArea; 34 | use Firstred\PostNL\Entity\Request\GetNearestLocations; 35 | use Firstred\PostNL\Exception\InvalidArgumentException; 36 | use Firstred\PostNL\Exception\InvalidConfigurationException; 37 | use Psr\Http\Message\RequestInterface; 38 | 39 | /** 40 | * @since 2.0.0 41 | * 42 | * @internal 43 | */ 44 | interface LocationServiceRequestBuilderInterface 45 | { 46 | /** 47 | * Build the 'get nearest locations' HTTP request. 48 | * 49 | * @param GetNearestLocations $getNearestLocations 50 | * 51 | * @return RequestInterface 52 | * 53 | * @throws InvalidArgumentException 54 | * @throws InvalidConfigurationException 55 | * @since 2.0.0 56 | */ 57 | public function buildGetNearestLocationsRequest(GetNearestLocations $getNearestLocations): RequestInterface; 58 | 59 | /** 60 | * Build the 'get locations in area' HTTP. 61 | * 62 | * @param GetLocationsInArea $getLocations 63 | * 64 | * @return RequestInterface 65 | * 66 | * @since 2.0.0 67 | * 68 | * @throws InvalidConfigurationException 69 | * @throws InvalidArgumentException 70 | */ 71 | public function buildGetLocationsInAreaRequest(GetLocationsInArea $getLocations): RequestInterface; 72 | 73 | /** 74 | * Build the 'get single location' HTTP request. 75 | * 76 | * @param GetLocation $getLocation 77 | * 78 | * @return RequestInterface 79 | * 80 | * @throws InvalidConfigurationException 81 | * @throws InvalidArgumentException 82 | * 83 | * @since 2.0.0 84 | */ 85 | public function buildGetLocationRequest(GetLocation $getLocation): RequestInterface; 86 | } 87 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/Rest/LabellingServiceRestResponseProcessor.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor\Rest; 31 | 32 | use Firstred\PostNL\Entity\Response\GenerateLabelResponse; 33 | use Firstred\PostNL\Exception\ApiException; 34 | use Firstred\PostNL\Exception\DeserializationException; 35 | use Firstred\PostNL\Exception\HttpClientException; 36 | use Firstred\PostNL\Exception\InvalidConfigurationException; 37 | use Firstred\PostNL\Exception\NotSupportedException; 38 | use Firstred\PostNL\Exception\ResponseException; 39 | use Firstred\PostNL\Service\ResponseProcessor\LabellingServiceResponseProcessorInterface; 40 | use Psr\Http\Message\ResponseInterface; 41 | 42 | /** 43 | * @since 2.0.0 44 | * 45 | * @internal 46 | */ 47 | class LabellingServiceRestResponseProcessor extends AbstractRestResponseProcessor implements LabellingServiceResponseProcessorInterface 48 | { 49 | /** 50 | * Process the 'generate label' server response. 51 | * 52 | * @param ResponseInterface $response 53 | * 54 | * @return GenerateLabelResponse 55 | * 56 | * @throws HttpClientException 57 | * @throws NotSupportedException 58 | * @throws ResponseException 59 | * @throws DeserializationException 60 | * @throws ApiException 61 | * @throws InvalidConfigurationException 62 | * 63 | * @since 2.0.0 64 | */ 65 | public function processGenerateLabelResponse(ResponseInterface $response): GenerateLabelResponse 66 | { 67 | $this->validateResponse(response: $response); 68 | $body = json_decode(json: static::getResponseText(response: $response)); 69 | 70 | if (isset($body->ResponseShipments)) { 71 | return GenerateLabelResponse::jsonDeserialize(json: (object) ['GenerateLabelResponse' => $body]); 72 | } 73 | 74 | throw new ResponseException(message: 'Invalid API response', response: $response); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firstred/postnl-api-php", 3 | "description": "PostNL REST API PHP Bindings", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Michael Dekker", 9 | "email": "git@michaeldekker.nl" 10 | } 11 | ], 12 | "keywords": ["postnl", "shipping", "shipments"], 13 | "scripts": { 14 | "docs:build": "sphinx-build -b html docs docsbuild", 15 | "test": "vendor/bin/phpunit -c phpunit.xml --testdox tests", 16 | "csfix": "vendor/bin/php-cs-fixer --config=.php-cs-fixer.php fix src/ tests/", 17 | "csfix:dryrun": "vendor/bin/php-cs-fixer --config=.php-cs-fixer.php --dry-run fix src/ tests/", 18 | "csfix:src": "vendor/bin/php-cs-fixer --config=.php-cs-fixer.php fix src/", 19 | "csfix:tests": "vendor/bin/php-cs-fixer --config=.php-cs-fixer.php fix tests/" 20 | }, 21 | "require": { 22 | "php": "^8.1", 23 | "composer/ca-bundle": "^1.0", 24 | "guzzlehttp/promises": "^1.0 || ^2.0", 25 | "guzzlehttp/psr7": "^1.7 || ^2.0", 26 | "paragonie/hidden-string": "^2.0", 27 | "php-http/discovery": "^1.9.1", 28 | "psr/cache": "^1.0 || ^2.0 || ^3.0", 29 | "psr/clock": "^1.0", 30 | "psr/http-factory": "^1.0", 31 | "psr/http-factory-implementation": "*", 32 | "psr/http-message": "^1.0 || ^2.0", 33 | "psr/http-message-implementation": "*", 34 | "psr/log": "^1.0.2 || ^2.0 || ^3.0", 35 | "setasign/fpdf": "^1.8", 36 | "setasign/fpdi": "^2.3", 37 | "symfony/deprecation-contracts": "^2.1 || ^3.0" 38 | }, 39 | "require-dev": { 40 | "cache/void-adapter": "^1.2", 41 | "friendsofphp/php-cs-fixer": "^3.16", 42 | "guzzlehttp/guzzle": "^7.2", 43 | "monolog/monolog": "^3.0", 44 | "php-http/mock-client": "^1.3", 45 | "phpunit/phpunit": "^10.5", 46 | "symfony/clock": "^6.0", 47 | "symfony/dotenv": "^6.0" 48 | }, 49 | "suggest": { 50 | "abbadon1334/phpdoc-to-rst": "Build the documentation", 51 | "giggsey/libphonenumber-for-php": "To automatically format and check phone numbers -- supports ^8.12", 52 | "guzzlehttp/guzzle": "One of the most popular HTTP clients available -- supports ^7.0", 53 | "guzzlehttp/psr7": "One of the most popular HTTP clients available -- supports ^7.0", 54 | "php-http/httplug": "Required if you want to use an alternative PSR-18, async or HTTPlug Client", 55 | "php-http/message-factory": "Required if you want to use an alternative PSR-18, async or HTTPlug Client", 56 | "psr/http-factory": "Required if you want to use an alternative PSR-18, async or HTTPlug Client", 57 | "symfony/http-client": "Another popular HTTP client you can use natively -- supports ^5.4" 58 | }, 59 | "autoload": { 60 | "files": ["src/deprecated.php"], 61 | "psr-4": { 62 | "Firstred\\PostNL\\": "src/" 63 | } 64 | }, 65 | "autoload-dev": { 66 | "psr-4": { 67 | "Firstred\\PostNL\\Tests\\": "tests/" 68 | } 69 | }, 70 | "support": { 71 | "email": "git@michaeldekker.nl", 72 | "docs": "https://postnl-php.readthedocs.io/", 73 | "source": "https://github.com/firstred/postnl-api-php", 74 | "issues": "https://github.com/firstred/postnl-api-php/issues" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Entity/Sustainability.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | 34 | /** 35 | * Class Sustainability. 36 | * 37 | * @since 1.4.2 38 | */ 39 | class Sustainability extends AbstractEntity 40 | { 41 | /** @var string|null */ 42 | #[SerializableProperty(type: 'string')] 43 | protected ?string $Code; 44 | 45 | /** @var string|null */ 46 | #[SerializableProperty(type: 'string')] 47 | protected ?string $Description; 48 | 49 | /** 50 | * @param string|null $Code 51 | * @param string|null $Description 52 | */ 53 | public function __construct(?string $Code = null, ?string $Description = null) 54 | { 55 | parent::__construct(); 56 | 57 | $this->setCode(Code: $Code); 58 | $this->setDescription(Description: $Description); 59 | } 60 | 61 | /** 62 | * @return string|null 63 | * 64 | * @since 1.4.2 65 | */ 66 | public function getCode(): ?string 67 | { 68 | return $this->Code; 69 | } 70 | 71 | /** 72 | * @param string|null $Code 73 | * 74 | * @return static 75 | * 76 | * @since 1.4.2 77 | */ 78 | public function setCode(?string $Code): static 79 | { 80 | $this->Code = $Code; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * @return string|null 87 | * 88 | * @since 1.4.2 89 | */ 90 | public function getDescription(): ?string 91 | { 92 | return $this->Description; 93 | } 94 | 95 | /** 96 | * @param string|null $Description 97 | * 98 | * @return static 99 | * 100 | * @since 1.4.2 101 | */ 102 | public function setDescription(?string $Description): static 103 | { 104 | $this->Description = $Description; 105 | 106 | return $this; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Entity/Request/GenerateBarcode.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Request; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | use Firstred\PostNL\Entity\Barcode; 35 | use Firstred\PostNL\Entity\Customer; 36 | 37 | /** 38 | * @since 1.0.0 39 | */ 40 | class GenerateBarcode extends AbstractEntity 41 | { 42 | /** @var Customer|null $Customer */ 43 | #[SerializableProperty(type: Customer::class)] 44 | protected ?Customer $Customer = null; 45 | 46 | /** @var Barcode|null $Barcode */ 47 | #[SerializableProperty(type: Barcode::class)] 48 | protected ?Barcode $Barcode = null; 49 | 50 | /** 51 | * @param Barcode|null $Barcode 52 | * @param Customer|null $Customer 53 | */ 54 | public function __construct(?Barcode $Barcode = null, ?Customer $Customer = null) 55 | { 56 | parent::__construct(); 57 | 58 | $this->setBarcode(Barcode: $Barcode); 59 | $this->setCustomer(Customer: $Customer); 60 | } 61 | 62 | /** 63 | * @return Customer|null 64 | */ 65 | public function getCustomer(): ?Customer 66 | { 67 | return $this->Customer; 68 | } 69 | 70 | /** 71 | * @param Customer|null $Customer 72 | * 73 | * @return static 74 | */ 75 | public function setCustomer(?Customer $Customer): static 76 | { 77 | $this->Customer = $Customer; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * @return Barcode|null 84 | */ 85 | public function getBarcode(): ?Barcode 86 | { 87 | return $this->Barcode; 88 | } 89 | 90 | /** 91 | * @param Barcode|null $Barcode 92 | * 93 | * @return static 94 | */ 95 | public function setBarcode(?Barcode $Barcode): static 96 | { 97 | $this->Barcode = $Barcode; 98 | 99 | return $this; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Service/LabellingServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Entity\Request\GenerateBarcode; 33 | use Firstred\PostNL\Entity\Request\GenerateLabel; 34 | use Firstred\PostNL\Entity\Response\GenerateLabelResponse; 35 | use Firstred\PostNL\Exception\CifDownException; 36 | use Firstred\PostNL\Exception\CifException; 37 | use Firstred\PostNL\Exception\HttpClientException; 38 | use Firstred\PostNL\Exception\InvalidArgumentException as PostNLInvalidArgumentException; 39 | use Firstred\PostNL\Exception\NotFoundException; 40 | use Firstred\PostNL\Exception\NotSupportedException; 41 | use Firstred\PostNL\Exception\ResponseException; 42 | use Psr\Cache\InvalidArgumentException as PsrCacheInvalidArgumentException; 43 | 44 | /** 45 | * @since 1.2.0 46 | */ 47 | interface LabellingServiceInterface extends ServiceInterface 48 | { 49 | /** 50 | * Generate a single barcode via REST. 51 | * 52 | * @throws CifDownException 53 | * @throws CifException 54 | * @throws ResponseException 55 | * @throws PsrCacheInvalidArgumentException 56 | * @throws HttpClientException 57 | * @throws NotSupportedException 58 | * @throws PostNLInvalidArgumentException 59 | * @throws NotFoundException 60 | * 61 | * @since 1.0.0 62 | */ 63 | public function generateLabel(GenerateLabel $generateLabel, bool $confirm = true): GenerateLabelResponse; 64 | 65 | /** 66 | * Generate multiple labels at once. 67 | * 68 | * @param array $generateLabels 69 | * 70 | * @return array 71 | * 72 | * @throws HttpClientException 73 | * @throws NotSupportedException 74 | * @throws PostNLInvalidArgumentException 75 | * @throws PsrCacheInvalidArgumentException 76 | * @throws ResponseException 77 | * 78 | * @since 1.0.0 79 | */ 80 | public function generateLabels(array $generateLabels): array; 81 | } 82 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/DeliveryDateServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Entity\Response\GetDeliveryDateResponse; 33 | use Firstred\PostNL\Entity\Response\GetSentDateResponse; 34 | use Firstred\PostNL\Exception\ApiException; 35 | use Firstred\PostNL\Exception\DeserializationException; 36 | use Firstred\PostNL\Exception\HttpClientException; 37 | use Firstred\PostNL\Exception\InvalidArgumentException as PostNLInvalidArgumentException; 38 | use Firstred\PostNL\Exception\InvalidConfigurationException; 39 | use Firstred\PostNL\Exception\NotSupportedException; 40 | use Firstred\PostNL\Exception\ResponseException; 41 | use Psr\Http\Message\ResponseInterface; 42 | 43 | /** 44 | * @since 2.0.0 45 | * 46 | * @internal 47 | */ 48 | interface DeliveryDateServiceResponseProcessorInterface 49 | { 50 | /** 51 | * Process the 'get delivery date' server response. 52 | * 53 | * @param ResponseInterface $response 54 | * 55 | * @return GetDeliveryDateResponse 56 | * 57 | * @throws ApiException 58 | * @throws HttpClientException 59 | * @throws PostNLInvalidArgumentException 60 | * @throws ResponseException 61 | * @throws DeserializationException 62 | * 63 | * @since 2.0.0 64 | */ 65 | public function processGetDeliveryDateResponse(ResponseInterface $response): GetDeliveryDateResponse; 66 | 67 | /** 68 | * Process the 'get sent date' server response. 69 | * 70 | * @param ResponseInterface $response 71 | * 72 | * @return GetSentDateResponse 73 | * 74 | * @throws ApiException 75 | * @throws DeserializationException 76 | * @throws HttpClientException 77 | * @throws NotSupportedException 78 | * @throws ResponseException 79 | * @throws InvalidConfigurationException 80 | * 81 | * @since 2.0.0 82 | */ 83 | public function processGetSentDateResponse(ResponseInterface $response): GetSentDateResponse; 84 | } 85 | -------------------------------------------------------------------------------- /src/Attribute/SerializableProperty.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Attribute; 31 | 32 | use Attribute; 33 | use Firstred\PostNL\Exception\InvalidArgumentException; 34 | use Firstred\PostNL\Exception\InvalidConfigurationException; 35 | use ReflectionClass; 36 | use ReflectionException; 37 | 38 | #[Attribute(flags: Attribute::TARGET_PROPERTY)] 39 | class SerializableProperty 40 | { 41 | /** 42 | * This indicates that the given property is serializable. All serialization details should 43 | * be passed to the attribute, making it completely serializable without relying on reflection 44 | * of the property itself. 45 | * 46 | * @param class-string|'bool'|'int'|'float'|'string' $type Property type 47 | * @param bool $isArray Should the property be an array 48 | * @param string[] $aliases Property shortname aliases such as `Address` 49 | * @param class-string[] $supportedServices Supported services, empty array = all 50 | * 51 | * @throws InvalidArgumentException 52 | * @throws InvalidConfigurationException 53 | * 54 | * @since 2.0.0 55 | */ 56 | public function __construct( 57 | public string $type, 58 | public bool $isArray = false, 59 | public array $aliases = [], 60 | public array $supportedServices = [], 61 | ) { 62 | try { 63 | foreach ($this->supportedServices as $supportedService) { 64 | $reflectionSupportedService = new ReflectionClass(objectOrClass: $supportedService); 65 | if (!$reflectionSupportedService->isInterface()) { 66 | throw new InvalidArgumentException(message: 'Only interfaces of services can be passed'); 67 | } 68 | } 69 | } catch (ReflectionException $e) { 70 | throw new InvalidConfigurationException(message: 'Reflection is not working', previous: $e); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Entity/Response/ConfirmingResponseShipment.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | use Firstred\PostNL\Entity\Warning; 35 | 36 | /** 37 | * @since 1.0.0 38 | */ 39 | class ConfirmingResponseShipment extends AbstractEntity 40 | { 41 | /** @var string|null $Barcode */ 42 | #[SerializableProperty(type: 'string')] 43 | protected ?string $Barcode = null; 44 | 45 | /** @var Warning[]|null $Warnings */ 46 | #[SerializableProperty(type: Warning::class, isArray: true)] 47 | protected ?array $Warnings = null; 48 | 49 | /** 50 | * @param string|null $Barcode 51 | * @param array|null $Warnings 52 | */ 53 | public function __construct( 54 | ?string $Barcode = null, 55 | /* @param Warning[]|null $Warnings */ 56 | ?array $Warnings = null 57 | ) { 58 | parent::__construct(); 59 | 60 | $this->setBarcode(Barcode: $Barcode); 61 | $this->setWarnings(Warnings: $Warnings); 62 | } 63 | 64 | /** 65 | * @return string|null 66 | */ 67 | public function getBarcode(): ?string 68 | { 69 | return $this->Barcode; 70 | } 71 | 72 | /** 73 | * @param string|null $Barcode 74 | * 75 | * @return static 76 | */ 77 | public function setBarcode(?string $Barcode): static 78 | { 79 | $this->Barcode = $Barcode; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * @return Warning[]|null 86 | */ 87 | public function getWarnings(): ?array 88 | { 89 | return $this->Warnings; 90 | } 91 | 92 | /** 93 | * @param Warning[]|null $Warnings 94 | * 95 | * @return static 96 | */ 97 | public function setWarnings(?array $Warnings): static 98 | { 99 | $this->Warnings = $Warnings; 100 | 101 | return $this; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Entity/Response/MergedLabel.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | use Firstred\PostNL\Entity\Label; 35 | 36 | /** 37 | * @since 1.0.0 38 | */ 39 | class MergedLabel extends AbstractEntity 40 | { 41 | /** @var string[]|null $Barcodes */ 42 | #[SerializableProperty(type: 'string', isArray: true)] 43 | protected ?array $Barcodes = null; 44 | 45 | /** @var Label[]|null $Labels */ 46 | #[SerializableProperty(type: Label::class, isArray: true)] 47 | protected ?array $Labels = null; 48 | 49 | /** 50 | * @param array|null $Barcodes 51 | * @param array|null $Labels 52 | */ 53 | public function __construct( 54 | /* @param string[]|null $Barcodes */ 55 | ?array $Barcodes = null, 56 | /* @param Label[]|null $Labels */ 57 | ?array $Labels = null, 58 | ) { 59 | parent::__construct(); 60 | 61 | $this->setBarcodes(Barcodes: $Barcodes); 62 | $this->setLabels(Labels: $Labels); 63 | } 64 | 65 | /** 66 | * @return string[]|null 67 | */ 68 | public function getBarcodes(): ?array 69 | { 70 | return $this->Barcodes; 71 | } 72 | 73 | /** 74 | * @param string[]|null $Barcodes 75 | * 76 | * @return static 77 | */ 78 | public function setBarcodes(?array $Barcodes): static 79 | { 80 | $this->Barcodes = $Barcodes; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * @return Label[]|null 87 | */ 88 | public function getLabels(): ?array 89 | { 90 | return $this->Labels; 91 | } 92 | 93 | /** 94 | * @param Label[]|null $Labels 95 | * 96 | * @return static 97 | */ 98 | public function setLabels(?array $Labels): static 99 | { 100 | $this->Labels = $Labels; 101 | 102 | return $this; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/HttpClient/HttpClientInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\HttpClient; 31 | 32 | use Firstred\PostNL\Exception\HttpClientException; 33 | use Psr\Http\Message\RequestInterface; 34 | use Psr\Http\Message\ResponseInterface; 35 | use Psr\Log\LoggerAwareInterface; 36 | use Psr\Log\LoggerInterface; 37 | 38 | /** 39 | * Interface ClientInterface. 40 | * 41 | * @since 1.0.0 42 | */ 43 | interface HttpClientInterface extends LoggerAwareInterface 44 | { 45 | /** 46 | * Get the logger. 47 | * 48 | * @return LoggerInterface 49 | */ 50 | public function getLogger(): LoggerInterface; 51 | 52 | /** 53 | * Adds a request to the list of pending requests 54 | * Using the ID you can replace a request. 55 | * 56 | * @param string $id Request ID 57 | * @param RequestInterface $request PSR-7 request 58 | * 59 | * @return int|string 60 | */ 61 | public function addOrUpdateRequest(string $id, RequestInterface $request): int|string; 62 | 63 | /** 64 | * Remove a request from the list of pending requests. 65 | * 66 | * @param string $id 67 | */ 68 | public function removeRequest(string $id); 69 | 70 | /** 71 | * Clear all requests. 72 | */ 73 | public function clearRequests(); 74 | 75 | /** 76 | * Do a single request. 77 | * 78 | * Exceptions are captured into the result array 79 | * 80 | * @param RequestInterface $request 81 | * 82 | * @return ResponseInterface 83 | * 84 | * @throws HttpClientException 85 | */ 86 | public function doRequest(RequestInterface $request): ResponseInterface; 87 | 88 | /** 89 | * Do all async requests. 90 | * 91 | * Exceptions are captured into the result array 92 | * 93 | * @param RequestInterface[] $requests 94 | * 95 | * @return ResponseInterface|ResponseInterface[]|HttpClientException|HttpClientException[] 96 | */ 97 | public function doRequests(array $requests = []): array|HttpClientException|ResponseInterface; 98 | } 99 | -------------------------------------------------------------------------------- /src/Exception/CifException.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Exception; 31 | 32 | /** 33 | * Class CifException. 34 | * 35 | * Thrown when the CIF API has a fatal error. 36 | * 37 | * @since 1.0.0 38 | */ 39 | class CifException extends ApiException 40 | { 41 | /** @var array */ 42 | protected array $messages; 43 | 44 | /** 45 | * CifException constructor. 46 | * 47 | * @param string|string[] $message In case of multiple errors, the format looks like: 48 | * [ 49 | * 'description' => string , 50 | * 'message' => string , 51 | * 'code' => int 52 | * ] 53 | * The code param will be discarded if `$message` is an array 54 | * @param int $code 55 | * @param \Throwable|null $previous 56 | */ 57 | public function __construct($message = '', int $code = 0, ?\Throwable $previous = null) 58 | { 59 | if (is_array(value: $message)) { 60 | $this->messages = $message; 61 | 62 | $message = $this->messages[0]['message']; 63 | if (!empty($this->messages[0]['description'])) { 64 | $message .= ' (' . $this->messages[0]['description'] . ')'; 65 | } 66 | $code = $this->messages[0]['code']; 67 | } else { 68 | $this->messages = [ 69 | [ 70 | 'message' => $message, 71 | 'description' => $message, 72 | 'code' => $code, 73 | ], 74 | ]; 75 | } 76 | 77 | parent::__construct(message: $message, code: $code, previous: $previous); 78 | } 79 | 80 | /** 81 | * Get error messages and codes. 82 | * 83 | * @return array|string|string[] 84 | */ 85 | public function getMessagesDescriptionsAndCodes(): array|string 86 | { 87 | return $this->messages; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Service/DeliveryDateServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Cache\CacheableServiceInterface; 33 | use Firstred\PostNL\Entity\Request\GetDeliveryDate; 34 | use Firstred\PostNL\Entity\Request\GetSentDateRequest; 35 | use Firstred\PostNL\Entity\Response\GetDeliveryDateResponse; 36 | use Firstred\PostNL\Entity\Response\GetSentDateResponse; 37 | use Firstred\PostNL\Exception\CifDownException; 38 | use Firstred\PostNL\Exception\CifException; 39 | use Firstred\PostNL\Exception\HttpClientException; 40 | use Firstred\PostNL\Exception\InvalidArgumentException as PostNLInvalidArgumentException; 41 | use Firstred\PostNL\Exception\NotFoundException; 42 | use Firstred\PostNL\Exception\NotSupportedException; 43 | use Firstred\PostNL\Exception\ResponseException; 44 | use Psr\Cache\InvalidArgumentException as PsrCacheInvalidArgumentException; 45 | 46 | /** 47 | * @since 1.0.0 48 | */ 49 | interface DeliveryDateServiceInterface extends ServiceInterface, CacheableServiceInterface 50 | { 51 | /** 52 | * Get the delivery date. 53 | * 54 | * @param GetDeliveryDate $getDeliveryDate 55 | * 56 | * @return GetDeliveryDateResponse 57 | * 58 | * @throws CifDownException 59 | * @throws CifException 60 | * @throws ResponseException 61 | * @throws HttpClientException 62 | * @throws PostNLInvalidArgumentException 63 | * @throws NotFoundException 64 | * @throws PsrCacheInvalidArgumentException 65 | * 66 | * @since 2.0.0 67 | */ 68 | public function getDeliveryDate(GetDeliveryDate $getDeliveryDate): GetDeliveryDateResponse; 69 | 70 | /** 71 | * Get the shipping date. 72 | * 73 | * @param GetSentDateRequest $getSentDate 74 | * 75 | * @return GetSentDateResponse 76 | * 77 | * @throws CifDownException 78 | * @throws CifException 79 | * @throws ResponseException 80 | * @throws HttpClientException 81 | * @throws NotSupportedException 82 | * @throws PostNLInvalidArgumentException 83 | * @throws NotFoundException 84 | * @throws PsrCacheInvalidArgumentException 85 | * 86 | * @since 2.0.0 87 | */ 88 | public function getSentDate(GetSentDateRequest $getSentDate): GetSentDateResponse; 89 | } 90 | -------------------------------------------------------------------------------- /src/Cache/CacheableServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Cache; 31 | 32 | use DateInterval; 33 | use DateTimeInterface; 34 | use Firstred\PostNL\Clock\ClockAwareInterface; 35 | use Firstred\PostNL\Service\ServiceInterface; 36 | use Psr\Cache\CacheItemInterface; 37 | use Psr\Cache\CacheItemPoolInterface; 38 | use Psr\Cache\InvalidArgumentException; 39 | 40 | /** 41 | * @since 2.0.0 42 | */ 43 | interface CacheableServiceInterface extends ServiceInterface, ClockAwareInterface 44 | { 45 | /** 46 | * Cache an item. 47 | * 48 | * @param CacheItemInterface $item 49 | * 50 | * @since 2.0.0 51 | */ 52 | public function cacheResponseItem(CacheItemInterface $item); 53 | 54 | /** 55 | * Retrieve a cached item. 56 | * 57 | * @param CacheableRequestEntityInterface $cacheableRequestEntity 58 | * 59 | * @return CacheItemInterface|null 60 | * 61 | * @throws InvalidArgumentException 62 | * 63 | * @since 2.0.0 64 | */ 65 | public function retrieveCachedResponseItem(CacheableRequestEntityInterface $cacheableRequestEntity): ?CacheItemInterface; 66 | 67 | /** 68 | * Delete an item from cache. 69 | * 70 | * @param CacheItemInterface $item 71 | * 72 | * @since 2.0.0 73 | */ 74 | public function removeCachedResponseItem(CacheItemInterface $item); 75 | 76 | /** 77 | * @return DateInterval|DateTimeInterface|int|null 78 | * 79 | * @since 1.2.0 80 | */ 81 | public function getTtl(): DateInterval|DateTimeInterface|int|null; 82 | 83 | /** 84 | * @param DateInterval|DateTimeInterface|int|null $ttl 85 | * 86 | * @return static 87 | * 88 | * @since 1.2.0 89 | */ 90 | public function setTtl(DateInterval|DateTimeInterface|int|null $ttl = null): static; 91 | 92 | /** 93 | * @return CacheItemPoolInterface|null 94 | * 95 | * @since 1.2.0 96 | */ 97 | public function getCache(): ?CacheItemPoolInterface; 98 | 99 | /** 100 | * @param CacheItemPoolInterface|null $cache 101 | * 102 | * @return static 103 | * 104 | * @since 1.2.0 105 | */ 106 | public function setCache(?CacheItemPoolInterface $cache = null): static; 107 | } 108 | -------------------------------------------------------------------------------- /src/Entity/Response/SendShipmentResponse.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | 35 | /** 36 | * @since 1.0.0 37 | */ 38 | class SendShipmentResponse extends AbstractEntity 39 | { 40 | /** @var MergedLabel[]|null $MergedLabels */ 41 | #[SerializableProperty(type: MergedLabel::class, isArray: true)] 42 | protected ?array $MergedLabels = null; 43 | 44 | /** @var ResponseShipment[]|null $ResponseShipments */ 45 | #[SerializableProperty(type: ResponseShipment::class, isArray: true)] 46 | protected ?array $ResponseShipments = null; 47 | 48 | /** 49 | * @param array|null $MergedLabels 50 | * @param array|null $ResponseShipments 51 | */ 52 | public function __construct( 53 | /* @param MergedLabel[]|null $MergedLabels */ 54 | ?array $MergedLabels = null, 55 | /* @param ResponseShipment[]|null $ResponseShipments */ 56 | ?array $ResponseShipments = null, 57 | ) { 58 | parent::__construct(); 59 | 60 | $this->setMergedLabels(MergedLabels: $MergedLabels); 61 | $this->setResponseShipments(ResponseShipments: $ResponseShipments); 62 | } 63 | 64 | /** 65 | * @return MergedLabel[]|null 66 | */ 67 | public function getMergedLabels(): ?array 68 | { 69 | return $this->MergedLabels; 70 | } 71 | 72 | /** 73 | * @param MergedLabel[]|null $MergedLabels 74 | * 75 | * @return static 76 | */ 77 | public function setMergedLabels(?array $MergedLabels): static 78 | { 79 | $this->MergedLabels = $MergedLabels; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * @return ResponseShipment[]|null 86 | */ 87 | public function getResponseShipments(): ?array 88 | { 89 | return $this->ResponseShipments; 90 | } 91 | 92 | /** 93 | * @param ResponseShipment[]|null $ResponseShipments 94 | * 95 | * @return static 96 | */ 97 | public function setResponseShipments(?array $ResponseShipments): static 98 | { 99 | $this->ResponseShipments = $ResponseShipments; 100 | 101 | return $this; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/Rest/ConfirmingServiceRestResponseProcessor.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor\Rest; 31 | 32 | use Firstred\PostNL\Entity\Response\ConfirmingResponseShipment; 33 | use Firstred\PostNL\Exception\CifDownException; 34 | use Firstred\PostNL\Exception\CifException; 35 | use Firstred\PostNL\Exception\DeserializationException; 36 | use Firstred\PostNL\Exception\HttpClientException; 37 | use Firstred\PostNL\Exception\InvalidConfigurationException; 38 | use Firstred\PostNL\Exception\NotSupportedException; 39 | use Firstred\PostNL\Exception\ResponseException; 40 | use Firstred\PostNL\Service\ResponseProcessor\ConfirmingServiceResponseProcessorInterface; 41 | use Psr\Http\Message\ResponseInterface; 42 | 43 | /** 44 | * @since 2.0.0 45 | * 46 | * @internal 47 | */ 48 | class ConfirmingServiceRestResponseProcessor extends AbstractRestResponseProcessor implements ConfirmingServiceResponseProcessorInterface 49 | { 50 | /** 51 | * Process the 'confirm label' server response. 52 | * 53 | * @param ResponseInterface $response 54 | * 55 | * @return ConfirmingResponseShipment[] 56 | * 57 | * @throws CifDownException 58 | * @throws CifException 59 | * @throws DeserializationException 60 | * @throws HttpClientException 61 | * @throws NotSupportedException 62 | * @throws ResponseException 63 | * @throws InvalidConfigurationException 64 | * 65 | * @since 2.0.0 66 | */ 67 | public function processConfirmResponse(ResponseInterface $response): array 68 | { 69 | $this->validateResponse(response: $response); 70 | $body = json_decode(json: static::getResponseText(response: $response)); 71 | 72 | if (!is_array(value: $body->ResponseShipments)) { 73 | $body->ResponseShipments = [$body->ResponseShipments]; 74 | } 75 | 76 | $objects = []; 77 | foreach ($body->ResponseShipments as $responseShipment) { 78 | $object = ConfirmingResponseShipment::jsonDeserialize(json: (object) ['ConfirmingResponseShipment' => $responseShipment]); 79 | $objects[] = $object; 80 | } 81 | 82 | if (!empty($objects)) { 83 | return $objects; 84 | } 85 | 86 | throw new ResponseException(message: 'Invalid response', response: $response); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Entity/CutOffTime.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | 34 | /** 35 | * @since 1.0.0 36 | */ 37 | class CutOffTime extends AbstractEntity 38 | { 39 | /** @var string|null $Day */ 40 | #[SerializableProperty(type: 'string')] 41 | protected ?string $Day = null; 42 | 43 | /** @var string|null $Time */ 44 | #[SerializableProperty(type: 'string')] 45 | protected ?string $Time = null; 46 | 47 | /** @var bool|null $Available */ 48 | #[SerializableProperty(type: 'bool')] 49 | protected ?bool $Available = null; 50 | 51 | /** 52 | * @param string|null $Day 53 | * @param string|null $Time 54 | * @param bool|null $Available 55 | */ 56 | public function __construct(?string $Day = null, ?string $Time = null, ?bool $Available = null) 57 | { 58 | parent::__construct(); 59 | 60 | $this->setDay(Day: $Day); 61 | $this->setTime(Time: $Time); 62 | $this->setAvailable(Available: $Available); 63 | } 64 | 65 | /** 66 | * @return string|null 67 | */ 68 | public function getDay(): ?string 69 | { 70 | return $this->Day; 71 | } 72 | 73 | /** 74 | * @param string|null $Day 75 | * 76 | * @return static 77 | */ 78 | public function setDay(?string $Day): static 79 | { 80 | $this->Day = $Day; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * @return string|null 87 | */ 88 | public function getTime(): ?string 89 | { 90 | return $this->Time; 91 | } 92 | 93 | /** 94 | * @param string|null $Time 95 | * 96 | * @return static 97 | */ 98 | public function setTime(?string $Time): static 99 | { 100 | $this->Time = $Time; 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * @return bool|null 107 | */ 108 | public function getAvailable(): ?bool 109 | { 110 | return $this->Available; 111 | } 112 | 113 | /** 114 | * @param bool|null $Available 115 | * 116 | * @return static 117 | */ 118 | public function setAvailable(?bool $Available): static 119 | { 120 | $this->Available = $Available; 121 | 122 | return $this; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Entity/Area.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | 34 | /** 35 | * @since 1.0.0 36 | */ 37 | class Area extends AbstractEntity 38 | { 39 | /** @var CoordinatesNorthWest|null $CoordinatesNorthWest */ 40 | #[SerializableProperty(type: CoordinatesNorthWest::class)] 41 | protected ?CoordinatesNorthWest $CoordinatesNorthWest = null; 42 | 43 | /** @var CoordinatesSouthEast|null $CoordinatesSouthEast */ 44 | #[SerializableProperty(type: CoordinatesSouthEast::class)] 45 | protected ?CoordinatesSouthEast $CoordinatesSouthEast = null; 46 | 47 | /** 48 | * @param CoordinatesNorthWest|null $CoordinatesNorthWest 49 | * @param CoordinatesSouthEast|null $CoordinatesSouthEast 50 | */ 51 | public function __construct( 52 | ?CoordinatesNorthWest $CoordinatesNorthWest = null, 53 | ?CoordinatesSouthEast $CoordinatesSouthEast = null, 54 | ) { 55 | parent::__construct(); 56 | 57 | $this->setCoordinatesNorthWest(CoordinatesNorthWest: $CoordinatesNorthWest); 58 | $this->setCoordinatesSouthEast(CoordinatesSouthEast: $CoordinatesSouthEast); 59 | } 60 | 61 | /** 62 | * @return CoordinatesNorthWest|null 63 | */ 64 | public function getCoordinatesNorthWest(): ?CoordinatesNorthWest 65 | { 66 | return $this->CoordinatesNorthWest; 67 | } 68 | 69 | /** 70 | * @param CoordinatesNorthWest|null $CoordinatesNorthWest 71 | * 72 | * @return static 73 | */ 74 | public function setCoordinatesNorthWest(?CoordinatesNorthWest $CoordinatesNorthWest): static 75 | { 76 | $this->CoordinatesNorthWest = $CoordinatesNorthWest; 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * @return CoordinatesSouthEast|null 83 | */ 84 | public function getCoordinatesSouthEast(): ?CoordinatesSouthEast 85 | { 86 | return $this->CoordinatesSouthEast; 87 | } 88 | 89 | /** 90 | * @param CoordinatesSouthEast|null $CoordinatesSouthEast 91 | * 92 | * @return static 93 | */ 94 | public function setCoordinatesSouthEast(?CoordinatesSouthEast $CoordinatesSouthEast): static 95 | { 96 | $this->CoordinatesSouthEast = $CoordinatesSouthEast; 97 | 98 | return $this; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Entity/Barcode.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | 34 | /** 35 | * @since 1.0.0 36 | */ 37 | class Barcode extends AbstractEntity 38 | { 39 | /** @var string|null $Type */ 40 | #[SerializableProperty(type: 'string')] 41 | protected ?string $Type = null; 42 | 43 | /** @var string|null $Range */ 44 | #[SerializableProperty(type: 'string')] 45 | protected ?string $Range = null; 46 | 47 | /** @var string|null $Serie */ 48 | #[SerializableProperty(type: 'string')] 49 | protected ?string $Serie = null; 50 | 51 | /** 52 | * @param string|null $Type 53 | * @param string|null $Range 54 | * @param string|null $Serie 55 | */ 56 | public function __construct( 57 | ?string $Type = null, 58 | ?string $Range = null, 59 | ?string $Serie = '000000000-999999999' 60 | ) { 61 | parent::__construct(); 62 | 63 | $this->setType(Type: $Type); 64 | $this->setRange(Range: $Range); 65 | $this->setSerie(Serie: $Serie); 66 | } 67 | 68 | /** 69 | * @return string|null 70 | */ 71 | public function getType(): ?string 72 | { 73 | return $this->Type; 74 | } 75 | 76 | /** 77 | * @param string|null $Type 78 | * 79 | * @return static 80 | */ 81 | public function setType(?string $Type): static 82 | { 83 | $this->Type = $Type; 84 | 85 | return $this; 86 | } 87 | 88 | /** 89 | * @return string|null 90 | */ 91 | public function getRange(): ?string 92 | { 93 | return $this->Range; 94 | } 95 | 96 | /** 97 | * @param string|null $Range 98 | * 99 | * @return static 100 | */ 101 | public function setRange(?string $Range): static 102 | { 103 | $this->Range = $Range; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * @return string|null 110 | */ 111 | public function getSerie(): ?string 112 | { 113 | return $this->Serie; 114 | } 115 | 116 | /** 117 | * @param string|null $Serie 118 | * 119 | * @return static 120 | */ 121 | public function setSerie(?string $Serie): static 122 | { 123 | $this->Serie = $Serie; 124 | 125 | return $this; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Service/RequestBuilder/Rest/ConfirmingServiceRestRequestBuilder.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\RequestBuilder\Rest; 31 | 32 | use Firstred\PostNL\Entity\AbstractEntity; 33 | use Firstred\PostNL\Entity\Request\Confirming; 34 | use Firstred\PostNL\Exception\InvalidArgumentException; 35 | use Firstred\PostNL\Exception\InvalidConfigurationException; 36 | use Firstred\PostNL\Service\ConfirmingServiceInterface; 37 | use Firstred\PostNL\Service\RequestBuilder\ConfirmingServiceRequestBuilderInterface; 38 | use Psr\Http\Message\RequestInterface; 39 | 40 | /** 41 | * @since 2.0.0 42 | * 43 | * @internal 44 | */ 45 | class ConfirmingServiceRestRequestBuilder extends AbstractRestRequestBuilder implements ConfirmingServiceRequestBuilderInterface 46 | { 47 | // Endpoints 48 | private const LIVE_ENDPOINT = 'https://api.postnl.nl/shipment/v2/confirm'; 49 | private const SANDBOX_ENDPOINT = 'https://api-sandbox.postnl.nl/shipment/v2/confirm'; 50 | 51 | /** 52 | * Build the 'confirm label' HTTP request. 53 | * 54 | * @throws InvalidArgumentException 55 | * @throws InvalidConfigurationException 56 | * 57 | * @since 2.0.0 58 | */ 59 | public function buildConfirmRequest(Confirming $confirming): RequestInterface 60 | { 61 | $this->setService(entity: $confirming); 62 | 63 | return $this->getRequestFactory()->createRequest( 64 | method: 'POST', 65 | uri: $this->isSandbox() ? static::SANDBOX_ENDPOINT : static::LIVE_ENDPOINT 66 | ) 67 | ->withHeader('apikey', value: $this->apiKey->getString()) 68 | ->withHeader('Accept', value: 'application/json') 69 | ->withHeader('Content-Type', value: 'application/json;charset=UTF-8') 70 | ->withBody(body: $this->getStreamFactory()->createStream(content: json_encode(value: $confirming))); 71 | } 72 | 73 | /** 74 | * Set this service on the given entity. 75 | * 76 | * This lets the entity know for which service it should serialize. 77 | * 78 | * @param AbstractEntity $entity 79 | * 80 | * @return void 81 | * 82 | * @throws InvalidArgumentException 83 | * @throws InvalidConfigurationException 84 | * 85 | * @since 2.0.0 86 | */ 87 | protected function setService(AbstractEntity $entity): void 88 | { 89 | $entity->setCurrentService(currentService: ConfirmingServiceInterface::class); 90 | 91 | parent::setService(entity: $entity); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Entity/Signature.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\Response\GetSignatureResponseSignature; 34 | 35 | /** 36 | * @since 1.0.0 37 | */ 38 | class Signature extends AbstractEntity 39 | { 40 | /** @var GetSignatureResponseSignature|null $GetSignatureResponseSignature */ 41 | #[SerializableProperty(type: GetSignatureResponseSignature::class)] 42 | protected ?GetSignatureResponseSignature $GetSignatureResponseSignature = null; 43 | 44 | /** @var Warning[]|null $Warnings */ 45 | #[SerializableProperty(type: Warning::class, isArray: true)] 46 | protected ?array $Warnings = null; 47 | 48 | /** 49 | * @param GetSignatureResponseSignature|null $GetSignatureResponseSignature 50 | * @param array|null $Warnings 51 | */ 52 | public function __construct( 53 | ?GetSignatureResponseSignature $GetSignatureResponseSignature = null, 54 | /* @param Warning[]|null $Warnings */ 55 | ?array $Warnings = null 56 | ) { 57 | parent::__construct(); 58 | 59 | $this->setGetSignatureResponseSignature(GetSignatureResponseSignature: $GetSignatureResponseSignature); 60 | $this->setWarnings(Warnings: $Warnings); 61 | } 62 | 63 | /** 64 | * @return GetSignatureResponseSignature|null 65 | */ 66 | public function getGetSignatureResponseSignature(): ?GetSignatureResponseSignature 67 | { 68 | return $this->GetSignatureResponseSignature; 69 | } 70 | 71 | /** 72 | * @param GetSignatureResponseSignature|null $GetSignatureResponseSignature 73 | * 74 | * @return static 75 | */ 76 | public function setGetSignatureResponseSignature(?GetSignatureResponseSignature $GetSignatureResponseSignature): static 77 | { 78 | $this->GetSignatureResponseSignature = $GetSignatureResponseSignature; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * @return Warning|null 85 | */ 86 | public function getWarnings(): ?array 87 | { 88 | return $this->Warnings; 89 | } 90 | 91 | /** 92 | * @param Warning[]|null $Warnings 93 | * 94 | * @return static 95 | */ 96 | public function setWarnings(?array $Warnings): static 97 | { 98 | $this->Warnings = $Warnings; 99 | 100 | return $this; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Entity/Response/GetSentDateResponse.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use DateTimeImmutable; 33 | use DateTimeInterface; 34 | use DateTimeZone; 35 | use Exception; 36 | use Firstred\PostNL\Attribute\SerializableProperty; 37 | use Firstred\PostNL\Entity\AbstractEntity; 38 | use Firstred\PostNL\Exception\InvalidArgumentException; 39 | 40 | /** 41 | * @since 1.0.0 42 | */ 43 | class GetSentDateResponse extends AbstractEntity 44 | { 45 | /** @var DateTimeInterface|null $SentDate */ 46 | #[SerializableProperty(type: DateTimeInterface::class)] 47 | protected ?DateTimeInterface $SentDate = null; 48 | 49 | /** @var string[]|null $Options */ 50 | #[SerializableProperty(type: 'string', isArray: true)] 51 | protected ?array $Options = null; 52 | 53 | /** 54 | * @throws InvalidArgumentException 55 | */ 56 | public function __construct( 57 | ?DateTimeInterface $GetSentDate = null, 58 | /* @param string[]|null $Options */ 59 | ?array $Options = null, 60 | ) { 61 | parent::__construct(); 62 | 63 | $this->setSentDate(SentDate: $GetSentDate); 64 | $this->setOptions(Options: $Options); 65 | } 66 | 67 | /** 68 | * @throws InvalidArgumentException 69 | * 70 | * @since 1.2.0 71 | */ 72 | public function setSentDate(string|DateTimeInterface|null $SentDate = null): static 73 | { 74 | if (is_string(value: $SentDate)) { 75 | try { 76 | $SentDate = new DateTimeImmutable(datetime: $SentDate, timezone: new DateTimeZone(timezone: 'Europe/Amsterdam')); 77 | } catch (Exception $e) { 78 | throw new InvalidArgumentException(message: $e->getMessage(), code: 0, previous: $e); 79 | } 80 | } 81 | 82 | $this->SentDate = $SentDate; 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * @return string[]|null 89 | */ 90 | public function getOptions(): ?array 91 | { 92 | return $this->Options; 93 | } 94 | 95 | /** 96 | * @param string[]|null $Options 97 | * 98 | * @return static 99 | */ 100 | public function setOptions(?array $Options): static 101 | { 102 | $this->Options = $Options; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * @return DateTimeInterface|null 109 | */ 110 | public function getSentDate(): ?DateTimeInterface 111 | { 112 | return $this->SentDate; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Entity/Response/GetLocationsInAreaResponse.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | use Firstred\PostNL\Exception\ServiceNotSetException; 35 | 36 | /** 37 | * @since 1.0.0 38 | */ 39 | class GetLocationsInAreaResponse extends AbstractEntity 40 | { 41 | /** @var GetLocationsResult|null $GetLocationsResult */ 42 | #[SerializableProperty(type: GetLocationsResult::class)] 43 | protected ?GetLocationsResult $GetLocationsResult = null; 44 | 45 | /** 46 | * @param GetLocationsResult|null $GetLocationsResult 47 | */ 48 | public function __construct( 49 | /* @param GetLocationsResult|null $GetLocationsResult */ 50 | ?GetLocationsResult $GetLocationsResult = null, 51 | ) { 52 | parent::__construct(); 53 | 54 | $this->setGetLocationsResult(GetLocationsResult: $GetLocationsResult); 55 | } 56 | 57 | /** 58 | * @return GetLocationsResult|null 59 | */ 60 | public function getGetLocationsResult(): ?GetLocationsResult 61 | { 62 | return $this->GetLocationsResult; 63 | } 64 | 65 | /** 66 | * @param GetLocationsResult|null $GetLocationsResult 67 | * 68 | * @return static 69 | */ 70 | public function setGetLocationsResult(?GetLocationsResult $GetLocationsResult): static 71 | { 72 | $this->GetLocationsResult = $GetLocationsResult; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * @return array 79 | * 80 | * @throws ServiceNotSetException 81 | */ 82 | public function jsonSerialize(): array 83 | { 84 | $json = []; 85 | if (!isset($this->currentService)) { 86 | throw new ServiceNotSetException(message: 'Service not set before serialization'); 87 | } 88 | 89 | foreach (array_keys(array: $this->getSerializableProperties()) as $propertyName) { 90 | if (!isset($this->$propertyName)) { 91 | continue; 92 | } 93 | 94 | if ('GetLocationsResult' === $propertyName) { 95 | $locations = []; 96 | foreach ($this->GetLocationsResult as $location) { 97 | $locations[] = $location; 98 | } 99 | $json[$propertyName] = ['ResponseLocation' => $locations]; 100 | } else { 101 | $json[$propertyName] = $this->$propertyName; 102 | } 103 | } 104 | 105 | return $json; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Entity/ProductOption.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | 34 | /** 35 | * @since 1.0.0 36 | */ 37 | class ProductOption extends AbstractEntity 38 | { 39 | /** @var string|null $Characteristic */ 40 | #[SerializableProperty(type: 'string', aliases: ['CharacteristicCode'])] 41 | protected ?string $Characteristic = null; 42 | 43 | /** @var string|null $Option */ 44 | #[SerializableProperty(type: 'string', aliases: ['OptionCode'])] 45 | protected ?string $Option = null; 46 | 47 | /** @var string|null $Description */ 48 | #[SerializableProperty(type: 'string', aliases: ['CharacteristicDescription', 'OptionDescription'])] 49 | protected ?string $Description = null; 50 | 51 | /** 52 | * @param string|null $Characteristic 53 | * @param string|null $Option 54 | * @param string|null $Description 55 | */ 56 | public function __construct(?string $Characteristic = null, ?string $Option = null, ?string $Description = null) 57 | { 58 | parent::__construct(); 59 | 60 | $this->setCharacteristic(Characteristic: $Characteristic); 61 | $this->setOption(Option: $Option); 62 | $this->setDescription(Description: $Description); 63 | } 64 | 65 | /** 66 | * @return string|null 67 | */ 68 | public function getCharacteristic(): ?string 69 | { 70 | return $this->Characteristic; 71 | } 72 | 73 | /** 74 | * @param string|null $Characteristic 75 | * 76 | * @return static 77 | */ 78 | public function setCharacteristic(?string $Characteristic): static 79 | { 80 | $this->Characteristic = $Characteristic; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * @return string|null 87 | */ 88 | public function getOption(): ?string 89 | { 90 | return $this->Option; 91 | } 92 | 93 | /** 94 | * @param string|null $Option 95 | * 96 | * @return static 97 | */ 98 | public function setOption(?string $Option): static 99 | { 100 | $this->Option = $Option; 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * @return string|null 107 | */ 108 | public function getDescription(): ?string 109 | { 110 | return $this->Description; 111 | } 112 | 113 | /** 114 | * @param string|null $Description 115 | * 116 | * @return static 117 | */ 118 | public function setDescription(?string $Description): static 119 | { 120 | $this->Description = $Description; 121 | 122 | return $this; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Service/LocationServiceInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service; 31 | 32 | use Firstred\PostNL\Cache\CacheableServiceInterface; 33 | use Firstred\PostNL\Entity\Request\GetLocation; 34 | use Firstred\PostNL\Entity\Request\GetLocationsInArea; 35 | use Firstred\PostNL\Entity\Request\GetNearestLocations; 36 | use Firstred\PostNL\Entity\Response\GetLocationsInAreaResponse; 37 | use Firstred\PostNL\Entity\Response\GetNearestLocationsResponse; 38 | use Firstred\PostNL\Exception\CifDownException; 39 | use Firstred\PostNL\Exception\CifException; 40 | use Firstred\PostNL\Exception\HttpClientException; 41 | use Firstred\PostNL\Exception\InvalidArgumentException as PostNLInvalidArgumentException; 42 | use Firstred\PostNL\Exception\NotFoundException; 43 | use Firstred\PostNL\Exception\NotSupportedException; 44 | use Firstred\PostNL\Exception\ResponseException; 45 | use Psr\Cache\InvalidArgumentException as PsrCacheInvalidArgumentException; 46 | 47 | /** 48 | * @since 1.2.0 49 | */ 50 | interface LocationServiceInterface extends ServiceInterface, CacheableServiceInterface 51 | { 52 | /** 53 | * Get the nearest locations. 54 | * 55 | * @throws CifDownException 56 | * @throws CifException 57 | * @throws HttpClientException 58 | * @throws NotSupportedException 59 | * @throws PostNLInvalidArgumentException 60 | * @throws PsrCacheInvalidArgumentException 61 | * @throws ResponseException 62 | * @throws NotFoundException 63 | * 64 | * @since 1.0.0 65 | */ 66 | public function getNearestLocations(GetNearestLocations $getNearestLocations): GetNearestLocationsResponse; 67 | 68 | /** 69 | * Get the nearest locations. 70 | * 71 | * @throws CifDownException 72 | * @throws CifException 73 | * @throws ResponseException 74 | * @throws PsrCacheInvalidArgumentException 75 | * @throws HttpClientException 76 | * @throws NotSupportedException 77 | * @throws PostNLInvalidArgumentException 78 | * @throws NotFoundException 79 | * 80 | * @since 1.0.0 81 | */ 82 | public function getLocationsInArea(GetLocationsInArea $getLocations): GetLocationsInAreaResponse; 83 | 84 | /** 85 | * Get the location via REST. 86 | * 87 | * @throws CifDownException 88 | * @throws CifException 89 | * @throws ResponseException 90 | * @throws PsrCacheInvalidArgumentException 91 | * @throws NotSupportedException 92 | * @throws PostNLInvalidArgumentException 93 | * @throws HttpClientException 94 | * @throws NotFoundException 95 | * 96 | * @since 1.0.0 97 | */ 98 | public function getLocation(GetLocation $getLocation): GetLocationsInAreaResponse; 99 | } 100 | -------------------------------------------------------------------------------- /src/Service/ResponseProcessor/LocationServiceResponseProcessorInterface.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Service\ResponseProcessor; 31 | 32 | use Firstred\PostNL\Entity\Response\GetLocationsInAreaResponse; 33 | use Firstred\PostNL\Entity\Response\GetNearestLocationsResponse; 34 | use Firstred\PostNL\Exception\CifDownException; 35 | use Firstred\PostNL\Exception\CifException; 36 | use Firstred\PostNL\Exception\DeserializationException; 37 | use Firstred\PostNL\Exception\HttpClientException; 38 | use Firstred\PostNL\Exception\InvalidConfigurationException; 39 | use Firstred\PostNL\Exception\NotSupportedException; 40 | use Firstred\PostNL\Exception\ResponseException; 41 | use Psr\Http\Message\ResponseInterface; 42 | 43 | /** 44 | * @since 2.0.0 45 | * 46 | * @internal 47 | */ 48 | interface LocationServiceResponseProcessorInterface 49 | { 50 | /** 51 | * Process the 'get nearest locations' server response. 52 | * 53 | * @param ResponseInterface $response 54 | * 55 | * @return GetNearestLocationsResponse 56 | * 57 | * @throws CifDownException 58 | * @throws CifException 59 | * @throws DeserializationException 60 | * @throws HttpClientException 61 | * @throws InvalidConfigurationException 62 | * @throws NotSupportedException 63 | * @throws ResponseException 64 | * 65 | * @since 2.0.0 66 | */ 67 | public function processGetNearestLocationsResponse(ResponseInterface $response): GetNearestLocationsResponse; 68 | 69 | /** 70 | * Process the 'get locations in area' server response. 71 | * 72 | * @param ResponseInterface $response 73 | * 74 | * @return GetLocationsInAreaResponse 75 | * 76 | * @throws CifDownException 77 | * @throws CifException 78 | * @throws DeserializationException 79 | * @throws HttpClientException 80 | * @throws InvalidConfigurationException 81 | * @throws NotSupportedException 82 | * @throws ResponseException 83 | * 84 | * @since 2.0.0 85 | */ 86 | public function processGetLocationsInAreaResponse(ResponseInterface $response): GetLocationsInAreaResponse; 87 | 88 | /** 89 | * Process the 'get location' server response. 90 | * 91 | * @param ResponseInterface $response 92 | * 93 | * @return GetLocationsInAreaResponse 94 | * 95 | * @throws CifDownException 96 | * @throws CifException 97 | * @throws DeserializationException 98 | * @throws HttpClientException 99 | * @throws InvalidConfigurationException 100 | * @throws NotSupportedException 101 | * @throws ResponseException 102 | * 103 | * @since 2.0.0 104 | */ 105 | public function processGetLocationResponse(ResponseInterface $response): GetLocationsInAreaResponse; 106 | } 107 | -------------------------------------------------------------------------------- /src/Entity/Response/CurrentStatusResponse.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2017-2023 Michael Dekker 25 | * @license https://opensource.org/licenses/MIT The MIT License 26 | */ 27 | 28 | declare(strict_types=1); 29 | 30 | namespace Firstred\PostNL\Entity\Response; 31 | 32 | use Firstred\PostNL\Attribute\SerializableProperty; 33 | use Firstred\PostNL\Entity\AbstractEntity; 34 | use Firstred\PostNL\Entity\Warning; 35 | 36 | /** 37 | * @since 1.0.0 38 | */ 39 | class CurrentStatusResponse extends AbstractEntity 40 | { 41 | /** @var CurrentStatusResponseShipment[]|null $Shipments */ 42 | #[SerializableProperty(type: CurrentStatusResponseShipment::class, isArray: true)] 43 | protected ?array $Shipments = null; 44 | 45 | /** @var Warning[]|null $Warnings */ 46 | #[SerializableProperty(type: Warning::class, isArray: true)] 47 | protected ?array $Warnings = null; 48 | 49 | /** 50 | * @param array|null $Shipments 51 | * @param array|null $Warnings 52 | */ 53 | public function __construct( 54 | /* @param CurrentStatusResponseShipment[]|null $Shipments */ 55 | ?array $Shipments = null, 56 | /* @param Warning[]|null $Warnings */ 57 | ?array $Warnings = null 58 | ) { 59 | parent::__construct(); 60 | 61 | $this->setShipments(Shipments: $Shipments); 62 | $this->setWarnings(Warnings: $Warnings); 63 | } 64 | 65 | /** 66 | * @return CurrentStatusResponseShipment[]|null 67 | */ 68 | public function getShipments(): ?array 69 | { 70 | return $this->Shipments; 71 | } 72 | 73 | /** 74 | * @param CurrentStatusResponseShipment[]|null $Shipments 75 | * 76 | * @return static 77 | */ 78 | public function setShipments(?array $Shipments): static 79 | { 80 | if (is_array(value: $Shipments)) { 81 | foreach ($Shipments as $shipment) { 82 | if (!$shipment instanceof CurrentStatusResponseShipment) { 83 | throw new \TypeError(message: 'Expected instance of `CurrentStatusResponseShipment`'); 84 | } 85 | } 86 | } 87 | 88 | $this->Shipments = $Shipments; 89 | 90 | return $this; 91 | } 92 | 93 | /** 94 | * @return Warning[]|null 95 | */ 96 | public function getWarnings(): ?array 97 | { 98 | return $this->Warnings; 99 | } 100 | 101 | /** 102 | * @param Warning[]|null $Warnings 103 | * 104 | * @return static 105 | */ 106 | public function setWarnings(?array $Warnings): static 107 | { 108 | if (is_array(value: $Warnings)) { 109 | foreach ($Warnings as $warning) { 110 | if (!$warning instanceof Warning) { 111 | throw new \TypeError(message: 'Expected instance of `Warning`'); 112 | } 113 | } 114 | } 115 | 116 | $this->Warnings = $Warnings; 117 | 118 | return $this; 119 | } 120 | } 121 | --------------------------------------------------------------------------------