Repository

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 FriendsOfTYPO3\BlogExample\Domain\Model\Blog), then the corresponding repository is named BlogRepository (with the full name FriendsOfTYPO3\BlogExample\Domain\Repository\BlogRepository).

The \TYPO3\CMS\Extbase\Persistence\Repository already offers a large number of useful functions. Therefore in simple classes extending the class Repository and leaving the class empty otherwise is sufficient.

The BlogRepository sets some default orderings and is otherwise empty:

Class T3docs\BlogExample\Domain\Repository\BlogRepository
class BlogRepository extends Repository
{

}

Magic find methods

The class Repository creates "magic" methods to find by attributes of model.

findBy[Property]

Finds all objects with the provided property.

findOneBy[Property]

Returns the first object found with the provided property.

countBy[Property]

Counts all objects with the provided property.

If necessary these methods can also be overridden by implementing them in the concrete repository.

Custom find methods

Custom find methods can be implemented. They can be used, for example, to filter by multiple properties, apply a different sorting. They can also be used for complex queries.

Attention

As Extbase repositories turn the results into objects querying large amounts of data is ressource intensive.

Example:

The PostRepository of the blog example extension implements several custom find methods, two of those shown below:

Class T3docs\BlogExample\Domain\Repository\PostRepository
use T3docs\BlogExample\Domain\Model\Blog;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;

class PostRepository extends Repository
{
    public function findByTagAndBlog(
        string $tag,
        Blog $blog
    ): QueryResultInterface {
        $query = $this->createQuery();
        return $query
            ->matching(
                $query->logicalAnd(
                    $query->equals('blog', $blog),
                    $query->equals('tags.name', $tag)
                )
            )
            ->execute();
    }

    public function findAllSortedByCategory(array $uids): QueryResultInterface
    {
        $q = $this->createQuery();
        $q->matching($q->in('uid', $uids));
        $q->setOrderings([
            'categories.title' => QueryInterface::ORDER_ASCENDING,
            'uid' => QueryInterface::ORDER_ASCENDING,
        ]);
        return $q->execute();
    }
}

Query settings

When the query settings should be used for all methods in the repository, the should be set in the method initializeObject() method.

Class T3docs\BlogExample\Domain\Repository\CommentRepository
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;

class CommentRepository extends Repository
{
    public function initializeObject()
    {
        /** @var QuerySettingsInterface $querySettings */
        $querySettings = GeneralUtility::makeInstance(Typo3QuerySettings::class);
        // Show comments from all pages
        $querySettings->setRespectStoragePage(false);
        $this->setDefaultQuerySettings($querySettings);
    }
}

Attention

Depending on the query settings hidden or even deleted objects can become visible. This might cause sensitive information to be disclosed. Use with care.

When the query settings should only be changed for a certain method they can be set in the method itself:

Class T3docs\BlogExample\Domain\Repository\CommentRepository
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;

class CommentRepository extends Repository
{
    public function findAllIgnoreEnableFields(): QueryResultInterface|array
    {
        $query = $this->createQuery();
        $query->getQuerySettings()->setIgnoreEnableFields(true);
        return $query->execute();
    }
}

Repository API

class TYPO3\CMS\Extbase\Persistence\Repository

The base repository - will usually be extended by a more concrete repository.

injectPersistenceManager(TYPO3\\CMS\\Extbase\\Persistence\\PersistenceManagerInterface $persistenceManager)
Parameters
  • $persistenceManager (TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface) -- the persistenceManager

add(object $object)

Adds an object to this repository

Parameters
  • $object (object) -- The object to add

remove(object $object)

Removes an object from this repository.

Parameters
  • $object (object) -- The object to remove

update(object $modifiedObject)

Replaces an existing object with the same identifier by the given object

Parameters
  • $modifiedObject (object) -- The modified object

findAll()

Returns all objects of this repository.

countAll()

Returns the total number objects of this repository.

removeAll()

Removes all objects of this repository as if remove() was called for all of them.

findByUid(int $uid)

Finds an object matching the given identifier.

Parameters
  • $uid (int) -- The identifier of the object to find

