PHPackages                             laravelui5/odata - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. laravelui5/odata

ActiveLibrary[HTTP &amp; Networking](/categories/http)

laravelui5/odata
================

Multi-OData endpoint support for Laravel

v1.0.0(2d ago)06↑1900%MITPHPPHP ^8.4

Since Apr 6Pushed 2d agoCompare

[ Source](https://github.com/laravelui5/odata)[ Packagist](https://packagist.org/packages/laravelui5/odata)[ Docs](https://github.com/laravelui5/odata)[ RSS](/packages/laravelui5-odata/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (14)Versions (2)Used By (0)

laravelui5/odata
================

[](#laravelui5odata)

A read-only OData v4 engine for Laravel 11+, built for OpenUI5 frontends.

This package is a clean-room rewrite of [flat3/lodata](https://github.com/flat3/lodata). Its protocol test suite served as the pivot: ~400 HTTP tests define the OData wire contract the new implementation must honor. No original implementation code was preserved; only relevant, refactored tests remain, forming the permanent regression suite.

What it does
------------

[](#what-it-does)

- read-only [OData v4](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html) engine
- Supports multiple service endpoints
- Supports schema caching (no discovery at request time; `php artisan odata:cache` pre-compiles the EDM to PHP classes)
- Serves `$metadata`, service documents, entity collections, single entities, navigation, functions, singletons
- Full query support: `$filter`, `$select`, `$orderby`, `$expand` (nested), `$top`, `$skip`, `$count`, `$search`, `$compute`
- Supports `$batch` with partial failure
- Supports server-driven paging via `Prefer: odata.maxpagesize`
- Serves streamed responses (large result sets never buffer in memory)

Requirements
------------

[](#requirements)

- PHP 8.4+
- Laravel 11+

Installation
------------

[](#installation)

```
composer require laravelui5/odata
```

The service provider registers automatically. Publish the config:

```
php artisan vendor:publish --tag=config --provider="LaravelUi5\OData\ODataServiceProvider"
```

Quick start
-----------

[](#quick-start)

### 1. Define a service

[](#1-define-a-service)

```
namespace App\OData;

use LaravelUi5\OData\ODataService;
use LaravelUi5\OData\Driver\Sql\EloquentEntitySetResolver;
use LaravelUi5\OData\Edm\Container\EntitySet;
use LaravelUi5\OData\Edm\Contracts\Container\PrimitiveTypeEnum;
use LaravelUi5\OData\Edm\Property\Property;
use LaravelUi5\OData\Edm\Type\EntityType;
use LaravelUi5\OData\Edm\Type\PrimitiveType;
use LaravelUi5\OData\Service\Contracts\EdmBuilderInterface;
use LaravelUi5\OData\Service\Contracts\RuntimeSchemaBuilderInterface;

class PartnerService extends ODataService
{
    public function serviceUri(): string  { return 'partners'; }
    public function namespace(): string   { return 'io.pragmatiqu.partners'; }

    protected function configure(EdmBuilderInterface $builder): EdmBuilderInterface
    {
        $this->discoverModel(Partner::class);

        return $builder->namespace($this->namespace());
    }
}
```

### 2. Register the service

[](#2-register-the-service)

Create a registry that returns your service:

```
namespace App\OData;

use LaravelUi5\OData\Service\Contracts\ODataServiceInterface;
use LaravelUi5\OData\Service\Contracts\ODataServiceRegistryInterface;

class AppServiceRegistry implements ODataServiceRegistryInterface
{
    public function services(): array
    {
        return [new PartnerService()];
    }

    public function resolve(string $fullPath): ODataServiceInterface
    {
        return new PartnerService();
    }
}
```

Point the config at it in `config/odata.php`:

```
'service_registry' => App\OData\AppServiceRegistry::class,
```

### 3. Use it

[](#3-use-it)

```
GET /odata/partners/Partners              → entity collection
GET /odata/partners/Partners(1)           → single entity
GET /odata/partners/Partners?$filter=name eq 'Acme'
GET /odata/partners/Partners?$select=id,name&$top=10&$orderby=name
GET /odata/partners/$metadata             → CSDL XML

```

Configuration
-------------

[](#configuration)

Published to `config/odata.php`:

KeyDefaultDescription`prefix``odata`URL route prefix`middleware``[]`Middleware for OData routes`streaming``true`Stream JSON responses`namespace``com.example.odata`Default XML namespace`version``4.0`OData protocol version`service_registry``ODataServiceRegistry::class`Registry implementation`pagination.max``null`Server max page size cap`pagination.default``200`Default page size when client sends no preferenceSchema caching
--------------

[](#schema-caching)

For production, pre-compile the EDM object graph to PHP classes:

```
php artisan odata:cache    # generates Edm/ directory next to each service class
php artisan odata:clear    # removes generated Edm/ directories
```

Cached classes are plain `readonly` PHP implementing `Edm\Contracts\` interfaces. On warm boot, `ODataService::schema()` loads them directly — skipping the builder entirely.

Architecture
------------

[](#architecture)

Three concentric layers. Each layer only depends on the layers inside it.

```
Http\         → routes requests to the engine
Protocol\     → parses OData URLs, plans queries, executes via handlers
Service\      → contracts, builders, caching, serialization
Edm\          → pure read-only metamodel (zero framework dependencies)
Driver\       → implements resolver contracts (Eloquent/SQL)

```

Services declare their schema in `configure()` (what the service looks like) and bind resolvers in `bindResolvers()` (how to fetch the data). The engine never touches the schema after planning — it works entirely from the resolved query plan.

Roadmap
-------

[](#roadmap)

Post-GA improvements for the extensibility layer:

- **Serialize EDXML** on `odata:cache` and serve XML directly
- **In-memory filter/sort/paginate helpers for custom resolvers.** Tier 3 (fully custom) resolvers must interpret the filter AST, ordering, and pagination themselves. A small utility (e.g. `InMemoryFilter::apply($rows, $plan)`) would reduce boilerplate for resolvers backed by REST APIs, PHP computation, or other non-SQL sources.
- **Nullable column declaration in AbstractEntitySet.** `columns()` maps names to `PrimitiveTypeEnum` but cannot express nullability. Marking a column nullable currently requires overriding `entityType()`. A declarative option (e.g. nullable enum wrapper or separate `nullable()` method) would close this gap.
- **Composite key order validation.** `entityType()` resolves key properties in column-declaration order, not in the order returned by `key()`. A validation warning during schema build would catch accidental reordering.
- **Discovery logging for skipped relations.** Polymorphic and through-relations on Eloquent models are silently ignored during discovery. A `logger->debug()` message would help developers understand why a navigation property is absent from `$metadata`.

Not in scope (by design)
------------------------

[](#not-in-scope-by-design)

- Write operations (POST/PUT/PATCH/DELETE)
- ETags / conditional requests
- `$apply` (aggregation)
- Actions

License
-------

[](#license)

MIT

###  Health Score

42

—

FairBetter than 89% of packages

Maintenance99

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

2d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/23b715678ce3da96c250994583e20daf46d15b55ce8de931d77d1b5db4b84a35?d=identicon)[mgerzabek](/maintainers/mgerzabek)

---

Top Contributors

[![mgerzabek](https://avatars.githubusercontent.com/u/1590082?v=4)](https://github.com/mgerzabek "mgerzabek (1 commits)")

---

Tags

laravelmodularizationodataodata-serverodatav4openui5laravelrestodata

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/laravelui5-odata/health.svg)

```
[![Health](https://phpackages.com/badges/laravelui5-odata/health.svg)](https://phpackages.com/packages/laravelui5-odata)
```

###  Alternatives

[omniphx/forrest

A Laravel library for Salesforce

2724.4M8](/packages/omniphx-forrest)[api-platform/laravel

API Platform support for Laravel

59126.4k5](/packages/api-platform-laravel)[flat3/lodata

OData v4.01 Producer for Laravel

96320.9k](/packages/flat3-lodata)[dragon-code/laravel-http-logger

Logging incoming HTTP requests

319.8k3](/packages/dragon-code-laravel-http-logger)[bjerke/laravel-bread

A boilerplate package for BREAD operations through REST API in Laravel

115.2k](/packages/bjerke-laravel-bread)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
