Skip to main content

Custom triggers

A trigger is a node that starts a workflow. It extends Qanna\WorkflowEngine\Trigger (itself a Node), so it has the same type() / label() / schema() descriptors, plus:

  • handle(WorkflowContext $context, array $config = []): TriggerResult — decides whether an incoming payload should start an execution.
  • register(Workflow $workflow): void — wires up whatever delivers events for a given workflow (a route, a cron entry, a model listener). Called once per workflow using this trigger, at application boot.

Generate one

php artisan workflow:make-node StripeEventTrigger --trigger --type=app::stripe-event
namespace App\Workflows\Triggers;

use Qanna\WorkflowEngine\Engine\Context\WorkflowContext;
use Qanna\WorkflowEngine\Engine\Schema\Schema;
use Qanna\WorkflowEngine\Models\Workflow;
use Qanna\WorkflowEngine\Trigger;
use Qanna\WorkflowEngine\TriggerResult;

class StripeEventTrigger extends Trigger
{
public static function type(): string
{
return 'app::stripe-event';
}

public static function label(): string
{
return 'Stripe event';
}

public static function schema(): array
{
return [
Schema::select('event')->options([
'invoice.paid' => 'Invoice paid',
'customer.subscription.deleted' => 'Subscription cancelled',
])->required(),
];
}

public function handle(WorkflowContext $context, array $config = []): TriggerResult
{
$payload = $context->get('payload');

if (($payload['type'] ?? null) !== $config['event']) {
return TriggerResult::ignore('event type mismatch');
}

return TriggerResult::continue($payload);
}

protected function register(Workflow $workflow): void
{
// e.g. nothing to do — your existing Stripe webhook controller calls
// Workflow::run($workflow->id, $stripeEvent) for every matching workflow.
}
}

TriggerResult

ConstructorMeaning
TriggerResult::continue($output = null)Start an execution. $output is recorded as the trigger step's output.
TriggerResult::ignore($reason = null)Don't start. Workflow::run() returns null; a workflow.trigger-ignored hook fires with the reason.

The engine resolves {{ }} expressions in the trigger's saved config before calling handle(), the same as it does for nodes.

register()

Runs at boot for every workflow whose trigger type matches. Use it to subscribe to the outside world. The built-in triggers show the patterns:

  • Webhook registers a POST route per workflow.
  • Schedule adds an entry to Laravel's scheduler.
  • Model event attaches Eloquent event listeners.

Because this happens at boot, a newly saved workflow's trigger is not wired up until the next boot — your app and queue workers must be restarted. The interactive builder reminds you of this.

Registering the trigger

use Qanna\WorkflowEngine\Engine\NodeRegistry;

$this->app->make(NodeRegistry::class)->register([
\App\Workflows\Triggers\StripeEventTrigger::class,
], 'trigger');

Registering under the 'trigger' category is what makes the engine call the trigger's register() at boot and offer it in workflow:build.