Plugin Integration
Voodflow provides a first-class API for third-party Laravel plugins and packages to expose their own events and models. This allows users to build workflows triggered by any plugin event — not just CRUD operations on core models.
There are three independent mechanisms, and you can use them together:
| What you need | Mechanism |
|---|---|
| Expose a custom event in the trigger picker | Voodflow::registerEvent() |
| Let Voodflow read fields from your model | HasVoodflow interface or Voodflow::registerModelFields() |
| Control the exact payload sent to a workflow | PayloadProvider interface |
| Customize the trigger identifier of an event | IdentifiableEvent interface |
1. Registering a Custom Event
Call Voodflow::registerEvent() inside your plugin's ServiceProvider::boot() to make an event selectable in the Event Trigger node.
use Voodflow\Voodflow\Voodflow;
public function boot(): void
{
Voodflow::registerEvent(
eventClass: \Vendor\MyPlugin\Events\InvoicePaid::class,
name: 'Invoice Paid',
description: 'Fired when an invoice is marked as paid',
group: 'MyPlugin',
);
Voodflow::registerEvent(
eventClass: \Vendor\MyPlugin\Events\SubscriptionExpired::class,
name: 'Subscription Expired',
group: 'MyPlugin',
);
}| Parameter | Type | Description |
|---|---|---|
eventClass | string | Fully-qualified class name of the event |
name | string | Human-readable label shown in the event picker |
description | string|null | Optional tooltip/description in the UI |
group | string|null | Groups events in the dropdown (e.g. "MyPlugin") |
Events are standard Laravel events dispatched with event(). Voodflow listens for them automatically — there is nothing else to configure.
// Anywhere in your plugin:
event(new \Vendor\MyPlugin\Events\InvoicePaid($invoice));2. Exposing Model Fields (HasVoodflow)
To let Voodflow read and map fields from your Eloquent model (e.g. for {{tags}} resolution in nodes), implement the HasVoodflow interface on the model:
use Voodflow\Voodflow\Contracts\HasVoodflow;
class Invoice extends Model implements HasVoodflow
{
public static function getVoodflowFields(): array
{
return [
'essential' => [
'id' => 'ID',
'number' => 'Invoice Number',
'total' => 'Total',
'status' => 'Status',
'due_date' => 'Due Date',
'created_at' => 'Created At',
],
'relations' => [
'customer' => [
'fields' => [
'id' => 'Customer ID',
'name' => 'Customer Name',
'email' => 'Customer Email',
],
],
'items' => [
'fields' => [
'description' => 'Item Description',
'quantity' => 'Quantity',
'unit_price' => 'Unit Price',
],
],
],
];
}
}Return value structure
| Key | Type | Description |
|---|---|---|
essential | array | Flat fields of this model. Key = field name, value = label. |
relations | array | Optional. Keyed by relation method name. |
relations.*.fields | array | Fields from the related model to expose. |
relations.*.expand | array | Nested relations to recursively expand. |
Once HasVoodflow is implemented, Voodflow automatically discovers the model's fields when an event carrying that model instance is fired.
3. Registering Fields for Third-Party Models
If you cannot modify a model (e.g. it belongs to another package), use Voodflow::registerModelFields() in your ServiceProvider::boot():
use Voodflow\Voodflow\Voodflow;
public function boot(): void
{
Voodflow::registerModelFields(
modelClass: \SomeVendor\Package\Models\Order::class,
fields: [
'essential' => [
'id' => 'Order ID',
'reference' => 'Reference',
'total' => 'Total',
'status' => 'Status',
],
'relations' => [
'customer' => [
'fields' => ['name' => 'Name', 'email' => 'Email'],
],
],
],
alias: 'order', // Optional: key used in the payload (defaults to model name)
);
}The optional alias parameter controls the key under which the model data is nested in the workflow context. For example, with alias: 'order', templates use {{order.total}} instead of {{Order.total}}.
4. Controlling the Payload (PayloadProvider)
By default, Voodflow serializes the public properties of your event class using reflection. To take full control of what data the workflow receives, implement PayloadProvider on your event:
use Voodflow\Voodflow\Contracts\PayloadProvider;
class InvoicePaid implements PayloadProvider
{
public function __construct(
public readonly Invoice $invoice,
public readonly string $paidBy,
) {}
public function toVoodflowPayload(): array
{
return [
'invoice' => [
'id' => $this->invoice->id,
'number' => $this->invoice->number,
'total' => $this->invoice->total,
'status' => $this->invoice->status,
],
'paid_by' => $this->paidBy,
'paid_at' => now()->toIso8601String(),
];
}
}The array returned by toVoodflowPayload() becomes the root context of the workflow execution. All {{tags}} in downstream nodes resolve against this structure.
5. Customizing the Event Identifier (IdentifiableEvent)
By default, Voodflow uses the fully-qualified class name (FQCN) as the trigger identifier. If you want to use a stable, human-friendly string (for example to maintain compatibility across refactors), implement IdentifiableEvent:
use Voodflow\Voodflow\Contracts\IdentifiableEvent;
class InvoicePaid implements IdentifiableEvent
{
public function voodflowEventIdentifier(): string
{
return 'myplugin.invoice.paid';
}
}Changing the identifier of an existing event will break any workflow triggers already pointing to the old identifier. Use this when first creating the event, not as a retroactive refactor.
Full Example
A typical plugin ServiceProvider integrating all mechanisms:
namespace Vendor\MyPlugin;
use Illuminate\Support\ServiceProvider;
use Voodflow\Voodflow\Voodflow;
use Vendor\MyPlugin\Events\InvoicePaid;
use Vendor\MyPlugin\Events\SubscriptionExpired;
use Vendor\MyPlugin\Models\Invoice;
use Vendor\MyPlugin\Models\Subscription;
class MyPluginServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Register events in the trigger picker
Voodflow::registerEvent(
eventClass: InvoicePaid::class,
name: 'Invoice Paid',
description: 'Fired when an invoice payment is confirmed',
group: 'MyPlugin',
);
Voodflow::registerEvent(
eventClass: SubscriptionExpired::class,
name: 'Subscription Expired',
group: 'MyPlugin',
);
// Expose model fields for tag resolution
// (only needed if the models don't already implement HasVoodflow)
Voodflow::registerModelFields(
modelClass: Subscription::class,
fields: [
'essential' => [
'id' => 'ID',
'plan' => 'Plan',
'expires_at' => 'Expires At',
],
],
alias: 'subscription',
);
}
}Dispatch events from anywhere in your plugin as normal:
event(new InvoicePaid($invoice, auth()->id()));
event(new SubscriptionExpired($subscription));Interface Summary
| Interface / Class | Namespace | Purpose |
|---|---|---|
HasVoodflow | Voodflow\Voodflow\Contracts | Declare field schema on a model |
PayloadProvider | Voodflow\Voodflow\Contracts | Return a custom payload array from an event |
IdentifiableEvent | Voodflow\Voodflow\Contracts | Override the trigger identifier string |
Voodflow::registerEvent() | Voodflow\Voodflow\Voodflow | Register an event in the UI picker at runtime |
Voodflow::registerModelFields() | Voodflow\Voodflow\Voodflow | Register field schema for a third-party model |