Repositories

The repository design pattern is an abstraction over the storage of a specific model. In other words, they represent a collection of an entity (aka model). Repositories hold the logic for retrieving and filtering results from the collection. They do not represent database storage or any other form of persistence logic.

In practice, repositories are commonly home to methods like find(), findOneBy(), findActiveUsers(), findUserWithUsernameAndPassword(). Notice these methods imply retrieving or filtering a collection of data. These methods do not create, update, or delete data. Nor do they reveal the technology being used to persist the data (i.e database, in-memory, etc.).

SiteAdmin modules use the repository design pattern to access models which have been persisted to storage. They are directly mapped to a single model, and are used to query only that model.

Creating a Repository

The Repository Class

<?php
use sa\application\DefaultRepository;
class CompaniesRepository extends DefaultRepository
{
// <implement querying methods>
}

Default Methods

The DefaultRepository class offers a few common repository operations, so you can dive into using your repository without writing boilerplate code.

Method

Description

find($id)

Finds an entity by its primary key / identifier.

findAll()

Finds all entities in the repository.

findBy(array ​orderBy = null, ​offset = null)

Finds entities by a set of criteria.

findOneBy(array ​orderBy` = null)

Finds a single entity by a set of criteria.

search(array ​orderBy, ​offset = null, ​secondary_sort = null, ​search_start = true, $search_end = true)

Finds entities by a set of complex criteria.

Custom Repository methods

You'll likely need to create custom search queries for your model(s). For this, we use the Doctrine ORM query builder.

<?php
use sa\application\DefaultRepository;
class CompaniesRepository extends DefaultRepository
{
public function findCompaniesByName($searchTerm) {
$qb = $this->createQueryBuilder('c');
$qb->where($qb->expr()->like('LOWER(c.name)', ':name'))
->setParameter('name', '%' . strtolower(trim($searchTerm)) . '%');
return $qb->getQuery()->getResult();
}
}

Mapping Repository to Model

Each repository must be mapped to a model. This is achieved by adding the repository's namespace to a model's @Entity annotation.

Notice the repository class simply reads CompanyRepository. This is acceptable because both the Company and CompanyRepository classes reside in the same namespace. If they were in different namespaces, the annotation would instead read:

@Entity(repositoryClass="\other\namespace\CompanyRepository")

/modules/Companies/models/Company

<?php
/**
* @Entity(repositoryClass="CompanyRepository")
*/
class Company {
// <properties, getters/setters, helper methods>
}

Using a Repository

Access from Entity Manager

Deprecation NoticeAccessing repositories directly from the entity manager is deprecated. Use the IOC manager to access repositories instead.

You can get the instance of a repository via doctrine's entity manager. Because modules are often extended, you should use ioc::resolve('{entityName}') instead of hard-coding a model's namespace. This will allow the application to use the repositories mapped to extended models.

<?php
$companyRepository = app::$entityManager->getRepository(ioc::resolve('Company'));

Access from IOC

The IOC manager offers a simplified interface compared to the entity manager's getRepository() method, which requires manually resolving a model's IOC reference.

<?php
$companyRepository = ioc::getRepository('Company');