commercetools/spec-sdks

此包已被弃用,不再维护。作者建议使用 commercetools/commercetools-sdk 包。

commercetools Composable Commerce APIs 的官方 PHP SDK

10.6.0 2024-09-02 11:50 UTC

README

主题索引

简介

此存储库包含从 Composable Commerce API 参考生成的 PHP SDK。

用于对 Commercetools 进行 API 请求的客户端和请求构建器。

包和安装

composer require commercetools/commercetools-sdk

技术概述

SDK 包括以下项目

  • lib/commercetools-base/src:包含与 Composable Commerce 通信以执行请求的客户端,还包括与客户端相关的类,如令牌、中间件和处理程序,以及映射器和异常。
  • lib/commercetools-api/src:包含与 Composable Commerce HTTP API 通信的所有生成的模型和请求构建器。
  • lib/commercetools-import/src:包含与 Import API 通信的所有生成的模型和请求构建器。
  • lib/commercetools-history/src:包含与 Change History API 通信的所有生成的模型和请求构建器。

此外,SDK 还具有以下目录

  • examples/symfony-app:展示了如何在启用 NewRelic 监控的 Docker 环境中使用 PHP SDK 在 Symfony 应用程序中。
  • test/integration:SDK 的集成测试。对于任何使用 PHP SDK 的人来说,这是一种深入了解它的好方法。
  • test/unit:单元测试
  • lib/commercetools-api-tests:为 api 文件夹中的每个类生成的单元测试
  • lib/commercetools-history-tests:为 history 文件夹中的每个类生成的单元测试
  • lib/commercetools-import-tests:为 import 文件夹中的每个类生成的单元测试

PHP SDK 利用各种标准接口和组件来确保一致性和互操作性

占位符值

本指南中的示例代码使用占位符,应将其替换为以下值。

如果您没有API客户端,请遵循我们的获取您的API客户端指南。

入门指南

创建客户端

以下示例显示了如何通过在客户端创建过程中传递自定义URI来创建客户端。您将在导入API文件夹中找到相同的类。

namespace Commercetools;

use Commercetools\Api\Client\ClientCredentialsConfig;
use Commercetools\Api\Client\Config;
use Commercetools\Client\ClientCredentials;
use Commercetools\Client\ClientFactory;

require_once __DIR__ . '/vendor/autoload.php';

/** @var string $clientId */
/** @var string $clientSecret */
/** @var string $scope
 *   Provide the scope when you want to request a specific ones for the client. 
 *   Can be omitted to use all scopes of the oauth client.
 *   Format: `<the scope name>:<the project key>`.
 *   Example: `manage_products:project1`. $authConfig 
 */
$authConfig = new ClientCredentialsConfig(
    new ClientCredentials('{clientID}', '{clientSecret}', '{scope}'),
    [],
    'https://auth.{region}.commercetools.com/oauth/token'
);
$client = ClientFactory::of()->createGuzzleClient(
    new Config([], 'https://api.{region}.commercetools.com'),
    $authConfig
);

为不同区域定制端点

默认情况下,库使用api.europe-west1.gcp.commercetools.com端点。如果您使用不同的区域,您可以配置客户端以使用自定义端点。以下是us-central1区域的示例

$authConfig = new ClientCredentialsConfig(
    new ClientCredentials('{clientId}', '{clientSecret}'), 
    [], 
    'https://auth.us-central1.gcp.commercetools.com/oauth/token'
);

$config = new Config([], 'https://api.us-central1.gcp.commercetools.com');
$client = ClientFactory::of()->createGuzzleClient(
    $config,
    $authConfig,
);

请注意,认证端点应包含/oauth/token后缀,但API端点则不需要。

执行请求

有关产品API所有可用方法的详细信息,请在此处查看

有关导入API的信息,请在此处查看。

获取项目信息示例

use Commercetools\Api\Client\ApiRequestBuilder;
use GuzzleHttp\ClientInterface;

/** @var ClientInterface $client */
$builder =  new ApiRequestBuilder($client);
$request = $builder->withProjectKey('{projectKey}')->get();

为了避免在构建每个请求时指定项目密钥,可以使用Commercetools\Client命名空间中的值

use Commercetools\Client\ApiRequestBuilder;
use Commercetools\Client\ImportRequestBuilder;
use GuzzleHttp\ClientInterface;

/** @var ClientInterface $client */
$builder =  new ApiRequestBuilder('{projectKey}', $client);
$request = $builder->categories()->get();

$importBuilder =  new ImportRequestBuilder('{projectKey}', $client);
$request = $importBuilder->importSinks()->get();

