In classical TYPO3 extensions the frontend functionality is divided into
several frontend plugins. Normally each has a separate code base.
In contrast, there is only one code base in Extbase (a series of controllers and
actions). Nevertheless, it is possible to group controllers and actions
to make it possible to have multiple frontend plugins.

Why two files?

You may wonder why you need to edit both, file ext_localconf.php and file
Configuration/TCA/Overrides/tt_content.php, to configure a plugin. The reason lays in the architecture of TYPO3:
file ext_localconf.php is evaluated in the frontend and file Configuration/TCA/Overrides/tt_content.php in
the backend. Therefore, in file Configuration/TCA/Overrides/tt_content.php we add the entry to the plugin list (for
the backend). In addition, the list of controller / action combinations is required at runtime
in the frontend - and therefore this must be defined in the file file ext_localconf.php.

For the definition of a plugin, the files ext_localconf.php and Configuration/TCA/Overrides/tt_content.php
have to be adjusted.

In ext_localconf.php resides the definition of permitted controller action
Combinations. Also here you have to define which actions should not be cached.
In Configuration/TCA/Overrides/tt_content.php there is only the configuration of the plugin selector for the
backend. Let's have a look at the following two files:

In addition to the extension key and a unique name of the plugin (line 2 and 3),
the allowed combinations of the controller and actions are determined.
$controllerActionCombinations is an associative array. The Keys of this array
are the allowed controllers, and the values are a comma-separated list of
allowed actions per controller. The first action of the first controller is the
default action.

Additionally you need to specify which actions should not be cached. To do this,
the fourth parameter also is a list of controller action Combinations in the
same format as above, containing all the non-cached-actions.

Configuration/TCA/Overrides/tt_content.php:

\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin('Vendor.ExtensionName','ExamplePlugin','Title used in Backend');

The first two arguments must be completely identical to the definition in
ext_localconf.php.

Below there is a complete configuration example for the registration of a
frontend plugin within the files ext_localconf.php and Configuration/TCA/Overrides/tt_content.php.

Example B-1: Configuration of an extension in the file ext_localconf.php

The plugin name is Blog. It is important that the name is exactly the same
in ext_localconf.php and
Configuration/TCA/Overrides/tt_content.php. The default called method is
indexAction() of controller class
Vendor\ExampleExtension\Controller\BlogController since it's the first
element defined in the array and the first action in the list.

All actions which change data must not be cacheable. Above, this is for example
the deleteAction() action in the
Vendor\ExampleExtension\Controller\BlogController controller. In the
backend you can see "A Blog Example" in the list of plugins (see Figure B-1).

Figure B-1: In the selection field for frontend plugins, the name which was defined in the
file Configuration/TCA/Overrides/tt_content.php will be displayed

Furthermore, Extbase is clearing the TYPO3 cache automatically for update processes. This is called
Automatic cache clearing. This functionality is activated by default. If a domain object is
inserted, changed or deleted, then the cache of the corresponding page in which the object is
located is cleared. Additionally the setting
of TSConfig TCEMAIN.clearCacheCmd is evaluated for this page.

Figure B-2 is an example that is explained below:

Figure B-2: For the sysfolder in which the data was stored, the setting
TCEMAIN.clearCacheCmd defines that the cache of
the page Blog should be emptied.

The frontend plugin is on the page Blog with the 11. As a storage folder for all the Blogs and
Posts the SysFolder BLOGS is configured. If an entry is changed, the cache of the SysFolder
BLOGS is emptied and also the TSConfig configuration
TCEMAIN.clearCacheCmd for the SysFolder is evaluated.
This contains a comma-separated list of Page IDs, for which the cache should be emptied. In this
case, when updating a record in the SysFolder BLOGS (e.g. Blogs, Posts, Comments), the cache of
the page Blog, with ID 11, is cleared automatically, so the changes are immediately visible.

Even if the user enters incorrect data in a form (and this form will be
displayed again), the cache of the current page is deleted to force a new
representation of the form.

