Skip to content

Instantly share code, notes, and snippets.

@zdenekdrahos
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zdenekdrahos/eeae57058a1b0fb894da to your computer and use it in GitHub Desktop.
Save zdenekdrahos/eeae57058a1b0fb894da to your computer and use it in GitHub Desktop.
Dispatch Symfony events in transaction. https://coderwall.com/p/zfvjsq
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="dispatcher.transactional" class="TransactionalDispatcher">
<argument type="service" id="event_dispatcher"/>
<argument type="service" id="doctrine.orm.entity_manager"/>
</service>
</services>
</container>
services:
dispatcher.transactional:
class: TransactionalDispatcher
arguments:
- "@event_dispatcher"
- "@doctrine.orm.entity_manager"
<?php
use Doctrine\ORM\EntityManager;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class TransactionalDispatcher
{
/** @var EventDispatcherInterface */
private $dispatcher;
/** @var EntityManager */
private $entityManager;
/** @var Event */
private $event;
public function __construct(EventDispatcherInterface $dispatcher, EntityManager $manager)
{
$this->dispatcher = $dispatcher;
$this->entityManager = $manager;
}
public function dispatch($eventName, Event $event)
{
$this->beginTransaction();
$this->dispatchEvent($eventName, $event);
$this->endTransaction();
return $this->hasSucceed();
}
private function beginTransaction()
{
$this->entityManager->beginTransaction();
}
private function dispatchEvent($eventName, Event $event)
{
$this->event = $this->dispatcher->dispatch($eventName, $event);
}
private function endTransaction()
{
if ($this->hasSucceed()) {
$this->entityManager->commit();
} else {
$this->entityManager->rollback();
}
}
private function hasSucceed()
{
return !$this->event->isPropagationStopped();
}
}
<?php
use Mockery as m;
class TransactionalDispatcherTest extends \PHPUnit_Framework_TestCase
{
private $entityManager;
private $hasDispatcherSucceed;
public function setUp()
{
$this->entityManager = m::mock('Doctrine\ORM\EntityManager');
}
/** @dataProvider provideTransactions */
public function testShouldDispatchEventInTransaction($hasDispatcherSucceed, $expectedMethod)
{
$this->hasDispatcherSucceed = $hasDispatcherSucceed;
$this->entityManager->shouldReceive('beginTransaction')->once();
$this->entityManager->shouldReceive($expectedMethod)->once();
$this->assertSame($hasDispatcherSucceed, $this->dispatch());
}
public function provideTransactions()
{
return array(
'when propagation succeed should commit' => array(true, 'commit'),
'when propagation failed should rollback' => array(false, 'rollback'),
);
}
private function dispatch()
{
$event = m::mock('Symfony\Component\EventDispatcher\Event');
$event->shouldReceive('isPropagationStopped')->andReturn(!$this->hasDispatcherSucceed );
$dispatcher = m::mock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$dispatcher->shouldReceive('dispatch')->once()->andReturn($event);
$transactionalDispatcher = new TransactionalDispatcher($dispatcher, $this->entityManager);
return $transactionalDispatcher->dispatch('irrelevant event', $event);
}
public function tearDown()
{
m::close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment