From 1fcbe8284ad8453f6433ff8d4604f8ab72af46c0 Mon Sep 17 00:00:00 2001 From: Manuele Menozzi Date: Tue, 12 Sep 2023 12:20:12 +0200 Subject: [PATCH 1/2] Dispatch a SearchBuilder built event in importers getIdentifierModifiedSince (#5) --- config/services.xml | 2 + src/AttributeOptions/Importer.php | 15 ++++++-- ...rsModifiedSinceSearchBuilderBuiltEvent.php | 37 +++++++++++++++++++ src/Product/Importer.php | 4 ++ src/ProductAssociations/Importer.php | 6 +++ 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/Event/IdentifiersModifiedSinceSearchBuilderBuiltEvent.php diff --git a/config/services.xml b/config/services.xml index be473ae5..10c5bbeb 100644 --- a/config/services.xml +++ b/config/services.xml @@ -123,6 +123,7 @@ + @@ -130,6 +131,7 @@ + diff --git a/src/AttributeOptions/Importer.php b/src/AttributeOptions/Importer.php index 23167fc6..c1b4e59f 100644 --- a/src/AttributeOptions/Importer.php +++ b/src/AttributeOptions/Importer.php @@ -5,9 +5,12 @@ namespace Webgriffe\SyliusAkeneoPlugin\AttributeOptions; use Akeneo\Pim\ApiClient\AkeneoPimClientInterface; +use Akeneo\Pim\ApiClient\Search\SearchBuilder; use Sylius\Component\Attribute\AttributeType\SelectAttributeType; use Sylius\Component\Product\Model\ProductAttributeInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Webgriffe\SyliusAkeneoPlugin\Event\IdentifiersModifiedSinceSearchBuilderBuiltEvent; use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; final class Importer implements ImporterInterface @@ -22,6 +25,7 @@ final class Importer implements ImporterInterface public function __construct( private AkeneoPimClientInterface $apiClient, private RepositoryInterface $attributeRepository, + private EventDispatcherInterface $eventDispatcher, ) { } @@ -59,13 +63,18 @@ public function import(string $identifier): void } /** - * It's not possible to fetch only attributes or attribute options modified since a given date with the Akeneo - * REST API. So, the $sinceDate argument it's not used. + * As stated at https://api.akeneo.com/documentation/filter.html#by-update-date-3: + * > For Simple select and Multiple select attribute, an option update isn't considered as an attribute update. + * So, the $sinceDate argument it's not used here. */ public function getIdentifiersModifiedSince(\DateTime $sinceDate): array { + $searchBuilder = new SearchBuilder(); + $this->eventDispatcher->dispatch( + new IdentifiersModifiedSinceSearchBuilderBuiltEvent($this, $searchBuilder, $sinceDate), + ); /** @var array> $akeneoAttributes */ - $akeneoAttributes = $this->apiClient->getAttributeApi()->all(); + $akeneoAttributes = $this->apiClient->getAttributeApi()->all(50, ['search' => $searchBuilder->getFilters()]); $syliusSelectAttributes = $this->attributeRepository->findBy(['type' => SelectAttributeType::TYPE]); $syliusSelectAttributes = array_filter( array_map( diff --git a/src/Event/IdentifiersModifiedSinceSearchBuilderBuiltEvent.php b/src/Event/IdentifiersModifiedSinceSearchBuilderBuiltEvent.php new file mode 100644 index 00000000..4b985728 --- /dev/null +++ b/src/Event/IdentifiersModifiedSinceSearchBuilderBuiltEvent.php @@ -0,0 +1,37 @@ +importer; + } + + public function getSearchBuilder(): SearchBuilder + { + return $this->searchBuilder; + } + + public function getSinceDate(): DateTimeInterface + { + return $this->sinceDate; + } +} diff --git a/src/Product/Importer.php b/src/Product/Importer.php index e6056605..4d59da91 100644 --- a/src/Product/Importer.php +++ b/src/Product/Importer.php @@ -20,6 +20,7 @@ use Sylius\Component\Resource\Factory\FactoryInterface; use Sylius\Component\Resource\Model\ResourceInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Webgriffe\SyliusAkeneoPlugin\Event\IdentifiersModifiedSinceSearchBuilderBuiltEvent; use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; use Webgriffe\SyliusAkeneoPlugin\ReconcilerInterface; use Webgriffe\SyliusAkeneoPlugin\ValueHandlersResolverInterface; @@ -112,6 +113,9 @@ public function getIdentifiersModifiedSince(DateTime $sinceDate): array { $searchBuilder = new SearchBuilder(); $searchBuilder->addFilter('updated', '>', $sinceDate->format('Y-m-d H:i:s')); + $this->eventDispatcher->dispatch( + new IdentifiersModifiedSinceSearchBuilderBuiltEvent($this, $searchBuilder, $sinceDate), + ); $products = $this->apiClient->getProductApi()->all(50, ['search' => $searchBuilder->getFilters()]); $identifiers = []; foreach ($products as $product) { diff --git a/src/ProductAssociations/Importer.php b/src/ProductAssociations/Importer.php index 227f92ee..36e802b4 100644 --- a/src/ProductAssociations/Importer.php +++ b/src/ProductAssociations/Importer.php @@ -18,6 +18,8 @@ use Sylius\Component\Product\Repository\ProductAssociationTypeRepositoryInterface; use Sylius\Component\Resource\Factory\FactoryInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Webgriffe\SyliusAkeneoPlugin\Event\IdentifiersModifiedSinceSearchBuilderBuiltEvent; use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; use Webmozart\Assert\Assert; @@ -35,6 +37,7 @@ public function __construct( private RepositoryInterface $productAssociationRepository, private ProductAssociationTypeRepositoryInterface $productAssociationTypeRepository, private FactoryInterface $productAssociationFactory, + private EventDispatcherInterface $eventDispatcher, ) { } @@ -130,6 +133,9 @@ public function getIdentifiersModifiedSince(DateTime $sinceDate): array { $searchBuilder = new SearchBuilder(); $searchBuilder->addFilter('updated', '>', $sinceDate->format('Y-m-d H:i:s')); + $this->eventDispatcher->dispatch( + new IdentifiersModifiedSinceSearchBuilderBuiltEvent($this, $searchBuilder, $sinceDate), + ); $products = $this->apiClient->getProductApi()->all(50, ['search' => $searchBuilder->getFilters()]); $identifiers = []; foreach ($products as $product) { From ca89ebd01b34cd3d70e798fc1591b74b1d073c16 Mon Sep 17 00:00:00 2001 From: Manuele Menozzi Date: Tue, 12 Sep 2023 12:51:01 +0200 Subject: [PATCH 2/2] Document how to customize which identifiers to enqueue (#5) --- docs/architecture_and_customization.md | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/architecture_and_customization.md b/docs/architecture_and_customization.md index b2d937ee..5766f3e4 100644 --- a/docs/architecture_and_customization.md +++ b/docs/architecture_and_customization.md @@ -178,3 +178,46 @@ Another provided importer is the **attribute options importer** (`\Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer`). This importer imports the Akeneo simple select and multi select attributes options into Sylius select attributes. The select attributes must already exist on Sylius with the same code they have on Akeneo. + +## Customize which Akeneo products to import + +Each built-in importer described above implements a `getIdentiferModifiedSince()` method. +This method is used to identify which Akeneo entity identifiers should be imported or reconciled when the corresponding CLI commands run. +By default, those methods return all the Akeneo identifiers of entities modified since the given date. +But maybe you want to only import a subset of those Akeneo entities. + +For example, you might want to only import Akeneo products that have a not-empty family and a completeness of 100% for the `ecommerce` Akeneo channel. +To do so you can define an event listener or subscriber for the `Webgriffe\SyliusAkeneoPlugin\Event\IdentifiersModifiedSinceSearchBuilderBuiltEvent` event and add the corresponding filters to the `SearchBuilder` object: + +```php +// src/EventSubscriber/IdentifiersModifiedSinceSearchBuilderBuiltEventSubscriber.php + +namespace App\EventSubscriber; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Webgriffe\SyliusAkeneoPlugin\Event\IdentifiersModifiedSinceSearchBuilderBuiltEvent; +use Webgriffe\SyliusAkeneoPlugin\Product\Importer as ProductImporter; +use Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer as ProductAssociationsImporter; + +final class IdentifiersModifiedSinceSearchBuilderBuiltEventSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents(): array + { + return [ + IdentifiersModifiedSinceSearchBuilderBuiltEvent::class => 'onIdentifiersModifiedSinceSearchBuilderBuilt', + ]; + } + + public function onIdentifiersModifiedSinceSearchBuilderBuilt(IdentifiersModifiedSinceSearchBuilderBuiltEvent $event): void + { + if (!$event->getImporter() instanceof ProductImporter && + !$event->getImporter() instanceof ProductAssociationsImporter) { + return; + } + + $searchBuilder = $event->getSearchBuilder(); + $searchBuilder->addFilter('family', 'NOT EMPTY'); + $searchBuilder->addFilter('completeness', '=', 100, ['scope' => 'ecommerce']); + } +} +```