Passed
Push — master ( 229462...d74785 )
by Andreas
02:20 queued 14s
created

DbalMigrator::endMigrations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
nc 1
nop 3
dl 0
loc 14
ccs 8
cts 8
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\Migrations\Metadata\MigrationPlanList;
9
use Doctrine\Migrations\Tools\BytesFormatter;
10
use Doctrine\Migrations\Version\Executor;
11
use Psr\Log\LoggerInterface;
12
use Symfony\Component\Stopwatch\StopwatchEvent;
13
use Throwable;
14
use const COUNT_RECURSIVE;
15
use function count;
16
17
/**
18
 * The DbalMigrator class is responsible for generating and executing the SQL for a migration.
19
 *
20
 * @internal
21
 */
22
class DbalMigrator implements Migrator
23
{
24
    /** @var Stopwatch */
25
    private $stopwatch;
26
27
    /** @var LoggerInterface */
28
    private $logger;
29
30
    /** @var Executor */
31
    private $executor;
32
33
    /** @var Connection */
34
    private $connection;
35
36
    /** @var EventDispatcher */
37
    private $dispatcher;
38
39 4
    public function __construct(
40
        Connection $connection,
41
        EventDispatcher $dispatcher,
42
        Executor $executor,
43
        LoggerInterface $logger,
44
        Stopwatch $stopwatch
45
    ) {
46 4
        $this->stopwatch  = $stopwatch;
47 4
        $this->logger     = $logger;
48 4
        $this->executor   = $executor;
49 4
        $this->connection = $connection;
50 4
        $this->dispatcher = $dispatcher;
51 4
    }
52
53
    /**
54
     * @return string[][]
55
     */
56 3
    private function executeMigrations(
57
        MigrationPlanList $migrationsPlan,
58
        MigratorConfiguration $migratorConfiguration
59
    ) : array {
60 3
        $allOrNothing = $migratorConfiguration->isAllOrNothing();
61
62 3
        if ($allOrNothing) {
63 2
            $this->connection->beginTransaction();
64
        }
65
66
        try {
67 3
            $this->dispatcher->dispatchMigrationEvent(Events::onMigrationsMigrating, $migrationsPlan, $migratorConfiguration);
68
69 3
            $sql = $this->executePlan($migrationsPlan, $migratorConfiguration);
70
71 2
            $this->dispatcher->dispatchMigrationEvent(Events::onMigrationsMigrated, $migrationsPlan, $migratorConfiguration);
72 1
        } catch (Throwable $e) {
73 1
            if ($allOrNothing) {
74 1
                $this->connection->rollBack();
75
            }
76
77 1
            throw $e;
78
        }
79
80 2
        if ($allOrNothing) {
81 1
            $this->connection->commit();
82
        }
83
84 2
        return $sql;
85
    }
86
87
    /**
88
     * @return array<string, string[]>
89
     */
90 3
    private function executePlan(MigrationPlanList $migrationsPlan, MigratorConfiguration $migratorConfiguration) : array
91
    {
92 3
        $sql  = [];
93 3
        $time = 0;
94
95 3
        foreach ($migrationsPlan->getItems() as $plan) {
96 3
            $versionExecutionResult = $this->executor->execute($plan, $migratorConfiguration);
97
98
            // capture the to Schema for the migration so we have the ability to use
99
            // it as the from Schema for the next migration when we are running a dry run
100
            // $toSchema may be null in the case of skipped migrations
101 2
            if (! $versionExecutionResult->isSkipped()) {
102 2
                $migratorConfiguration->setFromSchema($versionExecutionResult->getToSchema());
103
            }
104
105 2
            $sql[(string) $plan->getVersion()] = $versionExecutionResult->getSql();
106 2
            $time                             += $versionExecutionResult->getTime();
107
        }
108
109 2
        return $sql;
110
    }
111
112
    /**
113
     * @param string[][] $sql
114
     */
115 2
    private function endMigrations(
116
        StopwatchEvent $stopwatchEvent,
117
        MigrationPlanList $migrationsPlan,
118
        array $sql
119
    ) : void {
120 2
        $stopwatchEvent->stop();
121
122 2
        $this->logger->notice(
123 2
            'finished in {duration}ms, used {memory} memory, {migrations_count} migrations executed, {queries_count} sql queries',
124
            [
125 2
                'duration' => $stopwatchEvent->getDuration(),
126 2
                'memory' => BytesFormatter::formatBytes($stopwatchEvent->getMemory()),
127 2
                'migrations_count' => count($migrationsPlan),
128 2
                'queries_count' => count($sql, COUNT_RECURSIVE) - count($sql),
129
            ]
130
        );
131 2
    }
132
133
    /**
134
     * {@inheritDoc}
135
     */
136 4
    public function migrate(MigrationPlanList $migrationsPlan, MigratorConfiguration $migratorConfiguration) : array
137
    {
138 4
        if (count($migrationsPlan) === 0) {
139 1
            $this->logger->notice('No migrations to execute.');
140
141 1
            return [];
142
        }
143
144 3
        $dryRun = $migratorConfiguration->isDryRun();
145 3
        $this->logger->notice(
146 3
            ($dryRun ? 'Executing dry run of migration' : 'Migrating') . ' {direction} to {to}',
147
            [
148 3
                'direction' => $migrationsPlan->getDirection(),
149 3
                'to' => (string) $migrationsPlan->getLast()->getVersion(),
150
            ]
151
        );
152
153 3
        $stopwatchEvent = $this->stopwatch->start('migrate');
154
155 3
        $sql = $this->executeMigrations($migrationsPlan, $migratorConfiguration);
156
157 2
        $this->endMigrations($stopwatchEvent, $migrationsPlan, $sql);
158
159 2
        return $sql;
160
    }
161
}
162