Transactions are an implementation detail related to the persistence mechanism. The Domain layer shouldn't be aware of this low-level implementation detail. Thinking about beginning, committing, or rolling back a transaction at this level is a big smell. This level of detail belongs to the Infrastructure layer.
The best way of handling transactions is to not handle them at all. We could wrap our Application Services with a Decorator implementation for handling the transaction session automatically.
We've implemented a solution to this problem in one of our repositories, and you can check it out here:
interface TransactionalSession { /** * @return mixed */ public function executeAtomically(callable $operation); }
This contract takes a piece of code and executes it atomically. Depending on your persistence mechanism, you'll end up with different implementations.
Let's see how we could do it with Doctrine ORM:
class DoctrineSession implements TransactionalSession {...