Repository

All Extbase 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 that extend the Repository class 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
{

}
Copied!

Find methods

Changed in version 14.0

The "magic" find methods findByX(), findOneByX() and countByX() have been removed. See Migration

The Repository class provides the following methods for querying against arbitrary criteria:

findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): QueryResultInterface
Finds all objects with the provided criteria.
findOneBy(array $criteria, array $orderBy = null): object|null
Returns the first object found with the provided criteria.
count(array $criteria): int
Counts all objects with the provided criteria.

Example:

$this->blogRepository->findBy(['author' => 1, 'published' => true]);
Copied!

Custom find methods

Custom find methods can be implemented. They can be used for complex queries.

Example:

The PostRepository of the t3docs/blog-example example extension implements several custom find methods, two of them are 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();
    }
}
Copied!

Query settings

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

Class T3docs\BlogExample\Domain\Repository\CommentRepository
class CommentRepository extends Repository
{
    public function initializeObject(): void
    {
        $querySettings = $this->createQuery()->getQuerySettings();
        // Show comments from all pages
        $querySettings->setRespectStoragePage(false);
        $this->setDefaultQuerySettings($querySettings);
    }
}
Copied!

If you only want to change the query settings for a specific 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
    {
        $query = $this->createQuery();
        $query->getQuerySettings()->setIgnoreEnableFields(true);
        return $query->execute();
    }
}
Copied!

Repository API

class Repository
Fully qualified name
\TYPO3\CMS\Extbase\Persistence\Repository

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

injectPersistenceManager ( \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
param $persistenceManager

the persistenceManager

injectEventDispatcher ( \Psr\EventDispatcher\EventDispatcherInterface $eventDispatcher)
param $eventDispatcher

the eventDispatcher

injectFeatures ( \TYPO3\CMS\Core\Configuration\Features $features)
param $features

the features

add ( ?object $object)

Adds an object to this repository

param $object

The object to add

remove ( ?object $object)

Removes an object from this repository.

param $object

The object to remove

update ( ?object $modifiedObject)

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

param $modifiedObject

The modified object

findAll ( )

Returns all objects of this repository.

Returns
\QueryResultInterface|array
countAll ( )

Returns the total number objects of this repository.

Return description

The object count

Returns
int
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.

param $uid

The identifier of the object to find

Return description

The matching object if found, otherwise NULL

Returns
object|null
findByIdentifier ( ?mixed $identifier)

Finds an object matching the given identifier.

param $identifier

The identifier of the object to find

Return description

The matching object if found, otherwise NULL

Returns
object|null
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 )

param $defaultOrderings

The property names to order by

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.

param $defaultQuerySettings

the defaultQuerySettings

createQuery ( )

Returns a query for objects of this repository

Returns
\QueryInterface
findBy ( array $criteria, ?array $orderBy = NULL, ?int $limit = NULL, ?int $offset = NULL)
param $criteria

the criteria

param $orderBy

the orderBy, default: NULL

param $limit

the limit, default: NULL

param $offset

the offset, default: NULL

Returns
\QueryResultInterface
findOneBy ( array $criteria, ?array $orderBy = NULL)
param $criteria

the criteria

param $orderBy

the orderBy, default: NULL

Returns
?object
count ( array $criteria)
param $criteria

the criteria

Returns
int

Typo3QuerySettings and localization

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

Changed in version 12.0

The following methods can be used to set and get the language aspect from any \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface :

  • QuerySettingsInterface::getLanguageAspect(): LanguageAspect
  • QuerySettingsInterface::setLanguageAspect(LanguageAspect $aspect)

You can specify a custom language aspect per query as defined in the query settings in any repository class:

Example to use the fallback to the default language when working with overlays:

EXT:my_extension/Classes/Repository/MyRepository.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Domain\Repository;

use TYPO3\CMS\Core\Context\LanguageAspect;
use TYPO3\CMS\Extbase\Persistence\Repository;

final class MyRepository extends Repository
{
    public function findSomethingByLanguage(int $languageId, int $contentId)
    {
        $query = $this->createQuery();
        $query->getQuerySettings()->setLanguageAspect(
            new LanguageAspect(
                $languageId,
                $contentId,
                LanguageAspect::OVERLAYS_MIXED,
            ),
        );
        // query something
    }
}
Copied!

Debugging an Extbase query

When using complex queries in Extbase repositories it sometimes comes handy to debug them using the Extbase debug utilities.

EXT:my_extension/Classes/Repository/MyRepository.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Domain\Repository;

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;

final class MyRepository extends Repository
{
    public function findBySomething(string $something, bool $debugOn = false): QueryResultInterface
    {
        $query = $this->createQuery();
        $query = $query->matching($query->equals('some_field', $something));

        if ($debugOn) {
            $typo3DbQueryParser = GeneralUtility::makeInstance(Typo3DbQueryParser::class);
            $queryBuilder = $typo3DbQueryParser->convertQueryToDoctrineQueryBuilder($query);
            DebuggerUtility::var_dump($queryBuilder->getSQL());
            DebuggerUtility::var_dump($queryBuilder->getParameters());
        }

        return $query->execute();
    }
}
Copied!

Please note that \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser is marked as @internal and subject to unannounced changes.