Repositories
Table of Contents
Introduction
Repositories are simply collections of entities. They provide methods for adding, deleting, and retrieving entities, but they leave the actual data retrieval to data mappers. These data mappers can interact with an SQL database, cache, some other form of storage, or a mixture of storage mechanisms. By utilizing a unit of work, writes to the data mappers are scheduled and only executed when calling $unitOfWork->commit()
. This gives you the ability to wrap multiple repositories' writes into a single, "all-or-nothing" transaction.
Basic Usage
If your repository will not implement any methods outside of Opulence\Orm\Repositories\Repository
, you don't even have to create your own repository class. Just use Opulence\Orm\Repositories\Repository
:
use Blog\Domain\Posts\Post;
// Assume $dataMapper and $unitOfWork are already instantiated
$repo = new Repository(Post::class, $dataMapper, $unitOfWork);
However, if your repository implements any custom get*()
methods, you'll have to extend Opulence\Orm\Repositories\Repository
. Let's create an interface with this method:
namespace Blog\Domain\Posts;
use Opulence\Orm\Repositories\IRepository;
interface IPostRepository extends IRepository
{
public function getByTitle($title);
}
Let's implement this interface in the example below:
namespace Blog\Infrastructure\Persistence\Posts;
use Blog\Domain\Posts\IPostRepository;
use Opulence\Orm\Repositories\Repository;
class PostRepository extends Repository implements IPostRepository
{
public function getByTitle($title)
{
return $this->getFromDataMapper('getByTitle', [$title]);
}
}
Rather than calling $this->dataMapper->getByTitle()
directly, you should use the helper function $this->getFromDataMapper()
, which automatically handles registering entities to the entity registry. Next, you'll need to add the getByTitle()
method to your data mapper.
Adding Entities
$postToAdd = new Post(123, 'First Post', 'This is my first post');
$repository->add($postToAdd);
The new post will be scheduled for insertion by the unit of work.
Deleting Entities
$postToDelete = new Post(123, 'First Post', 'This is my first post');
$repository->delete($postToDelete);
The post will be scheduled for deletion by the unit of work.
Getting All Entities
$posts = $repository->getAll();
foreach ($posts as $post) {
echo $post->getTitle() . '<br />';
}
The list of post titles will be printed to the screen. Every entity returned by getAll()
is registered to the unit of work's entity registry.
Getting By Id
$post = $repository->getById(123);
echo $post->getTitle();
All entities returned by the repository are automatically registered to the unit of work's entity registry, effectively turning it into a cache. The repository first looks for the entity in the registry and returns it if it's already registered. Otherwise, the data mapper is called and the entity is registered for future queries.
Note: If no entity is found, an
Opulence\Orm\OrmException
will be thrown.
Committing Changes
As you can see, there is no save()
method in repositories. To actually save any writes made by the repository, you must call commit()
on the unit of work passed into the repository's constructor:
use Blog\Domain\Posts\Post;
use Blog\Infrastructure\Persistence\Posts\PostSqlDataMapper;
use Opulence\Orm\Repositories\Repository;
use Opulence\Orm\UnitOfWork;
// Assume $unitOfWork is already instantiated
$repository = new Repository(Post::class, new PostSqlDataMapper(), $unitOfWork);
$postToDelete = $repository->getById(123);
$repository->delete($postToDelete);
$unitOfWork->commit();
Whenever you call Repository::add()
or Repository::delete()
, the entity is scheduled to be written by the data mappers back to storage. Calling $unitOfWork->commit()
actually writes all the scheduled entities to storage.
Updating Entities
Updates are automatically tracked by the entity registry. For example, let's say we change a post's title:
$post = $repository->getById(123);
$post->setTitle('Better Title');
$unitOfWork->commit();
The entity registry will determine that $post
has been updated, and it will schedule the post to be updated in storage by the data mappers.