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 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/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; 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); 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()); }