jobjen / bol-retailer-php-client
Bol.com 零售商 API 客户端
Requires
- php: ^8.1
- ext-json: *
- guzzlehttp/guzzle: ^6.3|^7.0
Requires (Dev)
- phpstan/phpstan: ^0.12
- phpunit/phpunit: ^7|^8
- squizlabs/php_codesniffer: ^3.0
- vimeo/psalm: ^3.5
This package is auto-updated.
Last update: 2024-09-05 13:20:37 UTC
README
分支自: https://github.com/picqer/bol-retailer-php-client.
PHP 版 Bol.com 零售商 API 客户端
这是一个开源的 PHP 客户端,用于 Bol.com 零售商 API 的 10.6 版本。
安装
该项目可以通过 Composer 容易地安装
composer require jobjen/bol-retailer-php-client "^10"
使用
创建客户端实例并使用客户端凭证流程进行身份验证
$client = new \Jobjen\BolRetailerV10\Client(); $client->authenticateByClientCredentials('your-client-id', 'your-client-secret');
然后,您可以通过在客户端上调用 getOrders() 方法来获取开放订单的第一页
$reducedOrders = $client->getOrders(); foreach ($reducedOrders as $reducedOrder) { echo 'hello, I am order ' . $reducedOrder->orderId . PHP_EOL; }
为了节省对 Bol.com 的请求,您可能需要重用访问令牌
$accessToken = ... // your implementation of getting the access token from the storage $client = new \Jobjen\BolRetailerV10\Client(); $client->setAccessToken($accessToken); $client->setAccessTokenExpiredCallback(function(\Jobjen\BolRetailerV10\Client $client) { // Called at the beginning of a request to the Retailer API when the access token was expired (or // non-existent) and after a request that resulted in an error about an expired access token. // Authenticate and fetch the new access token $client->authenticateByClientCredentials('{your-client-id}', '{your-client-secret}'); $accessToken = $client->getAccessToken(); ... // store $accessToken for future use });
代码流身份验证
在代码流中进行身份验证时,在回调 URI 上接收和验证短代码后,需要检索第一个访问令牌和刷新令牌
$client = new \Jobjen\BolRetailerV10\Client(); $refreshToken = $client->authenticateByAuthorizationCode( '{your-client-id}', '{your-client-secret}', '{received-shortcode}', '{callback-uri}' ); $accessToken = $client->getAccessToken(); ... // store $accessToken and $refreshToken for future use $orders = $client->getOrders();
访问令牌需要用于向零售商 API 发送请求。
$client = new \Jobjen\BolRetailerV10\Client(); $accessToken = ... // your implementation of getting the access token from the storage $client->setAccessToken($accessToken); $orders = $client->getOrders();
访问令牌代码在有限的时间内有效(撰写时为 600 秒),因此需要定期使用刷新令牌进行刷新
$client = new \Jobjen\BolRetailerV10\Client(); $accessToken = ... // your implementation of getting the access token from the storage $client->setAccessToken($accessToken); $client->setAccessTokenExpiredCallback(function(\Jobjen\BolRetailerV10\Client $client) { // Called at the beginning of a request to the Retailer API when the access token was expired or // non-existent and after a request that resulted in an error about an expired access token. // This callback can attempt to refresh the access token. If after this callback the Client has // a valid access token, the request will continue or retried once. Otherwise, it will be // aborted with an Exception. $refreshToken = ... // your implementation of getting the refresh token from the storage $client->authenticateByRefreshToken('{your-client-id}', '{your-client-secret}', $refreshToken); $accessToken = $client->getAccessToken(); ... // store $accessToken for future use }); $orders = $client->getOrders();
上面的示例假设您的 Bol.com 集成帐户使用的是在使用后不会更改的刷新令牌(Bol.com 命名为“方法 1”)。
如果您的刷新令牌在使用后更改(“方法 2”),那么您需要在刷新后存储新的刷新令牌。在这种情况下,刷新令牌只能使用一次。当多个进程同时刷新时,可能会由于竞态条件而导致最后存储的已使用刷新令牌。这意味着从此之后无法刷新,并且用户需要手动重新登录。为了防止这种情况,您需要使用锁,以确保只存储和使用最新的刷新令牌。下面的示例使用阻塞互斥锁。
$client = new \Jobjen\BolRetailerV10\Client(); $accessToken = ... // your implementation of getting the access token from the storage $client->setAccessToken($accessToken); $client->setAccessTokenExpiredCallback(function(\Jobjen\BolRetailerV10\Client $client) use ($mutex) { // Called at the beginning of a request to the Retailer API when the access token was expired or // non-existent and after a request that resulted in an error about an expired access token. // Ensure only 1 process can be in the critical section, others are blocked and one is let in // when that process leaves the critical section $mutex->withLock(function () use ($client) { // your implementation of getting the latest access token from the storage (it might be // refreshed by another process) $accessToken = ... if (! $accessToken->isExpired()) { // No need to refresh the token, as it was already refreshed by another proces. Make sure the // client uses it. $client->setAccessToken($accessToken); return; } $refreshToken = ... // your implementation of getting the refresh token from the storage $newRefreshToken = $client->authenticateByRefreshToken( '{your-client-id}', '{your-client-secret}', $refreshToken ); $accessToken = $client->getAccessToken(); ... // store $accessToken and $newRefreshToken for future use } }); $orders = $client->getOrders();
异常
客户端上的方法可能会抛出异常。所有异常都有父类 Jobjen\BolRetailerV10\Exception\Exception
ConnectException
在连接出现问题时抛出(例如,API 服务器故障或网络问题)。您可以稍后重试。ServerException
(扩展ConnectException
)在服务器出现问题时抛出(例如,500 内部服务器错误)。您可以稍后重试。ResponseException
在接收到的响应无法处理时抛出(例如,格式不正确或类型意外)。重试不会有所帮助,需要进行调查。UnauthorizedException
在服务器响应为 400 未授权(例如,凭据无效)时抛出。RateLimitException
在 API 用户的节流限制达到时抛出。Exception
在 HTTP 库中发生错误时抛出,该错误不包含在上述情况中。我们的目标是尽可能地将错误映射到ConnectionException
或ResponseException
。
贡献
如果您想贡献,请遵循以下指南。
- 添加您想要贡献的版本的最新 API 规范,并生成模型和客户端(参见:“生成的模型和客户端”)。
- 有时由于错误或输出意外的代码,生成失败。请在此生成器类中修复此问题,不要手动修改生成的类。
- 如果由于 Bol.com API 规范中的某些怪异之处需要更改生成器,请将此情况添加到本 README 的“已知怪异之处”部分。如果检查当前已知怪异之处是否仍然相关将非常好。
- 如果您贡献了一个新的大版本,任何对 'v10' 的引用都必须替换为新版本。
- 将
/src
、/tests
和composer.json
中的命名空间重命名。 - 在测试用例和
BaseClient
中将 'v10' 替换为新版本。 - 将本 README 更新为指向新的迁移指南的链接,并将 'v10' 替换为新版本。
- 将
生成的模型和客户端
客户端和所有模型都是由提供的 零售商 API 规范(src/OpenApi/retailer.json
)和 共享 API 规范(src/OpenApi/shared.json
)生成的。这些规范已合并。生成代码确保没有错别字,不是每个操作都需要测试,并且可以轻松应用规范的未来(次要)更新。
生成的类包含映射方法参数和响应数据到模型所需的所有数据:规范仅用于生成它们。
要为最新的 Bol 零售商 API 版本构建类,请让代码使用此脚本下载最新的规范
composer run-script download-specs
客户端
客户端包含规范中指定的所有操作。'operationId' 的值被转换为 camelCase,并用作每个操作的名称。
规范为每个请求和响应(如果需要发送数据)定义了类型。如果此类类型的模型仅封装一个字段,则从操作中抽象出该模型以获得更平滑的开发体验。
- 客户端中的方法接受该字段作为参数,而不是模型。
- 客户端中的方法返回该模型中的字段,而不是模型本身。
要生成客户端,可以使用以下 composer 脚本
composer run-script generate-client
模型
模型类名等于规范中 'definitions' 数组的键。
要生成模型,可以使用以下 composer 脚本
composer run-script generate-models
已知怪异之处
- 规范中的一些类型定义是句子,例如 '容器,用于取消的订单项'。这些被转换为 CamelCase,并删除点。
- 规范中的一些操作(get-offer-export 和 get-unpublished-offer-report)没有指定响应模式(类型),而实际上有响应。目前,这仅适用于返回 CSV 的操作。
- 规范中定义了一个类型 'Return'。由于这是 PHP 中的保留关键字,因此不能用作模型(PHP <= 7)的类名,因此目前将其替换为 'ReturnObject'。
- 如果响应中的数组字段为空,则该字段有时会从响应中省略。例如,getOrders 的原始 JSON 响应为
您可能期望{ }
{ "orders": [ ] }
- 操作 'get-invoices' 规定响应为字符串,而实际上在 JSON 或 XML 中返回了某些数据模型。
- 操作 'get-invoices' 的描述中包含一个标记为 'ENSP' 的奇怪空格。