src/Core/Content/ImportExport/Event/Subscriber/ProductCategoryPathsSubscriber.php line 48

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\ImportExport\Event\Subscriber;
  3. use Shopware\Core\Content\Category\CategoryDefinition;
  4. use Shopware\Core\Content\ImportExport\Event\ImportExportBeforeImportRecordEvent;
  5. use Shopware\Core\Content\Product\ProductDefinition;
  6. use Shopware\Core\Framework\Api\Sync\SyncBehavior;
  7. use Shopware\Core\Framework\Api\Sync\SyncOperation;
  8. use Shopware\Core\Framework\Api\Sync\SyncServiceInterface;
  9. use Shopware\Core\Framework\Context;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  13. use Shopware\Core\Framework\Log\Package;
  14. use Shopware\Core\Framework\Uuid\Uuid;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Contracts\Service\ResetInterface;
  17. /**
  18.  * @internal
  19.  */
  20. #[Package('system-settings')]
  21. class ProductCategoryPathsSubscriber implements EventSubscriberInterfaceResetInterface
  22. {
  23.     /**
  24.      * @var array<string, string>
  25.      */
  26.     private array $categoryIdCache = [];
  27.     /**
  28.      * @internal
  29.      */
  30.     public function __construct(private readonly EntityRepository $categoryRepository, private readonly SyncServiceInterface $syncService)
  31.     {
  32.     }
  33.     /**
  34.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  35.      */
  36.     public static function getSubscribedEvents(): array
  37.     {
  38.         return [
  39.             ImportExportBeforeImportRecordEvent::class => 'categoryPathsToAssignment',
  40.         ];
  41.     }
  42.     public function categoryPathsToAssignment(ImportExportBeforeImportRecordEvent $event): void
  43.     {
  44.         $row $event->getRow();
  45.         $entityName $event->getConfig()->get('sourceEntity');
  46.         if ($entityName !== ProductDefinition::ENTITY_NAME || empty($row['category_paths'])) {
  47.             return;
  48.         }
  49.         $result = [];
  50.         $categoriesPaths explode('|', (string) $row['category_paths']);
  51.         $newCategoriesPayload = [];
  52.         foreach ($categoriesPaths as $path) {
  53.             $categories explode('>'$path);
  54.             $categoryId null;
  55.             foreach ($categories as $currentIndex => $categoryName) {
  56.                 if (empty($categoryName)) {
  57.                     continue;
  58.                 }
  59.                 $partialPath implode('>'\array_slice($categories0$currentIndex 1));
  60.                 if (isset($this->categoryIdCache[$partialPath])) {
  61.                     $categoryId $this->categoryIdCache[$partialPath];
  62.                     continue;
  63.                 }
  64.                 $criteria = new Criteria();
  65.                 $criteria->addFilter(new EqualsFilter('name'$categoryName));
  66.                 $criteria->addFilter(new EqualsFilter('parentId'$categoryId));
  67.                 $category $this->categoryRepository->search($criteriaContext::createDefaultContext())->first();
  68.                 if ($category === null && $categoryId === null) {
  69.                     break;
  70.                 }
  71.                 if ($category !== null) {
  72.                     $categoryId $category->getId();
  73.                     $this->categoryIdCache[$partialPath] = $categoryId;
  74.                     continue;
  75.                 }
  76.                 $parentId $categoryId;
  77.                 $categoryId Uuid::fromStringToHex($partialPath);
  78.                 $this->categoryIdCache[$partialPath] = $categoryId;
  79.                 $newCategoriesPayload[] = [
  80.                     'id' => $categoryId,
  81.                     'parent' => ['id' => $parentId],
  82.                     'name' => $categoryName,
  83.                 ];
  84.             }
  85.             if ($categoryId !== null) {
  86.                 $result[] = ['id' => $categoryId];
  87.             }
  88.         }
  89.         if (!empty($newCategoriesPayload)) {
  90.             $this->createNewCategories($newCategoriesPayload);
  91.         }
  92.         $record $event->getRecord();
  93.         $record['categories'] = !empty($record['categories']) ? array_merge($record['categories'], $result) : $result;
  94.         $event->setRecord($record);
  95.     }
  96.     public function reset(): void
  97.     {
  98.         $this->categoryIdCache = [];
  99.     }
  100.     /**
  101.      * @param list<array<string, mixed>> $payload
  102.      */
  103.     private function createNewCategories(array $payload): void
  104.     {
  105.         $this->syncService->sync([
  106.             new SyncOperation(
  107.                 'write',
  108.                 CategoryDefinition::ENTITY_NAME,
  109.                 SyncOperation::ACTION_UPSERT,
  110.                 $payload
  111.             ),
  112.         ], Context::createDefaultContext(), new SyncBehavior());
  113.     }
  114. }