Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Odata Laravel Package

laravelui5/odata

Laravel UI5 OData adds OData service support to Laravel, letting you expose Eloquent models with query options such as $filter, $select, $expand, $orderby, and $count. It integrates with Laravel routing and is designed for SAPUI5/OpenUI5 frontends.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This package sits directly on top of Laravel's Eloquent layer and derives its OData $metadata from Schema::getColumns(), so it fits any Laravel application whose domain is already modelled as Eloquent relations. It is not a generic OData framework bolted onto PHP — it is a discovery-and-translation layer whose quality is bounded by how faithfully Eloquent models describe the schema. That is a good fit for teams already standardised on Laravel, and a poor fit where the data model lives outside Eloquent or where the schema is intentionally hand-authored.

What v3.1.0 changes in kind, not just degree. Three of the changes are correctness fixes that alter observable behaviour:

  • Metadata is now expressive. Nullable, Precision/Scale and MaxLength are emitted from the column schema, and #[ODataProperty(nullable:)] finally takes effect. Clients (notably UI5 V4 types) treat these as enforced constraints, so the contract between server and UI tightens.
  • Discovery stops lying about polymorphic relations. MorphTo, MorphToMany and MorphOneOrMany are excluded outright, on the grounds that no ReferentialConstraint can express a type-column join. This removes previously advertised navigation properties.
  • The filter and key paths refuse rather than guess. Untranslatable constructs now answer 501 unsupported_filter, malformed comparisons 400 invalid_filter, and bad key literals 400 invalid_key. Previously these returned 200 with silently wrong result sets.

Integration feasibility. High for greenfield or well-modelled Laravel services. The new ColumnFacetResolverInterface seam (bound with bindIf, one binding, default ColumnFacetsAsDeclared) is a clean extension point for installation-wide facet policy — e.g. announcing an installation-wide price scale over a decimal(19,6) column. TypeFacets gaining withNullable()/withMaxLength()/withPrecision()/withScale()/isDefault() makes resolvers cheap to write without copying facets by hand. Validation is fail-fast: a LogicException at schema build time when facets don't fit the Edm type, so misconfiguration surfaces in CI, not in production traffic.

Technical risk.

  • Behavioural break disguised as a minor version. Clients that depended on $filter=false returning everything, on unsupported functions returning everything or nothing, or on Products(abc) coercing to Products(0), will now see 400/501. This is the correct direction, but it is a consumer-visible contract change shipping under a 3.1.0 label.
  • Silent removal of polymorphic navigations. Any client or report reading those navigation properties will fail at runtime with no metadata entry to explain why.
  • Cache asymmetry. odata:cache previously dropped facets, collection flags and default values, so a warm service announced a different schema than a cold one. That is fixed, but the corollary is that every existing cache is stale relative to v3.1.0 and must be rebuilt — and after rebuild, the new facets will appear to clients.
  • Streaming versus status codes. EntitySetHandler now runs the query to the first row before committing the response, so refusals and SQL errors carry their real status. Rows still stream. This is a genuine improvement, but it shifts the first-byte latency and changes how client-side error handling must be written.

Key questions for engineering. Do we have consumers of polymorphic navigation properties, and what are the explicit alternatives from services/model-discovery? What is the package's stated BC policy for these refusal semantics, and do we pin to 3.1.x? Which facet overrides are installation facts versus model facts, and who owns the resolver binding? Does any client rely on the old @odata.nextLink shape (<Set>?$skip=n)?

Integration Approach

Stack fit. Laravel + Eloquent + this package + a UI5 V4 (or Excel/Power BI) consumer is the intended shape. The release notes call out UI5 explicitly — sap.ui.model.odata.type.Decimal now formats with the right scale, and V4 types read Nullable and MaxLength as two-way binding constraints. Teams on UI5 get the most value; teams consuming via generated OData clients get schema fidelity but must regenerate proxies.

Migration path.

  1. Pin 3.1.0 in a branch, run the suite, and diff cold $metadata against the currently served document. Treat the diff as the migration spec.
  2. Rebuild every odata:cache artefact and confirm warm output is byte-identical to cold — the package ships a test asserting this, but our own resolvers need the same guarantee.
  3. Decide and register ColumnFacetResolverInterface before the first production cache build. Because it is a single bindIf binding, provider order does not matter, but ownership does: agree one owner or the binding silently loses.
  4. Audit clients for the removed polymorphic navigations and for pagination that assumed the old @odata.nextLink.
  5. Roll out server-first, then clients, with a short window where clients tolerate both status-code behaviours.

Compatibility. $expand=lines($count=true) is additive and safe — one withCount sub-select per counted navigation, computed under the expand's $filter and not limited by its $top/$skip, and it survives $select. $batch parts correctly use their own URL for nextLink. The parser now accepts in and spaced lambdas (id in (1,3), nav/any(p: p/name eq 'x'), ( id eq 1 ), contains( name , 'x' )), which widens the accepted grammar without breaking valid prior queries. tolower/toupper translating to LOWER()/UPPER() fixes UI5's case-insensitive filters. None of these require client changes; the refusals do.

Sequencing. Metadata rebuild and cache rebuild are one atomic step and must precede any client release. Facet overrides must be settled before the cache is built, because the resolver runs at build time and a cached service keeps the value returned then.

Operational Impact

Maintenance. The consolidation of both translators under AbstractFilterTranslator is the single most valuable operational change here: filter and search semantics can no longer drift apart, and the refusal taxonomy (501 unsupported_filter, 400 invalid_filter, 400 invalid_expand, 501 unsupported_expand, 400 invalid_key, 400 parse_error) gives on-call a precise vocabulary. Expect a modest maintenance load for the resolver seam — it is a new extension point with one binding and no chain, so policy composition must be done inside a resolver, not across several.

Support. Two new ticket classes will appear immediately after rollout: (a) clients receiving 400/501 where they previously received 200 with wrong data — these are wins, but they will be reported as regressions; (b) clients missing navigation properties for polymorphic relations. Pre-empt both with a changelog entry and a client-facing note before deploy.

Scaling. $expand with $count adds one withCount sub-select per counted navigation at any nesting depth — depth-multiplied cost is possible and should be bounded by policy. Facet resolution runs at schema-build time only, so it is a cold-start cost, not a per-request cost, provided the cache is warm. Streaming is preserved, which keeps memory flat for large sets.

Failure modes.

  • Stale cache serving a superseded schema. Because the resolver's output is frozen at build time, an installation fact change (a currency's decimal policy, say) requires a cache rebuild — otherwise warm and cold diverge silently again, which is exactly the 3.0.3 enum failure repeating.
  • LogicException at cold build only. A facet/type mismatch throws when the schema is built. A deployment that never builds cold can carry a broken resolver undetected; CI must build cold every time.
  • Silent data loss from a warm cache masking a resolver bug — mitigated by the identical-warm-and-cold test, but only for the cases that test covers.
  • Errors surfacing before the first row now return their true status, which is correct, but any client that parsed a 200 body and ignored the status will misbehave.

Ramp-up. Engineers need working knowledge of Eloquent schema introspection, the OData ABNF subset actually parsed (now including in and spaced lambdas, whitespace around parens/commas, and mirrored comparisons like 3 lt id), and the facet rules per Edm type — Scale and Precision only on Edm.Decimal, Precision additionally on temporal types, MaxLength only on Edm.String/Edm.Binary, and never a Scale above its Precision. Front-end engineers need the UI5 V4 type story, because Nullable="false" and MaxLength are now enforced in two-way bindings. Budget roughly a day for a backend engineer and half a day for a UI5 engineer, plus a joint session on the metadata diff.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console