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(WorkflowVersion $version): void — wires up whatever delivers events for a given workflow (a route, a cron entry, a model listener). Called at application boot once for the published version of each workflow using this trigger.

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\WorkflowVersion;
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(WorkflowVersion $version): void
{
// e.g. nothing to do — your existing Stripe webhook controller calls
// Workflow::run($version->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 the published version of every workflow whose trigger type matches. Workflows that have never been published are skipped. $version carries the published content — $version->workflow_id, $version->version, $version->trigger['config'], $version->nodes, and so on. 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 published version'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.

Upgrading: register() previously received the Workflow model. Change the parameter to WorkflowVersion $version and read the workflow id from $version->workflow_id.

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.