Each Extbase extension has some settings which can be modified using TypoScript. Many of these
settings affect aspects of the internal Configuration of Extbase and Fluid. There is also a block
settings in which you can set Extension specific settings, which can be accessed in the
controllers and Templates of your extensions.

Tip

These options are always available. Integrators can use them to configure the behaviour, even
if not intended or provided by the author of the extension.

plugin.tx_[lowercasedextensionname]

The TypoScript configuration of the extension is always located below this
TypoScript path. The "lowercase extension name" is the extension key with no
underscore (_), as for example in blogexample. The configuration is divided into
the following sections:

Here reside are all the domain-specific extension settings. These settings are
available in the controllers as the array variable $this->settings and in any Fluid
template with {settings}.

Tip

The settings allow you to pass arbitrary information to a template, even for 3rd party extensions.
Just make sure you prefix them with a unique vendor to prevent collisions with further updates
of the extensions.

This can be used to specify the root paths for all fluid layouts in this
extension. If nothing is specified, the path
extensionName/Resources/Private/Layouts is used. All layouts that are necessary
for this extension should reside in this folder.

view.partialRootPaths

This can be used to specify the root paths for all fluid partials in this
extension. If nothing is specified, the path
extensionName/Resources/Private/Partials is used. All partials that are
necessary for this extension should reside in this folder.

view.pluginNamespace

This can be used to specify an alternative namespace for the plugin.
Use this to shorten the Extbase default plugin namespace or to access
arguments from other extensions by setting this option to their namespace.
.. todo: This is not understandable without an example.

view.templateRootPaths

This can be used to specify the root paths for all fluid templates in this
extension. If nothing is specified, the path
extensionName/Resources/Private/Templates is used. All layouts that are necessary
for this extension should reside in this folder.

All root paths are defined as array which enables you to define multiple root paths that
will be used by Extbase to find the desired template files.

The feature is best described by an example.
Imagine you installed the extension news, which provides several plugins for
rendering news in the frontend.

The default template directory of that extension is the following:

EXT:news/Resources/Private/Templates/

Let's assume you want to change the output of the plugins because you need to use
different css classes for example. You can simply create your own extension and
add the following TypoScript setup:

Imagine there is a news plugin that lists news entries. In that case, the listAction method
of the NewsController will be called. By convention, Extbase will look for an html file
called List.html in a folder News in all of the configured template root paths.

If there is just one root path configured, that's the one being chosen right away. Once there
are more paths defined, Extbase will check them in reverse order i.e. from highest key
to lowest. Following our example, Extbase will check the given path with key 10 first and if
no template file is found, it will proceed with 0.

Tip

If there is no root path defined at all, a fallback path will be created during runtime.
The fallback path consists of the extension key and a fixed directory path.

More information on root paths can be found in the TypoScript reference:
templateRootPaths

Under this key you can modify localized strings for this extension.
If you specify for example plugin.tx_blogexample._LOCAL_LANG.default.read_more=More>> then the standard translation for the key read_more is overwritten by the
string More>>.

The MVC Framework is the heart of Extbase. Below we will give you an overview of
the class hierarchy for the controllers and the API of the ActionControllers.

Normally you will let your controllers inherit from ActionController. If you
have special requirements that can not be realized with the ActionController,
you should have a look at the controllers below.

\TYPO3\CMS\Extbase\Mvc\Controller\ControllerInterface

This basic interface that must be implemented by all controllers.

TYPO3\CMS\Extbase\Mvc\Controller\AbstractController

Abstract controller with the basic functionality of the ControllerInterface.

TYPO3\CMS\Extbase\Mvc\Controller\ActionController

The most widely used controller in Extbase. It extends the AbstractController. An overview of its API is given in
the following section.

TYPO3\CMS\Extbase\Mvc\Controller\CommandController

Extend this controller if you want to provide commands to the scheduler or command line
interface.

If no fluid template is found for the current action, Extbase attempts to find a
PHP-View-Class for the action. The naming scheme of the PHP-View-Class can be
changed here. By default names are used according to the scheme
@vendor@extensionView@controller@action@format. All string-parts marked with @
are replaced by the corresponding values. If no view class with this name is
found, @format is removed from the pattern and again tried to find a view class
with that name.

