Events Reference
Entity Builder uses Symfony events to allow modules to hook into the operation lifecycle.
Event Overview
sequenceDiagram
participant S as Subscriber
participant VM as ValidationManager
participant OP as OperationProcessor
participant O as Operation
Note over VM,O: Validation Phase
VM->>S: PRE_VALIDATE event
S-->>VM: (may modify)
VM->>O: validate()
VM->>S: POST_VALIDATE event
S-->>VM: (may add errors)
Note over OP,O: Execution Phase
OP->>S: PRE_EXECUTE event
S-->>OP: (may cancel)
OP->>O: execute()
OP->>S: POST_EXECUTE event
S-->>OP: (may log/react)
Event Constants
All events are defined in Drupal\eb\Event\OperationEvents:
Constant
Event Name
Description
PRE_VALIDATE
eb.operation.pre_validate
Before operation validation
POST_VALIDATE
eb.operation.post_validate
After operation validation
PRE_EXECUTE
eb.operation.pre_execute
Before operation execution
POST_EXECUTE
eb.operation.post_execute
After operation execution
Event Classes
OperationPreValidateEvent
Dispatched before an operation is validated.
Namespace: Drupal\eb\Event\OperationPreValidateEvent
Methods:
Method
Return Type
Description
getOperation()
OperationInterface
The operation being validated
Use Cases:
Modify operation data before validation
Add contextual information
OperationPostValidateEvent
Dispatched after an operation is validated.
Namespace: Drupal\eb\Event\OperationPostValidateEvent
Methods:
Method
Return Type
Description
getOperation()
OperationInterface
The validated operation
getResult()
ValidationResult
Validation result
addError()
void
Add validation error
addWarning()
void
Add validation warning
Use Cases:
Add custom validation rules
Log validation results
Enforce business rules
OperationPreExecuteEvent
Dispatched before an operation is executed.
Namespace: Drupal\eb\Event\OperationPreExecuteEvent
Methods:
Method
Return Type
Description
getOperation()
OperationInterface
The operation to execute
cancel(string $message)
void
Cancel execution
isCancelled()
bool
Check if cancelled
getCancellationMessage()
string
Get cancellation message
Use Cases:
Prevent execution based on external conditions
Add pre-execution logging
Trigger external systems
OperationPostExecuteEvent
Dispatched after an operation is executed.
Namespace: Drupal\eb\Event\OperationPostExecuteEvent
Methods:
Method
Return Type
Description
getOperation()
OperationInterface
The executed operation
getResult()
ExecutionResult
Execution result
Use Cases:
Log execution results
Trigger cache invalidation
Notify external systems
Update related entities
Creating an Event Subscriber
Step 1: Create the Subscriber Class
<? php
namespace Drupal\my_module\EventSubscriber ;
use Drupal\eb\Event\OperationEvents ;
use Drupal\eb\Event\OperationPreExecuteEvent ;
use Drupal\eb\Event\OperationPostExecuteEvent ;
use Symfony\Component\EventDispatcher\EventSubscriberInterface ;
/**
* Subscribes to Entity Builder operation events.
*/
class MyOperationSubscriber implements EventSubscriberInterface {
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents () : array {
return [
OperationEvents :: PRE_EXECUTE => [ 'onPreExecute' , 0 ],
OperationEvents :: POST_EXECUTE => [ 'onPostExecute' , 0 ],
];
}
/**
* Reacts before operation execution.
*/
public function onPreExecute ( OperationPreExecuteEvent $event ) : void {
$operation = $event -> getOperation ();
$operationType = $operation -> getDataValue ( 'operation' );
// Example: Prevent bundle deletion on production
if ( $operationType === 'delete_bundle' && $this -> isProduction ()) {
$event -> cancel ( 'Bundle deletion is disabled on production.' );
}
}
/**
* Reacts after operation execution.
*/
public function onPostExecute ( OperationPostExecuteEvent $event ) : void {
$operation = $event -> getOperation ();
$result = $event -> getResult ();
if ( $result -> isSuccess ()) {
// Log to external system
$this -> logToExternalSystem ( $operation );
}
}
/**
* Check if running on production.
*/
protected function isProduction () : bool {
// Implementation
return FALSE ;
}
/**
* Log to external system.
*/
protected function logToExternalSystem ( $operation ) : void {
// Implementation
}
}
Step 2: Register as a Service
# my_module.services.yml
services :
my_module.operation_subscriber :
class : Drupal\my_module\EventSubscriber\MyOperationSubscriber
tags :
- { name : event_subscriber }
Example: Custom Validation
Add custom validation rules:
<? php
namespace Drupal\my_module\EventSubscriber ;
use Drupal\eb\Event\OperationEvents ;
use Drupal\eb\Event\OperationPostValidateEvent ;
use Symfony\Component\EventDispatcher\EventSubscriberInterface ;
/**
* Adds custom validation rules.
*/
class CustomValidationSubscriber implements EventSubscriberInterface {
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents () : array {
return [
OperationEvents :: POST_VALIDATE => [ 'onPostValidate' , 0 ],
];
}
/**
* Adds custom validation.
*/
public function onPostValidate ( OperationPostValidateEvent $event ) : void {
$operation = $event -> getOperation ();
$operationType = $operation -> getDataValue ( 'operation' );
if ( $operationType === 'create_bundle' ) {
$bundleId = $operation -> getDataValue ( 'bundle_id' );
// Enforce naming convention
if ( ! str_starts_with ( $bundleId , 'myprefix_' )) {
$event -> addError (
'Bundle ID must start with "myprefix_".' ,
'bundle_id' ,
'naming_convention'
);
}
}
}
}
Example: Audit Logging
Log all operations to an external system:
<? php
namespace Drupal\my_module\EventSubscriber ;
use Drupal\eb\Event\OperationEvents ;
use Drupal\eb\Event\OperationPostExecuteEvent ;
use Psr\Log\LoggerInterface ;
use Symfony\Component\EventDispatcher\EventSubscriberInterface ;
/**
* Logs operations to external audit system.
*/
class AuditLogSubscriber implements EventSubscriberInterface {
/**
* Constructor.
*/
public function __construct (
protected LoggerInterface $logger ,
) {}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents () : array {
return [
OperationEvents :: POST_EXECUTE => [ 'onPostExecute' , - 100 ],
];
}
/**
* Logs operation result.
*/
public function onPostExecute ( OperationPostExecuteEvent $event ) : void {
$operation = $event -> getOperation ();
$result = $event -> getResult ();
$this -> logger -> info ( 'EB Operation: @type - @status' , [
'@type' => $operation -> getDataValue ( 'operation' ),
'@status' => $result -> isSuccess () ? 'success' : 'failed' ,
]);
}
}
Event Priority
Subscribers can specify priority (higher runs first):
public static function getSubscribedEvents () : array {
return [
// Run early (priority 100)
OperationEvents :: PRE_EXECUTE => [ 'onPreExecute' , 100 ],
// Run late (priority -100)
OperationEvents :: POST_EXECUTE => [ 'onPostExecute' , - 100 ],
];
}
Best Practices
Keep subscribers lightweight - Don't perform expensive operations
Use appropriate priority - Let core handlers run first
Handle exceptions - Don't break the execution flow
Log sparingly - Avoid excessive logging in production
Test thoroughly - Events can have unexpected side effects