<?php
declare(strict_types=1);
namespace CioProductExtension\Subscriber;
use CioProductExtension\Definition\CioProductExtensionEntity;
use Shopware\Core\Content\Product\ProductDefinition;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProductCloneCioExtensionSubscriber implements EventSubscriberInterface
{
private EntityRepository $productRepository;
private EntityRepository $cioProductExtensionRepository;
public function __construct(
EntityRepository $productRepository,
EntityRepository $cioProductExtensionRepository
) {
$this->productRepository = $productRepository;
$this->cioProductExtensionRepository = $cioProductExtensionRepository;
}
/**
* @return array<class-string, string>
*/
public static function getSubscribedEvents(): array
{
return [
EntityWrittenContainerEvent::class => 'onEntityWrittenContainerEvent',
];
}
/**
* CIO-AI-Driven
*
* Duplicates the cio_product_extension entity when a product is cloned in the administration,
* because the relation between product.cio_extension_id and cio_product_extension.id must be 1:1.
*
* Important: Guards against empty/invalid IDs to avoid loading all products accidentally.
*/
public function onEntityWrittenContainerEvent(EntityWrittenContainerEvent $event): void
{
if (!$event->isCloned()) {
return;
}
$productWrittenEvent = $event->getEventByEntityName(ProductDefinition::ENTITY_NAME);
if ($productWrittenEvent === null) {
return;
}
$productIds = $this->filterValidIds($productWrittenEvent->getIds());
if ($productIds === []) {
return;
}
$context = $event->getContext();
$products = $this->productRepository->search(new Criteria($productIds), $context)->getEntities();
$newExtensionPayloads = [];
$productUpdatePayloads = [];
$oldExtensionIds = [];
foreach ($products as $product) {
$cioExtensionId = $product->get('cioExtensionId');
if (!\is_string($cioExtensionId) || $cioExtensionId === '' || !Uuid::isValid($cioExtensionId)) {
continue;
}
$oldExtensionIds[$cioExtensionId] = true;
}
if ($oldExtensionIds === []) {
return;
}
$oldExtensionsById = $this->fetchExtensionsById(array_keys($oldExtensionIds), $context);
foreach ($products as $product) {
$productId = $product->getUniqueIdentifier();
$oldExtensionId = $product->get('cioExtensionId');
if (!\is_string($oldExtensionId) || $oldExtensionId === '' || !Uuid::isValid($oldExtensionId)) {
continue;
}
$oldExtension = $oldExtensionsById[$oldExtensionId] ?? null;
$newExtensionId = Uuid::randomHex();
$newExtensionPayloads[] = [
'id' => $newExtensionId,
'meldebestand' => $oldExtension ? $oldExtension->getMeldebestand() : null,
'reportFlag' => $oldExtension ? $oldExtension->getReportFlag() : null,
];
$productUpdatePayloads[] = [
'id' => $productId,
'cioExtensionId' => $newExtensionId,
];
}
if ($newExtensionPayloads !== []) {
$this->cioProductExtensionRepository->create($newExtensionPayloads, $context);
}
if ($productUpdatePayloads !== []) {
$this->productRepository->update($productUpdatePayloads, $context);
}
}
/**
* @param array<int, mixed> $ids
*
* @return list<string>
*/
private function filterValidIds(array $ids): array
{
$validIds = [];
foreach ($ids as $id) {
if (!\is_string($id)) {
continue;
}
if ($id === '' || !Uuid::isValid($id)) {
continue;
}
$validIds[] = $id;
}
return array_values(array_unique($validIds));
}
/**
* @param list<string> $extensionIds
*
* @return array<string, CioProductExtensionEntity>
*/
private function fetchExtensionsById(array $extensionIds, Context $context): array
{
if ($extensionIds === []) {
return [];
}
$extensions = $this->cioProductExtensionRepository->search(new Criteria($extensionIds), $context)->getEntities();
$extensionsById = [];
foreach ($extensions as $extension) {
if (!$extension instanceof CioProductExtensionEntity) {
continue;
}
$extensionsById[$extension->getUniqueIdentifier()] = $extension;
}
return $extensionsById;
}
}