Functions and Singletons
Beyond entity sets, OData services can expose functions (parameterized queries) and singletons (named single instances).
Functions
A function is a side-effect-free operation that returns a value. Functions are declared in the schema and bound to a resolver.
Declaring a function
php
use LaravelUi5\OData\Edm\EdmFunction;
use LaravelUi5\OData\Edm\FunctionParameter;
use LaravelUi5\OData\Edm\Container\FunctionImport;
use LaravelUi5\OData\Edm\Type\PrimitiveType;
use LaravelUi5\OData\Edm\Contracts\Container\PrimitiveTypeEnum;
$int32 = new PrimitiveType(PrimitiveTypeEnum::Int32);
$string = new PrimitiveType(PrimitiveTypeEnum::String);
// Function without parameters
$countFunc = new EdmFunction(
name: 'GetFlightCount',
returnType: $int32,
);
$countImport = new FunctionImport('GetFlightCount', $countFunc);
// Function with parameters
$byOriginFunc = new EdmFunction(
name: 'GetFlightsByOrigin',
returnType: $int32,
parameters: [new FunctionParameter('origin', $string)],
);
$byOriginImport = new FunctionImport('GetFlightsByOrigin', $byOriginFunc);Registering on the builder
php
$builder
->addFunction($countFunc)
->addFunction($byOriginFunc)
->addFunctionImport($countImport)
->addFunctionImport($byOriginImport);Binding a resolver
php
use LaravelUi5\OData\Service\Contracts\FunctionResolverInterface;
use LaravelUi5\OData\Service\Contracts\QueryPlanInterface;
use LaravelUi5\OData\Protocol\Planning\FunctionInvocationPlan;
protected function bindFunctions(RuntimeSchemaBuilderInterface $builder): void
{
$container = $builder->getEdmx()->getEntityContainer();
$builder->bindFunctionImport(
$container->getFunctionImport('GetFlightCount'),
new class implements FunctionResolverInterface {
public function resolve(QueryPlanInterface $plan): mixed
{
return Flight::count();
}
},
);
$builder->bindFunctionImport(
$container->getFunctionImport('GetFlightsByOrigin'),
new class implements FunctionResolverInterface {
public function resolve(QueryPlanInterface $plan): mixed
{
/** @var FunctionInvocationPlan $plan */
$origin = $plan->parameters['origin']->value ?? null;
return Flight::where('origin', $origin)->count();
}
},
);
}Calling functions via URL
GET /odata/GetFlightCount()
GET /odata/GetFlightsByOrigin(origin='lhr')EdmFunction constructor parameters
| Parameter | Type | Default | Purpose |
|---|---|---|---|
name | string | required | Function name |
isBound | bool | false | Bound to a type or set |
isComposable | bool | false | Result can be further queried |
returnType | ?TypeInterface | null | Return type |
returnsCollection | bool | false | Returns a collection |
isReturnTypeNullable | bool | true | Return may be null |
parameters | list<FunctionParameterInterface> | [] | Parameters |
annotations | list<AnnotationInterface> | [] | Annotations |
FunctionParameter constructor parameters
| Parameter | Type | Default | Purpose |
|---|---|---|---|
name | string | required | Parameter name |
type | TypeInterface | required | Parameter type |
isCollection | bool | false | Collection parameter |
isNullable | bool | true | Nullable parameter |
facets | ?TypeFacetsInterface | null | Type facets |
annotations | list<AnnotationInterface> | [] | Annotations |
Singletons
A singleton is a named single entity instance. It is addressable by name (not by key) and always returns one entity.
Declaring a singleton
php
use LaravelUi5\OData\Edm\Container\Singleton;
$defaultFlightSingleton = new Singleton('DefaultFlight', $flightType);
$builder->addSingleton($defaultFlightSingleton);Binding a resolver
php
use LaravelUi5\OData\Service\Contracts\SingletonResolverInterface;
$builder->bindSingleton(
$container->getSingleton('DefaultFlight'),
new class implements SingletonResolverInterface {
public function resolve(): array
{
return ['id' => 0, 'origin' => 'default', 'destination' => 'default'];
}
},
);Querying a singleton
GET /odata/DefaultFlight
GET /odata/DefaultFlight?$select=origin,destinationThe singleton appears in the service document with "kind": "Singleton".