Skip to content

Execution Model

LaravelUi5 defines a unified execution model for its executable artifacts: Actions, Resources, and Cards.

The goal of this model is to provide a single, consistent, and declarative way to:

  • locate domain context,
  • validate input,
  • inject configuration,
  • and execute business logic

— while remaining fully Laravel-idiomatic and compatible with UI5’s manifest-driven client paradigm.

1. Core Idea

Executable artifacts declare what they need. The framework fulfills the contract before execution. The artifact itself only contains business logic.

This separation ensures:

  • predictable behavior,
  • early error detection,
  • minimal controller complexity,
  • and a stable foundation for SDK- and platform-level extensions.

2. Executable Artifacts

Three artifact types participate in the execution model:

  • Actions – state-changing operations (POST / PATCH / DELETE), via handle()
  • Resources – read-only domain data endpoints, via provide()
  • Cards – read-only data providers behind a UI5 card manifest, via provide()

All three follow the same execution pipeline, differing only in the invoked method name and the HTTP response format.

What sits outside the pipeline, and why

Tiles, Charts and Reports are also backed by providers, but they are not invoked through ExecutableInvoker. They are slot-driven: their inputs come from the slot pipeline as a resolved name => value bag, and the invoker has no seat for a scalar bag like that — its argument resolution is per-parameter, by name and by type.

So they are invoked through Container::call() instead, with the bag passed explicitly:

php
$container->call([app($report->getProvider()), 'provide'], ['slots' => $slots]);

That is the same mechanism the invoker wraps internally, so service dependencies are still method-injected — but the invoker's Parameter stage is absent, because a Report has no route parameters to resolve. Its Settings still arrive: a provider extending AbstractConfigurable receives the settings its artifact declared, whichever path invokes it.

plannedThe emitter and controller paths have no settings step yet — today only Action, Resource and Card are injected.

The missing Parameter stage is a deliberate boundary, not an omission. The Parameter API contract fixes ExecutableInvoker's shape, and widening it to carry a scalar bag would have made one pipeline serve two genuinely different input models.

3. The Execution Pipeline

Every executable artifact is invoked through the same four-stage pipeline:

3.1 Artifact Resolution

The incoming request is resolved to a concrete artifact via the Ui5ContextInterface bound for the request.

At this point, the framework knows:

  • what is being executed (Action, Card, Resource),
  • and which handler or provider is responsible.

3.2 Parameter Resolution (Domain Context)

Domain-identifying input is declared via #[Parameter] attributes:

php
#[Parameter(
    name: 'user', 
    uriKey: 'user', 
    type: ParameterType::Model, 
    model: User::class
)]

Characteristics:

  • Parameters are positional path segments
  • They define domain context, not payload
  • They are resolved before execution
  • Mismatches result in immediate errors

The ParameterResolver:

  • validates path structure and arity,
  • casts values according to declared types,
  • resolves models where applicable,
  • and returns a typed argument map keyed by parameter name.

3.3 Settings Injection (Runtime Configuration)

Runtime configuration is declared via #[Setting] attributes:

php
#[Setting(
    key: 'maxItems',
    type: ValueType::Integer,
    default: 10,
    note: 'Maximum number of items',
    level: EditLevel::Administrator
)]

Settings characteristics:

  • key–value based
  • JSON-safe primitives
  • UI-editable
  • intentionally weakly referenced
  • not part of the domain model

Settings are declared on the artifact and injected into the handler or provider it points at. In Core they resolve deterministically to their declared defaults — see Settings for the full declaration reference and what the SDK layers on top.

Resolved settings are injected as virtual, read-only properties into the handler or provider instance.

Example usage inside a handler:

php
$this->maxItems;

Rules:

  • No property declaration required
  • No mutation allowed
  • Property name collisions are rejected
  • Access to undeclared settings throws an error

3.4 Payload Validation (FormRequests)

Request bodies (payloads) are never handled via declarative parameters.

Instead, Laravel’s native FormRequest mechanism is used.

If a handler method declares a FormRequest parameter:

php
public function handle(CreateUserRequest $request, User $owner)

The framework will:

  • instantiate the request via the container,
  • execute authorize() and validation,
  • abort on validation failure using standard Laravel error responses,
  • inject the validated request into the method call.

This ensures:

  • full Laravel compatibility,
  • standardized error payloads,
  • no duplication of validation logic.

4. Method Invocation

After parameters and settings are resolved, the framework invokes the target method via Laravel’s container:

  • method signatures are reflected,
  • arguments are matched by name,
  • strict type checks are enforced,
  • invocation is fully container-managed.

All of this is handled centrally by the ExecutableInvoker service.

5. Controllers as Orchestrators

Controllers do not implement execution logic.

Their responsibility is limited to:

  • selecting the correct artifact,
  • choosing the appropriate method to invoke,
  • and formatting the HTTP response.

Examples:

  • ActionDispatchController → JSON response
  • CardController → Blade-rendered JSON manifest
  • ResourceController → JSON data

The execution semantics are identical across those three. ReportController and the dashboard emitters orchestrate the same way but resolve slots instead of calling the invoker (see §2) — ReportController returns text/html with Cache-Control: no-store; export formats are a host or SDK layer on top of that same HTML, never a Core response type.

6. Execution Responsibilities by Input Channel

Input TypePurposeMechanismReaches
PathDomain context#[Parameter]invoked artifacts
BodyPayload / mutationFormRequest → DTOinvoked artifacts
SettingsRuntime configuration#[Setting]invoked artifacts
SlotsResolved contextual values#[Slot]slot-driven artifacts (§2)

Each channel:

  • has a single responsibility,
  • is validated independently,
  • and never overlaps with the others.

7. Design Guarantees

The execution model guarantees that:

  • All required input is validated before business logic runs
  • Handlers are free of framework plumbing
  • Errors surface as early and explicitly as possible
  • Execution behavior is consistent across all artifact types
  • Core remains deterministic and context-free

8. Mental Model (Summary)

If an executable method is called, all declared parameters, settings, and payloads are valid.

This allows developers to focus exclusively on domain logic, while the framework ensures correctness, consistency, and clarity.