From cb035827384671504a4d189b7975f0e0f669cbc4 Mon Sep 17 00:00:00 2001 From: Nicolas MELONI Date: Mon, 6 Nov 2023 10:09:28 +0100 Subject: [PATCH] Import category position from Akeneo --- docs/CONFIGURE_DETAIL.md | 3 ++ .../SynoliaSyliusAkeneoExtension.php | 2 +- src/Entity/CategoryConfiguration.php | 16 ++++++++ src/Fixture/CategoryConfigurationFixture.php | 4 ++ src/Form/Type/CategoriesConfigurationType.php | 5 +++ .../Doctrine/DoctrineSortableManager.php | 40 +++++++++++++++++++ src/Migrations/Version20231106080715.php | 29 ++++++++++++++ .../Configuration/CategoryConfiguration.php | 2 +- .../CategoryConfigurationInterface.php | 2 +- src/Resources/translations/messages.en.yml | 1 + src/Resources/translations/messages.fr.yml | 1 + src/Task/Category/CreateUpdateEntityTask.php | 22 +++------- ...onfigurationToApiConnectionTransformer.php | 1 + 13 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 src/Manager/Doctrine/DoctrineSortableManager.php create mode 100644 src/Migrations/Version20231106080715.php diff --git a/docs/CONFIGURE_DETAIL.md b/docs/CONFIGURE_DETAIL.md index daa438a8..c5f71f42 100644 --- a/docs/CONFIGURE_DETAIL.md +++ b/docs/CONFIGURE_DETAIL.md @@ -53,6 +53,8 @@ The category import configuration contains two configurations. `excluded_category_codes` allows you to choose the categories that you want to exclude from the import. +`use_akeneo_positions` import category position from Akeneo, this will bypass the default sortable event. + **Selecting a parent will exclude the parent and its children**. ```yaml @@ -66,6 +68,7 @@ synolia_sylius_akeneo: - led_tvs - audio_video - mp3_players + use_akeneo_positions: true ``` diff --git a/src/DependencyInjection/SynoliaSyliusAkeneoExtension.php b/src/DependencyInjection/SynoliaSyliusAkeneoExtension.php index 6e97e757..40b30bbf 100644 --- a/src/DependencyInjection/SynoliaSyliusAkeneoExtension.php +++ b/src/DependencyInjection/SynoliaSyliusAkeneoExtension.php @@ -126,7 +126,7 @@ private function processCategoryConfiguration(ContainerBuilder $container, array $categoryConfigurationProviderDefinition ->setArgument('$categoryCodesToImport', $config['category_configuration']['root_category_codes']) ->setArgument('$categoryCodesToExclude', $config['category_configuration']['excluded_category_codes']) - ->setArgument('$categoryCodesToExclude', $config['category_configuration']['use_akeneo_positions']) + ->setArgument('$useAkeneoPositions', $config['category_configuration']['use_akeneo_positions']) ; $container->setAlias(CategoryConfigurationProviderInterface::class, CategoryConfigurationProvider::class); diff --git a/src/Entity/CategoryConfiguration.php b/src/Entity/CategoryConfiguration.php index d60dfc41..9534312c 100644 --- a/src/Entity/CategoryConfiguration.php +++ b/src/Entity/CategoryConfiguration.php @@ -48,6 +48,10 @@ class CategoryConfiguration implements ResourceInterface #[ORM\Column(type: Types::ARRAY)] private array $rootCategories = []; + /** @ORM\Column(type="boolean") */ + #[ORM\Column(type: Types::BOOLEAN)] + private bool $useAkeneoPositions = false; + public function getId(): int { return $this->id; @@ -88,4 +92,16 @@ public function setRootCategories(array $rootCategories): self return $this; } + + public function useAkeneoPositions(): bool + { + return $this->useAkeneoPositions; + } + + public function setUseAkeneoPositions(bool $useAkeneoPositions): self + { + $this->useAkeneoPositions = $useAkeneoPositions; + + return $this; + } } diff --git a/src/Fixture/CategoryConfigurationFixture.php b/src/Fixture/CategoryConfigurationFixture.php index 1b0cef21..110ad37d 100644 --- a/src/Fixture/CategoryConfigurationFixture.php +++ b/src/Fixture/CategoryConfigurationFixture.php @@ -23,6 +23,7 @@ public function load(array $options): void $categoryConfiguration = $this->categoriesConfigurationFactory->createNew(); $categoryConfiguration->setRootCategories($options['root_categories_to_import']); $categoryConfiguration->setNotImportCategories($options['categories_to_exclude']); + $categoryConfiguration->setUseAkeneoPositions($options['use_akeneo_positions']); $this->entityManager->persist($categoryConfiguration); $this->entityManager->flush(); @@ -46,6 +47,9 @@ protected function configureOptionsNode(ArrayNodeDefinition $optionsNode): void ->arrayNode('categories_to_exclude') ->scalarPrototype()->defaultValue([])->end() ->end() + ->arrayNode('use_akeneo_positions') + ->scalarPrototype()->defaultFalse()->end() + ->end() ->end() ; } diff --git a/src/Form/Type/CategoriesConfigurationType.php b/src/Form/Type/CategoriesConfigurationType.php index 01d3558f..019062a9 100644 --- a/src/Form/Type/CategoriesConfigurationType.php +++ b/src/Form/Type/CategoriesConfigurationType.php @@ -5,6 +5,7 @@ namespace Synolia\SyliusAkeneoPlugin\Form\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; @@ -26,6 +27,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => false, 'multiple' => true, ]) + ->add('use_akeneo_positions', CheckboxType::class, [ + 'label' => 'sylius.ui.admin.akeneo.categories.use_akeneo_positions', + 'required' => false, + ]) ->add('submit', SubmitType::class, [ 'attr' => ['class' => 'ui icon primary button'], 'label' => 'sylius.ui.admin.akeneo.save', diff --git a/src/Manager/Doctrine/DoctrineSortableManager.php b/src/Manager/Doctrine/DoctrineSortableManager.php new file mode 100644 index 00000000..e783fcc1 --- /dev/null +++ b/src/Manager/Doctrine/DoctrineSortableManager.php @@ -0,0 +1,40 @@ +entityManager->getEventManager()->getListeners() as $eventName => $listeners) { + foreach ($listeners as $listener) { + if ($listener instanceof SortableListener) { + $this->originalEventListeners[$eventName] = $listener; + $this->entityManager->getEventManager()->removeEventListener($eventName, $listener); + } + } + } + } + + public function enableSortableEventListener(): void + { + if ($this->originalEventListeners === []) { + return; + } + + foreach ($this->originalEventListeners as $eventName => $listener) { + $this->entityManager->getEventManager()->addEventListener($eventName, $listener); + } + } +} diff --git a/src/Migrations/Version20231106080715.php b/src/Migrations/Version20231106080715.php new file mode 100644 index 00000000..8e4532b3 --- /dev/null +++ b/src/Migrations/Version20231106080715.php @@ -0,0 +1,29 @@ +addSql('ALTER TABLE akeneo_api_configuration_categories ADD useAkeneoPositions TINYINT(1) NOT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE akeneo_api_configuration_categories DROP useAkeneoPositions'); + } +} diff --git a/src/Model/Configuration/CategoryConfiguration.php b/src/Model/Configuration/CategoryConfiguration.php index c54298e3..ea5267c8 100644 --- a/src/Model/Configuration/CategoryConfiguration.php +++ b/src/Model/Configuration/CategoryConfiguration.php @@ -37,7 +37,7 @@ public function setCategoryCodesToExclude(array $categoryCodesToExclude): self return $this; } - public function isUseAkeneoPositions(): bool + public function useAkeneoPositions(): bool { return $this->useAkeneoPositions; } diff --git a/src/Model/Configuration/CategoryConfigurationInterface.php b/src/Model/Configuration/CategoryConfigurationInterface.php index 3ba73110..317cd361 100644 --- a/src/Model/Configuration/CategoryConfigurationInterface.php +++ b/src/Model/Configuration/CategoryConfigurationInterface.php @@ -14,7 +14,7 @@ public function setCategoryCodesToImport(array $categoryCodesToImport): self; public function setCategoryCodesToExclude(array $categoryCodesToExclude): self; - public function isUseAkeneoPositions(): bool; + public function useAkeneoPositions(): bool; public function setUseAkeneoPositions(bool $useAkeneoPositions): self; } diff --git a/src/Resources/translations/messages.en.yml b/src/Resources/translations/messages.en.yml index f4449496..5f92095a 100644 --- a/src/Resources/translations/messages.en.yml +++ b/src/Resources/translations/messages.en.yml @@ -65,6 +65,7 @@ sylius: main_category: Main category root_categories: Sylius Root categories empty_local_replace_by: Replace empty local by + use_akeneo_positions: Import category position from Akeneo products: title: Products subtitle: Products configuration diff --git a/src/Resources/translations/messages.fr.yml b/src/Resources/translations/messages.fr.yml index f81ea285..c23b1b14 100644 --- a/src/Resources/translations/messages.fr.yml +++ b/src/Resources/translations/messages.fr.yml @@ -65,6 +65,7 @@ sylius: main_category: Catégorie principale root_categories: Catégories racines de Sylius empty_local_replace_by: Remplacer la locale vide par + use_akeneo_positions: Importer la position des catégories d'Akeneo products: title: Produits subtitle: Configuration des produits diff --git a/src/Task/Category/CreateUpdateEntityTask.php b/src/Task/Category/CreateUpdateEntityTask.php index 668f6584..dc792d0e 100644 --- a/src/Task/Category/CreateUpdateEntityTask.php +++ b/src/Task/Category/CreateUpdateEntityTask.php @@ -6,7 +6,6 @@ use Behat\Transliterator\Transliterator; use Doctrine\ORM\EntityManagerInterface; -use Gedmo\Sortable\SortableListener; use Psr\Log\LoggerInterface; use Sylius\Component\Core\Model\TaxonInterface; use Sylius\Component\Resource\Factory\FactoryInterface; @@ -23,6 +22,7 @@ use Synolia\SyliusAkeneoPlugin\Event\Category\BeforeProcessingTaxonEvent; use Synolia\SyliusAkeneoPlugin\Exceptions\UnsupportedAttributeTypeException; use Synolia\SyliusAkeneoPlugin\Logger\Messages; +use Synolia\SyliusAkeneoPlugin\Manager\Doctrine\DoctrineSortableManager; use Synolia\SyliusAkeneoPlugin\Payload\Category\CategoryPayload; use Synolia\SyliusAkeneoPlugin\Payload\PipelinePayloadInterface; use Synolia\SyliusAkeneoPlugin\Provider\Configuration\Api\CategoryConfigurationProviderInterface; @@ -64,6 +64,7 @@ public function __construct( private TaxonAttributeTypeMatcher $taxonAttributeTypeMatcher, private TaxonAttributeValueBuilder $taxonAttributeValueBuilder, private CategoryConfigurationProviderInterface $categoryConfigurationProvider, + private DoctrineSortableManager $sortableManager, ) { } @@ -153,27 +154,14 @@ public function __invoke(PipelinePayloadInterface $payload): PipelinePayloadInte $this->dispatcher->dispatch(new AfterProcessingTaxonEvent($resource, $taxon)); - if ($this->categoryConfigurationProvider->get()->isUseAkeneoPositions()) { + if ($this->categoryConfigurationProvider->get()->useAkeneoPositions()) { $taxon->setPosition($resource['position']); - foreach ($this->entityManager->getEventManager()->getAllListeners() as $listenerTypes) { - foreach ($listenerTypes as $listener) { - if (get_class($listener) === SortableListener::class) { - $this->entityManager->getEventManager()->removeEventListener([ - 'onFlush', - 'loadClassMetadata', - 'prePersist', - 'postPersist', - 'preUpdate', - 'postRemove', - 'postFlush', - ], $listener); - } - } - } + $this->sortableManager->disableSortableEventListener(); } $this->entityManager->flush(); + $this->sortableManager->enableSortableEventListener(); if ($this->entityManager->getConnection()->isTransactionActive()) { $this->entityManager->commit(); diff --git a/src/Transformer/Configuration/DatabaseCategoryConfigurationToApiConnectionTransformer.php b/src/Transformer/Configuration/DatabaseCategoryConfigurationToApiConnectionTransformer.php index d4e88670..3724491d 100644 --- a/src/Transformer/Configuration/DatabaseCategoryConfigurationToApiConnectionTransformer.php +++ b/src/Transformer/Configuration/DatabaseCategoryConfigurationToApiConnectionTransformer.php @@ -14,6 +14,7 @@ public function transform(CategoryConfiguration $configuration): CategoryConfigu return new \Synolia\SyliusAkeneoPlugin\Model\Configuration\CategoryConfiguration( $configuration->getRootCategories(), $configuration->getNotImportCategories(), + $configuration->useAkeneoPositions(), ); } }