<?php
declare(strict_types=1);
namespace NetInventors\NetiNextCmsElementBuilder\Subscriber;
use NetInventors\NetiNextCmsElementBuilder\Components\SlotConfigIterator;
use NetInventors\NetiNextCmsElementBuilder\Core\Content\Element\ElementEntity;
use Pixup\PixupTranslatorSW6\Model\Event\FetcherEvent;
use Pixup\PixupTranslatorSW6\Model\Event\ParserEvent;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PixupTranslatorSubscriber implements EventSubscriberInterface
{
private Context $context;
/**
* @var array<string, ElementEntity>
*/
private array $elements = [];
private EntityRepositoryInterface $cmsSlotRepository;
private EntityRepositoryInterface $elementRepository;
private SlotConfigIterator $slotConfigIterator;
public function __construct(
EntityRepositoryInterface $cmsSlotRepository,
EntityRepositoryInterface $elementRepository,
SlotConfigIterator $slotConfigIterator
) {
/**
* The method is internal but the use is required.
*
* @psalm-suppress InternalMethod
*/
$this->context = Context::createDefaultContext();
$this->cmsSlotRepository = $cmsSlotRepository;
$this->elementRepository = $elementRepository;
$this->slotConfigIterator = $slotConfigIterator;
}
public static function getSubscribedEvents(): array
{
return [
'pixuptranslator.fetcher.count' => 'onCountElements',
'pixuptranslator.fetcher.parse' => 'onTranslateElements',
];
}
/**
* The FetcherEvent class is not available for psalm, because it was implemented in another plugin.
*
* @psalm-suppress UndefinedClass
*
* @param FetcherEvent $event
*
* @return void
*/
public function onCountElements(FetcherEvent $event): void
{
if (
$event->getEntityName() !== 'cms_slot'
|| $event->getFieldName() !== 'config'
) {
return;
}
$cmsSlotId = Uuid::fromBytesToHex((string)$event->getEntityId());
$cmsSlot = $this->getCmsSlotById($cmsSlotId);
// Just in case we get invalid data...
if (null === $cmsSlot) {
return;
}
$element = $this->getElementData($cmsSlot);
if (null === $element) {
return;
}
$characterCount = (int)$event->getCount();
/** @var null|array<string, array> $elementConfig */
$elementConfig = $element->getConfig()['config'] ?? null;
/** @var array<string, mixed> $cmsSlotConfig */
$cmsSlotConfig = (array)$cmsSlot->getConfig();
if (null === $elementConfig) {
return;
}
$this->slotConfigIterator->iterate(
$cmsSlotConfig,
$elementConfig,
/**
* @param string $i
* @param int|string|array|null $value
* @param array $element
*
* The parameter $i is not used.
*
* @psalm-suppress UnusedClosureParam
*
* @return int|string|array|null
*/
function (string $i, $value, array $element) use (&$characterCount) {
/** @var int $characterCount */
switch ($element['type']) {
case 'text':
case 'textarea':
case 'html':
if (is_string($value)) {
$characterCount += strlen($value);
}
break;
case 'link':
if (is_array($value) && isset($value['title']) && is_string($value['title'])) {
$characterCount += strlen($value['title']);
}
break;
}
return $value;
}
);
$event->setCount($characterCount);
}
/**
* The ParserEvent class is not available for psalm, because it was implemented in another plugin.
*
* @psalm-suppress UndefinedClass
*
* @param ParserEvent $event
*
* @return void
*/
public function onTranslateElements(ParserEvent $event): void
{
if (
$event->getEntityName() !== 'cms_slot'
|| $event->getFieldName() !== 'config'
|| $event->getSrcEntityId() !== $event->getTargetEntityId()
) {
return;
}
$cmsSlotId = (string)$event->getSrcEntityId();
$cmsSlot = $this->getCmsSlotById($cmsSlotId);
// Just in case we get invalid data...
if (null === $cmsSlot) {
return;
}
$element = $this->getElementData($cmsSlot);
if (null === $element) {
return;
}
/** @var array<string, mixed> $sourceField */
$sourceField = (array)$event->getSourceField();
/** @var array<string, mixed> $targetField */
$targetField = (array)$event->getTargetField();
/** @var null|array<string, array> $elementConfig */
$elementConfig = $element->getConfig()['config'] ?? null;
if (null === $elementConfig) {
return;
}
$sourceField = $this->slotConfigIterator->iterateForTranslator(
$sourceField,
$targetField,
$elementConfig,
/**
* @param string $i
* @param int|string|array|null $sourceValue
* @param array $element
* @param int|string|array|null $targetValue
*
* The parameter $i is not used.
*
* @psalm-suppress UnusedClosureParam
*
* @return int|string|array|null
*/
function (string $i, $sourceValue, array $element, $targetValue) use ($event) {
switch ($element['type']) {
case 'text':
case 'textarea':
case 'html':
$sourceValue = (string)$event->getTranslation($sourceValue, $targetValue);
break;
case 'link':
if (is_array($sourceValue) && isset($sourceValue['title']) && is_string($sourceValue['title'])) {
$sourceValue['title'] = (string)$event->getTranslation(
$sourceValue['title'],
is_array($targetValue) ? $targetValue['title'] : null
);
}
break;
}
return $sourceValue;
}
);
$event->setResField($sourceField);
}
private function getElementData(CmsSlotEntity $cmsSlot): ?ElementEntity
{
$this->loadElements();
return $this->elements[$cmsSlot->getType()] ?? null;
}
private function loadElements(): void
{
if ($this->elements !== []) {
return;
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('deleted', false));
$criteria->addFilter(new EqualsFilter('active', true));
$result = $this->elementRepository->search($criteria, $this->context);
/** @var ElementEntity $entity */
foreach ($result->getElements() as $entity) {
$this->elements[$entity->getSlotName()] = $entity;
}
}
private function getCmsSlotById(string $cmsSlotId): ?CmsSlotEntity
{
$criteria = new Criteria([ $cmsSlotId ]);
$result = $this->cmsSlotRepository->search($criteria, $this->context);
/** @var CmsSlotEntity|null $cmsSlot */
$cmsSlot = $result->first();
if ($cmsSlot instanceof CmsSlotEntity) {
return $cmsSlot;
}
return null;
}
}