Files
kupshop/bundles/KupShop/AdminBundle/Util/BlocksHistory.php
2025-08-02 16:30:27 +02:00

277 lines
8.2 KiB
PHP

<?php
namespace KupShop\AdminBundle\Util;
use Doctrine\DBAL\Connection;
use KupShop\ContentBundle\Util\Block;
use Query\Operator;
class BlocksHistory
{
public const TYPE_BY_ID = 'bh.id';
public const TYPE_BY_ROOT_ID = 'id_root_block';
private $block;
public function __construct(Block $block)
{
$this->block = $block;
}
/**
* @return bool
*/
public function saveBlocksHistory(array $blocks)
{
if ($this->isChangeInBlocks($blocks)) {
$rootId = $this->getBlocksRootId($blocks);
// Skip if no root block present
if (!$rootId) {
return false;
}
// get actual blocks hierarchy
$blocksHierarchy = $this->block->getBlocks($rootId);
$id_admin = getAdminUser()['id'] ?? null;
// ignore superuser
$id_admin = $id_admin === 0 ? null : $id_admin;
if ($idLastHistory = $this->getLastFreshHistory($rootId)) {
// update history
sqlQueryBuilder()->update('blocks_history')
->set('date', 'NOW()')
->set('id_admin', ':id_admin')
->set('data', ':data')
->where(Operator::equals(['id' => $idLastHistory]))
->setParameter('id_admin', $id_admin)
->setParameter('data', json_encode($blocksHierarchy))
->execute();
} else {
// insert history
sqlQueryBuilder()->insert('blocks_history')
->values(
[
'id_root_block' => $rootId,
'id_admin' => ':id_admin',
'date' => 'NOW()',
'data' => ':data',
]
)
->setParameter('id_admin', $id_admin)
->setParameter('data', json_encode($blocksHierarchy))
->execute();
}
return true;
}
return false;
}
public function setBlocksHistoryName(string $name, int $historyId)
{
return sqlQueryBuilder()->update('blocks_history')
->set('name', ':name')
->setParameter('name', $name)
->where(Operator::equals(['id' => $historyId]))->execute();
}
public function deleteBlocksHistory(int $historyId)
{
return sqlQueryBuilder()->delete('blocks_history')->where(Operator::equals(['id' => $historyId]))->execute();
}
/**
* @return bool
*
* @throws \Exception
*/
public function revertBlocksHistory(int $id)
{
$connection = sqlGetConnection();
try {
$connection->transactional(
function (Connection $connection) use ($id) {
$history = $this->getBlocksHistory($id, BlocksHistory::TYPE_BY_ID);
if (empty($history['blocks'])) {
throw new \RuntimeException();
}
sqlQueryBuilder()->delete('blocks')->where(Operator::equals(['id_root' => $history['id_root']]))->execute();
$this->insertRevertedBlocks($history['blocks']);
}
);
} catch (\RuntimeException $e) {
return false;
}
return true;
}
private function insertRevertedBlocks(array $blocks)
{
foreach ($blocks as $block) {
$children = $block['children'] ?? null;
$photos = $block['photos'];
unset($block['photos'], $block['children']);
if (empty($block['json_content'])) {
$blockObj = new \stdClass();
$blockObj->type = 'legacy';
$settings = new \stdClass();
$settings->html = $block['content'];
$blockObj->settings = $settings;
$json = json_encode([$blockObj]);
$block['json_content'] = $json;
}
sqlQueryBuilder()->insert('blocks')
->directValues($block)
->execute();
foreach ($photos as $photo) {
if (!empty($photo['id'])) {
sqlQueryBuilder()->insert('photos_blocks_relation')
->values(['id_photo' => $photo['id'], 'id_block' => $block['id']])
->execute();
}
}
if ($children) {
$this->insertRevertedBlocks($children);
}
}
}
/**
* @param string $type
*
* @return array
*/
public function getBlocksHistory(int $id, $type = self::TYPE_BY_ROOT_ID)
{
$histories = sqlQueryBuilder()->select('bh.*, a.login')->from('blocks_history', 'bh')
->leftJoin('bh', 'admins', 'a', 'bh.id_admin = a.id')
->where(Operator::equals([$type => $id]))
->orderBy('date', 'DESC')
->execute()->fetchAll();
$dateFormat = \Settings::getDateFormat().' '.\Settings::getTimeFormat();
$return = [];
foreach ($histories as $history) {
$return[$history['id']] = [
'id' => $history['id'],
'id_root' => $history['id_root_block'],
'admin_login' => $history['login'],
'name' => $history['name'],
'date' => (new \DateTime($history['date']))->format($dateFormat),
'blocks' => json_decode($history['data'], true),
];
}
if ($type == self::TYPE_BY_ID) {
return reset($return);
}
return $return;
}
/**
* @return bool
*/
public function isChangeInBlocks(array $blocks)
{
foreach ($blocks as $blockId => $block) {
if ($blockId == 0) {
continue;
}
if ($blockId < 0 || $this->isBlockUpdated($block)) {
return true;
}
}
return false;
}
/**
* @param array $block Array that represents single block
*
* @return bool
*/
public function isBlockUpdated(array $block)
{
if (!empty($block['delete'])) {
return true;
}
$dbBlock = $this->getBlock($block['id']);
$compare = ['id' => $block['id'], 'name' => $block['name'], 'content' => $block['content'] ?? ''];
if (!empty($block['photos'])) {
$compare['photos'] = $block['photos'];
}
// Editace z adminu, ignoruju obsah
if (!isset($block['content'])) {
unset($dbBlock['content']);
unset($compare['content']);
}
if ($compare == $dbBlock) {
return false;
}
return true;
}
public function getLastFreshHistory(int $rootId)
{
$lastHistory = sqlQueryBuilder()->select('id')->from('blocks_history')
->where(Operator::equals(['id_root_block' => $rootId]))
->andWhere('date > DATE_SUB(NOW(), INTERVAL 1 HOUR)')
->orderBy('date', 'DESC')
->setMaxResults(1)
->execute()->fetch();
if ($lastHistory) {
return $lastHistory['id'];
}
return false;
}
private function getBlocksRootId(array $blocks)
{
$blockId = null;
foreach ($blocks as $block) {
if (!empty($block['id'])) {
$blockId = $block['id'];
}
}
return sqlQueryBuilder()->select('id_root')->from('blocks')
->where(Operator::equals(['id' => $blockId]))
->execute()->fetchColumn();
}
private function getBlock(int $id)
{
$block = sqlQueryBuilder()->select('b.id, b.name, b.content, GROUP_CONCAT(pb.id_photo) as photos')->from('blocks', 'b')
->leftJoin('b', 'photos_blocks_relation', 'pb', 'pb.id_block = b.id')
->where(Operator::equals(['id' => $id]))
->execute()->fetch();
$block['photos'] = explode(',', $block['photos']);
$block['photos'] = array_filter($block['photos'], function ($x) {
return !empty($x);
});
if (empty($block['photos'])) {
unset($block['photos']);
}
return $block;
}
}