Skip to main content

List operations

filter(), map(), sort(), any(), every() (and its alias all()) run an expression once per item in a list. Inside that expression, the item currently being processed is available as current.

$engine->evaluate('trigger.items.filter(current.active)', [
'trigger' => ['items' => [
['name' => 'Widget', 'active' => true],
['name' => 'Gadget', 'active' => false],
]],
]);
// → [['name' => 'Widget', 'active' => true]]

current

current is the per-item value. For a list of records it's the record; for a list of scalars it's the scalar:

// list of records
$engine->evaluate('trigger.items.map(current.name)', $context);
// → ["Widget", "Gadget"]

// list of scalars
$engine->evaluate('trigger.scores.filter(current > 50)', ['trigger' => ['scores' => [40, 75, 90]]]);
// → [75, 90]

current can appear anywhere in the per-item expression — in a comparison, inside a method chain, inside a nested method's arguments, or inside a function call:

$engine->evaluate('trigger.items.filter(current.name.startsWith(current.prefix))', $context);
$engine->evaluate('trigger.items.filter(coalesce(current.active, false))', $context);

The operations

filter(predicate)

Keeps items for which the predicate is truthy. Returns a re-indexed list.

$engine->evaluate('trigger.orders.filter(current.total > 100)', $context);

map(transform)

Replaces each item with the result of the transform expression.

$engine->evaluate('trigger.items.map(current.price * 1.1)', $context);
$engine->evaluate('trigger.users.map(current.name.upper())', $context);

sort(by)

Sorts the list. With no argument, sorts values directly. With a current expression, sorts by the value that expression produces for each item. Does not mutate the input.

$engine->evaluate('trigger.nums.sort()', ['trigger' => ['nums' => [3, 1, 2]]]);
// → [1, 2, 3]

$engine->evaluate('trigger.items.sort(current.price)', $context);

any(predicate) / every(predicate) / all(predicate)

any() returns true if the predicate is truthy for at least one item. every() (and its alias all()) returns true only if it's truthy for every item. Both return a bool, not a list.

$engine->evaluate('trigger.cart.items.any(current.price > 100)', $context);
$engine->evaluate('trigger.cart.items.every(current.inStock)', $context);

Chaining and nesting

List operations return lists, so they chain with each other and with any other array method:

$engine->evaluate(
'trigger.items.filter(current.active).map(current.name.upper()).first()',
$context,
);
// → "WIDGET"

They also nest — a predicate can itself run a list operation over a nested list:

$engine->evaluate(
'trigger.orders.filter(current.items.any(current.price > 100)).map(current.id)',
$context,
);
// → orders that contain at least one item over 100

In a nested operation, current refers to the item of the innermost operation currently running.

Non-current predicates pass through

filter() and map() only apply their per-item logic when the argument actually references current. An argument that doesn't (a constant, or a plain path) is passed to the underlying method as a value — in practice you always want a current expression here.

Grouping

groupBy(key) is related but not a current operation — it buckets a list of records by the value of a field:

$engine->evaluate('trigger.orders.groupBy("status")', $context);
// → ['paid' => [...], 'pending' => [...]]