commercetools/commercetools-sdk

commercetools Composable Commerce API 的官方 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客户端时添加中间件。可以使用中间件数组添加多个中间件。

中间件工厂(属于工厂模式)的范围是处理所有可用的中间件,并有机会对它们进行自定义。

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

默认中间件

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
);

RetryNAMiddleware

方法 createRetryNAMiddleware 旨在创建满足特定条件时重试 HTTP 请求的中介。这种中介在可能出现暂时性错误(如临时服务器不可用)的场景中特别有用。

$maxRetries = 3;

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

OAuthHandlerMiddleware

方法 createMiddlewareForOAuthHandler 创建用于处理 OAuth2 认证的中介,确保包括必要的 OAuth 凭证。

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

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

LoggerMiddleware

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

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

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

ReauthenticateMiddleware

方法 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 列表,它对应于每个属性的名称和类型,以及一些其他信息。每个名称/类型对必须在项目范围内是唯一的,因此如果您创建了一个类型为 String 的属性 "foo",您不能创建另一个 ProductType,其中 "foo" 有另一种类型(例如 LocalizedString)。如果您这样做,您将收到类似以下错误消息

"具有名称 'foo' 的属性在产品类型 'exampleproducttype' 中的类型不同。"

在此场景中,我们提供了两个 ProductTypesbookt-shirt

book 产品类型包含以下属性

t-shirt 产品类型包含以下属性

$color作为AttributeLocalizedEnumValue,颜色为绿色和红色,以及德语和英语翻译。$size作为AttributePlainEnumValue,尺寸为S、M和X。$laundrySymbols为一组AttributeLocalizedEnumValue,包含温度和烘干方式。$matchingProducts为一组ProductReference,可指向与当前产品相似的产品。$rrp为包含推荐零售价的Money。$availableSince为DateTime,表示产品自何时起在商店中对客户可用。所有可用的属性类型可以在“所有已知实现类”中的AttributeType中找到。

创建书籍产品类型的代码

$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();

请参阅测试代码

产品类型有一个键(字符串),可以用作逻辑上识别产品类型的键。该键具有唯一约束。

创建产品

要创建产品,您需要引用产品类型。由于开发系统的产品类型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");
    }

请参阅测试代码

读取属性

获取属性值的简单方法是通过使用Attribute的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()方法作为属性的转换,例如,如果您有一个EnumValue,但将其提取为布尔值,因为这些方法将传递的值转换为类型

$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