以下是一些执行请求的示例

use Commercetools\Client\ApiRequestBuilder;
use GuzzleHttp\ClientInterface;

/** @var ClientInterface $client */
$builder =  new ApiRequestBuilder('{projectKey}', $client);
$request = $builder->with()->get();

// executing the request and mapping the response directly to a domain model
$project = $request->execute();

// send the request to get the response object 
$response = $request->send();
// map the response to a domain model
$project = $request->mapFromResponse($response);

// send the request asynchronously 
$promise = $request->sendAsync();
// map the response to a domain model
$project = $request->mapFromResponse($promise->wait());

// send the request using a client instance
$response = $client->send($request);
$project = $request->mapFromResponse($response);

配置

应用 PSRs

PHP SDK 利用各种标准接口和组件来确保一致性和互操作性

$authHandler = HandlerStack::create();
$authHandler->push(
    MiddlewareFactory::createLoggerMiddleware(new Logger('auth', [new StreamHandler('./logs/requests.log')]))
);
$authConfig = new ClientCredentialsConfig(new ClientCredentials($clientId, $clientSecret), [
    'handler' => $authHandler,
]);
$logger = new Logger('client', [new StreamHandler('./logs/requests.log')]);
$client = ClientFactory::of()->createGuzzleClientForHandler(
    new Config(['maxRetries' => 3]),
    OAuthHandlerFactory::ofAuthConfig($authConfig),
    $logger
);
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
$filesystemCache = new FilesystemAdapter();

$config = new Config(['timeout' => 30]);
$client = ClientFactory->createGuzzleClientForHandler(
    $config,
    OAuthHandlerFactory::ofAuthConfig($authConfig, $cache)
);
//set up the client something like the examples before

// create a guzzle request
/** @var CategoryBuilder $category */
$request = $client->with()->categories()->withId($category->getId())->get()->withExpand('parent');
$result = $request->execute();

$request = new \GuzzleHttp\Psr7\Request('GET', '{projectKey}/categories/{ID}');
$response = $client->send($request);
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Psr16Cache;

$filesystemCache = new FilesystemAdapter();
$cache = new Psr16Cache($filesystemCache);

$config = new Config(['timeout' => 30]);
$client = ClientFactory->createGuzzleClientForHandler(
    $config,
    OAuthHandlerFactory::ofAuthConfig($authConfig, $cache)
);

错误处理

错误处理已通过ExceptionFactory类提供。该类中的方法封装了将Guzzle异常转换为基于HTTP响应状态码的自定义异常的逻辑。可以直接在请求中调用或在错误处理的中继件中调用。直接在请求处理中调用或在中间件中直接处理

    if ($e->getCode() >= 500) {
        throw ExceptionFactory::createServerException($e, $apiRequest, $response, $result);
    } else {
        throw ExceptionFactory::createClientException($e, $apiRequest, $response, $result);
    }

身份验证

工厂类ProviderFactory用于管理认证和令牌处理。

创建令牌存储

要生成使用不同流程(刷新流程和匿名流程)管理令牌的TokenStorageProvider,可以使用ProviderFactory::createTokenStorageProvider($anonTokenUrl, $refreshTokenUrl, $clientCredentials, $client, $tokenStorage, $anonymousIdProvider);

密码流程

ProviderFactory::createPasswordFlowProvider($passwordTokenUrl, $clientCredentials, $client, $tokenStorage);方法创建一个密码流程令牌提供程序,用于使用用户名和密码安全地认证用户。

匿名流程

createAnonymousFlowProvider($anonTokenUrl, $clientCredentials, $client, $refreshFlowTokenProvider, $anonymousIdProvider);方法构建一个匿名流程令牌提供程序,用于管理匿名用户的令牌,并集成API的匿名令牌端点。

刷新流程

createRefreshFlowProvider($refreshTokenUrl, $clientCredentials, $client, $tokenStorage)方法设置一个刷新流程令牌提供程序,以无缝处理令牌刷新操作,确保持续访问API资源。

中间件

我们在PHP SDK中引入了中间件来添加功能。

您可以在创建PHP SDK客户端时添加中间件。可以使用中间件数组添加多个中间件。

MiddlewareFactory(一个工厂模式)的作用范围是处理所有可用的中间件,并有机会对其进行自定义。

本类中包含的方法旨在创建一个中间件数组。

默认中间件

createDefaultMiddlewares方法创建一个包含默认值的数组,包括OAuth处理程序、身份验证、记录器、重试和关联ID。

