Skip to content

Releases: laravelui5/odata

`odata:cache` entity-set / type name collision

05 Jun 12:22

Choose a tag to compare

EdmxWriter::writeEntitySet() emitted each cached entity set as use {ns}\Types\{TypeName}; followed by final readonly class {SetName} implements EntitySetInterface, then called {TypeName}::instance() by short name. When an entity set's name equalled its entity type's name, the import and the class declaration collided and PHP fataled Cannot redeclare class … (previously declared as local import) at autoload time — taking the whole app down, not just OData.

Fix: writeEntitySet() now references the type by FQN — \{$typeFqcn}::instance() (the FQN was already computed locally) — and drops the use {ns}\Types\{TypeName}; line from the generated template. This aligns the method with the rest of EdmxWriter, which already references types by FQN in every other emitter (singleton / type / complex-type / nav-init).

Generator-only change: no runtime behaviour, EDMX shape, or wire format moves — the regenerated classes are byte-identical except for the type reference. Consumers regenerate their Edm/ caches after the bump.

PHP backed enum → Edm.EnumType

06 May 17:32

Choose a tag to compare

Note: this release is additive for primitive-only consumers and surfaces a new opt-in feature for backed-enum columns. It ships as a patch alongside v1.0.2/v1.0.3 because all three current consumers (laravelui5/core, laravelui5/sdk, pragmatiqu/timesheet.biz) are in-house. SemVer credit is spent here deliberately; the next release that crosses the public funnel boundary should bump the major.

Added

  • PHP backed enum → Edm.EnumType bridge. Declare a column as a PHP int-backed enum class-string and the engine reflects it into an <EnumType> element in $metadata and emits the symbolic member name on the wire ("tier":"Single").
public function columns(): array                        
{
    return [                    
        'id'   => EdmPrimitiveType::Int64,
        'tier' => LicenseTier::class,   // ← new 
    ];
}

Implementation lives across EnumType::fromBackedEnum(), AbstractEntitySet::entityType(), EdmBuilder::addEntityType() (now auto-registers enum types it discovers), EdmBuilder::addEnumType() (now idempotent on identical re-registration, throws on same-qualified-name collisions with different definitions), and Protocol\Execution\RowCoercion (per-property value→name lookup, unknown ints fall through unchanged).

Changed

  • EdmBuilder::addEntityType() now walks declared properties to auto-register any EnumTypeInterface it finds on the schema. Consumers never touch addEnumType() directly. Latent inconsistencies (manually pre-registered enum + entity-type-carried enum with diverging definitions) now throw \LogicException at build time.

Migration

No code changes required — composer update picks up the bridge.
EdmPrimitiveType column declarations continue to work exactly as before.

To adopt for an enum-typed column: swap 'tier' => EdmPrimitiveType::Int64 for 'tier' => LicenseTier::class, then drop any UI5 formatter that was reconstructing the label client-side. The new wire payload is what sap.ui.model.odata.type.Enum parses by default.

Out of scope (deferred)

String-backed enums, IsFlags, complex types, POST/PATCH deserialization ("Single" → 1). Open them as new atoms when a consumer asks.

RFC 3339 wire coercion for temporal types

06 May 16:35

Choose a tag to compare

Note: this release contains a wire-format change (UI5 consumers using targetType: 'any' workarounds will see different bytes on the wire). It ships as a patch because all three current consumers (laravelui5/core, laravelui5/sdk, pragmatiqu/timesheet.biz) are in-house and patched in lock-step with the release. SemVer credit is spent here deliberately; a future release that crosses the public funnel boundary should bump the major.

Fixed

  • Edm.DateTimeOffset / Edm.Date / Edm.TimeOfDay wire format. Row-emission path now coerces declared temporal columns to OData v4 / RFC 3339 strings before JSON encoding. Previously, MySQL DATETIME/DATE/TIME values (e.g. 2026-05-05 12:34:56) passed through unchanged — invalid per the spec, returning NaN from Date.parse() in Safari and silently coerced to local time in Chrome.

Coercion happens via Carbon::parse(...):

  • Edm.DateTimeOffset->toRfc3339String()
  • Edm.Date->toDateString() (Y-m-d)
  • Edm.TimeOfDay->format('H:i:s')

