MVC pattern and request flow in Extbase
Extbase structures extensions around the Model-View-Controller (MVC) pattern. MVC separates three concerns that have a tendency to become entangled in less structured code:
- Model — what your data looks like and how it is persisted
- View — how the data is presented to the user
- Controller — what happens when an HTTP request arrives and which data the response should contain
To make this concrete: a visitor clicks "Read more" on an event listing. The
browser sends an HTTP GET request to a URL like
/events?tx_.
The controller receives that request, asks the model layer (the
repository) for the
Event with UID 42, hands the object to the
view, and the view renders it as HTML. Each layer does one job and one
job only.
Keeping these three things separate means you can change how data is stored without touching the templates, and change the output format without touching the business logic. It also means that any TYPO3 developer who knows Extbase can immediately orient themselves in an unfamiliar extension.
On this page
The three Extbase layers
- Model
-
Domain objects — PHP classes that represent the data your extension works with. An event, a product, a blog post. Models extend
\TYPO3\and are stored inCMS\ Extbase\ Domain Object\ Abstract Entity Classes/. Their properties map to database columns. Models know nothing about HTTP, templates, or how they are displayed.Domain/ Model/ Repositories sit alongside models and are the only entry point to the database. A controller never queries the database directly — it asks a repository for objects.
- View
- Fluid templates in
Resources/. The view receives variables from the controller and renders them as HTML (or JSON, or any other format). The view knows nothing about where data came from or what triggered the request.Private/ Templates/ - Controller
- The coordinator. It receives a request, asks repositories for the data it
needs, hands that data to the view, and returns a response. Controllers live
in
Classes/and extendController/ \TYPO3\.CMS\ Extbase\ Mvc\ Controller\ Action Controller
The strict separation is intentional. When something goes wrong, you know exactly which layer to look at.
How a request flows through Extbase
When TYPO3 renders a page containing an Extbase plugin, the following sequence happens:
-
TYPO3 hands off to Extbase
The plugin content element is rendered by the TYPO3 content object renderer. Control passes to
\TYPO3\, which reads the plugin configuration to determine which extension and plugin is involved.CMS\ Extbase\ Core\ Bootstrap -
An Extbase request object is built
The PSR-7 server request is wrapped in an Extbase
\TYPO3\object. This object carries the controller name, action name, and any arguments extracted from the URL or POST data — for example, the UID of a record to display.CMS\ Extbase\ Mvc\ Request -
The dispatcher resolves the controller
\TYPO3\looks up which controller class corresponds to the requested controller name and instantiates it via the DI container.CMS\ Extbase\ Mvc\ Dispatcher -
The controller action runs
The dispatcher calls
processon the controller. The controller resolves the action method name (for exampleRequest () listorAction show), maps incoming arguments to typed PHP parameters via property mapping, runs validation, and then calls the action method.Action -
The action builds the response
Inside the action, the controller assigns variables to the view and returns a
Response. For a standard HTML response this means callingInterface $this->html, which renders the matching Fluid template and wraps the output in a PSR-7 response.Response () -
TYPO3 renders the response into the page
The rendered HTML is returned to the content object renderer and inserted into the page at the position of the plugin content element.
Note
If an action calls
$this->redirect or returns a
\TYPO3\, the dispatcher loops and
processes the new target action before returning a final response. This is
how multi-step flows (for example: form → validate → confirm) work within a
single page request.
Controller actions in Extbase
Each public method in a controller whose name ends in
Action is a
potential action. The action name in the URL is the method name without the
Action suffix, lowercased:
list is addressed as
action=list.
Actions can declare typed parameters. Extbase's property mapping resolves them automatically from the request:
use MyVendor\MyExtension\Domain\Model\Event;
use Psr\Http\Message\ResponseInterface;
public function showAction(Event $event): ResponseInterface
{
$this->view->assign('event', $event);
return $this->htmlResponse();
}
When the URL contains event=42, Extbase loads the
Event object
with UID 42 from the repository and passes it directly to the action. You never
write a repository lookup for this — the framework handles it.
Primitive types work the same way: a parameter typed
int receives an
integer,
string a string. Validation runs before the action is called;
if it fails,
error handles the error rather than your action
running with invalid data.
Extbase action responses
Actions must return a
\Psr\. The two most
common helpers on
\TYPO3\ are:
$this->html— renders the Fluid template matching the current action and returns a 200 HTML responseResponse () $this->json— returns a 200 JSON response; use withResponse () \TYPO3\to control which properties are serialisedCMS\ Extbase\ Mvc\ View\ Json View
For redirects and forwards:
$this->redirect— sends a 303 redirect to another action('list') return new \— passes control to another action within the same request, without a redirectTYPO3\ CMS\ Extbase\ Http\ Forward Response ('list')
See also
ActionController: actions, arguments and responses — the full controller reference, including argument handling, error actions, and backend controllers.
Extbase domain model — how models and repositories work.
View layer in Extbase — Fluid templates and response types.