$authConfig = new ClientCredentialsConfig(new ClientCredentials($clientId, $clientSecret), [
            'handler' => $authHandler,
        ]);
$oauthHandler = OAuthHandlerFactory::ofAuthConfig($authConfig),
$logger = new Logger('client', [new StreamHandler('./logs/requests.log')]);
$maxRetries = 3;
$correlationIdProvider = new DefaultCorrelationIdProvider();

$middlewares = MiddlewareFactory::createDefaultMiddlewares(
    $oauthHandler,
    $logger,
    $maxRetries,
    $correlationIdProvider
);

CorrelationId中间件

createCorrelationIdMiddleware方法创建一个中间件,将关联ID添加到HTTP请求的头部。

$correlationIdProvider = new DefaultCorrelationIdProvider();

$correlationIdMiddleware = MiddlewareFactory::createCorrelationIdMiddleware(
    $correlationIdProvider
);

RetryNAMiddle中间件

方法 createRetryNAMiddleware 用于创建满足特定条件时重试HTTP请求的中介。此中介特别适用于可能发生短暂错误(如临时服务器不可用)的场景。

$maxRetries = 3;

$retryMiddleware = MiddlewareFactory::createRetryNAMiddleware($maxRetries);

OAuthHandler中间件

方法 createMiddlewareForOAuthHandler 创建用于处理OAuth2身份验证的中介,确保包含必要的OAuth凭证。

$tokenProvider = new YourTokenProvider();
$oauthHandler = OAuthHandlerFactory::ofProvider($tokenProvider),

$oauthMiddleware = MiddlewareFactory::createMiddlewareForOAuthHandler($oauthHandler);

Logger中间件

方法 createLoggerMiddleware 创建用于记录HTTP请求和响应的中介。

$logger = new Logger('auth');
$logger->pushHandler(new StreamHandler('./logs/requests.log', Logger::DEBUG));

$loggerMiddleware = MiddlewareFactory::createLoggerMiddleware($logger);

Reauthenticate中间件

方法 createReauthenticateMiddleware 创建在遇到无效令牌错误(HTTP 401)时自动重新认证HTTP请求的中介。它使用OAuth2Handler刷新令牌并重试请求,直到达到指定的次数。

$authConfig = new ClientCredentialsConfig(new ClientCredentials($clientId, $clientSecret), [
            'handler' => $authHandler,
        ]);
$oauthHandler = OAuthHandlerFactory::ofAuthConfig($authConfig),
//maxRetries have the default value 1 as a second parameter of the function
$reauthMiddleware = MiddlewareFactory::createReauthenticateMiddleware($oauthHandler);

查询

对于下面提到的示例,我们设置 $builder 如下所示

use Commercetools\Client\ApiRequestBuilder;
use GuzzleHttp\ClientInterface;

/** @var ClientInterface $client */
$builder =  new ApiRequestBuilder('{projectKey}', $client);

由于传递给 with() 方法的变量大部分是标量,这意味着我们可以将数组传递给方法的相应参数,如下面的示例所示。

谓词

系统允许在查询API时使用谓词。谓词作为查询参数字符串添加到请求本身。以下示例显示了输入变量的使用

$builder
    ->customers()
    ->get()
    ->withWhere('lastName=:lastName')
    ->withPredicateVar("lastName", $customerSignIn->getCustomer()->getLastName());

在参数数量可变的情况下,也可以在谓词中使用数组值。

$builder
    ->productProjections()
    ->get()
    ->withWhere('masterVariant(sku in :skus)')
    ->withPredicateVar("skus", ["foo", "bar"]);

通过 ID/键获取

$builder
    ->productProjections()
    ->withId('test_id')
    ->get();
$builder
    ->productProjections()
    ->withKey('test_key')
    ->get();

排序

有关详细信息,请参阅排序

使用一个参数进行排序

$builder
    ->products()
    ->get()
    ->withSort("masterData.current.name.en asc");

使用多个参数进行排序

$builder
    ->products()
    ->get()
    ->withSort(["masterData.current.name.en asc", "id asc"]);

分页

限制返回文档的数量或页面大小

$builder
    ->products()
    ->get()
    ->withLimit(4)
    ->withOffset(4);

产品与产品类型

创建产品类型

ProductType 类似于一个模式,定义了产品属性的结构。

ProductType 包含一个 AttributeDefinition 列表,它对应于每个属性的名字和类型,以及一些附加信息。每个名字/类型对在项目中必须是唯一的,因此如果您创建了一个名为 "foo" 的String类型的属性,您不能创建另一个ProductType,其中 "foo" 有另一个类型(例如 LocalizedString)。如果您这样做,您将收到一个类似以下错误消息