Null values on nullable columns pass through. Already-correct strings round-trip cleanly. Implementation lives in Protocol\Execution\RowCoercion; both EntitySetHandler and EntityHandler apply it.

Migration

No code changes required in consumer PHP. composer update picks up the fix; columns declared as EdmPrimitiveType::DateTimeOffset (or Date / TimeOfDay) start emitting spec-compliant strings automatically.

UI5 frontends should drop two now-obsolete workarounds:

  • targetType: 'any' on bindings against temporal columns — the default type parsers now work correctly.
  • Custom formatters that re-parse MySQL-style strings — the wire is already RFC 3339.

grep -rn "targetType.*'any'" <ui5-source-roots> is a reasonable starting survey.

Edm namespace cleanup

06 May 16:18

Choose a tag to compare

Note: this release is technically API-breaking (enum rename + interface relocations). It ships as a patch because all three current consumers (laravelui5/core, laravelui5/sdk, pragmatiqu/timesheet.biz) are in-house and patched in lock-step with the release. SemVer credit is spent here deliberately; a future release that crosses the public funnel boundary should bump the major.

Changed (breaking)

  • Renamed LaravelUi5\OData\Edm\Contracts\Container\PrimitiveTypeEnumLaravelUi5\OData\Edm\EdmPrimitiveType. The new name describes what the type is (the EDM primitive type) rather than what PHP shape it happens to take (an enum). Drops the dead Enum suffix; gains the Edm prefix shared with Edm.String, Edm.EnumType, etc. Lives flat under Edm\ because vocabulary enums are PHP vehicles, not contracts.
  • Relocated three type-level contracts misfiled under Edm\Contracts\Container\. CSDL §13 reserves EntityContainer for
    EntitySet, Singleton, ActionImport, FunctionImport only; type-level constructs are Schema-level peers of EntityContainer, not children of it. Moved:
    • Contracts\Container\PrimitiveTypeInterfaceContracts\Type\PrimitiveTypeInterface
    • Contracts\Container\EnumTypeInterfaceContracts\Type\EnumTypeInterface
    • Contracts\Container\EnumMemberInterfaceContracts\Type\EnumMemberInterface

After this move Edm\Contracts\Container\ is aligned with the CSDL §13 surface (Container children only) — symmetric with Edm\Container\ on the implementation side.

  • No deprecation alias is shipped. Consumers update use statements and PrimitiveTypeEnum::* references in the same release dance.

Migration

find <consumer-source-roots> -name '*.php' -exec sed -i '' \
    -e 's|LaravelUi5\\OData\\Edm\\Contracts\\Container\\PrimitiveTypeEnum|LaravelUi5\\OData\\Edm\\EdmPrimitiveType|g' \
    -e 's|LaravelUi5\\OData\\Edm\\Contracts\\Container\\PrimitiveTypeInterface|LaravelUi5\\OData\\Edm\\Contracts\\Type\\Primi
  tiveTypeInterface|g' \                                                                                                     
    -e 's|LaravelUi5\\OData\\Edm\\Contracts\\Container\\EnumTypeInterface|LaravelUi5\\OData\\Edm\\Contracts\\Type\\EnumTypeIn
  terface|g' \                                                                                                               
    -e 's|LaravelUi5\\OData\\Edm\\Contracts\\Container\\EnumMemberInterface|LaravelUi5\\OData\\Edm\\Contracts\\Type\\EnumMemb
  erInterface|g' \                                                                                                           
    -e 's|PrimitiveTypeEnum|EdmPrimitiveType|g' \           
    {} \;                                                                                                                    

Afterwards grep for PHP-escaped class-string literals — sed's single-backslash pattern misses 'LaravelUi5\OData\…' (double-backslash in source). The pattern that catches them:

grep -rn 'Contracts\\\\Container\\\\\(EdmPrimitiveType\|PrimitiveTypeInterface\|EnumTypeInterface\|EnumMemberInterface\)' <consumer-source-roots>

Support Laravel 13.x

22 Apr 05:12

Choose a tag to compare

v1.0.1

WIP allow Laravel 13

🎉 LaravelUi5 OData 1.0.0 — First Stable Release

06 Apr 09:19

Choose a tag to compare