RequestTransactionSubscriber   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Importance

Changes 0
Metric Value
wmc 5
lcom 2
cbo 2
dl 0
loc 69
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A getSubscribedEvents() 0 10 1
A startTransaction() 0 4 1
A finishTransaction() 0 11 1
A rollbackTransaction() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Explicit Architecture POC,
7
 * which is created on top of the Symfony Demo application.
8
 *
9
 * (c) Herberto Graça <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Acme\App\Infrastructure\Persistence;
16
17
use Acme\App\Core\Port\Lock\LockManagerInterface;
18
use Acme\App\Core\Port\Persistence\TransactionServiceInterface;
19
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
20
use Symfony\Component\HttpKernel\KernelEvents;
21
22
final class RequestTransactionSubscriber implements EventSubscriberInterface
23
{
24
    private const DEFAULT_PRIORITY = 10;
25
26
    /**
27
     * @var TransactionServiceInterface
28
     */
29
    private $transactionService;
30
31
    /**
32
     * @var LockManagerInterface
33
     */
34
    private $lockManager;
35
36
    /**
37
     * @var int
38
     */
39
    private static $priority = self::DEFAULT_PRIORITY;
40
41
    public function __construct(
42
        TransactionServiceInterface $transactionService,
43
        LockManagerInterface $lockManager,
44
        int $requestTransactionSubscriberPriority = self::DEFAULT_PRIORITY
45
    ) {
46
        $this->transactionService = $transactionService;
47
        $this->lockManager = $lockManager;
48
        self::$priority = $requestTransactionSubscriberPriority;
49
    }
50
51
    /**
52
     * Return the subscribed events, their methods and possibly their priorities
53
     * (the higher the priority the earlier the method is called).
54
     *
55
     * @see http://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber
56
     */
57
    public static function getSubscribedEvents(): array
58
    {
59
        return [
60
            KernelEvents::CONTROLLER => ['startTransaction', self::$priority],
61
            KernelEvents::RESPONSE => ['finishTransaction', self::$priority],
62
            // In the case that both the Exception and Response events are triggered, we want to make sure the
63
            // transaction is rolled back before trying to commit it.
64
            KernelEvents::EXCEPTION => ['rollbackTransaction', self::$priority + 1],
65
        ];
66
    }
67
68
    public function startTransaction(): void
69
    {
70
        $this->transactionService->startTransaction();
71
    }
72
73
    public function finishTransaction(): void
74
    {
75
        // This is is when the ORM writes all staged changes to the DB so we should do this only once in a request,
76
        // and only if the use case was successful.
77
        // If we would use a command bus, we would do this in one of its middlewares.
78
        $this->transactionService->finishTransaction();
79
80
        // We release all locks here, so that they can be reacquired when processing the events in the
81
        // EventFlusherSubscriber, which runs after this subscriber.
82
        $this->lockManager->releaseAll();
83
    }
84
85
    public function rollbackTransaction(): void
86
    {
87
        $this->transactionService->rollbackTransaction();
88
        $this->lockManager->releaseAll();
89
    }
90
}
91