"名为 'foo' 的属性在产品类型 'exampleproducttype' 上的类型不同。"

在这种情况下,我们提供了两个 ProductTypes,即 bookt-shirt

book 产品类型包含以下属性

$isbn as String,国际标准书号 The t-shirt 产品类型包含以下属性

颜色作为 AttributeLocalizedEnumValue,有绿色和红色以及它们的德语和英语翻译。尺寸作为 AttributePlainEnumValue,有S、M和X。洗衣符号作为 AttributeLocalizedEnumValue,有温度和烘干选项。匹配产品作为 ProductReference 集合,可以指向与当前产品类似的产品。建议零售价为 Money。产品上市时间为 DateTime,表示产品在商店中对客户可用的日期。所有可用的属性类型,您可以在 "所有已知实现类" 中找到。

创建图书产品类型的代码

$isbn = AttributeDefinitionBuilder::of()
    ->withType(AttributeTextTypeBuilder::of()->build())
    ->withName(self::ISBN_ATTR_NAME)
    ->withLabel(LocalizedStringBuilder::of("ISBN")->build())
    ->withIsRequired(false)
    ->build();

$productType = ProductTypeBuilder::of()
    ->withName(self::BOOK_PRODUCT_TYPE_NAME)
    ->withDescription("books")
    ->withAttributes(AttributeDefinitionCollection::of()->add($isbn))
    ->build();
    
$builder =  new ApiRequestBuilder('{projectKey}', $client);
$request = $builder
              ->productTypes()
              ->withId($productType->getId())
              ->get();
$productTypeQueryResponse = $request->execute();

查看 测试代码

创建T恤产品类型的代码

$green = AttributeLocalizedEnumValueBuilder::of()
                    ->withKey("green")
                    ->withLabel(LocalizedStringBuilder::fromArray(["en" => "green", "de" => "grün"])->build())
                    ->build();
$red = AttributeLocalizedEnumValueBuilder::of()
            ->withKey("red")
            ->withLabel(LocalizedStringBuilder::fromArray(["en" => "red", "de" => "rot"])->build())
            ->build();
$color = AttributeDefinitionDraftBuilder::of()
            ->withName(self::COLOR_ATTR_NAME)
            ->withLabel(LocalizedStringBuilder::fromArray(["en" => "color"])->build())
            ->withType(AttributeLocalizedEnumTypeBuilder::of()
                        ->withValues(AttributeLocalizedEnumValueCollection::fromArray([$green, $red]))
                        ->build())
            ->withIsRequired(true)
            ->build();
$small = AttributePlainEnumValueBuilder::of()
            ->withKey("S")
            ->withLabel("S")
            ->build();
$medium = AttributePlainEnumValueBuilder::of()
            ->withKey("M")
            ->withLabel("M")
            ->build();
$sizeX = AttributePlainEnumValueBuilder::of()
            ->withKey("X")
            ->withLabel("X")
            ->build();
$size = AttributeDefinitionDraftBuilder::of()
            ->withName(self::SIZE_ATTR_NAME)
            ->withLabel(LocalizedStringBuilder::fromArray(["en" => "Size"])->build())
            ->withType(AttributeEnumTypeBuilder::of()
                            ->withValues(AttributePlainEnumValueCollection::fromArray([$small, $medium, $sizeX]))
                            ->build())
            ->withIsRequired(true)
            ->build();
$cold = AttributeLocalizedEnumValueBuilder::of()
            ->withKey("cold")
            ->withLabel(LocalizedStringBuilder::fromArray(["en" => "Wash at or below 30°C ", "de" => "30°C"])->build())
            ->build();
$hot = AttributeLocalizedEnumValueBuilder::of()
            ->withKey("hot")
            ->withLabel(LocalizedStringBuilder::fromArray(["en" => "Wash at or below 60°C", "de" => "60°C"])->build())
            ->build();
$tumbleDrying = AttributeLocalizedEnumValueBuilder::of()
                    ->withKey("tumbleDrying")
                    ->withLabel(LocalizedStringBuilder::fromArray(["en" => "Tumble Drying", "de" => "Trommeltrocknen"])->build())
                    ->build();
$noTumbleDrying = AttributeLocalizedEnumValueBuilder::of()
                    ->withKey("noTumbleDrying")
                    ->withLabel(LocalizedStringBuilder::fromArray(["en" => "no tumble drying", "de" => "Nicht im Trommeltrockner trocknen"])->build())
                    ->build();
