Custom Processors
A webhook processor gathers the payload for an event and sends the request to every subscriber. Replacing the processor for an event is the way to change what is sent, to whom, and what happens with the answer.
How an Event Reaches a Processor
Three event listeners are registered in services.yml, each listening to a set of Pimcore events. A listener does not
send the request itself. It checks that a processor is tagged for the event, writes an entry into the
bundle_data_hub_webhooks_queue table and dispatches a message. The Symfony Messenger worker then hands the entry to
the processor, which calls fire().
ElementEventListener
Handles the add and update events for Data Objects, Documents and Assets.
Pimcore\Bundle\DataHubWebhooksBundle\EventListener\ElementEventListener:
tags:
- { name: kernel.event_listener, event: pimcore.dataobject.postAdd, method: processEvent }
- { name: kernel.event_listener, event: pimcore.dataobject.postUpdate, method: processEvent }
- { name: kernel.event_listener, event: pimcore.dataobject.postUpdateFailure, method: processEvent }
- { name: kernel.event_listener, event: pimcore.asset.postAdd, method: processEvent }
# ...
ElementDeleteEventListener
Handles the delete events. It is separate because the element no longer exists once the worker runs, so this listener extracts the payload while the element is still available and stores it as context information on the queue entry.
Pimcore\Bundle\DataHubWebhooksBundle\EventListener\ElementDeleteEventListener:
tags:
- { name: kernel.event_listener, event: pimcore.dataobject.postDelete, method: processEvent }
- { name: kernel.event_listener, event: pimcore.dataobject.postDeleteFailure, method: processEvent }
- { name: kernel.event_listener, event: pimcore.asset.postDelete, method: processEvent }
# ...
WorkflowEventListener
Handles the workflow events. It stores the workflow name, the transition and the marking as context information.
Pimcore\Bundle\DataHubWebhooksBundle\EventListener\WorkflowEventListener:
tags:
- { name: kernel.event_listener, event: workflow.entered, method: processEvent }
- { name: kernel.event_listener, event: workflow.completed, method: processEvent }
The element listeners skip events on data object folders and events carrying the isAutoSave argument.
The Shipped Processors
Every processor implements Processors\WebhookProcessorInterface:
| Class | Adds |
|---|---|
AbstractWebhookProcessor | The behaviour shared by all processors. |
AssetWebhookProcessor | Asset specifics, such as embedding binary data. |
DataObjectWebhookProcessor | Data object specifics, such as including unpublished objects. |
DocumentWebhookProcessor | Document specifics, such as userModification. |
WorkflowWebhookProcessor | Workflow specifics, such as transitions and markings. |
Each event is wired to a processor by a tagged service. The $httpMethod argument decides the verb of the request:
pimcore.webhooks.processor.dataobject.postAdd:
class: Pimcore\Bundle\DataHubWebhooksBundle\Processors\DataObjectWebhookProcessor
arguments:
$httpMethod: 'POST'
tags:
- { name: pimcore.datahub.webhooks_event, event: pimcore.dataobject.postAdd}
pimcore.webhooks.processor.dataobject.postUpdate:
class: Pimcore\Bundle\DataHubWebhooksBundle\Processors\DataObjectWebhookProcessor
arguments:
$httpMethod: 'PUT'
tags:
- { name: pimcore.datahub.webhooks_event, event: pimcore.dataobject.postUpdate}
pimcore.webhooks.processor.dataobject.postDelete:
class: Pimcore\Bundle\DataHubWebhooksBundle\Processors\DataObjectWebhookProcessor
arguments:
$httpMethod: 'DELETE'
tags:
- { name: pimcore.datahub.webhooks_event, event: pimcore.dataobject.postDelete}
Writing Your Own Processor
AssetWebhookProcessor, DataObjectWebhookProcessor, DocumentWebhookProcessor and WorkflowWebhookProcessor are
final and cannot be subclassed. AbstractWebhookProcessor is not final, but it is marked @internal, so its
behaviour may change without a deprecation path.
The stable contract is the interface Processors\WebhookProcessorInterface.
Implement WebhookProcessorInterface and register the class as a tagged service, exactly as shown above. The
interface
requires three methods:
fire(): executes the webhook based on the Datahub configuration.matchByEvent(): reports whether this processor handles the current event.matchBySchema(): reports whether the event and its element match the Datahub configuration, meaning workspaces, types and the rest of the schema.
Overridable Hooks
Extending AbstractWebhookProcessor gives you the shared behaviour and these hooks. Accept the @internal caveat above
before relying on them.
| Method | Purpose | Default |
|---|---|---|
mustSkipWebhookRequest() | Skip sending the request to a subscriber. | Returns false. |
updateRequestBodyForSubscriber() | Adjust the payload per subscriber. | Returns the payload unchanged. |
getHttpMethodForSubscriber() | Choose the HTTP method per subscriber. | Returns the $httpMethod of the service definition. |
getAdditionalOptionsForSubscriber() | Add request options per subscriber, for example authentication headers. | Returns the custom headers configured on the Subscribers tab. |
handleResponse() | React to the subscriber's response, for example by updating the element. | Does nothing. |