By overriding this method you can build and configure a completely individual
view object. This method should return a complete view object. In general,
however, it is sufficient to overwrite resolveViewObjectName().

resolveViewObjectName()

Resolves the name of the view object, if no suitable fluid template could be
found.

All public and protected methods that end in action (for example indexAction or showAction),
are automatically registered as actions of the controller.

Many of these actions have parameters. These appear as annotations in the Doc-Comment-Block
of the specified method, as shown in Example B-3:

Example B-3: Actions with parameters

<?phpdeclare(strict_types=1);namespaceEx\BlogExample\Controller;useTYPO3\CMS\Extbase\AnnotationasExtbase;useTYPO3\CMS\Extbase\Mvc\Controller\ActionController;classBlogControllerextendsActionController{/** * Displays a form for creating a new blog, optionally pre-filled with partial information. * * @param \Ex\BlogExample\Domain\Model\Blog $newBlog A fresh blog object which should be taken * as a basis for the form if it is set. * * @return void * * @Extbase\IgnoreValidation("newBlog") */publicfunctionnewAction(\Ex\BlogExample\Domain\Model\Blog$newBlog=NULL){$this->view->assign('newBlog',$newBlog);}}

It is important to specify the full type in the @param annotation as this is used for the validation
of the object. Note that not only simple data types such as String, Integer or Float can be validated,
but also complex object types (see also the section "Validating domain objects" in Chapter 9).

In addition, on actions showing the forms used to create domain objects, the validation of domain
objects must be explicitly disabled - therefore the annotation
@TYPO3\CMS\Extbase\Annotation\IgnoreValidation is necessary.

Default values can, as usual in PHP, just be indicated in the method signature. In the above case,
the default value of the parameter $newBlog is set to NULL. If an action returns NULL or nothing,
then automatically $this->view->render() is called, and thus the view is rendered.

Sometimes it is necessary to execute code before calling an action. For example, if complex
arguments must be registered or required classes must be instantiated.

There is a generic initialization method called initializeAction(), which is called after
the registration of arguments, but before calling the appropriate action method itself. After the
generic initializeAction(), if it exists, a method named initialize[ActionName]() is called.
Here you can perform action specific initializations (e.g. initializeShowAction()).

If an argument validation error has occurred, the method errorAction() is called. There,
in $this->argumentsMappingResults you have a list of occurred warnings and errors of the argument
mappings available. This default errorAction refers back to the referrer, if the referrer
was sent with it.

All repositories inherit from \TYPO3\CMS\Extbase\Persistence\Repository. A repository is always
responsible for precisely one type of domain object. The naming of the repositories is important:
If the domain object is, for example, Blog (with full name \\Ex\\BlogExample\\Domain\\Model\\Blog),
then the corresponding repository is named BlogRepository (with full name
\\Ex\\BlogExample\\Domain\\Repository\\BlogRepository).

Create a Query object within the repository through $this->createQuery(). You can give the query
object a constraint using $query->matching($constraint). The following comparison operations for
generating a single condition are available:

$query->equals($propertyName,$operand,$caseSensitive);

Simple comparison between the value of the property provided by $propertyName and the operand.
In the case of strings you can specified additionally, whether the comparison is case-sensitive.

$query->in($propertyName,$operand);

Checks if the value of the property $propertyName is present within the series of values in $operand.

$query->contains($propertyName,$operand);

Checks whether the specified property $propertyName containing a collection has an element
$operand within that collection.

$query->like($propertyName,$operand);

Comparison between the value of the property specified by $propertyName and a string $operand.
In this string, the %-character is interpreted as placeholder (similar to * characters in search
engines, in reference to the SQL syntax).

$query->lessThan($propertyName,$operand);

Checks if the value of the property $propertyName is less than the operand.

$query->lessThanOrEqual($propertyName,$operand);

