diff --git a/README.md b/README.md index 418771a..c1def47 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,9 @@ framework: 'Setono\MetaConversionsApiBundle\Message\Command\SendEvent': async ``` +Every command the bundle dispatches implements +`Setono\MetaConversionsApiBundle\Message\Command\CommandInterface`, so you can route them as a group instead. + With a transport, Messenger also retries a failed send and moves it to the failure transport when it keeps failing. What ends up in the transport is the finished payload: the user data is already normalised and hashed by the SDK, and @@ -249,6 +252,20 @@ final class AddCustomerToConversionsApiEvent You can also replace a step instead of adding to it: alias `PixelProviderInterface`, `FbpContextInterface` or `FbcContextInterface` to your own service, or register a listener above the corresponding populate priority. +### Passing context to your own listeners + +The second constructor argument of `ConversionsApiEventRaised` carries anything your listeners need but that must +never be sent to Meta, such as the order the event was raised for. The bundle never reads it. + +```php +$this->eventDispatcher->dispatch(new ConversionsApiEventRaised($event, ['order' => $order])); + +// in a listener +if ($event->hasContext('order')) { + $order = $event->getContext('order'); +} +``` + ### Why did my event not show up? Every listener that drops an event says so at debug level on the `setono_meta_conversions_api` Monolog channel: the diff --git a/UPGRADE.md b/UPGRADE.md index cacb97b..655d82b 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -75,6 +75,15 @@ anything to `framework.messenger`. `SendEvent` is dispatched on your application `?ConsentContextInterface $consentContext` and `bool $consentEnabled` / `bool $clientSideEnabled` / `bool $serverSideEnabled` arguments. Adapt subclasses, decorators and custom service definitions. +## Removed container parameters + +`setono_meta_conversions_api.client_side.enabled` and `setono_meta_conversions_api.server_side.enabled` are gone. No +service used them once the subscribers became conditional, and whether a side is enabled is visible from whether its +services exist. The `consent.*`, `pixels`, `cookies.*`, `filters.*` and `test_event_code.*` parameters are unchanged. + +`ConversionsApiEventRaised::$event` and `::$context` are now `readonly`. The `Event` object itself stays mutable, +which is what enrichment listeners need, but the properties can no longer be swapped out. `getContext()` is new. + ## Cookies New `cookies` options: diff --git a/src/DependencyInjection/SetonoMetaConversionsApiExtension.php b/src/DependencyInjection/SetonoMetaConversionsApiExtension.php index 49aff52..37f9102 100644 --- a/src/DependencyInjection/SetonoMetaConversionsApiExtension.php +++ b/src/DependencyInjection/SetonoMetaConversionsApiExtension.php @@ -34,8 +34,6 @@ public function load(array $configs, ContainerBuilder $container): void $container->setParameter('setono_meta_conversions_api.consent.enabled', $config['consent']['enabled']); $container->setParameter('setono_meta_conversions_api.consent.category', $config['consent']['category']); - $container->setParameter('setono_meta_conversions_api.client_side.enabled', $config['client_side']['enabled']); - $container->setParameter('setono_meta_conversions_api.server_side.enabled', $config['server_side']['enabled']); $container->setParameter('setono_meta_conversions_api.pixels', $config['pixels']); $container->setParameter('setono_meta_conversions_api.filters.user_agent', $config['filters']['user_agent']); diff --git a/src/Event/ConversionsApiEventRaised.php b/src/Event/ConversionsApiEventRaised.php index 1d914aa..c708b1b 100644 --- a/src/Event/ConversionsApiEventRaised.php +++ b/src/Event/ConversionsApiEventRaised.php @@ -49,9 +49,13 @@ final class ConversionsApiEventRaised extends StoppableEvent public const PRIORITY_SEND = -1000; /** - * @param array $context + * @param Event $event The event that will be rendered client side and sent server side. Listeners are expected + * to mutate it, which is how enrichment works + * @param array $context Anything your own listeners need but that must not be sent to Meta, for + * instance the order or the customer the event was raised for. The bundle + * never reads it */ - public function __construct(public Event $event, public array $context = []) + public function __construct(public readonly Event $event, public readonly array $context = []) { } @@ -59,4 +63,9 @@ public function hasContext(string $key): bool { return array_key_exists($key, $this->context); } + + public function getContext(string $key, mixed $default = null): mixed + { + return $this->context[$key] ?? $default; + } } diff --git a/src/Message/Command/CommandInterface.php b/src/Message/Command/CommandInterface.php index bce05c8..4e19073 100644 --- a/src/Message/Command/CommandInterface.php +++ b/src/Message/Command/CommandInterface.php @@ -4,6 +4,14 @@ namespace Setono\MetaConversionsApiBundle\Message\Command; +/** + * Implemented by every command the bundle dispatches, so they can be routed as a group: + * + * framework: + * messenger: + * routing: + * 'Setono\MetaConversionsApiBundle\Message\Command\CommandInterface': async + */ interface CommandInterface { } diff --git a/tests/Integration/DependencyInjection/SetonoMetaConversionsApiExtensionTest.php b/tests/Integration/DependencyInjection/SetonoMetaConversionsApiExtensionTest.php index ea945dc..6b0db05 100644 --- a/tests/Integration/DependencyInjection/SetonoMetaConversionsApiExtensionTest.php +++ b/tests/Integration/DependencyInjection/SetonoMetaConversionsApiExtensionTest.php @@ -43,8 +43,6 @@ public function it_sets_parameters(): void $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.consent.enabled', false); $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.consent.category', DefaultConsents::CONSENT_MARKETING); - $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.client_side.enabled', true); - $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.server_side.enabled', true); $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.pixels', []); $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.filters.user_agent', []); $this->assertContainerBuilderHasParameter('setono_meta_conversions_api.test_event_code.value', null); diff --git a/tests/Unit/Event/ConversionsApiEventRaisedTest.php b/tests/Unit/Event/ConversionsApiEventRaisedTest.php index 049f303..a555e32 100644 --- a/tests/Unit/Event/ConversionsApiEventRaisedTest.php +++ b/tests/Unit/Event/ConversionsApiEventRaisedTest.php @@ -51,6 +51,16 @@ public function it_has_context(): void self::assertFalse($event->hasContext('customer')); } + #[Test] + public function it_returns_context(): void + { + $event = new ConversionsApiEventRaised(new Event(Event::EVENT_VIEW_CONTENT), ['order' => 1]); + + self::assertSame(1, $event->getContext('order')); + self::assertNull($event->getContext('customer')); + self::assertSame('fallback', $event->getContext('customer', 'fallback')); + } + /** * The documented pipeline only holds as long as the bundle's own listeners keep their relative order, so this * pins it down. It is the contract integrators position their own listeners against