jobjen/bol-retailer-php-client

Bol.com 零售商 API 客户端

v1 2024-05-06 11:45 UTC

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 库中发生错误时抛出,该错误不包含在上述情况中。我们的目标是尽可能地将错误映射到 ConnectionExceptionResponseException

贡献

如果您想贡献,请遵循以下指南。

  • 添加您想要贡献的版本的最新 API 规范,并生成模型和客户端(参见:“生成的模型和客户端”)。
  • 有时由于错误或输出意外的代码,生成失败。请在此生成器类中修复此问题,不要手动修改生成的类。
  • 如果由于 Bol.com API 规范中的某些怪异之处需要更改生成器,请将此情况添加到本 README 的“已知怪异之处”部分。如果检查当前已知怪异之处是否仍然相关将非常好。
  • 如果您贡献了一个新的大版本,任何对 'v10' 的引用都必须替换为新版本。
    • /src/testscomposer.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' 的奇怪空格。