Skip to content

Commit 45243ed

Browse files
authored
Merge pull request #42 from picqer/specs-downloader
Script to download latest specs
2 parents 452a528 + 2c64bb1 commit 45243ed

File tree

11 files changed

+163
-77
lines changed

11 files changed

+163
-77
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Bol.com Retailer API client for PHP
2-
This is an open source PHP client for the [Bol.com Retailer API](https://api.bol.com/retailer/public/Retailer-API/v10/releasenotes.html) version 10.4.
2+
This is an open source PHP client for the [Bol.com Retailer API](https://api.bol.com/retailer/public/Retailer-API/v10/releasenotes.html) version 10.6.
33

44
## Installation
55
This project can easily be installed through Composer:
@@ -179,10 +179,15 @@ Please follow the guidelines below if you want to contribute.
179179
- Keep in mind that we want to support PHP 7.1 as long as possible.
180180

181181
## Generated Models and Client
182-
The Client and all models are generated by the supplied [Retailer API specifications](https://api.bol.com/retailer/public/apispec/Retailer%20API%20-%20v10) (`src/OpenApi/retailer.json`) and [Shared API specification](https://api.bol.com/retailer/public/apispec/Shared%20API%20-%20v10) (`src/OpenApi/shared.json`). These specifications are merged. Generating the code ensures there are no typos, not every operation needs a test and future (minor) updates to the specifications can easily be applied. To build the classes for the latest Bol Retailer API version, replace the two specification files with the latest version first.
182+
The Client and all models are generated by the supplied [Retailer API specifications](https://api.bol.com/retailer/public/apispec/Retailer%20API%20-%20v10) (`src/OpenApi/retailer.json`) and [Shared API specification](https://api.bol.com/retailer/public/apispec/Shared%20API%20-%20v10) (`src/OpenApi/shared.json`). These specifications are merged. Generating the code ensures there are no typos, not every operation needs a test and future (minor) updates to the specifications can easily be applied.
183183

184184
The generated classes contain all data required to properly map method arguments and response data to the models: the specifications are only used to generate them.
185185

186+
To build the classes for the latest Bol Retailer API version, let the code download the newest specs with this script:
187+
```
188+
composer run-script download-specs
189+
```
190+
186191
### Client
187192
The Client contains all operations specified in the specifications. The 'operationId' value is converted to camelCase and used as method name for each operation.
188193

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"test": "phpunit",
4242
"check-style": "phpcs src tests",
4343
"fix-style": "phpcbf src tests",
44+
"download-specs": "Picqer\\BolRetailerV10\\OpenApi\\SpecsDownloader::run",
4445
"generate-client": "Picqer\\BolRetailerV10\\OpenApi\\ClientGenerator::run",
4546
"generate-models": "Picqer\\BolRetailerV10\\OpenApi\\ModelGenerator::run"
4647
},

src/Client.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,26 +1577,19 @@ public function getInvoiceRequests(?string $shipmentId = null, ?int $page = 1, ?
15771577
/**
15781578
* Uploads an invoice associated with shipment id.
15791579
* @param string $shipmentId The id of the shipment associated with the invoice.
1580-
* @param string $invoice
15811580
* @return Model\ProcessStatus|null
15821581
* @throws Exception\ConnectException when an error occurred in the HTTP connection.
15831582
* @throws Exception\ResponseException when an unexpected response was received.
15841583
* @throws Exception\UnauthorizedException when the request was unauthorized.
15851584
* @throws Exception\RateLimitException when the throttling limit has been reached for the API user.
15861585
* @throws Exception\Exception when something unexpected went wrong.
15871586
*/
1588-
public function uploadInvoice(string $shipmentId, string $invoice): ?Model\ProcessStatus
1587+
public function uploadInvoice(string $shipmentId): ?Model\ProcessStatus
15891588
{
15901589
$url = "retailer/shipments/invoices/{$shipmentId}";
15911590
$options = [
1592-
'multipart' => [
1593-
[
1594-
'name' => 'invoice',
1595-
'contents' => \GuzzleHttp\Psr7\Utils::tryFopen($invoice, 'r'),
1596-
],
1597-
],
15981591
'produces' => 'application/vnd.retailer.v10+json',
1599-
'consumes' => 'multipart/form-data',
1592+
'consumes' => 'application/json',
16001593
];
16011594
$responseTypes = [
16021595
'202' => Model\ProcessStatus::class,

src/Model/RetailerInformationResponse.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ public function getModelDefinition(): array
1919
return [
2020
'retailerId' => [ 'model' => null, 'enum' => null, 'array' => false ],
2121
'displayName' => [ 'model' => null, 'enum' => null, 'array' => false ],
22+
'companyName' => [ 'model' => null, 'enum' => null, 'array' => false ],
23+
'vatNumber' => [ 'model' => null, 'enum' => null, 'array' => false ],
24+
'kvkNumber' => [ 'model' => null, 'enum' => null, 'array' => false ],
2225
'registrationDate' => [ 'model' => null, 'enum' => null, 'array' => false ],
2326
'topRetailer' => [ 'model' => null, 'enum' => null, 'array' => false ],
2427
'ratingMethod' => [ 'model' => null, 'enum' => Enum\RetailerInformationResponseRatingMethod::class, 'array' => false ],
@@ -37,6 +40,21 @@ public function getModelDefinition(): array
3740
*/
3841
public $displayName;
3942

43+
/**
44+
* @var string The company name of the retailer.
45+
*/
46+
public $companyName;
47+
48+
/**
49+
* @var string The VAT number of the retailer.
50+
*/
51+
public $vatNumber;
52+
53+
/**
54+
* @var string The KVK number of the retailer.
55+
*/
56+
public $kvkNumber;
57+
4058
/**
4159
* @var string A date representing the registration date for the retailer within bol.com
4260
*/

src/Model/SubscriptionRequest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public function getModelDefinition(): array
2020
'resources' => [ 'model' => null, 'enum' => null, 'array' => true ],
2121
'url' => [ 'model' => null, 'enum' => null, 'array' => false ],
2222
'subscriptionType' => [ 'model' => null, 'enum' => Enum\SubscriptionRequestSubscriptionType::class, 'array' => false ],
23+
'enabled' => [ 'model' => null, 'enum' => null, 'array' => false ],
2324
];
2425
}
2526

@@ -40,4 +41,9 @@ public function getModelDefinition(): array
4041
* events will be subscribed to. Be aware that certain event types are only available for specific types.
4142
*/
4243
public $subscriptionType;
44+
45+
/**
46+
* @var bool Whether the subscription is enabled and will receive notifications or not. Defaults to true.
47+
*/
48+
public $enabled;
4349
}

src/Model/SubscriptionResponse.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public function getModelDefinition(): array
2121
'resources' => [ 'model' => null, 'enum' => null, 'array' => true ],
2222
'url' => [ 'model' => null, 'enum' => null, 'array' => false ],
2323
'subscriptionType' => [ 'model' => null, 'enum' => Enum\SubscriptionResponseSubscriptionType::class, 'array' => false ],
24+
'enabled' => [ 'model' => null, 'enum' => null, 'array' => false ],
2425
];
2526
}
2627

@@ -46,4 +47,9 @@ public function getModelDefinition(): array
4647
* events will be subscribed to. Be aware that certain event types are only available for specific types.
4748
*/
4849
public $subscriptionType;
50+
51+
/**
52+
* @var bool Whether the subscription is enabled and will receive notifications or not. Defaults to true.
53+
*/
54+
public $enabled;
4955
}

src/OpenApi/ClientGenerator.php

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php
22

3-
43
namespace Picqer\BolRetailerV10\OpenApi;
54

65
class ClientGenerator
@@ -216,7 +215,7 @@ protected function kebabCaseToCamelCase(string $name): string
216215
$name = str_replace(' ', '-', $name);
217216

218217
$nameElems = explode('-', $name);
219-
for ($i=1; $i<count($nameElems); $i++) {
218+
for ($i = 1; $i < count($nameElems); $i++) {
220219
$nameElems[$i] = ucfirst($nameElems[$i]);
221220
}
222221
return implode('', $nameElems);
@@ -258,8 +257,8 @@ protected function extractArguments(array $methodDefinition): array
258257
if ($parameter['in'] == 'query' && isset($parameter['schema']['$ref'])) {
259258
continue;
260259
} elseif ($parameter['in'] == 'query' && isset($parameter['schema']['enum'])) {
261-
$wrappingType = ucfirst($this->kebabCaseToCamelCase($methodDefinition['operationId'] .'-'. $parameter['name']));
262-
$argument['php'] = 'Enum\\'.$wrappingType;
260+
$wrappingType = ucfirst($this->kebabCaseToCamelCase($methodDefinition['operationId'] . '-' . $parameter['name']));
261+
$argument['php'] = 'Enum\\' . $wrappingType;
263262
$argument['doc'] = $argument['php'];
264263
$argument['name'] = $this->kebabCaseToCamelCase($parameter['name']);
265264
$argument['paramName'] = $parameter['name'];
@@ -322,24 +321,24 @@ protected function extractArguments(array $methodDefinition): array
322321

323322
if (isset($propSchema['type']) && $propSchema['type'] == 'array') {
324323
$itemsType = $this->getType($propSchema['items']['$ref']);
325-
$argument['doc'] = 'Model\\'.$itemsType.'[]';
324+
$argument['doc'] = 'Model\\' . $itemsType . '[]';
326325
$argument['php'] = 'array';
327326
} elseif (isset($propSchema['type'])) {
328327
$wrappingType = static::$paramTypeMapping[$propSchema['type']];
329328
$argument['doc'] = $wrappingType;
330329
$argument['php'] = $wrappingType;
331330
} else {
332331
$wrappingType = $this->getType($propSchema['$ref']);
333-
$argument['doc'] = 'Model\\'.$wrappingType;
334-
$argument['php'] = 'Model\\'.$wrappingType;
332+
$argument['doc'] = 'Model\\' . $wrappingType;
333+
$argument['php'] = 'Model\\' . $wrappingType;
335334
}
336335
$argument['property'] = $property;
337336
$argument['name'] = $property;
338-
$argument['wrapperPhp'] = 'Model\\'.$type;
337+
$argument['wrapperPhp'] = 'Model\\' . $type;
339338
}
340339

341-
if (!isset($argument['property'])) {
342-
$argument['php'] = 'Model\\'.$type;
340+
if (! isset($argument['property'])) {
341+
$argument['php'] = 'Model\\' . $type;
343342
$argument['doc'] = $argument['php'];
344343
$argument['name'] = lcfirst($type);
345344
}
@@ -397,7 +396,7 @@ protected function argumentValueToString($argument): string
397396
protected function addQueryParams(array $arguments, array &$code): void
398397
{
399398
$amount = array_reduce($arguments, function ($amount, $argument) {
400-
return $argument['in'] == 'query' ? $amount+1 : $amount;
399+
return $argument['in'] == 'query' ? $amount + 1 : $amount;
401400
});
402401

403402
if ($amount == 0) {
@@ -441,7 +440,7 @@ protected function addBodyParam(array $arguments, array &$code): void
441440
protected function addFormData(array $arguments, array &$code): void
442441
{
443442
$containsFileArgument = in_array(true, array_map(
444-
static fn (array $argument): bool => $argument['is_file'] ?? false,
443+
static fn(array $argument): bool => $argument['is_file'] ?? false,
445444
$arguments,
446445
));
447446
$formData = [];
@@ -524,8 +523,8 @@ protected function getReturnType(array $responses): array
524523
if (isset($refSchema['properties'][$property]['type'], $refSchema['properties'][$property]['items']['$ref']) && $refSchema['properties'][$property]['type'] == 'array') {
525524
return [
526525
'doc' => 'Model\\' . $this->getType(
527-
$refSchema['properties'][$property]['items']['$ref']
528-
) . '[]',
526+
$refSchema['properties'][$property]['items']['$ref']
527+
) . '[]',
529528
'php' => 'array',
530529
'property' => $property
531530
];
@@ -555,7 +554,7 @@ protected function getEnumName(string $name): string
555554
// We add the first `_` for enums starting with a integer character
556555
$prefix = is_numeric($name[0]) ? '_' : '';
557556

558-
return $prefix.strtoupper($name);
557+
return $prefix . strtoupper($name);
559558
}
560559

561560
protected function wrapComment(string $comment, string $linePrefix, int $maxLength = 120): string

src/OpenApi/ModelGenerator.php

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php
22

3-
43
namespace Picqer\BolRetailerV10\OpenApi;
54

65
class ModelGenerator
@@ -50,12 +49,12 @@ public function generateEnums(): void
5049
foreach ($this->specs['paths'] as $path => $methodsDef) {
5150
foreach ($methodsDef as $method => $methodDef) {
5251
foreach ($methodDef['parameters'] ?? [] as $parameterDef) {
53-
if (!isset($parameterDef['schema']['enum']) || !array_values(array_filter($parameterDef['schema']['enum']))) {
52+
if (! isset($parameterDef['schema']['enum']) || ! array_values(array_filter($parameterDef['schema']['enum']))) {
5453
continue;
5554
}
5655

5756
$this->generateEnum(
58-
ucfirst($this->kebabCaseToCamelCase($methodDef['operationId'] .'-'. $parameterDef['name'])),
57+
ucfirst($this->kebabCaseToCamelCase($methodDef['operationId'] . '-' . $parameterDef['name'])),
5958
static::$propTypeMapping[$parameterDef['schema']['type']],
6059
$parameterDef['schema']['enum']
6160
);
@@ -65,12 +64,12 @@ public function generateEnums(): void
6564

6665
foreach ($this->specs['components']['schemas'] as $type => $modelSchema) {
6766
foreach ($modelSchema['properties'] as $property => $propertyDef) {
68-
if (!isset($propertyDef['enum']) || !array_values(array_filter($propertyDef['enum']))) {
67+
if (! isset($propertyDef['enum']) || ! array_values(array_filter($propertyDef['enum']))) {
6968
continue;
7069
}
7170

7271
$this->generateEnum(
73-
ucfirst($this->kebabCaseToCamelCase($type .'-'. $property)),
72+
ucfirst($this->kebabCaseToCamelCase($type . '-' . $property)),
7473
static::$propTypeMapping[$propertyDef['type']],
7574
$propertyDef['enum']
7675
);
@@ -146,7 +145,7 @@ protected function generateSchema(string $type, array $modelSchema, array &$code
146145
$enum = 'null';
147146
$array = 'false';
148147

149-
if (isset($propDefinition['type']) && !isset($propDefinition['enum'])) {
148+
if (isset($propDefinition['type']) && ! isset($propDefinition['enum'])) {
150149
if ($propDefinition['type'] == 'array') {
151150
$array = 'true';
152151
if (isset($propDefinition['items']['$ref'])) {
@@ -155,8 +154,8 @@ protected function generateSchema(string $type, array $modelSchema, array &$code
155154
}
156155
} elseif (isset($propDefinition['$ref'])) {
157156
$model = $this->getType($propDefinition['$ref']) . '::class';
158-
} elseif (isset($propDefinition['enum'])) {
159-
$enum = 'Enum\\' . ucfirst($this->kebabCaseToCamelCase($type .'-'. $name)) . '::class';
157+
} elseif (isset($propDefinition['enum'])) {
158+
$enum = 'Enum\\' . ucfirst($this->kebabCaseToCamelCase($type . '-' . $name)) . '::class';
160159
} else {
161160
// TODO create exception class for this one
162161
throw new \Exception('Unknown property definition');
@@ -172,15 +171,15 @@ protected function generateSchema(string $type, array $modelSchema, array &$code
172171
protected function generateFields(string $type, array $modelSchema, array &$code): void
173172
{
174173
foreach ($modelSchema['properties'] as $name => $propDefinition) {
175-
if (isset($propDefinition['type']) && !isset($propDefinition['enum'])) {
174+
if (isset($propDefinition['type']) && ! isset($propDefinition['enum'])) {
176175
$propType = static::$propTypeMapping[$propDefinition['type']];
177176
if ($propType == 'array' && isset($propDefinition['items']['$ref'])) {
178177
$propType = $this->getType($propDefinition['items']['$ref']) . '[]';
179178
}
180179
} elseif (isset($propDefinition['$ref'])) {
181180
$propType = $this->getType($propDefinition['$ref']);
182181
} elseif (isset($propDefinition['enum'])) {
183-
$propType = 'Enum\\' . ucfirst($this->kebabCaseToCamelCase($type .'-'. $name));
182+
$propType = 'Enum\\' . ucfirst($this->kebabCaseToCamelCase($type . '-' . $name));
184183
} else {
185184
// TODO create exception class for this one
186185
throw new \Exception('Unknown property definition');
@@ -317,7 +316,6 @@ protected function generateMonoFieldAccessors(array $modelSchema, array &$code):
317316
}
318317

319318

320-
321319
protected function getType(string $ref): string
322320
{
323321
//strip #/components/schemas/
@@ -367,7 +365,7 @@ protected function getFieldsWithMonoFieldModelType(array $modelSchema): array
367365
$propType = $propDefinition['type'];
368366
}
369367

370-
if (!isset($this->specs['components']['schemas'][$propType])) {
368+
if (! isset($this->specs['components']['schemas'][$propType])) {
371369
continue;
372370
}
373371

@@ -403,7 +401,7 @@ protected function kebabCaseToCamelCase(string $name): string
403401
$name = str_replace(' ', '-', $name);
404402

405403
$nameElems = explode('-', $name);
406-
for ($i=1; $i<count($nameElems); $i++) {
404+
for ($i = 1; $i < count($nameElems); $i++) {
407405
$nameElems[$i] = ucfirst($nameElems[$i]);
408406
}
409407
return implode('', $nameElems);
@@ -420,7 +418,7 @@ protected function getEnumName(string $name): string
420418
// We add the first `_` for enums starting with a integer character
421419
$prefix = is_numeric($name[0]) ? '_' : '';
422420

423-
return $prefix.strtoupper($name);
421+
return $prefix . strtoupper($name);
424422
}
425423

426424
protected function wrapComment(string $comment, string $linePrefix, int $maxLength = 120): string

src/OpenApi/SpecsDownloader.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Picqer\BolRetailerV10\OpenApi;
4+
5+
class SpecsDownloader
6+
{
7+
private const SPECS = [
8+
[
9+
'source' => 'https://api.bol.com/retailer/public/apispec/Retailer%20API%20-%20v10',
10+
'target' => 'retailer.json',
11+
],
12+
[
13+
'source' => 'https://api.bol.com/retailer/public/apispec/Shared%20API%20-%20v10',
14+
'target' => 'shared.json',
15+
],
16+
];
17+
18+
public static function run(): void
19+
{
20+
foreach (static::SPECS as $spec) {
21+
$sourceFile = file_get_contents($spec['source']);
22+
23+
// Tidy JSON formatting
24+
$sourceTidied = json_encode(json_decode($sourceFile), JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE);
25+
26+
file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . $spec['target'], $sourceTidied);
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)