272 lines
9.3 KiB
PHP
272 lines
9.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace External\ZNZBundle\Synchronizers;
|
|
|
|
use External\ZNZBundle\Exception\ZNZException;
|
|
use External\ZNZBundle\Resources\script\FixTranslatedBlocksScript;
|
|
use External\ZNZBundle\Util\ZNZApi;
|
|
use External\ZNZBundle\Util\ZNZTranslationsUtil;
|
|
use KupShop\ContentBundle\Util\Block;
|
|
use KupShop\KupShopBundle\Context\ContextManager;
|
|
use KupShop\KupShopBundle\Util\Database\QueryHint;
|
|
use Query\Operator;
|
|
use Symfony\Contracts\Service\Attribute\Required;
|
|
|
|
class BlockDescriptionSynchronizer extends BaseSynchronizer
|
|
{
|
|
protected static string $type = 'blockDescription';
|
|
|
|
#[Required]
|
|
public ZNZApi $znzApi;
|
|
#[Required]
|
|
public Block $block;
|
|
#[Required]
|
|
public ZNZTranslationsUtil $translationsUtil;
|
|
#[Required]
|
|
public ContextManager $contextManager;
|
|
|
|
public static function getHandledTables(): array
|
|
{
|
|
return [
|
|
'ProduktPopis' => 'processProductDescription',
|
|
// 'ZnackaPopis' => 'processProducerDescription',
|
|
'RadaPopis' => 'processSeriesDescription',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Aktualizace popisu+ směrem z Heliosu do e-shopu. Pokud jiný e-shop poslal změnu do Heliosu, tak byla vygenerována
|
|
* změna, kterou je potřeba na ostatních shopech zpracovat a tím zaktualizovat popis+.
|
|
*/
|
|
public function processProductDescription(array $item): void
|
|
{
|
|
[$productId, $_] = $this->znzUtil->getProductMapping($item['IDProdukt']);
|
|
if (!$productId) {
|
|
return;
|
|
}
|
|
|
|
$this->updateBlocks(
|
|
'products',
|
|
$productId,
|
|
$item
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Aktualizace popisu výrobce. Pokud jiný e-shop poslal svůj popis do Heliosu, tak
|
|
* byla vygenerována změna, díky které se ten popis propíše na ostatní shopy. Tahle fce zařídí, že
|
|
* se ta změna propíše.
|
|
*/
|
|
public function processProducerDescription(array $item): void
|
|
{
|
|
$parameterListId = $this->znzUtil->getParameterValueMapping(
|
|
$this->znzUtil->getParameterByKey('ZnackaOption'),
|
|
$item['IDZnacka']
|
|
);
|
|
|
|
if (!$parameterListId) {
|
|
return;
|
|
}
|
|
|
|
// najdu vyrobce
|
|
$producerId = sqlQueryBuilder()
|
|
->select('pr.id')
|
|
->from('producers', 'pr')
|
|
->join('pr', 'parameters_list', 'pl', 'pl.id = :parameterListId')
|
|
->where('pr.name = pl.value')
|
|
->setParameter('parameterListId', $parameterListId)
|
|
->execute()->fetchOne();
|
|
|
|
if (!$producerId) {
|
|
return;
|
|
}
|
|
|
|
$this->updateBlocks(
|
|
'producers',
|
|
$producerId,
|
|
$item
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Aktualizace obsahu šablony, Šablony se používají pro popisek Řady. Pokud jiný e-shop poslal svůj popis
|
|
* do Heliosu, tak byla vygenerována změna, díky které se ten popis propíše na ostatní shopy. Tahle fce
|
|
* zařídí, že se ta změna propíše.
|
|
*/
|
|
public function processSeriesDescription(array $item): void
|
|
{
|
|
if (empty($item['IDRada'])) {
|
|
return;
|
|
}
|
|
|
|
$templateId = $this->znzUtil->getSeriesTemplateId($item['IDRada']);
|
|
|
|
$this->updateBlocks(
|
|
'templates',
|
|
$templateId,
|
|
$item
|
|
);
|
|
}
|
|
|
|
public function updateBlocks(string $tableName, int $objectId, array $item): void
|
|
{
|
|
$data = $this->prepareData($item);
|
|
if ($data === null) {
|
|
return;
|
|
}
|
|
|
|
$blocks = $this->prepareBlocks($data);
|
|
|
|
$rootBlockId = QueryHint::withRouteToMaster(fn () => $this->block->getRootBlockId($tableName, $objectId));
|
|
|
|
if ($item['meta']['translation'] ?? false) {
|
|
[$localBlocksByPositions, $localBlocksContent] = sqlGetConnection()->transactional(function () use ($rootBlockId) {
|
|
$localBlocks = sqlQueryBuilder()
|
|
->select('id, position, json_content')
|
|
->from('blocks')
|
|
->where(Operator::equals(['id_root' => $rootBlockId]))
|
|
->execute()->fetchAllAssociative();
|
|
|
|
$blocksByPositions = [];
|
|
$blocksContent = [];
|
|
foreach ($localBlocks as $localBlock) {
|
|
$blocksByPositions[$localBlock['position']] = $localBlock['id'];
|
|
$blocksContent[$localBlock['id']] = $localBlock['json_content'];
|
|
}
|
|
|
|
if (count($blocksByPositions) === 1) {
|
|
$blocksByPositions = array_values($blocksByPositions);
|
|
}
|
|
|
|
return [$blocksByPositions, $blocksContent];
|
|
});
|
|
|
|
$this->translateBlocks($item['meta']['language'], $blocks, $localBlocksByPositions, $localBlocksContent);
|
|
|
|
$this->translationsUtil->updateBlockTranslations([$rootBlockId]);
|
|
|
|
return;
|
|
}
|
|
|
|
$this->block->updateBlocks($tableName, $objectId, $blocks);
|
|
|
|
$this->translationsUtil->updateBlockTranslations([$rootBlockId]);
|
|
}
|
|
|
|
private function prepareBlocks(array $data): array
|
|
{
|
|
// pripravim si fotky, ktere jsou pouzity v bloku
|
|
$photosMapping = [];
|
|
foreach ($data['photos'] ?? [] as $remoteId => [$znzPhotoId, $photoUrl]) {
|
|
if (!($photoId = $this->znzUtil->getMapping('photo', $znzPhotoId))) {
|
|
$photoId = $this->znzUtil->getDownloader()->importProductImage($photoUrl, true);
|
|
}
|
|
|
|
$photosMapping[$remoteId] = $photoId;
|
|
}
|
|
|
|
// rekurzivne produjdu bloky
|
|
return $this->recursivelyBlocksWalk($data['blocks'] ?? [], function ($block) use ($photosMapping) {
|
|
// rekurzivne nahradim ID fotek v json contentu
|
|
$data = $this->recursivelyReplacePhotoIdsInBlockContent(
|
|
json_decode($block['json_content'] ?? '', true) ?: [],
|
|
$photosMapping
|
|
);
|
|
|
|
$block['json_content'] = json_encode($data);
|
|
|
|
// smazu HTML obsah, aby se pri aktualizaci znovu vyrenderoval
|
|
unset($block['content']);
|
|
|
|
return $block;
|
|
});
|
|
}
|
|
|
|
/** Vraci rozparsovana data blocku. Pokud se vrati null, tak nechceme provadet update. */
|
|
private function prepareData(array $item): ?array
|
|
{
|
|
$data = json_decode($item['PopisRich'] ?: '', true) ?: [];
|
|
|
|
// pokud je aktualni website autorem zmeny, tak ji preskakuju, protoze je zbytecny synchronizovat neco, co uz mam
|
|
if (($data['from'] ?? null) === $this->configuration->getMainWebsite()) {
|
|
return null;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function translateBlocks(string $language, array $blocks, array $localBlocksByPositions, array $localBlocksContent): void
|
|
{
|
|
foreach ($blocks as $key => $block) {
|
|
if (!($blockId = ($localBlocksByPositions[$block['position']] ?? null))) {
|
|
if (!($blockId = ($localBlocksByPositions[$key] ?? null))) {
|
|
throw new ZNZException('Unable to update translation of block content: cannot find block to translate!');
|
|
}
|
|
}
|
|
|
|
$defaultData = json_decode($localBlocksContent[$blockId] ?? '', true) ?: [];
|
|
if (!empty($defaultData)) {
|
|
$fixedTranslatedData = FixTranslatedBlocksScript::fixBlockIds(
|
|
$defaultData,
|
|
json_decode($block['json_content'] ?: '', true) ?: []
|
|
);
|
|
|
|
if ($fixedTranslatedData) {
|
|
$block['json_content'] = json_encode($fixedTranslatedData);
|
|
}
|
|
}
|
|
|
|
$this->block->translateBlock($language, (int) $blockId, $block);
|
|
|
|
// Pokud mam sub bloky, tak prelozim i ty
|
|
foreach ($block['children'] ?? [] as $childBlock) {
|
|
$this->translateBlocks($language, $childBlock, $localBlocksByPositions, $localBlocksContent);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getBlockIdByPositions(int $position, array $blocksByPositions): ?int
|
|
{
|
|
if ($blockId = ($localBlocksByPositions[$position] ?? null)) {
|
|
return (int) $blockId;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function recursivelyBlocksWalk(array $blocks, callable $fn): array
|
|
{
|
|
foreach ($blocks as &$block) {
|
|
$block = $fn($block);
|
|
if (!empty($block['children'])) {
|
|
$block['children'] = $this->recursivelyBlocksWalk($block['children'], $fn);
|
|
}
|
|
}
|
|
|
|
return $blocks;
|
|
}
|
|
|
|
private function recursivelyReplacePhotoIdsInBlockContent(array $data, array $photosMapping): array
|
|
{
|
|
foreach ($data as &$item) {
|
|
if (!empty($item['settings']['photo']['id'])) {
|
|
$item['settings']['photo']['id'] = $photosMapping[$item['settings']['photo']['id']] ?? $item['settings']['photo']['id'];
|
|
}
|
|
|
|
if (!empty($item['settings']['photos'])) {
|
|
foreach ($item['settings']['photos'] as $photoKey => $photoItem) {
|
|
$item['settings']['photos'][$photoKey]['photo']['id'] = $photosMapping[$photoItem['photo']['id']] ?? $photoItem['photo']['id'];
|
|
}
|
|
}
|
|
|
|
if (!empty($item['children'])) {
|
|
$item['children'] = $this->recursivelyReplacePhotoIdsInBlockContent($item['children'], $photosMapping);
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
}
|