From 0cc3a13cec0c046b70b95fc367e235e1e386123e Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Wed, 7 Jan 2026 15:50:30 +0100 Subject: [PATCH 1/4] fix: Resolve Implicitly marking parameter $... as nullable is deprecated deprecation messages These deprecations are visible when running find ./src -type f -name '*.php' -exec php -l {} \; grep -v 'No syntax errors' using PHP 8.4 --- src/MyParcelComApi.php | 26 ++++++++++--------- src/MyParcelComApiInterface.php | 6 ++--- .../Interfaces/ShipmentInterface.php | 2 +- src/Resources/Proxy/ShipmentProxy.php | 2 +- src/Resources/Shipment.php | 2 +- src/Utils/UrlBuilder.php | 2 +- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/MyParcelComApi.php b/src/MyParcelComApi.php index 9003daa9..f49b5036 100644 --- a/src/MyParcelComApi.php +++ b/src/MyParcelComApi.php @@ -69,9 +69,9 @@ class MyParcelComApi implements MyParcelComApiInterface public static function createSingleton( AuthenticatorInterface $authenticator, string $apiUri = 'https://api.sandbox.myparcel.com', - ClientInterface $httpClient = null, - CacheInterface $cache = null, - ResourceFactoryInterface $resourceFactory = null, + ?ClientInterface $httpClient = null, + ?CacheInterface $cache = null, + ?ResourceFactoryInterface $resourceFactory = null, ): self { return self::$singleton = (new self($apiUri, $httpClient, $cache, $resourceFactory)) ->authenticate($authenticator); @@ -91,9 +91,9 @@ public static function getSingleton(): ?self */ public function __construct( string $apiUri = 'https://api.sandbox.myparcel.com', - ClientInterface $httpClient = null, - CacheInterface $cache = null, - ResourceFactoryInterface $resourceFactory = null, + ?ClientInterface $httpClient = null, + ?CacheInterface $cache = null, + ?ResourceFactoryInterface $resourceFactory = null, ) { if ($httpClient === null) { $httpClient = HttpClientDiscovery::find(); @@ -154,7 +154,7 @@ public function getPickUpDropOffLocations( string $postalCode, ?string $streetName = null, ?string $streetNumber = null, - CarrierInterface $specificCarrier = null, + ?CarrierInterface $specificCarrier = null, bool $onlyActiveContracts = true, int $ttl = self::TTL_10MIN, ?array $filters = null, @@ -242,7 +242,7 @@ public function getDefaultShop(int $ttl = self::TTL_10MIN): ShopInterface } public function getServices( - ShipmentInterface $shipment = null, + ?ShipmentInterface $shipment = null, array $filters = ['has_active_contract' => 'true'], int $ttl = self::TTL_10MIN, ): ResourceCollectionInterface { @@ -453,8 +453,10 @@ public function resolveDynamicServiceRates( return $this->jsonToResources($json['data'], $included); } - public function getShipments(ShopInterface $shop = null, int $ttl = self::TTL_NO_CACHE): ResourceCollectionInterface - { + public function getShipments( + ?ShopInterface $shop = null, + int $ttl = self::TTL_NO_CACHE + ): ResourceCollectionInterface { $url = new UrlBuilder($this->apiUri . self::PATH_SHIPMENTS); $url->addQuery([ @@ -1337,7 +1339,7 @@ protected function sendResource( return reset($resources); } - protected function getResourceUri(string $resourceType, string $id = null): string + protected function getResourceUri(string $resourceType, ?string $id = null): string { return implode( '/', @@ -1384,7 +1386,7 @@ private function arrayToFilter(array &$filters, array $keys, mixed $value): void */ private function determineCarriersForPudoLocations( bool $onlyActiveContracts, - CarrierInterface $specificCarrier = null, + ?CarrierInterface $specificCarrier = null, ): array { // If we're looking for a specific carrier but it doesn't // matter if it has active contracts, just return it immediately. diff --git a/src/MyParcelComApiInterface.php b/src/MyParcelComApiInterface.php index a48b50be..c7fc5532 100644 --- a/src/MyParcelComApiInterface.php +++ b/src/MyParcelComApiInterface.php @@ -78,7 +78,7 @@ public function getPickUpDropOffLocations( string $postalCode, ?string $streetName = null, ?string $streetNumber = null, - CarrierInterface $specificCarrier = null, + ?CarrierInterface $specificCarrier = null, bool $onlyActiveContracts = true, int $ttl = self::TTL_10MIN, ?array $filters = null, @@ -106,7 +106,7 @@ public function getDefaultShop(int $ttl = self::TTL_10MIN): ShopInterface; * @throws MyParcelComException */ public function getServices( - ShipmentInterface $shipment = null, + ?ShipmentInterface $shipment = null, array $filters = ['has_active_contract' => 'true'], int $ttl = self::TTL_10MIN, ): ResourceCollectionInterface; @@ -158,7 +158,7 @@ public function resolveDynamicServiceRates( * @throws MyParcelComException */ public function getShipments( - ShopInterface $shop = null, + ?ShopInterface $shop = null, int $ttl = self::TTL_NO_CACHE, ): ResourceCollectionInterface; diff --git a/src/Resources/Interfaces/ShipmentInterface.php b/src/Resources/Interfaces/ShipmentInterface.php index eb1c4a8c..b1f7e41a 100644 --- a/src/Resources/Interfaces/ShipmentInterface.php +++ b/src/Resources/Interfaces/ShipmentInterface.php @@ -158,7 +158,7 @@ public function addFile(FileInterface $file): self; /** * @return FileInterface[] */ - public function getFiles(string $type = null): array; + public function getFiles(?string $type = null): array; public function setShipmentStatus(ShipmentStatusInterface $status): self; diff --git a/src/Resources/Proxy/ShipmentProxy.php b/src/Resources/Proxy/ShipmentProxy.php index 5000b0c7..95b4c581 100644 --- a/src/Resources/Proxy/ShipmentProxy.php +++ b/src/Resources/Proxy/ShipmentProxy.php @@ -390,7 +390,7 @@ public function addFile(FileInterface $file): self return $this; } - public function getFiles(string $type = null): array + public function getFiles(?string $type = null): array { return $this->getResource()->getFiles($type); } diff --git a/src/Resources/Shipment.php b/src/Resources/Shipment.php index 7b70bea0..dd3f73a4 100644 --- a/src/Resources/Shipment.php +++ b/src/Resources/Shipment.php @@ -591,7 +591,7 @@ public function addFile(FileInterface $file): self return $this; } - public function getFiles(string $type = null): array + public function getFiles(?string $type = null): array { // For multi-colli `master` shipments we make this function return all files from the related `colli` shipments. if (!empty($this->getColli())) { diff --git a/src/Utils/UrlBuilder.php b/src/Utils/UrlBuilder.php index aa9c33f0..d7af9ba6 100644 --- a/src/Utils/UrlBuilder.php +++ b/src/Utils/UrlBuilder.php @@ -16,7 +16,7 @@ class UrlBuilder protected ?string $fragment = null; protected array $query = []; - public function __construct(string $url = null) + public function __construct(?string $url = null) { if ($url !== null) { $this->setUrl($url); From 18355f3ccff35ae9e99cc332b6be79c2d2d96222 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Wed, 7 Jan 2026 16:53:01 +0100 Subject: [PATCH 2/4] feat: Process response from GET /service when ?include=service-options is provided --- src/Resources/Service.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Resources/Service.php b/src/Resources/Service.php index 8ad4499c..215c65fe 100644 --- a/src/Resources/Service.php +++ b/src/Resources/Service.php @@ -7,6 +7,7 @@ use MyParcelCom\ApiSdk\Resources\Interfaces\CarrierInterface; use MyParcelCom\ApiSdk\Resources\Interfaces\ResourceInterface; use MyParcelCom\ApiSdk\Resources\Interfaces\ServiceInterface; +use MyParcelCom\ApiSdk\Resources\Interfaces\ServiceOptionInterface; use MyParcelCom\ApiSdk\Resources\Interfaces\ServiceRateInterface; use MyParcelCom\ApiSdk\Resources\Traits\JsonSerializable; use MyParcelCom\ApiSdk\Resources\Traits\ProcessIncludes; @@ -33,9 +34,11 @@ class Service implements ServiceInterface const ATTRIBUTE_VOLUMETRIC_WEIGHT_DIVISOR = 'volumetric_weight_divisor'; const RELATIONSHIP_CARRIER = 'carrier'; + const RELATIONSHIP_SERVICE_OPTIONS = 'service_options'; const INCLUDES = [ ResourceInterface::TYPE_CARRIER => self::RELATIONSHIP_CARRIER, + ResourceInterface::TYPE_SERVICE_OPTION => self::RELATIONSHIP_SERVICE_OPTIONS, ]; private ?string $id = null; @@ -63,6 +66,9 @@ class Service implements ServiceInterface self::RELATIONSHIP_CARRIER => [ 'data' => null, ], + self::RELATIONSHIP_SERVICE_OPTIONS => [ + 'data' => [], + ], ]; /** @var ServiceRateInterface[] */ @@ -143,6 +149,29 @@ public function getCarrier(): CarrierInterface return $this->relationships[self::RELATIONSHIP_CARRIER]['data']; } + public function setServiceOptions(array $serviceOptions): self + { + $this->relationships[self::RELATIONSHIP_SERVICE_OPTIONS]['data'] = []; + + foreach ($serviceOptions as $serviceOption) { + $this->addServiceOption($serviceOption); + } + + return $this; + } + + public function addServiceOption(ServiceOptionInterface $serviceOption): self + { + $this->relationships[self::RELATIONSHIP_SERVICE_OPTIONS]['data'][] = $serviceOption; + + return $this; + } + + public function getServiceOptions(): array + { + return $this->relationships[self::RELATIONSHIP_SERVICE_OPTIONS]['data']; + } + public function setHandoverMethod(string $handoverMethod): self { $this->attributes[self::ATTRIBUTE_HANDOVER_METHOD] = $handoverMethod; From 16256d805068e37c034a2f26fad90aa8ebabaf38 Mon Sep 17 00:00:00 2001 From: Martin Boer Date: Thu, 8 Jan 2026 23:32:39 +0100 Subject: [PATCH 3/4] :white_check_mark: fix tests now expecting service_options on service --- tests/Feature/ResourceFactoryTest.php | 5 ++++- tests/Unit/Resources/ServiceTest.php | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/Feature/ResourceFactoryTest.php b/tests/Feature/ResourceFactoryTest.php index d2d85698..0281f676 100644 --- a/tests/Feature/ResourceFactoryTest.php +++ b/tests/Feature/ResourceFactoryTest.php @@ -304,12 +304,15 @@ public function testCreateService() 'uses_volumetric_weight' => true, ], 'relationships' => [ - 'carrier' => [ + 'carrier' => [ 'data' => [ 'id' => 'carrier-id-1', 'type' => 'carriers', ], ], + 'service_options' => [ + 'data' => [], + ], ], ]; diff --git a/tests/Unit/Resources/ServiceTest.php b/tests/Unit/Resources/ServiceTest.php index f867415b..bbf15e03 100644 --- a/tests/Unit/Resources/ServiceTest.php +++ b/tests/Unit/Resources/ServiceTest.php @@ -37,7 +37,10 @@ public function testName() public function testPackageType() { $service = new Service(); - $this->assertEquals(Service::PACKAGE_TYPE_PARCEL, $service->setPackageType(Service::PACKAGE_TYPE_PARCEL)->getPackageType()); + $this->assertEquals( + Service::PACKAGE_TYPE_PARCEL, + $service->setPackageType(Service::PACKAGE_TYPE_PARCEL)->getPackageType(), + ); } /** @test */ @@ -199,12 +202,15 @@ public function testJsonSerialize() 'uses_volumetric_weight' => true, ], 'relationships' => [ - 'carrier' => [ + 'carrier' => [ 'data' => [ 'id' => 'carrier-id-1', 'type' => 'carriers', ], ], + 'service_options' => [ + 'data' => [], + ], ], ], $service->jsonSerialize()); } From 6bc6bdb795fd12154f9885165cf19d8dd7e40b71 Mon Sep 17 00:00:00 2001 From: Martin Boer Date: Thu, 8 Jan 2026 23:37:19 +0100 Subject: [PATCH 4/4] :construction_worker: run tests on PHP 8.4 --- .github/workflows/ci.yml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39068384..f66ce864 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Composer uses: php-actions/composer@v6 with: @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Composer uses: php-actions/composer@v6 with: @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Composer uses: php-actions/composer@v6 with: @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Composer uses: php-actions/composer@v6 with: @@ -61,3 +61,18 @@ jobs: version: 9 php_version: 8.3 configuration: phpunit.xml + php84: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Composer + uses: php-actions/composer@v6 + with: + php_version: 8.4 + - name: PHPUnit + uses: php-actions/phpunit@v4 + with: + version: 9 + php_version: 8.4 + configuration: phpunit.xml