Skip to content

Commit

Permalink
Allow to choose which product to import on webhook (#194)
Browse files Browse the repository at this point in the history
  • Loading branch information
lruozzi9 committed Dec 15, 2023
1 parent cf1f11e commit 3e94c80
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 30 deletions.
1 change: 1 addition & 0 deletions config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<argument type="service" id="monolog.logger.webgriffe_sylius_akeneo_plugin" />
<argument type="service" id="webgriffe_sylius_akeneo.command_bus" />
<argument type="string">%webgriffe_sylius_akeneo.webhook.secret%</argument>
<argument type="service" id="event_dispatcher" />
<call method="setContainer">
<argument type="service" id="service_container" />
</call>
Expand Down
40 changes: 40 additions & 0 deletions docs/architecture_and_customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ with the same code they have on Akeneo.

## Customize which Akeneo products to import

### Customize Akeneo products to import from the command

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.
Expand Down Expand Up @@ -229,3 +231,41 @@ final class IdentifiersModifiedSinceSearchBuilderBuiltEventSubscriber implements
}
}
```

### Customize Akeneo products to import from the webhook

By default, the webhook is configured to import all the Akeneo products and product model that have been created or
updated on Akeneo. But maybe you want to only import a subset of those Akeneo entities. In this case you can define an
event listener or subscriber for the `Webgriffe\SyliusAkeneoPlugin\Event\AkeneoProductChangedEvent` event and change the
value of the property ignorable of the event based on given product:

```php
// src/EventSubscriber/AkeneoProductChangedEventSubscriber.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 AkeneoProductChangedEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
AkeneoProductChangedEvent::class => 'onAkeneoProductChanged',
];
}
public function onAkeneoProductChanged(AkeneoProductChangedEvent $event): void
{
$akeneoProduct = $event->getAkeneoProduct();
if ($akeneoProduct['family'] === null) {
$event->setIgnorable(true);
}
}
}
```

The same can be applied to the `Webgriffe\SyliusAkeneoPlugin\Event\AkeneoProductModelChangedEvent` event.
5 changes: 5 additions & 0 deletions docs/upgrade/upgrade-2.*.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ nav_order: 0
parent: Upgrade
---

# Upgrade from `v2.4.0` to `v2.4.1`

The v2.4.1 version now allow you to choose which product and product model to import through webhook entry point.
Take a look at the [customization documentation](../architecture_and_customization.html) to see how to configure it.

# Upgrade from `v2.3.0` to `v2.4.0`

The v2.4.0 version introduces the Product Model importer. If you are using the webhook no changes are requested as it will be automatically enqueued on every update.
Expand Down
93 changes: 63 additions & 30 deletions src/Controller/WebhookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Webgriffe\SyliusAkeneoPlugin\Event\AkeneoProductChangedEvent;
use Webgriffe\SyliusAkeneoPlugin\Event\AkeneoProductModelChangedEvent;
use Webgriffe\SyliusAkeneoPlugin\Message\ItemImport;
use Webgriffe\SyliusAkeneoPlugin\Product\Importer as ProductImporter;
use Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer as ProductAssociationsImporter;
Expand All @@ -21,7 +24,7 @@
* uuid: string,
* identifier: string,
* enabled: bool,
* family: string,
* family: ?string,
* categories: string[],
* groups: string[],
* parent: ?string,
Expand Down Expand Up @@ -64,7 +67,17 @@ public function __construct(
private LoggerInterface $logger,
private MessageBusInterface $messageBus,
private string $secret,
private ?EventDispatcherInterface $eventDispatcher = null,
) {
if ($this->eventDispatcher === null) {
trigger_deprecation(
'webgriffe/sylius-akeneo-plugin',
'v2.4.1',
'Not passing a "%s" instance to "%s" constructor is deprecated and will not be possible anymore in the next major version.',
EventDispatcherInterface::class,
self::class,
);
}
}

/**
Expand Down Expand Up @@ -117,39 +130,59 @@ public function postAction(Request $request): Response
foreach ($akeneoEvents['events'] as $akeneoEvent) {
$this->logger->debug(sprintf('Received event %s with id "%s"', $akeneoEvent['action'], $akeneoEvent['event_id']));

$resource = $akeneoEvent['data']['resource'];
if (array_key_exists('identifier', $resource)) {
$productCode = $resource['identifier'];
$this->logger->debug(sprintf(
'Dispatching product import message for %s',
$productCode,
));
$this->messageBus->dispatch(new ItemImport(
ProductImporter::AKENEO_ENTITY,
$productCode,
));
$this->logger->debug(sprintf(
'Dispatching product associations import message for %s',
$productCode,
));
$this->messageBus->dispatch(new ItemImport(
ProductAssociationsImporter::AKENEO_ENTITY,
$productCode,
));
if (array_key_exists('identifier', $akeneoEvent['data']['resource'])) {
/** @var AkeneoEventProduct $resource */
$resource = $akeneoEvent['data']['resource'];
$event = new AkeneoProductChangedEvent($resource, $akeneoEvent);
$this->eventDispatcher?->dispatch($event);
if (!$event->isIgnorable()) {
$this->importProduct($resource['identifier']);
}
}
if (array_key_exists('code', $resource)) {
$productModelCode = $resource['code'];
$this->logger->debug(sprintf(
'Dispatching product model import message for %s',
$productModelCode,
));
$this->messageBus->dispatch(new ItemImport(
ProductModelImporter::AKENEO_ENTITY,
$productModelCode,
));
if (array_key_exists('code', $akeneoEvent['data']['resource'])) {
/** @var AkeneoEventProductModel $resource */
$resource = $akeneoEvent['data']['resource'];
$event = new AkeneoProductModelChangedEvent($resource, $akeneoEvent);
$this->eventDispatcher?->dispatch($event);
if (!$event->isIgnorable()) {
$this->importProductModel($resource['code']);
}
}
}

return new Response();
}

private function importProduct(string $productCode): void
{
$this->logger->debug(sprintf(
'Dispatching product import message for %s',
$productCode,
));
$this->messageBus->dispatch(new ItemImport(
ProductImporter::AKENEO_ENTITY,
$productCode,
));

$this->logger->debug(sprintf(
'Dispatching product associations import message for %s',
$productCode,
));
$this->messageBus->dispatch(new ItemImport(
ProductAssociationsImporter::AKENEO_ENTITY,
$productCode,
));
}

private function importProductModel(string $productModelCode): void
{
$this->logger->debug(sprintf(
'Dispatching product model import message for %s',
$productModelCode,
));
$this->messageBus->dispatch(new ItemImport(
ProductModelImporter::AKENEO_ENTITY,
$productModelCode,
));
}
}
67 changes: 67 additions & 0 deletions src/Event/AkeneoProductChangedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Webgriffe\SyliusAkeneoPlugin\Event;

/**
* @psalm-type AkeneoEventProduct = array{
* uuid: string,
* identifier: string,
* enabled: bool,
* family: ?string,
* categories: string[],
* groups: string[],
* parent: ?string,
* values: array<string, array>,
* created: string,
* updated: string,
* associations: array<string, array>,
* quantified_associations: array<string, array>,
* }
* @psalm-type AkeneoEvent = array{
* action: string,
* event_id: string,
* event_datetime: string,
* author: string,
* author_type: string,
* pim_source: string,
* data: array{
* resource: AkeneoEventProduct|array
* },
* }
*/
final class AkeneoProductChangedEvent
{
private bool $ignorable = false;

/**
* @param AkeneoEventProduct $akeneoProduct
* @param AkeneoEvent $akeneoEvent
*/
public function __construct(
private array $akeneoProduct,
private array $akeneoEvent,
) {
}

public function getAkeneoProduct(): array
{
return $this->akeneoProduct;
}

public function getAkeneoEvent(): array
{
return $this->akeneoEvent;
}

public function isIgnorable(): bool
{
return $this->ignorable;
}

public function setIgnorable(bool $ignorable): void
{
$this->ignorable = $ignorable;
}
}
65 changes: 65 additions & 0 deletions src/Event/AkeneoProductModelChangedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Webgriffe\SyliusAkeneoPlugin\Event;

/**
* @psalm-type AkeneoEventProductModel = array{
* code: string,
* family: string,
* family_variant: string,
* parent: ?string,
* categories: string[],
* values: array<string, array>,
* created: string,
* updated: string,
* associations: array<string, array>,
* quantified_associations: array<string, array>,
* }
* @psalm-type AkeneoEvent = array{
* action: string,
* event_id: string,
* event_datetime: string,
* author: string,
* author_type: string,
* pim_source: string,
* data: array{
* resource: array|AkeneoEventProductModel
* },
* }
*/
final class AkeneoProductModelChangedEvent
{
private bool $ignorable = false;

/**
* @param AkeneoEventProductModel $akeneoProductModel
* @param AkeneoEvent $akeneoEvent
*/
public function __construct(
private array $akeneoProductModel,
private array $akeneoEvent,
) {
}

public function getAkeneoProductModel(): array
{
return $this->akeneoProductModel;
}

public function getAkeneoEvent(): array
{
return $this->akeneoEvent;
}

public function isIgnorable(): bool
{
return $this->ignorable;
}

public function setIgnorable(bool $ignorable): void
{
$this->ignorable = $ignorable;
}
}

0 comments on commit 3e94c80

Please sign in to comment.