# Operations

OData's operations allow for completely customized interactions with the service, outside the data-driven CRUD capabilities seen so far. Through operations, you can perform remote procedure calls that operate like static methods, or class instance methods on entities and entity sets.

Lodata supports both Functions (opens new window) and Actions (opens new window). By OData convention operations that define themselves as Functions MUST return data and MUST have no observable side effects, and Actions MAY have side effects when invoked and MAY return data. Lodata does not enforce the side effect restriction, but does enforce the return data requirement.

Lodata can expose operations on uninstantiated classes, class instances and anonymous functions. If a class name is provided, the class will be resolved to an instance via the Laravel service container (opens new window) for every operation call. If an instance is provided, it will be re-used for each invocation of the operation.

The simplest way to expose a method on a resolvable class is to decorate it with the LodataFunction or LodataAction attribute, and then to use auto-discovery on the class. If using a version of PHP that does not support attributes, or operations containing anonymous functions then operations can be created manually.

TIP

As you implement these examples in your own application it is useful to observe changes to the model in the CSDL metadata documents.

In the examples that follow each has the code provided by a class using attributes, an alternative using manual setup or an anonymous function, the request in cURL format, and the expected response. All of these examples can be used with the same syntax for actions.

# Hello World!

Here is the simple 'Hello world!' example. We create a class with a method, decorate the method with the LodataFunction attribute, and pass the class into discovery. The OData identifier is taken from the method name. The inline example shows the same functionality by creating an Operation and attaching an anonymous function.

# Return types

If the return type of the method is void then Lodata assumes an Edm.String response. To properly type a string response you can add the PHP return type string.

This method also works with int (converted to Edm.Int64), float (converted to Edm.Double), bool (converted to Edm.Boolean) and array (converted to a collection).


To use more specific OData types such as Edm.DateTimeOffset you can use Lodata's Type objects as return types:

# Arguments

Arguments can be specified for the callback, and then supplied as key/value pairs in the URL (or the body for actions).


More complex arguments using OData types can also be passed. Here we have an Edm.DateTimeOffset and an Edm.Duration, where the duration is added to the timestamp, and the new value returned.

TIP

Here the get() method is used to return the Carbon object contained within the DateTimeOffset, and the float number of seconds within the Duration.

# Nullable types

In the previous examples none of the arguments or the return types supported being null. You can type-hint that an argument can be null. For Action operations, the return type can be nullable.

# Bound parameters

Internally, OData URLs are resolved through function composition. This enables the output of one operation to be passed into the input of the next operation, as the second operation's "bound parameter".

In this example, the DateTimeOffset generated by the first function call is automatically inserted as the bound parameter of the second function call.

A further use of path composition is to pick a property from an entity and pass it into a function. For example a function that took an Edm.Date as its bound property and returned the age of the person could be called as: http://localhost:8000/odata/people/1/dob/age().

# Binding entities

In addition to primitive types, entities picked from a set can be passed into a function. In this example a simple collection is defined, and the URL picks the first one by its entity ID and passes it into the function using its binding parameter.

# Returning entities

Generated entities can also be returned from an operation. In this case the return type of randomperson() is Entity. The returned entity type must be configured for OData to present it in the metadata document. This can be specified in the attribute's name parameter. In this example a random person entity is created by the operation.

# Parameter aliases

A parameter alias can be used in place of an inline parameter value. The value for the alias is specified as a separate query option using the name of the parameter alias.

For example via the function import EmployeesByManager, passing 3 for the ManagerID parameter:

http://localhost:8000/odata/EmployeesByManager(ManagerID=@p1)?@p1=3
1

# Class instances

A class instance can be provided for the operation, and the same instance will be called with each invocation.

# Namespacing

Operations can be namespaced to provide more organization for unbound functions and actions on the model.

# Transaction

To provide additional context to a Function that may require it, the Function can ask for the current Transaction by adding that argument to the method. In this example the example method would receive the Transaction on the $transaction parameter. The transaction contains all the available context for the request, and can provide information such as the current system query options.

public class MethodResponder {
    #[LodataFunction]
    public function example(Transaction $transaction): string
    {
      return $transaction->getRequest()->getMethod();
    }
}
1
2
3
4
5
6
7

# Upgrading from 3.x

Lodata 3 had a completely different way of describing operations, this section briefly describes a previous example and the more simplified layout of the new example.