Checks if the value of the property $propertyName is less than or equal to the operand.

$query->greaterThan($propertyName,$operand);

Checks if the value of the property $propertyName is greater than the operand.

$query->greaterThanOrEqual($propertyName,$operand);

Checks if the value of the property $propertyName is greater than or equal to the operand.

Since 1.1 (TYPO3 4.3) $propertyName is not necessarily only a simple property-name but also can be a "property path".

Example: $query->equals('categories.title','tools') searches for objects having a category titled
"tools" assigned. If necessary, you can combine multiple conditions with boolean operations.

$query->logicalAnd($constraint1,$constraint2);

Two conditions are joined with a logical and, it gives back the resulting condition. Since Extbase
1.1 (TYPO3 4.3) also an array of conditions is allowed.

$query->logicalOr($constraint1,$constraint2);

Two conditions are joined with a logical or, it gives back the resulting condition. Since Extbase
1.1 (TYPO3 4.3) also an array of conditions is allowed.

$query->logicalNot($constraint);

Returns a condition that inverts the result of the given condition (logical not).

You can write your own validators for domain models. These must be located in
the folder Domain/Validator/, they must be named exactly as the corresponding
Domain model, but with the suffix Validator and implement the interface
\TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface. For more details, see the
following Section.

Extbase provides a generic validation system which is used in many places in Extbase. Extbase
provides validators for common data types, but you can also write your own validators. Each
Validator implements the \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface
that defines the following methods:

validate($value)

Checks whether the object that was passed to the validator is valid. If not,
a \TYPO3\CMS\Extbase\Validation\Error object should be returned.

getOptions()

Enables you to define validator options. These options apply to any further call
of the method validate().

You can call Validators in your own code with the method createValidator($validatorName,$validatorOptions) in \TYPO3\CMS\Extbase\Validation\ValidatorResolver. Though in
general, this is not necessary. Validators are often used in conjunction with domain objects and
controller actions.

In this code section, the validators for the $title attribute of the Blog object is defined. $title
must be a text (ie, no HTML is allowed), and also the length of the string is checked with the
StringLength-Validator (it must be between 1 and 80 characters). Several validators for a property
can be separated by commas. Parameter of the validators are set in parentheses. You can omit the
quotes for validator options if they are superfluous as in the example above. If complex validation
rules are necessary (for example, multiple fields to be checked for equality), you must implement
your own validator.

If the argument has a simple type (string, integer, etc.), this type is checked.

If the argument is a domain object, the annotations @TYPO3\CMS\Extbase\Annotation\Validate in the domain object is taken into
account and - if set - the appropriate validator in the folder Domain/Validator for the
existing domain object is run.

If there is set an annotation @TYPO3\CMS\Extbase\Annotation\IgnoreValidation for the argument,
no validation is done.

Additional validation rules can be specified via further @TYPO3\CMS\Extbase\Annotation\Validate annotations in the methods
PHPDoc block.

If the arguments of an action can not be validated, then the errorAction is executed, which will
usually jump back to the last screen. It is important that validation is not performed in certain
cases. Further information for the usage of the annotation @TYPO3\CMS\Extbase\Annotation\IgnoreValidation see
"Case study: Edit an existing object" in Chapter 9.

Multilingual websites are widespread nowadays, which means that the
web-available texts have to be localized. Extbase provides the helper class
\TYPO3\CMS\Extbase\Utility\LocalizationUtility for the translation of the labels. In addition,
there is the Fluid ViewHelper <f:translate>, with the help of whom you can use that
functionality in templates.

The localization class has only one public static method called translate, which
does all the translation. The method can be called like this:

The identifier to be translated. If then format LLL:path:key is given, then this
identifier is used and the parameter $extensionName is ignored. Otherwise, the
file Resources/Private/Language/locallang.xlf from the given extension is loaded
and the resulting text for the given key in the current language returned.

$extensionName

The extension name. It can be fetched from the request.

$arguments

Allows you to specify an array of arguments passed to the function vsprintf. Allows you to
fill wildcards in localized strings with values.