Using the engine in Laravel
The container binding
The service provider registers Engine as a singleton, constructed
from config('expression-engine'). Resolve it however you normally
resolve services:
use Qanna\ExpressionEngine\Engine;
class EvaluateWorkflowStep
{
public function __construct(private Engine $engine) {}
public function handle(array $context): bool
{
return (bool) $this->engine->evaluate($this->step->condition, $context);
}
}
Because it's a singleton, any custom methods or functions you
register persist for the rest of the request —
register them once, in a service provider's boot().
The facade
Qanna\ExpressionEngine\Facades\ExpressionEngine proxies the same
singleton:
use Qanna\ExpressionEngine\Facades\ExpressionEngine;
ExpressionEngine::resolve('Hi {{ trigger.user.name }}', $context);
ExpressionEngine::evaluate('trigger.order.total > 100', $context);
Every method listed in the Engine API reference is available on the facade.
Templated payloads with resolveArray()
A common Laravel use is a stored action — a notification, an outgoing
webhook, a queued job's parameters — whose fields contain {{ }}
placeholders. resolveArray() resolves them all in one call:
$payload = ExpressionEngine::resolveArray([
'url' => $action->endpoint,
'headers' => [
'X-Order-Ref' => '{{ trigger.order.ref }}',
],
'body' => [
'customer' => '{{ trigger.order.customer.name }}',
'total' => '{{ trigger.order.total }}',
'line_count' => '{{ trigger.order.lines.count() }}',
'is_priority' => '{{ trigger.order.total > 500 }}',
],
], ['trigger' => ['order' => $order->toArray()]]);
Http::post($payload['url'], $payload['body']);
String fields that are a single placeholder keep their real type —
total stays numeric, is_priority stays boolean, line_count stays an
integer. See the single-expression
exception.
Passing Eloquent data as context
The engine reads arrays, so hand it ->toArray() output (or any array
you assemble):
ExpressionEngine::evaluate('trigger.order.lines.filter(current.shipped).count()', [
'trigger' => ['order' => $order->load('lines')->toArray()],
]);
Strict mode per call
The container binding uses the configured strict value. If one caller
needs the opposite behaviour, construct a dedicated instance:
$strict = new Engine([...config('expression-engine'), 'strict' => true]);
Trying expressions interactively
php artisan expression:playground opens a REPL against a live engine and
context — see the CLI reference. It's the fastest
way to check what an expression does before you store it.