Skip to main content
FiQueLa allows you to write custom scalar functions and plug them directly into your queries. A custom function is a PHP class that extends one of the provided base classes and implements two methods.

Base classes

ClassNamespaceUse when
SingleFieldFunctionFQL\Functions\Core\SingleFieldFunctionYour function operates on a single field
MultipleFieldsFunctionFQL\Functions\Core\MultipleFieldsFunctionYour function takes multiple fields or mixed arguments
NoFieldFunctionFQL\Functions\Core\NoFieldFunctionYour function takes no field argument (e.g. generators)

Required methods

Every custom function must implement two methods:
MethodUsed inSignatureDescription
__invokeSingleFieldFunction, MultipleFieldsFunction__invoke(array $item, array $resultItem): mixedCalled for each row with the source row and computed result fields.
__invokeNoFieldFunction__invoke(): mixedCalled for each row with no arguments.
__toStringAll__toString(): stringReturns the FQL string representation of the function call.
For SingleFieldFunction and MultipleFieldsFunction: $item contains the raw source row; $resultItem contains fields already computed for the current row. Use $this->getFieldValue($field, $item, $resultItem) to resolve field names against both.

Example: SingleFieldFunction

The following example appends a _custom suffix to any string field.
use FQL\Functions\Core\SingleFieldFunction;

class CustomSuffix extends SingleFieldFunction
{
    public function __invoke(array $item, array $resultItem): mixed
    {
        $value = (string) $this->getFieldValue($this->field, $item, $resultItem);
        return $value . '_custom';
    }

    public function __toString(): string
    {
        return sprintf('customSuffix(%s)', $this->field);
    }
}
Use $this->field to access the field name passed to the constructor.

Example: MultipleFieldsFunction

The following example concatenates multiple fields with a pipe separator.
use FQL\Functions\Core\MultipleFieldsFunction;

class PipeJoin extends MultipleFieldsFunction
{
    public function __invoke(array $item, array $resultItem): mixed
    {
        $parts = [];
        foreach ($this->fields as $field) {
            $value = $this->getFieldValue($field, $item, $resultItem);
            if ($value !== null) {
                $parts[] = (string) $value;
            }
        }
        return implode('|', $parts);
    }

    public function __toString(): string
    {
        return sprintf('pipeJoin(%s)', implode(', ', $this->fields));
    }
}
Use $this->fields (an array) to access all field arguments.

Example: NoFieldFunction

The following example returns the current PHP memory usage.
use FQL\Functions\Core\NoFieldFunction;

class MemoryUsage extends NoFieldFunction
{
    public function __invoke(): mixed
    {
        return memory_get_usage(true);
    }

    public function __toString(): string
    {
        return 'memoryUsage()';
    }
}

Using a custom function in a query

Pass an instance of your custom function to ->custom(), then chain ->as() to assign an alias.
use FQL\Query\Provider;

$query = Provider::fromFile('./data/products.json')
    ->from('data.products')
    ->select('id', 'name')
    ->custom(new CustomSuffix('name'))->as('suffixedName')
    ->custom(new PipeJoin('id', 'sku', 'ean'))->as('compositeKey')
    ->custom(new MemoryUsage())->as('memBytes');
Custom functions are scalar — they run once per row, not once per group. To build a custom aggregate function, implement FQL\Interface\InvokableAggregate and FQL\Interface\IncrementalAggregate directly.

Field resolution helpers

Base classes provide a getFieldValue helper that resolves a field name from the source row or the already-computed result row:
// Resolves from $item first, then from $resultItem (computed aliases)
$value = $this->getFieldValue('price', $item, $resultItem);

// Quoted strings are returned as literal values
$literal = $this->getFieldValue('"hello"', $item, $resultItem); // returns 'hello'