'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; } }