Transactions

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
{
private $entityManager;

public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}

public function executeAtomically(callable $operation)
{
return $this->entityManager->transactional($operation);
}
}

This is how a client would use the previous code:

/** @var EntityManager $em */
$nonTxApplicationService = new SignUpUserService(
$em->getRepository('BoundedContextDomainModelUserUser')
);

$txApplicationService = new TransactionalApplicationService(
$nonTxApplicationService,
new DoctrineSession($em)
);

$response = $txApplicationService->execute(
new SignUpUserRequest(
'[email protected]',
'password'
)
);

Now that we have the Doctrine implementation for transactional sessions, it would be great to create a Decorator for our Application Services. With this approach, we make transactional requests transparent to the Domain:

class TransactionalApplicationService implements ApplicationService
{
private $session;
private $service;

public function __construct(
ApplicationService $service, TransactionalSession $session
) {
$this->session = $session;
$this->service = $service;
}

public function execute(BaseRequest $request)
{
$operation = function () use ($request) {
return $this->service->execute($request);
};

return $this->session->executeAtomically($operation);
}
}

A nice side effect of using Doctrine Session is that it automatically manages the flush method, so you don't need to add the flush inside your Domain or Infrastructure.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset