custom/plugins/NetiNextCmsElementBuilder/src/Subscriber/PixupTranslatorSubscriber.php line 148

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace NetInventors\NetiNextCmsElementBuilder\Subscriber;
  4. use NetInventors\NetiNextCmsElementBuilder\Components\SlotConfigIterator;
  5. use NetInventors\NetiNextCmsElementBuilder\Core\Content\Element\ElementEntity;
  6. use Pixup\PixupTranslatorSW6\Model\Event\FetcherEvent;
  7. use Pixup\PixupTranslatorSW6\Model\Event\ParserEvent;
  8. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
  9. use Shopware\Core\Framework\Context;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  13. use Shopware\Core\Framework\Uuid\Uuid;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. class PixupTranslatorSubscriber implements EventSubscriberInterface
  16. {
  17.     private Context $context;
  18.     /**
  19.      * @var array<string, ElementEntity>
  20.      */
  21.     private array                     $elements = [];
  22.     private EntityRepositoryInterface $cmsSlotRepository;
  23.     private EntityRepositoryInterface $elementRepository;
  24.     private SlotConfigIterator        $slotConfigIterator;
  25.     public function __construct(
  26.         EntityRepositoryInterface $cmsSlotRepository,
  27.         EntityRepositoryInterface $elementRepository,
  28.         SlotConfigIterator        $slotConfigIterator
  29.     ) {
  30.         /**
  31.          * The method is internal but the use is required.
  32.          *
  33.          * @psalm-suppress InternalMethod
  34.          */
  35.         $this->context            Context::createDefaultContext();
  36.         $this->cmsSlotRepository  $cmsSlotRepository;
  37.         $this->elementRepository  $elementRepository;
  38.         $this->slotConfigIterator $slotConfigIterator;
  39.     }
  40.     public static function getSubscribedEvents(): array
  41.     {
  42.         return [
  43.             'pixuptranslator.fetcher.count' => 'onCountElements',
  44.             'pixuptranslator.fetcher.parse' => 'onTranslateElements',
  45.         ];
  46.     }
  47.     /**
  48.      * The FetcherEvent class is not available for psalm, because it was implemented in another plugin.
  49.      *
  50.      * @psalm-suppress UndefinedClass
  51.      *
  52.      * @param FetcherEvent $event
  53.      *
  54.      * @return void
  55.      */
  56.     public function onCountElements(FetcherEvent $event): void
  57.     {
  58.         if (
  59.             $event->getEntityName() !== 'cms_slot'
  60.             || $event->getFieldName() !== 'config'
  61.         ) {
  62.             return;
  63.         }
  64.         $cmsSlotId Uuid::fromBytesToHex((string)$event->getEntityId());
  65.         $cmsSlot   $this->getCmsSlotById($cmsSlotId);
  66.         // Just in case we get invalid data...
  67.         if (null === $cmsSlot) {
  68.             return;
  69.         }
  70.         $element $this->getElementData($cmsSlot);
  71.         if (null === $element) {
  72.             return;
  73.         }
  74.         $characterCount = (int)$event->getCount();
  75.         /** @var null|array<string, array> $elementConfig */
  76.         $elementConfig $element->getConfig()['config'] ?? null;
  77.         /** @var array<string, mixed> $cmsSlotConfig */
  78.         $cmsSlotConfig = (array)$cmsSlot->getConfig();
  79.         if (null === $elementConfig) {
  80.             return;
  81.         }
  82.         $this->slotConfigIterator->iterate(
  83.             $cmsSlotConfig,
  84.             $elementConfig,
  85.             /**
  86.              * @param string                $i
  87.              * @param int|string|array|null $value
  88.              * @param array                 $element
  89.              *
  90.              * The parameter $i is not used.
  91.              *
  92.              * @psalm-suppress UnusedClosureParam
  93.              *
  94.              * @return int|string|array|null
  95.              */
  96.             function (string $i$value, array $element) use (&$characterCount) {
  97.                 /** @var int $characterCount */
  98.                 switch ($element['type']) {
  99.                     case 'text':
  100.                     case 'textarea':
  101.                     case 'html':
  102.                         if (is_string($value)) {
  103.                             $characterCount += strlen($value);
  104.                         }
  105.                         break;
  106.                     case 'link':
  107.                         if (is_array($value) && isset($value['title']) && is_string($value['title'])) {
  108.                             $characterCount += strlen($value['title']);
  109.                         }
  110.                         break;
  111.                 }
  112.                 return $value;
  113.             }
  114.         );
  115.         $event->setCount($characterCount);
  116.     }
  117.     /**
  118.      * The ParserEvent class is not available for psalm, because it was implemented in another plugin.
  119.      *
  120.      * @psalm-suppress UndefinedClass
  121.      *
  122.      * @param ParserEvent $event
  123.      *
  124.      * @return void
  125.      */
  126.     public function onTranslateElements(ParserEvent $event): void
  127.     {
  128.         if (
  129.             $event->getEntityName() !== 'cms_slot'
  130.             || $event->getFieldName() !== 'config'
  131.             || $event->getSrcEntityId() !== $event->getTargetEntityId()
  132.         ) {
  133.             return;
  134.         }
  135.         $cmsSlotId = (string)$event->getSrcEntityId();
  136.         $cmsSlot   $this->getCmsSlotById($cmsSlotId);
  137.         // Just in case we get invalid data...
  138.         if (null === $cmsSlot) {
  139.             return;
  140.         }
  141.         $element $this->getElementData($cmsSlot);
  142.         if (null === $element) {
  143.             return;
  144.         }
  145.         /** @var array<string, mixed> $sourceField */
  146.         $sourceField = (array)$event->getSourceField();
  147.         /** @var array<string, mixed> $targetField */
  148.         $targetField = (array)$event->getTargetField();
  149.         /** @var null|array<string, array> $elementConfig */
  150.         $elementConfig $element->getConfig()['config'] ?? null;
  151.         if (null === $elementConfig) {
  152.             return;
  153.         }
  154.         $sourceField $this->slotConfigIterator->iterateForTranslator(
  155.             $sourceField,
  156.             $targetField,
  157.             $elementConfig,
  158.             /**
  159.              * @param string                $i
  160.              * @param int|string|array|null $sourceValue
  161.              * @param array                 $element
  162.              * @param int|string|array|null $targetValue
  163.              *
  164.              * The parameter $i is not used.
  165.              *
  166.              * @psalm-suppress UnusedClosureParam
  167.              *
  168.              * @return int|string|array|null
  169.              */
  170.             function (string $i$sourceValue, array $element$targetValue) use ($event) {
  171.                 switch ($element['type']) {
  172.                     case 'text':
  173.                     case 'textarea':
  174.                     case 'html':
  175.                         $sourceValue = (string)$event->getTranslation($sourceValue$targetValue);
  176.                         break;
  177.                     case 'link':
  178.                         if (is_array($sourceValue) && isset($sourceValue['title']) && is_string($sourceValue['title'])) {
  179.                             $sourceValue['title'] = (string)$event->getTranslation(
  180.                                 $sourceValue['title'],
  181.                                 is_array($targetValue) ? $targetValue['title'] : null
  182.                             );
  183.                         }
  184.                         break;
  185.                 }
  186.                 return $sourceValue;
  187.             }
  188.         );
  189.         $event->setResField($sourceField);
  190.     }
  191.     private function getElementData(CmsSlotEntity $cmsSlot): ?ElementEntity
  192.     {
  193.         $this->loadElements();
  194.         return $this->elements[$cmsSlot->getType()] ?? null;
  195.     }
  196.     private function loadElements(): void
  197.     {
  198.         if ($this->elements !== []) {
  199.             return;
  200.         }
  201.         $criteria = new Criteria();
  202.         $criteria->addFilter(new EqualsFilter('deleted'false));
  203.         $criteria->addFilter(new EqualsFilter('active'true));
  204.         $result $this->elementRepository->search($criteria$this->context);
  205.         /** @var ElementEntity $entity */
  206.         foreach ($result->getElements() as $entity) {
  207.             $this->elements[$entity->getSlotName()] = $entity;
  208.         }
  209.     }
  210.     private function getCmsSlotById(string $cmsSlotId): ?CmsSlotEntity
  211.     {
  212.         $criteria = new Criteria([ $cmsSlotId ]);
  213.         $result   $this->cmsSlotRepository->search($criteria$this->context);
  214.         /** @var CmsSlotEntity|null $cmsSlot */
  215.         $cmsSlot $result->first();
  216.         if ($cmsSlot instanceof CmsSlotEntity) {
  217.             return $cmsSlot;
  218.         }
  219.         return null;
  220.     }
  221. }