$laundryLabelType = AttributeSetTypeBuilder::of()
                        ->withElementType(AttributeLocalizedEnumTypeBuilder::of()
                                            ->withValues(AttributeLocalizedEnumValueCollection::fromArray([$cold, $hot, $tumbleDrying, $noTumbleDrying]))
                                            ->build())
                        ->build();
$laundrySymbols = AttributeDefinitionDraftBuilder::of()
                    ->withType($laundryLabelType)
                    ->withName(self::LAUNDRY_SYMBOLS_ATTR_NAME)
                    ->withLabel(LocalizedStringBuilder::fromArray(["en" => "washing labels"])->build())
                    ->withIsRequired(false)
                    ->build();

$matchingProducts = AttributeDefinitionDraftBuilder::of()
                        ->withName(self::MATCHING_PRODUCTS_ATTR_NAME)
                        ->withLabel(LocalizedStringBuilder::fromArray(["en" => "matching products"])->build())
                        ->withType(AttributeSetTypeBuilder::of()
                                    ->withElementType(AttributeReferenceTypeBuilder::of()
                                                        ->withReferenceTypeId("product")
                                                        ->build())
                                    ->build())
                        ->withIsRequired(false)
                        ->build();
$rrp = AttributeDefinitionDraftBuilder::of()
            ->withName(self::RRP_ATTR_NAME)
            ->withLabel(LocalizedStringBuilder::fromArray(["en" => "recommended retail price"])->build())
            ->withType(AttributeMoneyTypeBuilder::of()->build())
            ->withIsRequired(false)
            ->build();
$availableSince = AttributeDefinitionDraftBuilder::of()
                    ->withName(self::AVAILABLE_SINCE_ATTR_NAME)
                    ->withLabel(LocalizedStringBuilder::fromArray(["en" => "available since"])->build())
                    ->withType(AttributeDateTimeTypeBuilder::of()->build())
                    ->withIsRequired(false)
                    ->build();
$attributes = AttributeDefinitionDraftCollection::fromArray([$color, $size, $laundrySymbols, $matchingProducts, $rrp, $availableSince]);

$productTypeDraft = ProductTypeDraftBuilder::of()
                      ->withKey(ProductTypeFixture::uniqueProductTypeString())
                      ->withName(self::PRODUCT_TYPE_NAME)
                      ->withDescription("a 'T' shaped cloth")
                      ->withAttributes($attributes)
                      ->build();
$productType = $builder
    ->with()
    ->productTypes()
    ->post($productTypeDraft)
    ->execute();

查看 测试代码

产品类型有一个键(String),可以作为键逻辑上识别产品类型。键具有唯一约束。

创建产品

要创建一个产品,您需要引用产品类型。由于开发系统的产品类型ID不会是生产系统的ID,因此有必要通过名称查找产品类型

$productType = $builder
            ->with()
            ->productTypes()
            ->get()
            ->withQueryParam('where', 'name="' . $name . '"')
            ->execute();

return $productType->getResults()->current() ?: null;

查看 测试代码

向产品变体添加属性的最简单方法是使用 php ProductVariantDraftBuilder::of()->withAttributes($attributes),这使您可以直接将属性值放入草稿中。但它不能检查您是否放对了对象和类型。

书籍示例

$attributes = AttributeCollection::of()
                ->add(
                    AttributeBuilder::of()
                        ->withName(self::ISBN_ATTR_NAME)
                        ->withValue("978-3-86680-192-9")
                        ->build());
$productVariantDraft = ProductVariantDraftBuilder::of()
                        ->withAttributes($attributes)
                        ->build();
$productTypeResourceIdentifier = ProductTypeResourceIdentifierBuilder::of()
                                    ->withId($productType->getId())
                                    ->build();
$productDraft = ProductDraftBuilder::of()
                ->withProductType($productTypeResourceIdentifier)
                ->withName(LocalizedStringBuilder::of()->put("en", "a book")->build())
                ->withSlug(LocalizedStringBuilder::of()->put("en", ProductTypeFixture::uniqueProductTypeString())->build())
                ->withMasterVariant($productVariantDraft)
                ->build();

$product = $builder->products()
    ->post($productDraft)
    ->execute();

查看 测试代码

T恤示例

$referenceableProduct = ProductFixture::referenceableProduct($builder);
$productType = ProductTypeFixture::fetchProductTypeByName($builder, self::PRODUCT_TYPE_NAME);

if (!$productType) {
    $productType = ProductTypeFixture::createProductType($builder, self::PRODUCT_TYPE_NAME);
}