findByIdentifier(mixed $identifier)

Finds an object matching the given identifier.

Parameters
  • $identifier (mixed) -- The identifier of the object to find

setDefaultOrderings(array $defaultOrderings)

Sets the property names to order the result by per default.

Expected like this: array( 'foo' => TYPO3CMSExtbasePersistenceQueryInterface::ORDER_ASCENDING, 'bar' => TYPO3CMSExtbasePersistenceQueryInterface::ORDER_DESCENDING )

Parameters
  • $defaultOrderings (array) -- the defaultOrderings

setDefaultQuerySettings(TYPO3\\CMS\\Extbase\\Persistence\\Generic\\QuerySettingsInterface $defaultQuerySettings)

Sets the default query settings to be used in this repository.

A typical use case is an initializeObject() method that creates a QuerySettingsInterface object, configures it and sets it to be used for all queries created by the repository.

Warning: Using this setter fully overrides native query settings created by QueryFactory->create(). This especially means that storagePid settings from configuration are not applied anymore, if not explicitly set. Make sure to apply these to your own QuerySettingsInterface object if needed, when using this method.

Parameters
  • $defaultQuerySettings (TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface) -- the defaultQuerySettings

createQuery()

Returns a query for objects of this repository

__call(non-empty-string $methodName, array<int, mixed> $arguments)

Dispatches magic methods (findBy[Property]())

Parameters
  • $methodName (non-empty-string) -- The name of the magic method

  • $arguments (array) -- The arguments of the magic method

Typo3QuerySettings and localization

Extbase renders the translated records in the same way TypoScript rendering does.

Changed in version 11.0: Setting Typo3QuerySettings->languageMode was deprecated and does not influence how Extbase queries records.

Typo3QuerySettings->languageOverlayMode = true

Setting Typo3QuerySettings->languageOverlayMode to true makes Extbase fetch records from default language and overlay them with translated values. When a record is hidden in the default language, it is not displayed in the translation. Also, records without translation parents will not be shown.

For relations, Extbase reads relations from a translated record (so it’s not possible to inherit a field value from translation source) and then passes the related records through $pageRepository->getRecordOverlay().

For example: when you have a translated tt_content record with a FAL relation, Extbase will show only those sys_file_reference records which are connected to the translated record (not caring whether some of these files have l10n_parent set).

Typo3QuerySettings->languageOverlayMode = false

Setting Typo3QuerySettings->languageOverlayMode to false makes Extbase fetch aggregate root records from a given language only.

Extbase will follow relations (child records) as they are, without checking their sys_language_uid fields, and then it will pass these records through $pageRepository->getRecordOverlay().

This way, the aggregate root record's sorting and visibility do not depend on the default language records.

Moreover, the relations of a record, which are often stored using default language uids are translated in the final result set (so overlay happens).

Example: Given a translated tt_content record having a relation to two categories (in the mm table translated tt_content record is connected to category uid in default language), and one of the categories is translated. Extbase will return a tt_content model with both categories.

If you want to have just translated category shown, remove the relation in the translated tt_content record in the TYPO3 backend.

Setting the Typo3QuerySettings->languageOverlayMode

Note

By default Typo3QuerySettings uses the site language configuration.

You need to change Typo3QuerySettings manually only if your Extbase code should behave differently to tt_content rendering.

Setting setLanguageOverlayMode() on a query influences only fetching of the aggregate root. Relations are always fetched with setLanguageOverlayMode(true).

When querying data in translated language, and having setLanguageOverlayMode(true), the relations (child objects) are overlaid even if the aggregate root is not translated.

$repository->findByUid() and language overlay modes

$repository->findByUid() internally sets respectSysLanguage(false).

Therefore it behaves differently than a regular query by uid.

Note

$query->matching($query->equals('uid', 11)); and $repository->findByUid() do behave different in some langauge scenarios:

The regular query will return null if passed uid doesn't match the language set in the $querySettings->setLanguageUid() method.

The bottom line is you can use $repository->findByUid() using translated record uid to get the translated content independently from language set in the global context.