Coming from Lodata
If your Laravel app serves OData through flat3/lodata today, this page maps what you have onto laravelui5/odata. The protocol is the same, and so is the idea of turning Eloquent models into entity sets. What changes is the shape: a service class instead of a facade call, and an engine that only reads. Why this package exists at all is told in a post of its own.
1. Install and configure
composer require laravelui5/odata
php artisan vendor:publish --provider="LaravelUi5\OData\ODataServiceProvider"Most keys in config/odata.php carry the name you know from config/lodata.php:
config/lodata.php | config/odata.php | |
|---|---|---|
prefix | prefix | default odata, so clients keep their URL |
middleware | middleware | |
streaming | streaming | |
namespace | namespace | |
version | version | default 4.0 |
pagination.max, pagination.default | pagination.max, pagination.default | default page size 200 |
readonly | none | the engine is always read-only |
authorization | read_authorizer | a class instead of a gate, see §4 |
discovery.* | none | there is no discovery cache; the schema cache is odata:cache (Caching) |
| none | service_registry | which service answers a request, see §2 |
2. From discover() to a service class
In Lodata, models are discovered in a service provider:
// app/Providers/AppServiceProvider.php
public function boot(): void
{
\Lodata::discover(\App\Models\User::class);
}Here they are bound in a service class, in configure():
namespace App\OData;
use App\Models\User;
use LaravelUi5\OData\ODataService;
use LaravelUi5\OData\Service\Contracts\EdmBuilderInterface;
class AppService extends ODataService
{
public function serviceUri(): string
{
return '';
}
public function namespace(): string
{
return 'com.example.odata';
}
protected function configure(EdmBuilderInterface $builder): EdmBuilderInterface
{
$this->discoverModel(User::class);
return $builder->namespace($this->namespace());
}
}An empty serviceUri() puts the service at the root of the prefix, /odata/, where Lodata served its model. Entity sets are named the same way, as the plural of the model: User becomes Users.
Where Lodata used one of its own entity set drivers (a SQL query, a collection, a data source of your own), configure() takes a custom entity set:
$this->discoverCustomEntitySet(\App\OData\ActiveCustomers::class);How to write one, from a plain SQL view to a fully custom source, is on custom entity sets.
Finally, tell the package which service answers. The default registry serves an empty service, so a registry of your own is required, even for one service:
namespace App\OData;
use LaravelUi5\OData\Service\Contracts\ODataServiceInterface;
use LaravelUi5\OData\Service\Contracts\ODataServiceRegistryInterface;
class ServiceRegistry implements ODataServiceRegistryInterface
{
public function resolve(string $fullPath): ODataServiceInterface
{
return new AppService();
}
public function services(): array
{
return [new AppService()];
}
}// config/odata.php
'service_registry' => App\OData\ServiceRegistry::class,A registry that returns different services for different paths is how several services share one app; see multiple services.
3. Keeping fields out
Lodata leaves out a list of sensitive property names during discovery (discovery.blacklist). Here there is no list; you decide per model. Eloquent's $hidden keeps a column's value out of every response, but the column still appears in $metadata. To keep it out of the schema as well, mark it #[ODataIgnore], or give the set an entity type of its own with only the columns you want. Both are on model discovery.
4. Authorization
Lodata asks a gate named lodata about every request once authorization is switched on. Here a read authorizer is bound in config/odata.php (read_authorizer). It sees the parsed query plan and records a verdict per entity set: allow, deny the request, or drop an $expand the actor may not see. The contract and an example are on read authorization.
5. Writes
With readonly switched off, Lodata creates, updates and deletes entities. laravelui5/odata does not: PUT, PATCH, DELETE and every POST outside $batch are refused. Writes stay in your application, in controllers or actions with their own validation. With LaravelUi5 Core, a write is a Ui5Action.
6. Functions
Lodata's operations become functions: declared on the builder in configure() and bound to a resolver in bindFunctions(). Actions, the writing kind of operation, are not supported. See functions and singletons.
7. What does not come across
$apply, the aggregation extension. A request with it is answered with501.- Asynchronous requests.
- An OpenAPI document.
- Connection files for Excel and Power BI. Both connect with the service URL instead; see Excel and Power BI.
8. Check it
Point your client at the new $metadata and compare it with Lodata's: entity set names, property types, keys. Then run the requests your client sends. The query options ($filter, $select, $expand, $orderby, $top, $skip, $count, $search, $compute) are each documented under Query Options.