Validation in Extbase
Extbase validates incoming request arguments automatically before your action
method is called. If validation fails, the framework calls
error instead of the intended action. Use
# on a parameter to let an action receive an object
even if it is invalid — for example to redisplay a form with its errors.
Validators can be Extbase built-ins, custom classes, or — since TYPO3 v14 — Symfony constraints.
On this page
Where validation fits into the Extbase request lifecycle
The sequence for every request that carries arguments is:
- Property mapping — everything arriving from the request is a string or an array of strings. Property mapping converts these into typed PHP values and objects (see Extbase property mapper).
- Validation — the mapped values are checked against any
#attributes declared on the action parameter, on the domain model property, or both. Property validators run first; action parameter validators run afterwards. Either alone is sufficient — both can be combined on the same type.[Validate] - Action dispatch — if validation passes, the action method is called with the resolved arguments.
- Error handling — if validation fails,
erroris called instead. The default implementation redirects the user to the referring request (typically the action that rendered the form), carrying the validation errors so they can be displayed.Action ()
This means you declare what valid data looks like; Extbase decides when to run the checks and where to route the request on failure.
Note
Validation is not limited to form submissions. It runs on every action that receives typed arguments including detail, filter, and search actions that read their input from URL parameters. A record created in the TYPO3 backend may satisfy TCA validation but still fail Extbase model validation when the same record is loaded as an action argument in the frontend. See Extbase model validation and TCA validation are independent for a full explanation.
Where to declare validators
Validators can be declared on action parameters, on domain model properties, or both.
On an action parameter — validates the value passed to an action before the action runs:
use TYPO3\CMS\Extbase\Attribute\Validate;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class ConferenceController extends ActionController
{
public function createAction(
#[Validate('NotEmpty')]
#[Validate('StringLength', options: ['maximum' => 255])]
string $title,
): ResponseInterface {
// $title is guaranteed non-empty and at most 255 characters
}
}
On a domain model property — validates the property every time the model is used as an action argument:
use TYPO3\CMS\Extbase\Attribute\Validate;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
class Conference extends AbstractEntity
{
#[Validate('NotEmpty')]
#[Validate('StringLength', options: ['maximum' => 255])]
protected string $title = '';
}
Placing validators on the model above means that every action that receives a
Conference argument benefits from the same rules,
without having to repeat the attribute on every parameter.
Tip
Validators do not have to live on the persisted domain model. A base model
can carry no validators at all, while separate
DTO classes carry different validator sets
for different use cases — for example a ConferenceRegistrationForm DTO
with strict seat-count validation and a ConferenceDraftForm DTO with
only a title requirement. Each DTO is mapped by property mapping just like
a domain model and can have its own independent validation rules.
When a form submission fails validation, Extbase re-calls the originating
action (typically newAction() or editAction()). If that action has the
model as a typed parameter and declares
# on it,
the Form ViewHelper <f:form> view helper can read the submitted
values from the object and Form.validationResults ViewHelper <f:form.validationResults>
can display the errors inline — the object does not need to be valid for
this to work.
Ignoring the validation result with
#[IgnoreValidation]
Sometimes you need to receive an object without running its validators, for example when displaying a "new" form that is pre-populated from a submitted but invalid object, or when an action intentionally accepts a partially filled model.
Place
# on the parameter to tell Extbase to ignore
the validation result for that argument and dispatch the action regardless:
use TYPO3\CMS\Extbase\Attribute\IgnoreValidation;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class ConferenceController extends ActionController
{
public function newAction(
#[IgnoreValidation]
Conference $conference = null,
): ResponseInterface {
$this->view->assign('conference', $conference ?? new Conference());
return $this->htmlResponse();
}
}
Validation still runs —
# does not skip it. It
instructs Extbase to call the action even when the argument is invalid.
This is what allows
new to receive a partially filled
Conference back from a failed
create and hand it to
the template so f:form can redisplay the submitted values with inline
errors.
Without
#, the framework would see the invalid
Conference, call
error, which redirects back to
new, which would validate again — an infinite cycle.
Customising
errorAction()
The built-in
error adds a generic flash message and redirects the user to the referring request. For most contact or registration forms this
is sufficient.
To show a custom error flash message, override
get:
protected function getErrorFlashMessage(): bool|string
{
return 'Please correct the errors in the form before saving.';
}
Return
false to suppress the flash message.
To completely change how validation errors are handled — for example to return
a JSON response — override
error itself:
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Error\Result;
protected function errorAction(): ResponseInterface
{
$errors = $this->arguments->validate();
return $this->jsonResponse(json_encode([
'errors' => $this->flattenErrors($errors),
]))->withStatus(422); // choose the status code appropriate for your API; 422 or 400 are common choices
}
Displaying validation errors in Fluid templates
Extbase makes validation errors available in Fluid via the
f:form.validationResults view helper. Wrap form fields with it to show
per-field error messages:
<f:form action="create" name="conference" object="{conference}">
<f:form.validationResults for="conference.title">
<f:for each="{validationResults.errors}" as="error">
<p class="error">{error.message}</p>
</f:for>
</f:form.validationResults>
<f:form.textfield property="title" />
<f:form.submit value="Save" />
</f:form>
The for attribute is the dot-notation path to the validated object or
property. Leave it empty to access all errors in the current request.
What to read next
- Built-in validators and the #[Validate] attribute — the full list of validators that ship with Extbase and their configuration options.
- Writing a custom Extbase validator — how to write a validator for domain rules that the built-in validators cannot express.
- Extbase property mapper — how request data is mapped to objects before validation runs.
New in version 14.0
Symfony validators can be used in Extbase directly — see Feature #106945 for details.