Are Doctrine2 repositories a good place to save my entities?
When I read docs about repositories, it is often to work with entities & collection but in a "read-only" manner.
There are never examples where repositories have methods like insertUser(User $user)
or updateUser(User $user)
.
However, when using SOA, Service should not be working with Entity Manager (that's right, isn't it?) so:
- Should my service be aware of the global EntityManager?
- Should my service know only about the used Repositories (let's say, UserRepository & ArticleRepository)
From that both questions, another one, should my service ever explicitly persist()
& flush()
my entities ?
Solution 1:
Yes, repositories are generally used for queries only.
Here is how I do it. The service layer manages the persistence. The controller layer knows of the service layer, but knows nothing of how the model objects are persisted nor where do they come from. For what the controller layer cares is asking the service layer to persist and return objects — it doesn't care how it's actually done.
The service layer itself is perfectly suitable to know about the the persistence layer: entity or document managers, repositories, etc.
Here's some code to make it clearer:
class UserController
{
public function indexAction()
{
$users = $this->get('user.service')->findAll();
// ...
}
public function createAction()
{
// ...
$user = new User();
// fill the user object here
$this->get('user.service')->create($user);
// ...
}
}
class UserService
{
const ENTITY_NAME = 'UserBundle:User';
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function findAll()
{
return $this->em->getRepository(self::ENTITY_NAME)->findAll();
}
public function create(User $user)
{
// possibly validation here
$this->em->persist($user);
$this->em->flush($user);
}
}
Solution 2:
If you take a look at the repository pattern http://martinfowler.com/eaaCatalog/repository.html ,
it is stated that repositories uses a "collection-like interface".
Later, it is also written " Objects can be added to and removed from the Repository, as they can from a simple collection of objects".
I'm not saying this is a bible, but there is conceptually nothing wrong to see a repository like a collection that you can query. But as it is a collection, you can add, remove, ... In fact, the ObjectRepository should implement Doctrine\Common\Collection :)
On the other hand, the most important is not to mess reads and writes, as CQS says. That's maybe why they didn't allow directly that, to avoid abuses and read/write mix.
EDIT: I should have talked about flush
. This should not be made in the repository itself, as it might break transactional consistency.
You'd better move the flush
call to something that wraps the whole business transaction logic (a command bus handling a command f.e?)
Solution 3:
Well, how do you get your repository when not using the entityManager? After all, the entities are not going to be saved magically without a connection to the database, so your service must somehow be aware of any kind of connection.
I don't know about the SOA Services, but in my eyes it makes no difference at all if you use $_em->getRepository()->save($entity)
or $_em->persist($entity)
. On the other hand, if you use flush in your repository, you might end up with way more queries than needed as your repository is now aware of the business logic.
I think there is a way to do this "the SOA way", but I guess it's not persisting the entities within the repository.