$productReference = ProductReferenceBuilder::of()->withId($referenceableProduct->getId())->build();
$datetime = new \DateTime('2015-02-02');
$datetime = $datetime->format(\DateTime::ATOM);
$attributes = AttributeCollection::of()
    ->add(AttributeBuilder::of()->withName(self::COLOR_ATTR_NAME)->withValue("green")->build())
    ->add(AttributeBuilder::of()->withName(self::SIZE_ATTR_NAME)->withValue("S")->build())
    ->add(AttributeBuilder::of()->withName(self::LAUNDRY_SYMBOLS_ATTR_NAME)->withValue(["cold", "tumbleDrying"])->build())
    ->add(AttributeBuilder::of()->withName(self::RRP_ATTR_NAME)->withValue(MoneyBuilder::of()->withCentAmount(300)->withCurrencyCode("EUR")->build())->build())
    ->add(AttributeBuilder::of()->withName(self::AVAILABLE_SINCE_ATTR_NAME)->withValue($datetime)->build())
    ->add(AttributeBuilder::of()->withName(self::MATCHING_PRODUCTS_ATTR_NAME)->withValue([$productReference])->build());
$productVariantDraft = ProductVariantDraftBuilder::of()
    ->withAttributes($attributes)
    ->build();
$productTypeResourceIdentifier = ProductTypeResourceIdentifierBuilder::of()
    ->withId($productType->getId())
    ->build();
$productDraft = ProductDraftBuilder::of()
    ->withProductType($productTypeResourceIdentifier)
    ->withKey(ProductFixture::uniqueProductString())
    ->withName(LocalizedStringBuilder::of()->put('en', 'basic shirt')->build())
    ->withSlug(LocalizedStringBuilder::of()->put('en', ProductFixture::uniqueProductString())->build())
    ->withMasterVariant($productVariantDraft)
    ->build();

$product = $builder->products()
    ->post($productDraft)
    ->execute();

查看 测试代码

字段或类型的错误值将导致带有错误代码 "InvalidField" 的 BadRequestException。

$productType = $builder->productTypes()
            ->post($productTypeDraft)
            ->execute();
$productVariantDraft  = ProductVariantDraftBuilder::of()
    ->withAttributes(AttributeCollection::of()
        ->add(AttributeBuilder::of()
                ->withName(self::COLOR_ATTR_NAME)
                ->withValue(1) //1 is of illegal type and of illegal key
                ->build()))
    ->build();
$productTypeResourceIdentifier = ProductTypeResourceIdentifierBuilder::of()
    ->withId($productType->getId())
    ->build();
$productDraft = ProductDraftBuilder::of()
    ->withProductType($productTypeResourceIdentifier)
    ->withName(LocalizedStringBuilder::of()->put("en", "basic shirt")->build())
    ->withSlug(LocalizedStringBuilder::of()->put("en", ProductTypeFixture::uniqueProductTypeString())->build())
    ->withMasterVariant($productVariantDraft)

查看 测试代码

作为替代,您可以在同一位置声明您的属性,并使用这些属性来读取和写入属性值

$green = AttributeLocalizedEnumValueBuilder::of()
            ->withKey("green")
            ->withLabel(LocalizedStringBuilder::of()->put("en", "green ")->put("de", "grün")->build())
            ->build();
$cold = AttributeLocalizedEnumValueBuilder::of()
    ->withKey("cold")
    ->withLabel(LocalizedStringBuilder::of()->put("en", "Wash at or below 30°C ")->put("de", "30°C")->build())
    ->build();
$tumbleDrying = AttributeLocalizedEnumValueBuilder::of()
    ->withKey("tumbleDrying")
    ->withLabel(LocalizedStringBuilder::of()->put("en", "tumble drying")->put("de", "Trommeltrocknen")->build())
    ->build();
$productReference = ProductReferenceBuilder::of()->withId($referenceableProduct->getId())->build();

$attributes = AttributeCollection::of()
    ->add(AttributeBuilder::of()->withName(self::COLOR_ATTR_NAME)->withValue("green")->build())
    ->add(AttributeBuilder::of()->withName(self::SIZE_ATTR_NAME)->withValue("S")->build())
    ->add(AttributeBuilder::of()->withName(self::LAUNDRY_SYMBOLS_ATTR_NAME)->withValue(["cold", "tumbleDrying"])->build())
    ->add(AttributeBuilder::of()->withName(self::RRP_ATTR_NAME)->withValue(MoneyBuilder::of()->withCentAmount(300)->withCurrencyCode("EUR")->build())->build())
    ->add(AttributeBuilder::of()->withName(self::AVAILABLE_SINCE_ATTR_NAME)->withValue($datetime)->build())
    ->add(AttributeBuilder::of()->withName(self::MATCHING_PRODUCTS_ATTR_NAME)->withValue([$productReference])->build());
$productVariantDraft = ProductVariantDraftBuilder::of()
    ->withAttributes($attributes)
    ->build();
$productTypeResourceIdentifier = ProductTypeResourceIdentifierBuilder::of()
    ->withId($productType->getId())
    ->build();
$productDraft = ProductDraftBuilder::of()
    ->withProductType($productTypeResourceIdentifier)
    ->withKey(ProductFixture::uniqueProductString())
    ->withName(LocalizedStringBuilder::of()->put('en', 'basic shirt')->build())
    ->withSlug(LocalizedStringBuilder::of()->put('en', ProductFixture::uniqueProductString())->build())
    ->withMasterVariant($productVariantDraft)
    ->build();
$product = $builder->products()
    ->post($productDraft)
    ->execute();

$masterVariant = $product->getMasterData()->getStaged()->getMasterVariant();
foreach ($masterVariant->getAttributes() as $attribute) {
    if ($attribute->getName() === self::COLOR_ATTR_NAME) {
        assertEquals($attribute->getValue()->key, "green");
    }
    if ($attribute->getName() === self::SIZE_ATTR_NAME) {
        assertEquals($attribute->getValue()->key, "S");
    }

查看 测试代码

读取属性

获取属性值的简单方法是通过使用属性的 getValue() 方法,如 php $attribute->getValue()

$product = $this->createProduct();
$masterVariant = $product->getMasterData()->getStaged()->getMasterVariant();
foreach ($masterVariant->getAttributes() as $attribute) {
    if ($attribute->getName() === self::SIZE_ATTR_NAME) {
        assertEquals($attribute->getValue()->key, "S");
    }
}

查看 测试代码

您也可以使用 php getValueAs() 方法作为属性的转换,如您有一个枚举值但将其提取为布尔值,因为这些方法将传递的值转换为类型

$product = $builder->products()->post($productDraft)->execute();
$masterVariant = $product->getMasterData()->getStaged()->getMasterVariant();

$result = null;
foreach ($masterVariant->getAttributes() as $attribute) {
    if ($attribute->getName() === self::SIZE_ATTR_NAME) {
        /** @var AttributeAccessor $attrAccessor */
        $attrAccessor = $attribute->with(AttributeAccessor::of());

        $result = $attrAccessor->getValueAsBool();
    }
}

$this->assertIsBool($result);

查看 测试代码

更新产品的属性值

下面是一些关于设置属性值的示例,类似于产品创建

图书示例

$product = $this->createBookProduct();
$masterVariantId = 1;
$productUpdate = ProductUpdateBuilder::of()
    ->withVersion($product->getVersion())
    ->withActions(
        ProductUpdateActionCollection::fromArray([
            ProductSetAttributeActionBuilder::of()
                ->withVariantId($masterVariantId)
                ->withName(self::ISBN_ATTR_NAME)
                ->withValue("978-3-86680-192-8")
                ->build()
        ])
        )->build();

$productUpdated = $builder
    ->products()
    ->withId($product->getId())
    ->post($productUpdate)
    ->execute();
$masterVariant = $productUpdated->getMasterData()->getStaged()->getMasterVariant();
$attribute = ProductTypeFixture::findAttributes($masterVariant->getAttributes(), self::ISBN_ATTR_NAME);

assertEquals($attribute->getValue(), "978-3-86680-192-8");

查看 测试代码

T恤示例

$masterVariantId = 1;
$productUpdatedAction = ProductUpdateBuilder::of()
    ->withVersion($product->getVersion())
    ->withActions(
        ProductUpdateActionCollection::fromArray([
            ProductSetAttributeActionBuilder::of()
                ->withVariantId($masterVariantId)
                ->withName(self::COLOR_ATTR_NAME)
                ->withValue("red")
                ->build(),
            ProductSetAttributeActionBuilder::of()
                ->withVariantId($masterVariantId)
                ->withName(self::SIZE_ATTR_NAME)
                ->withValue("M")
                ->build(),
            ProductSetAttributeActionBuilder::of()
                ->withVariantId($masterVariantId)
                ->withName(self::LAUNDRY_SYMBOLS_ATTR_NAME)
                ->withValue(["cold"])
                ->build(),
            ProductSetAttributeActionBuilder::of()
                ->withVariantId($masterVariantId)
                ->withName(self::RRP_ATTR_NAME)
                ->withValue(MoneyBuilder::of()->withCurrencyCode("EUR")->withCentAmount(2000)->build())
                ->build(),
        ])
    )->build();
$productUpdated = $builder
    ->with()
    ->products()
    ->withId($product->getId())
    ->post($productUpdatedAction)
    ->execute();

$attributesUpdatedProduct = $productUpdated->getMasterData()->getStaged()->getMasterVariant()->getAttributes();

self::assertEquals(ProductTypeFixture::findAttribute($attributesUpdatedProduct, self::SIZE_ATTR_NAME)->getValue()->key, "M");
self::assertEquals(ProductTypeFixture::findAttribute($attributesUpdatedProduct, self::COLOR_ATTR_NAME)->getValue()->key, "red");
self::assertEquals(ProductTypeFixture::findAttribute($attributesUpdatedProduct, self::LAUNDRY_SYMBOLS_ATTR_NAME)->getValue()[0]->key, "cold");
self::assertEquals(ProductTypeFixture::findAttribute($attributesUpdatedProduct, self::RRP_ATTR_NAME)->getValue()->centAmount, 2000);

查看 测试代码

为导入订单创建属性

导入订单的属性值与更新产品的操作不同。在订单中,您提供枚举类型的全值,而不是像所有其他类型那样只提供键。这使得可以动态创建新的枚举值。其他属性的行为如预期。

示例

$product = $this->createProduct($builder);
$attributes = AttributeCollection::of()
    ->add(AttributeBuilder::of()->withName(self::COLOR_ATTR_NAME)->withValue("yellow")->build())
    ->add(AttributeBuilder::of()->withName(self::RRP_ATTR_NAME)->withValue(MoneyBuilder::of()->withCurrencyCode("EUR")->withCentAmount(30)->build())->build());

$productVariantImportDraft = ProductVariantImportDraftBuilder::of()
                                ->withId(1)
                                ->withAttributes($attributes)
                                ->build();
$lineItemImportDraft = LineItemImportDraftBuilder::of()
    ->withProductId($product->getId())
    ->withVariant($productVariantImportDraft)
    ->withQuantity(1)
    ->withPrice(ProductFixture::priceDraft())
    ->withName(LocalizedStringBuilder::of()->put("en", "product name")->build())
    ->build();
$orderImportDraft = OrderImportDraftBuilder::of()
    ->withLineItems(LineItemImportDraftCollection::of()->add($lineItemImportDraft))
    ->withTotalPrice(MoneyBuilder::of()->withCentAmount(20)->withCurrencyCode("EUR")->build())
    ->withOrderState(OrderState::COMPLETE)
    ->build();
$order = $builder->orders()
    ->importOrder()
    ->post($orderImportDraft)
    ->execute();
    
$productVariant = $order->getLineItems()->current()->getVariant();
$colorAttribute = ProductTypeFixture::findAttribute($productVariant->getAttributes(), self::COLOR_ATTR_NAME);
assertEquals("yellow", $colorAttribute->getValue());
$rrpAttribute = ProductTypeFixture::findAttribute($productVariant->getAttributes(), self::RRP_ATTR_NAME);
assertEquals(30, $rrpAttribute->getValue()->centAmount);

查看 测试代码

序列化

在PHP SDK中,一些类实现了 JsonSerializable 接口,并且它们有一个定制的 jsonSerialize() 方法,可以轻松地将类的实例转换为JSON字符串。这意味着当调用 json_encode() 方法时,对象将被正确转换和格式化为JSON字符串。

请看下面的示例

$messagePayload = new MessageDeliveryPayloadModel(
    "{projectKey}",
    null, // Replace with an actual Reference object if needed
    null, // Replace with an actual UserProvidedIdentifiers object if needed
    "uniqueId456", // ID
    1, // The version
    new DateTimeImmutable("2024-08-06T12:34:56+00:00"), // CreatedAt
    new DateTimeImmutable("2024-08-06T12:34:56+00:00"), // LastModifiedAt
    42, // SequenceNumber
    1, // Resource version
    null, // Replace with an actual PayloadNotIncluded object if needed
    "Message" // notification type
);

$messagePayloadJSON = json_encode($messagePayload);

从SDK v1迁移指南

要从1.x版本迁移到2.x版本,下面有一些指南

可观察性

要监控和观察SDK,请参阅官方文档可观察性,其中有一个示例应用程序,展示了如何使用New Relic和Datadog监控PHP SDK。

文档

许可证

MIT