ROUTING & HANDLERS FEATURE
Parameterized Route
Path parameters like {slug} are extracted and injected via setters — with regex validation at the router level.
Feature Guide
A quick orientation block that answers the essential questions: what this feature does, how it works, why it matters, and the key concepts behind it.
What this does
Path parameters like {slug} are extracted from the URL and injected into the payload DTO via setter methods.
How it works
The router uses regex requirements to constrain what each parameter matches. The PayloadHydrator calls setters on the payload DTO with the extracted values. Default values are used when a parameter is not present.
Why it matters
Typed path parameters with regex constraints prevent invalid data from reaching handler code. The handler can trust that $payload->slug is always a valid, matched value.
Key concepts
- requirements
- Regex patterns that constrain path parameter values at the routing level.
- PayloadHydrator
- Populates payload DTO properties by calling setter methods with request data.
Verified against Semitexa Ultimate 2026.09.19.1020
Parameterized Route
A path parameter is declared inline in the route pattern and constrained by requirements on the same access attribute. Nothing else registers it — no separate attribute on the property, no route file.
#[AsPublicPayload(
path: '/demo/routing/parameterized/{slug}',
methods: ['GET'],
responseWith: DemoFeatureResource::class,
produces: ['application/json', 'text/html'],
requirements: ['slug' => '[a-z0-9-]+'],
defaults: ['slug' => 'headphones'],
)]
class ParameterizedRoutePayload
{
protected string $slug = '';
public function getSlug(): string
{
return $this->slug;
}
public function setSlug(string $slug): void
{
$this->slug = $slug;
}
}
That is Semitexa\Demo\Application\Payload\Request\Routing\ParameterizedRoutePayload, served live at /demo/routing/parameterized/{slug}.
How the value reaches the payload
PayloadHydrator reads the route pattern and requirements from the payload's access attribute — any attribute extending AbstractPayloadRoute, so this works the same for public, protected and service payloads. It matches the incoming path, then merges the extracted parameters with the request body and query data.
Each value is then applied by setter name. The key is converted from snake_case to camelCase and prefixed with set, so slug looks for setSlug() and a query key user_id looks for setUserId(). A setter that does not exist, or that does not take exactly one required argument, is skipped silently — the property keeps its declared default. This is why the example declares protected string $slug = '' rather than leaving it uninitialised: a typo in the setter name costs you the value, not an error.
There is no property-level attribute involved. If you are looking for something to put above $slug, there isn't one.
Requirements are enforced, not advisory
The regex decides whether the route matches at all. Against the route above:
| Request | Result |
|---|---|
/demo/routing/parameterized/wireless-mouse |
200 |
/demo/routing/parameterized/NOT_VALID |
404 — uppercase and _ fail [a-z0-9-]+ |
A value that fails the constraint never reaches the handler, so handler code can treat $payload->getSlug() as already validated against that pattern. It is a routing constraint, not a validation message: the client gets a 404, not a field error. When you need an explanation instead of a miss, validate in the payload and let payload validation produce the response.
defaults does not make the segment optional
This is the part that surprises people. The route above declares defaults: ['slug' => 'headphones'], and yet:
| Request | Result |
|---|---|
/demo/routing/parameterized |
404 |
/demo/routing/parameterized/ |
404 |
defaults supplies a value when the route is matched without that parameter — it does not make the {slug} segment optional in the pattern. If you want the bare path to work, declare it as its own route, or make the segment optional in the pattern itself.
Checking a live route
routes:show prints the compiled pattern, the payload, and the resolved handler and resource for any route — see routing debugging.
How it works
The router uses regex requirements to constrain what each parameter matches. The PayloadHydrator calls setters on the payload DTO with the extracted values. Default values are used when a parameter is not present.
Why it matters
Typed path parameters with regex constraints prevent invalid data from reaching handler code. The handler can trust that $payload->slug is always a valid, matched value.
Key concepts
- requirements
- Regex patterns that constrain path parameter values at the routing level.
- PayloadHydrator
- Populates payload DTO properties by calling setter methods with request data.