EbayTaxonomyService.getCategoryAspects() now returns 'usage' alongside 'required'. eBay has three effective tiers for category 177/Notebooks: required=true + usage=RECOMMENDED → hard gate (3 aspects) required=false + usage=RECOMMENDED → search ranking signal (17 aspects) required=false + usage=OPTIONAL → truly optional (11 aspects) Integration test covers all three tiers explicitly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
78 lines
2.7 KiB
PHP
78 lines
2.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Infrastructure\Channel\Ebay;
|
|
|
|
use Symfony\Contracts\Cache\CacheInterface;
|
|
use Symfony\Contracts\Cache\ItemInterface;
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
|
final class EbayTaxonomyService
|
|
{
|
|
public function __construct(
|
|
private readonly HttpClientInterface $httpClient,
|
|
private readonly EbayOAuthClient $oauthClient,
|
|
private readonly CacheInterface $cache,
|
|
private readonly string $apiBaseUrl,
|
|
private readonly string $marketplaceId,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Returns item aspects for a given eBay category, including eBay's usage tier.
|
|
*
|
|
* usage values:
|
|
* 'RECOMMENDED' — eBay search-ranking signal; include whenever possible
|
|
* 'OPTIONAL' — truly optional, low impact
|
|
*
|
|
* @return list<array{name: string, required: bool, usage: string, values: list<string>}>
|
|
*/
|
|
public function getCategoryAspects(string $categoryId): array
|
|
{
|
|
$cacheKey = 'ebay_aspects_'.md5($this->marketplaceId.$categoryId);
|
|
|
|
return $this->cache->get($cacheKey, function (ItemInterface $item) use ($categoryId): array {
|
|
$item->expiresAfter(86400 * 7);
|
|
|
|
$token = $this->oauthClient->getAccessToken();
|
|
|
|
$response = $this->httpClient->request(
|
|
'GET',
|
|
$this->apiBaseUrl.'/commerce/taxonomy/v1/category_tree/'.$this->getTreeId().'/get_item_aspects_for_category',
|
|
[
|
|
'headers' => [
|
|
'Authorization' => 'Bearer '.$token,
|
|
'X-EBAY-C-MARKETPLACE-ID' => $this->marketplaceId,
|
|
],
|
|
'query' => ['category_id' => $categoryId],
|
|
],
|
|
);
|
|
|
|
/** @var array{aspects?: list<array{localizedAspectName: string, aspectConstraint?: array{aspectRequired?: bool, aspectUsage?: string}, aspectValues?: list<array{localizedValue: string}>}>} $data */
|
|
$data = $response->toArray();
|
|
$aspects = [];
|
|
|
|
foreach ($data['aspects'] ?? [] as $aspect) {
|
|
$aspects[] = [
|
|
'name' => $aspect['localizedAspectName'],
|
|
'required' => (bool) ($aspect['aspectConstraint']['aspectRequired'] ?? false),
|
|
'usage' => $aspect['aspectConstraint']['aspectUsage'] ?? 'OPTIONAL',
|
|
'values' => array_column($aspect['aspectValues'] ?? [], 'localizedValue'),
|
|
];
|
|
}
|
|
|
|
return $aspects;
|
|
});
|
|
}
|
|
|
|
private function getTreeId(): string
|
|
{
|
|
return match ($this->marketplaceId) {
|
|
'EBAY_DE' => '77',
|
|
'EBAY_US' => '0',
|
|
'EBAY_UK' => '3',
|
|
default => '77',
|
|
};
|
|
}
|
|
}
|