444 lines
14 KiB
PHP
444 lines
14 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace External\PompoBundle\Util;
|
|
|
|
use KupShop\CatalogBundle\ProductList\ProductList;
|
|
use KupShop\ContentBundle\Util\Block;
|
|
use KupShop\KupShopBundle\Context\ContextManager;
|
|
use KupShop\KupShopBundle\Context\LanguageContext;
|
|
use KupShop\KupShopBundle\Util\Contexts;
|
|
use KupShop\KupShopBundle\Util\Functional\Mapping;
|
|
use KupShop\KupShopBundle\Util\StringUtil;
|
|
use Query\Operator;
|
|
use WpjShop\GraphQL\Client;
|
|
use WpjShop\GraphQL\DataObjects\Product\CollectionItem;
|
|
use WpjShop\GraphQL\DataObjects\Product\LinkItem;
|
|
use WpjShop\GraphQL\DataObjects\Product\ParameterValue;
|
|
use WpjShop\GraphQL\DataObjects\Product\ProductParameter;
|
|
use WpjShop\GraphQL\DataObjects\Product\RelatedItem;
|
|
use WpjShop\GraphQL\Enums\ProductVisibility;
|
|
|
|
/**
|
|
* Slouží pro komunikaci mezi `prod/pompo` a `prod/nejhracka`. Z pompa se na nejhracku přenáší informace o produktu.
|
|
*/
|
|
class PompoGraphQLUpdater
|
|
{
|
|
private const GRAPHQL_URL = 'https://www.nejhracka.cz/admin/graphql';
|
|
private const GRAPHQL_ACCESS_TOKEN = '201ac0b08889d173f99cfc7230f3f327';
|
|
|
|
private ?Client $client = null;
|
|
|
|
private ProductList $productList;
|
|
private Block $block;
|
|
private ContextManager $contextManager;
|
|
|
|
private array $parametersCache = [];
|
|
|
|
private array $sectionsListCache = [];
|
|
private array $producersListCache = [];
|
|
|
|
public function __construct(ProductList $productList, Block $block, ContextManager $contextManager)
|
|
{
|
|
$this->productList = $productList;
|
|
$this->block = $block;
|
|
$this->contextManager = $contextManager;
|
|
}
|
|
|
|
public function updateEditableContent(int $id, array $data): bool
|
|
{
|
|
return $this->getClient()->editableContent->update($id, $data)['result'] ?? false;
|
|
}
|
|
|
|
public function updateProduct(int $id, array $data): array
|
|
{
|
|
return $this->getClient()->product
|
|
->addSelection(['descriptionPlus' => ['id']])
|
|
->update($id, $data) ?? [];
|
|
}
|
|
|
|
public function updateProductLinks(int $externalProductId, \Product $product): void
|
|
{
|
|
$links = [];
|
|
foreach ($product->links ?? [] as $link) {
|
|
$links[] = new LinkItem(
|
|
$link['title'],
|
|
$link['link'],
|
|
$link['type']
|
|
);
|
|
}
|
|
|
|
$this->client->product->updateLinks($externalProductId, $links);
|
|
}
|
|
|
|
public function updateProductRelated(int $externalProductId, \Product $product): void
|
|
{
|
|
$relatedProducts = [];
|
|
foreach ($product->products_related ?? [] as $item) {
|
|
if (empty($item->code)) {
|
|
continue;
|
|
}
|
|
|
|
if ($relatedExternalId = $this->getProductIdByCode($item->code)) {
|
|
$relatedProducts[] = new RelatedItem($relatedExternalId);
|
|
}
|
|
}
|
|
|
|
$this->client->product->updateRelated($externalProductId, $relatedProducts);
|
|
}
|
|
|
|
public function updateProductCollection(int $externalProductId, \Product $product): void
|
|
{
|
|
$collectionProducts = [];
|
|
foreach ($product->collections['own'] ?? [] as $item) {
|
|
if (empty($item->code)) {
|
|
continue;
|
|
}
|
|
|
|
if ($relatedExternalId = $this->getProductIdByCode($item->code)) {
|
|
$collectionProducts[] = new CollectionItem($relatedExternalId);
|
|
}
|
|
}
|
|
|
|
$this->client->product->updateCollections($externalProductId, $collectionProducts);
|
|
}
|
|
|
|
public function updateProductTranslations(int $externalProductId, int $externalEditableContentId, string $language, \Product $product): void
|
|
{
|
|
$translation = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('products_translations')
|
|
->where(Operator::equals(['id_product' => $product->id, 'id_language' => $language]))
|
|
->execute()->fetchAssociative();
|
|
|
|
$productData = [];
|
|
|
|
if (!empty($translation['title'])) {
|
|
$productData['title'] = $translation['title'];
|
|
}
|
|
|
|
if (!empty($translation['short_descr'])) {
|
|
$productData['description'] = $translation['short_descr'];
|
|
}
|
|
|
|
if (!empty($translation['long_descr'])) {
|
|
$productData['longDescription'] = $translation['long_descr'];
|
|
}
|
|
|
|
if (!empty($translation['figure'])) {
|
|
$productData['visibility'] = $this->getProductVisibility($translation['figure']);
|
|
}
|
|
|
|
if (!empty($translation['meta_title']) || !empty($translation['meta_description']) || !empty($translation['meta_keywords'])) {
|
|
$seoData = [];
|
|
|
|
if (!empty($translation['meta_title'])) {
|
|
$seoData['title'] = $translation['meta_title'];
|
|
}
|
|
|
|
if (!empty($translation['meta_description'])) {
|
|
$seoData['description'] = $translation['meta_description'];
|
|
}
|
|
|
|
if (!empty($translation['meta_keywords'])) {
|
|
$seoData['keywords'] = $translation['meta_keywords'];
|
|
}
|
|
|
|
$productData['seo'] = $seoData;
|
|
}
|
|
|
|
if (!empty($productData)) {
|
|
$this->getClient()->product->translate($externalProductId, $language, $productData);
|
|
}
|
|
|
|
// prelozit popis+
|
|
if (!empty($product->id_block)) {
|
|
$defaultBlocks = $this->getBlocks((int) $product->id_block);
|
|
$translatedBlocks = $this->getBlocks((int) $product->id_block, $language);
|
|
|
|
if (json_encode($defaultBlocks) !== json_encode($translatedBlocks)) {
|
|
$this->getClient()->editableContent->translate(
|
|
$externalEditableContentId,
|
|
$language,
|
|
$this->createEditableContentFromBlocks($translatedBlocks)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function updateProductParameters(int $externalProductId, \Product $product): void
|
|
{
|
|
$parameterUpdates = [];
|
|
|
|
foreach ($this->getParameters() as $externalParameter) {
|
|
$parameterUpdates[$externalParameter['id']] = [];
|
|
}
|
|
|
|
foreach ($product->param as $parameter) {
|
|
// pokud nenajdu parametr, tak ho vytvorim
|
|
if (!($externalParameterId = ($this->getParameterByName($parameter['name'])['id'] ?? false))) {
|
|
// nejdriv rozhodnu typ parametru
|
|
switch ($parameter['value_type']) {
|
|
case 'float':
|
|
$type = 'NUMBER';
|
|
break;
|
|
case 'char':
|
|
$type = 'TEXT';
|
|
break;
|
|
default:
|
|
$type = 'LIST';
|
|
}
|
|
|
|
// vytvorim parametr
|
|
$externalParameterId = $this->createParameter($parameter['name'],
|
|
$type,
|
|
empty($parameter['unit']) ? null : $parameter['unit']
|
|
)['id'];
|
|
}
|
|
|
|
$parameterUpdates[$externalParameterId] = array_map(fn ($x) => $x['value'], $parameter['values']);
|
|
}
|
|
|
|
// aktualizuju parametry na nejhracce
|
|
$productParameters = [];
|
|
foreach ($parameterUpdates as $externalParameterId => $values) {
|
|
$parameterType = $this->getParameterType($externalParameterId);
|
|
|
|
$productParameters[] = new ProductParameter(
|
|
$externalProductId,
|
|
$externalParameterId,
|
|
array_map(fn ($x) => new ParameterValue($x, $parameterType), $values)
|
|
);
|
|
}
|
|
|
|
$this->getClient()->product->updateParameterBulk($productParameters);
|
|
}
|
|
|
|
public function createParameter(string $name, string $type, ?string $unit = null): array
|
|
{
|
|
$result = $this->getClient()->parameter->create(
|
|
[
|
|
'name' => $name,
|
|
'type' => $type,
|
|
'unit' => $unit,
|
|
]
|
|
)['parameterCreate'];
|
|
|
|
// Pridam parametr do cache
|
|
return $this->parametersCache[] = $result;
|
|
}
|
|
|
|
public function getSections(bool $force = false): array
|
|
{
|
|
if (!$force && $this->sectionsListCache) {
|
|
return $this->sectionsListCache;
|
|
}
|
|
|
|
return $this->sectionsListCache = $this->getClient()->section->setSelection(
|
|
[
|
|
'id',
|
|
'name',
|
|
'visible',
|
|
'url',
|
|
'isVirtual',
|
|
'parent' => [
|
|
'id',
|
|
'name',
|
|
'parent' => [
|
|
'id',
|
|
'name',
|
|
'parent' => [
|
|
'id',
|
|
'name',
|
|
'parent' => [
|
|
'id',
|
|
'name',
|
|
'parent' => [
|
|
'id',
|
|
'name',
|
|
'parent' => [
|
|
'id',
|
|
'name',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
]
|
|
)->list()['items'] ?? [];
|
|
}
|
|
|
|
public function getSectionIdByPath(array $path): ?int
|
|
{
|
|
static $sectionsByKey = [];
|
|
|
|
$createKey = function (array $path) {
|
|
return StringUtil::slugify(implode('/', $path));
|
|
};
|
|
|
|
if (empty($sectionsByKey)) {
|
|
$sections = $this->getSections();
|
|
foreach ($sections as $section) {
|
|
$remotePath = $this->getRemoteSectionPath($section);
|
|
|
|
$sectionsByKey[$createKey($remotePath)] = $section['id'];
|
|
}
|
|
}
|
|
|
|
$key = $createKey($path);
|
|
|
|
return $sectionsByKey[$key] ?? null;
|
|
}
|
|
|
|
public function getRemoteSectionPath(array $section): array
|
|
{
|
|
$path = [];
|
|
|
|
$currentSection = $section;
|
|
while ($currentSection) {
|
|
$path[$currentSection['id']] = $currentSection['name'];
|
|
|
|
$currentSection = $currentSection['parent'];
|
|
}
|
|
|
|
return array_reverse($path, true);
|
|
}
|
|
|
|
public function getProducers(): array
|
|
{
|
|
if (!empty($this->producersListCache)) {
|
|
return $this->producersListCache;
|
|
}
|
|
|
|
return $this->producersListCache = $this->client->producer->list()['items'] ?? [];
|
|
}
|
|
|
|
public function getParameters(bool $force = false): array
|
|
{
|
|
if (!$force && !empty($this->parametersCache)) {
|
|
return $this->parametersCache;
|
|
}
|
|
|
|
return $this->parametersCache = $this->getClient()->parameter->list()['items'] ?? [];
|
|
}
|
|
|
|
public function getParameterType(int $parameterId): string
|
|
{
|
|
static $parameterTypes;
|
|
|
|
if (!$parameterTypes) {
|
|
$parameterTypes = Mapping::mapKeys($this->getParameters(), fn ($k, $v) => [$v['id'], $v['type']]);
|
|
}
|
|
|
|
return $parameterTypes[$parameterId] ?? 'LIST';
|
|
}
|
|
|
|
public function getParameterByName(string $name): ?array
|
|
{
|
|
$nameLower = mb_strtolower($name);
|
|
|
|
foreach ($this->getParameters() as $parameter) {
|
|
if (mb_strtolower($parameter['name']) === $nameLower) {
|
|
return $parameter;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getProducerIdByName(string $name): ?int
|
|
{
|
|
$nameLower = mb_strtolower($name);
|
|
|
|
foreach ($this->getProducers() as $producer) {
|
|
if (mb_strtolower($producer['name']) === $nameLower) {
|
|
return $producer['id'];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getProductIdByCode(string $code): ?int
|
|
{
|
|
return $this->getClient()->product->getByCode($code)['id'] ?? null;
|
|
}
|
|
|
|
public function getProductVisibility(string $visibility): string
|
|
{
|
|
switch ($visibility) {
|
|
case 'Y':
|
|
return ProductVisibility::VISIBLE;
|
|
case 'O':
|
|
return ProductVisibility::CLOSED;
|
|
default:
|
|
return ProductVisibility::HIDDEN;
|
|
}
|
|
}
|
|
|
|
public function getBlocks(int $rootBlockId, ?string $language = null): ?array
|
|
{
|
|
$language = $language ?: Contexts::get(LanguageContext::class)->getDefaultId();
|
|
|
|
return $this->contextManager->activateContexts([LanguageContext::class => $language], function () use ($rootBlockId) {
|
|
return $this->block->getBlocks($rootBlockId);
|
|
});
|
|
}
|
|
|
|
public function getProduct(int $productId, ?string $language = null): ?\Product
|
|
{
|
|
$productList = clone $this->productList;
|
|
$productList->andSpec(Operator::equals(['p.id' => $productId]));
|
|
$productList->fetchParameters();
|
|
$productList->fetchSections();
|
|
$productList->fetchLinks();
|
|
$productList->fetchCollections();
|
|
$productList->fetchProductsRelated();
|
|
$productList->fetchProducers();
|
|
|
|
$language = $language ?: Contexts::get(LanguageContext::class)->getDefaultId();
|
|
|
|
$products = $this->contextManager->activateContexts([LanguageContext::class => $language], function () use ($productList) {
|
|
return $productList->getProducts();
|
|
});
|
|
|
|
if (empty($products[$productId])) {
|
|
return null;
|
|
}
|
|
|
|
return $products[$productId];
|
|
}
|
|
|
|
public function createEditableContentFromBlocks(array $blocks): array
|
|
{
|
|
$data = [
|
|
'areas' => [],
|
|
'overwrite' => true,
|
|
];
|
|
|
|
foreach ($blocks as $block) {
|
|
$data['areas'][] = [
|
|
'id' => null,
|
|
'name' => $block['name'],
|
|
'data' => $block['json_content'] ?: '[]',
|
|
];
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
public function getClient(): Client
|
|
{
|
|
if (!$this->client) {
|
|
$this->client = new Client(
|
|
self::GRAPHQL_URL,
|
|
self::GRAPHQL_ACCESS_TOKEN
|
|
);
|
|
}
|
|
|
|
return $this->client;
|
|
}
|
|
}
|