Domain concept in Extbase

The domain layer is where you define the core logic and structure of your application — things like entities, value objects, repositories, and validators.

See https://en.wikipedia.org/wiki/Domain-driven_design for more in-depth information.

The Classes/Domain/ folder contains the domain logic of your Extbase extension. This is where you model real-world concepts in your application and define how they behave.

While Domain-Driven Design (DDD) suggests putting business-related services in the Domain layer, in most TYPO3 extensions you will actually see service classes placed in: Classes/Service/. It is also possible to put them in Classes/Domain/Service/.

Basic example of a model with a repository in Extbase

This example shows a basic model (representing a scientific paper in real life) and its corresponding repository.

packages/my_extension/Classes/Domain/Model/Paper.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Domain\Model;

use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;

class Paper extends AbstractEntity
{
    protected string $title = '';
    protected string $author = '';

    public function getTitle(): string
    {
        return $this->title;
    }

    public function setTitle(string $title): void
    {
        $this->title = $title;
    }

    public function getAuthor(): string
    {
        return $this->author;
    }

    public function setAuthor(string $author): void
    {
        $this->author = $author;
    }
}
Copied!

Properties that will be persisted must be declared as protected or public.

To make properties available in Fluid templates, you must provide either a public property or a public getter method (starting with get, has, or is).

This repository follows Extbase's naming conventions and may stay empty unless custom queries are needed.

packages/my_extension/Classes/Domain/Repository/PaperRepository.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Domain\Repository;

use MyVendor\MyExtension\Domain\Model\Paper;
use TYPO3\CMS\Extbase\Persistence\Repository;

/**
 * @extends Repository<Paper>
 */
class PaperRepository extends Repository {}
Copied!

Extbase automatically detects which model the repository belongs to based on the naming convention <ModelName>Repository. No registration is necessary.

The PHPDoc @extends Repository<Paper> annotation helps static analysis tools (like PHPStan or Psalm) and IDEs with type inference and autocompletion.

By default a model is persisted to a database table with the following naming scheme: tx_[extension]_domain_model_[model].php. To create and define the database table use TCA configuration:

packages/my_extension/Configuration/TCA/tx_myextension_domain_model_paper.php
<?php

return [
    'ctrl' => [
        'title' => 'Paper',
        'label' => 'title',
        'delete' => 'deleted',
    ],
    'columns' => [
        'title' => [
            'label' => 'Title',
            'config' => [
                'type' => 'input',
                'eval' => 'trim,required',
            ],
        ],
        'author' => [
            'label' => 'Author',
            'config' => [
                'type' => 'input',
                'eval' => 'trim',
            ],
        ],
    ],
    'types' => [
        '0' => [
            'showitem' => 'title, author',
        ],
    ],
];
Copied!

Subfolders of Classes/Domain/

Typical subfolders include:

Model

Contains domain entities, value objects, DTOs, and enums. These define your application's core data structures and behaviors.

Repository

Repositories provide methods for retrieving and saving domain objects. They abstract persistence logic from the rest of the application.

Validator

Provides custom validators for domain objects. Use these to enforce business rules and validate object states.