<?php declare(strict_types=1);
namespace DreiscCmsPro\Subscriber\CmsEvents;
use DreiscCmsPro\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockRepository;
use DreiscCmsPro\Core\Content\Cms\CmsPageRepository;
use DreiscCmsPro\DreiscCmsPro;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
use Shopware\Core\Content\Cms\CmsPageEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ParentBlockIdRepairerSubscriber implements EventSubscriberInterface
{
/**
* @var array
*/
protected static $repairerInProgress = [];
/**
* @var CmsPageRepository
*/
protected $cmsPageRepository;
/**
* @var CmsBlockRepository
*/
protected $cmsBlockRepository;
/**
* @param CmsPageRepository $cmsPageRepository
* @param CmsBlockRepository $cmsBlockRepository
*/
public function __construct(CmsPageRepository $cmsPageRepository, CmsBlockRepository $cmsBlockRepository)
{
$this->cmsPageRepository = $cmsPageRepository;
$this->cmsBlockRepository = $cmsBlockRepository;
}
public static function getSubscribedEvents()
{
return [
EntityWrittenContainerEvent::class => 'onEntityWrittenContainerEvent'
];
}
/**
* See also:
* @see DreiscCmsPro::activate()
* @see DreiscCmsPro::postUpdate()
*/
public function onEntityWrittenContainerEvent(EntityWrittenContainerEvent $entityWrittenContainerEvent)
{
/** cms_page */
$cmsPageEntityWrittenEvent = $entityWrittenContainerEvent->getEventByEntityName('cms_page');
if(null !== $cmsPageEntityWrittenEvent) {
foreach($cmsPageEntityWrittenEvent->getWriteResults() as $writeResult) {
$operation = $writeResult->getOperation();
if (in_array($operation, ['insert', 'update'])) {
$primaryKey = $writeResult->getPrimaryKey();
if (is_array($primaryKey)) {
foreach($primaryKey as $key) {
$this->handleCmsPage($key, $operation);
}
} else {
$this->handleCmsPage($primaryKey, $operation);
}
}
}
}
}
private function handleCmsPage(string $clonedCmsPageId, string $operation)
{
/**
* Since we are also updating the cms_page entity in the updateCmsPageParentBlockIds method,
* we need to make sure that we are not creating a loop.
*/
if (in_array($clonedCmsPageId, self::$repairerInProgress)) {
return;
}
self::$repairerInProgress[$clonedCmsPageId] = $clonedCmsPageId;
/** Load the original and cloned cms page */
$clonedCmsPage = $this->getWithAssociations($clonedCmsPageId);
if ('insert' === $operation) {
/**
* At first, we set the parent block id to the right ids
*
* This only in an insert operation. For a duplication of the selection, the correct values are already set via JavaScript.
* Executing the updateCmsPageParentBlockIds method would destroy the construct in this case.
*/
$this->updateCmsPageParentBlockIds($clonedCmsPage);
}
/** Next, we correct the stored block ids */
$this->setCmsPageBlockIds($clonedCmsPage);
unset(self::$repairerInProgress[$clonedCmsPageId]);
}
/**
* @param CmsPageEntity|null $clonedCmsPage
* @return array
*/
private function updateCmsPageParentBlockIds(?CmsPageEntity $clonedCmsPage): void
{
/** @var CmsSectionEntity $clonedSection */
foreach ($clonedCmsPage->getSections() as $clonedSection) {
/** @var CmsBlockEntity $clonedBlock */
foreach ($clonedSection->getBlocks() as $clonedBlock) {
$customFields = $clonedBlock->getCustomFields();
if (null !== $customFields && !empty($customFields['dreisc_cms_parent_block_id'])) {
/** Fetching the referenced cms parent block */
/** @var CmsBlockEntity $referencedBlockEntity */
$referencedBlockEntity = $this->cmsBlockRepository->get($customFields['dreisc_cms_parent_block_id']);
/** Fetch the cloned parent block */
/** We can identify the block by the fact that the block id stored in the custom fields does not match the actual id. */
$criteria = new Criteria();
$criteria->addFilter(
new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('customFields.dreisc_cms_block_id', $referencedBlockEntity->getId()),
new NotFilter(
NotFilter::CONNECTION_AND,
[
new EqualsFilter('id', $referencedBlockEntity->getId())
]
)
]
)
);
/** @var CmsBlockEntity $clonedParentBlock */
$clonedParentBlock = $this->cmsBlockRepository->search($criteria)->first();
if (null !== $clonedParentBlock) {
$this->cmsBlockRepository->update([[
'id' => $clonedBlock->getId(),
'customFields' => [
'dreisc_cms_parent_block_id' => $clonedParentBlock->getId()
]
]]);
}
}
}
}
}
/**
* @param CmsPageEntity|null $clonedCmsPage
* @return array
*/
public function setCmsPageBlockIds(?CmsPageEntity $clonedCmsPage): void
{
/** @var CmsSectionEntity $clonedSection */
foreach ($clonedCmsPage->getSections() as $clonedSection) {
/** @var CmsBlockEntity $clonedBlock */
foreach ($clonedSection->getBlocks() as $clonedBlock) {
$this->cmsBlockRepository->update([[
'id' => $clonedBlock->getId(),
'customFields' => [
'dreisc_cms_block_id' => $clonedBlock->getId()
]
]]);
}
}
}
private function getWithAssociations($id): ?CmsPageEntity
{
$criteria = new Criteria([ $id ]);
$criteria->addAssociations([
'sections',
'sections.blocks'
]);
return $this->cmsPageRepository->search(
$criteria,
Context::createDefaultContext()
)->first();
}
}