Generating URLs with the UriBuilder
The
Uri generates URLs
for Extbase actions. When routing configuration is in place, it produces the
clean URL defined by the matching route variant. Without routing configuration
it produces the raw namespaced query string.
The UriBuilder is available in two contexts: inside a controller action via
$this->uri, and inside Fluid templates via
<f:
and
<f:.
Generating URLs in a controller action
Use
uri to generate a URL for any action. It is available as
$this->uri in any controller action:
<?php
namespace MyVendor\MyExtension\Controller;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class ConferenceController extends ActionController
{
public function listAction(): ResponseInterface
{
$conferences = $this->conferenceRepository->findAll();
// Link to the detail action on the same plugin/page,
// using the first conference as an example
$uri = $this->uriBuilder->uriFor(
'show', // action name — no 'Action' suffix
['conference' => $conferences->getFirst()],
'Conference', // controller name
);
$this->view->assign('conferences', $conferences);
$this->view->assign('detailUri', $uri);
return $this->htmlResponse();
}
}
uri signature:
uriFor(
?string $actionName = null,
?array $controllerArguments = null,
?string $controllerName = null,
?string $extensionName = null,
?string $pluginName = null,
): string
All parameters are optional. When omitted, the current controller, extension,
and plugin are used. Only pass
$extension and
$plugin
when linking to a different plugin than the one handling the current request.
Linking to a plugin on a different page
The most common routing mistake: list and detail are on separate pages, but the list template generates detail links without telling the UriBuilder which page to target. The result is a link back to the list page instead of the detail page.
Use
set before calling
uri.
reset
clears all previously set options — call it before each URL generation inside
a loop:
use MyVendor\MyExtension\Domain\Model\Conference;
use Psr\Http\Message\ResponseInterface;
class ConferenceController extends ActionController
{
public function listAction(): ResponseInterface
{
$conferences = $this->conferenceRepository->findAll();
foreach ($conferences as $conference) {
$uri = $this->uriBuilder
->reset()
->setTargetPageUid(42) // UID of the detail page
->uriFor('show', ['conference' => $conference], 'Conference');
// …
}
return $this->htmlResponse();
}
}
The detail page UID is typically stored in TypoScript settings (or site set settings) so it does not need to be hardcoded:
$detailPageUid = (int)($this->settings['detailPageUid'] ?? 0);
$uri = $this->uriBuilder
->reset()
->setTargetPageUid($detailPageUid)
->uriFor('show', ['conference' => $conference], 'Conference');
Absolute URLs
For use in emails, JSON responses, or redirects, generate an absolute URL:
$uri = $this->uriBuilder
->reset()
->setCreateAbsoluteUri(true)
->uriFor('show', ['conference' => $conference], 'Conference');
Generating URLs in Fluid templates
<f: and
<f: are the Fluid equivalents of
uri. When routing configuration is in place, they produce the
same clean URLs automatically.
<f:link.action action="show" controller="Conference" arguments="{conference: conference}">
{conference.title}
</f:link.action>
To link to a plugin on a different page, use
page:
<f:link.action
action="show"
controller="Conference"
arguments="{conference: conference}"
pageUid="{settings.detailPageUid}"
>
{conference.title}
</f:link.action>
For a plain URL string without an
<a> tag, use
<f:
with the same attributes — useful when you need to construct the link yourself:
<a href="{f:uri.action(action: 'show', controller: 'Conference', arguments: '{conference: conference}', pageUid: settings.detailPageUid)}"
title="{conference.title}"
class="conference-link">{conference.title}</a>
Why is my URL not clean?
If a URL comes out as a raw query string with cHash instead of the
expected clean URL, work through this list:
- No enhancer configured — the plugin has no entry under
routeinEnhancers EXT:ormy_ extension/ Configuration/ Sets/ My Extension/ route- enhancers. yaml config/.sites/<site- identifier>/ config. yaml - Wrong page —
set(orTarget Page Uid () pagein Fluid) is missing or points to the wrong page. The enhancer'sUid limitmust include the target page UID or match the page via an expression.To Pages - No matching route variant — the controller/action combination passed
to
uridoes not match anyFor () _controllerentry in therouteslist inEXT:.my_ extension/ Configuration/ Sets/ My Extension/ route- enhancers. yaml - Missing aspect — a placeholder has a
\d+requirement but no StaticRangeMapper or StaticValueMapper aspect, so TYPO3 cannot treat the parameter as static and appendscHash. - Stale cache — after changing the site configuration, clear all caches via Admin Tools > Maintenance.
With URLs generating correctly, see Routing examples and common mistakes for complete worked examples covering the most common plugin configurations.