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:
$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.
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:
#[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:
#[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:
$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:
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 responseCardController→ Blade-rendered JSON manifestResourceController→ 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 Type | Purpose | Mechanism | Reaches |
|---|---|---|---|
| Path | Domain context | #[Parameter] | invoked artifacts |
| Body | Payload / mutation | FormRequest → DTO | invoked artifacts |
| Settings | Runtime configuration | #[Setting] | invoked artifacts |
| Slots | Resolved 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.