Failed Conditions
Push — master ( 0469de...12f4fc )
by Jonathan
02:19
created

VersionExecutor::executeMigration()   C

Complexity

Conditions 9
Paths 96

Size

Total Lines 82
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
eloc 43
nc 96
nop 6
dl 0
loc 82
ccs 40
cts 40
cp 1
crap 9
rs 5.5259
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\Migrations\Configuration\Configuration;
9
use Doctrine\Migrations\Exception\SkipMigration;
10
use Doctrine\Migrations\Provider\SchemaDiffProviderInterface;
11
use Throwable;
12
use function count;
13
use function microtime;
14
use function round;
15
use function rtrim;
16
use function sprintf;
17
use function ucfirst;
18
19
final class VersionExecutor implements VersionExecutorInterface
20
{
21
    /** @var Configuration */
22
    private $configuration;
23
24
    /** @var Connection */
25
    private $connection;
26
27
    /** @var SchemaDiffProviderInterface */
28
    private $schemaProvider;
29
30
    /** @var OutputWriter */
31
    private $outputWriter;
32
33
    /** @var ParameterFormatterInterface */
34
    private $parameterFormatter;
35
36
    /** @var string[] */
37
    private $sql = [];
38
39
    /** @var mixed[] */
40
    private $params = [];
41
42
    /** @var mixed[] */
43
    private $types = [];
44
45 110
    public function __construct(
46
        Configuration $configuration,
47
        Connection $connection,
48
        SchemaDiffProviderInterface $schemaProvider,
49
        OutputWriter $outputWriter,
50
        ParameterFormatterInterface $parameterFormatter
51
    ) {
52 110
        $this->configuration      = $configuration;
53 110
        $this->connection         = $connection;
54 110
        $this->schemaProvider     = $schemaProvider;
55 110
        $this->outputWriter       = $outputWriter;
56 110
        $this->parameterFormatter = $parameterFormatter;
57 110
    }
58
59
    /**
60
     * @return string[]
61
     */
62 1
    public function getSql() : array
63
    {
64 1
        return $this->sql;
65
    }
66
67
    /**
68
     * @return mixed[]
69
     */
70 1
    public function getParams() : array
71
    {
72 1
        return $this->params;
73
    }
74
75
    /**
76
     * @return mixed[]
77
     */
78 1
    public function getTypes() : array
79
    {
80 1
        return $this->types;
81
    }
82
83
    /**
84
     * @param mixed[] $params
85
     * @param mixed[] $types
86
     */
87 41
    public function addSql(string $sql, array $params = [], array $types = []) : void
88
    {
89 41
        $this->sql[] = $sql;
90
91 41
        if (empty($params)) {
92 27
            return;
93
        }
94
95 23
        $this->addQueryParams($params, $types);
96 23
    }
97
98 53
    public function execute(
99
        Version $version,
100
        AbstractMigration $migration,
101
        string $direction,
102
        bool $dryRun = false,
103
        bool $timeAllQueries = false
104
    ) : VersionExecutionResult {
105 53
        $versionExecutionResult = new VersionExecutionResult();
106
107 53
        $this->startMigration($version, $migration, $direction, $dryRun);
108
109
        try {
110 53
            $this->executeMigration(
111 53
                $version,
112 53
                $migration,
113 53
                $versionExecutionResult,
114 53
                $direction,
115 53
                $dryRun,
116 53
                $timeAllQueries
117
            );
118
119 50
            $versionExecutionResult->setSql($this->sql);
120 50
            $versionExecutionResult->setParams($this->params);
121 50
            $versionExecutionResult->setTypes($this->types);
122 7
        } catch (SkipMigration $e) {
123 6
            $this->skipMigration(
124 6
                $e,
125 6
                $version,
126 6
                $migration,
127 6
                $direction,
128 6
                $dryRun
129
            );
130
131 6
            $versionExecutionResult->setSkipped(true);
132 1
        } catch (Throwable $e) {
133 1
            $this->migrationError($e, $version, $migration);
134
135 1
            $versionExecutionResult->setError(true);
136 1
            $versionExecutionResult->setException($e);
137
138 1
            throw $e;
139
        }
140
141 52
        return $versionExecutionResult;
142
    }
143
144 53
    private function startMigration(
145
        Version $version,
146
        AbstractMigration $migration,
147
        string $direction,
148
        bool $dryRun
149
    ) : void {
150 53
        $this->sql    = [];
151 53
        $this->params = [];
152 53
        $this->types  = [];
153
154 53
        $this->configuration->dispatchVersionEvent(
155 53
            $version,
156 53
            Events::onMigrationsVersionExecuting,
157 53
            $direction,
158 53
            $dryRun
159
        );
160
161 53
        if (! $migration->isTransactional()) {
162
            return;
163
        }
164
165
        //only start transaction if in transactional mode
166 53
        $this->connection->beginTransaction();
167 53
    }
168
169 53
    private function executeMigration(
170
        Version $version,
171
        AbstractMigration $migration,
172
        VersionExecutionResult $versionExecutionResult,
173
        string $direction,
174
        bool $dryRun,
175
        bool $timeAllQueries
176
    ) : VersionExecutionResult {
177 53
        $migrationStart = microtime(true);
178
179 53
        $version->setState(Version::STATE_PRE);
180
181 53
        $fromSchema = $this->schemaProvider->createFromSchema();
182
183 53
        $migration->{'pre' . ucfirst($direction)}($fromSchema);
184
185 51
        if ($direction === Version::DIRECTION_UP) {
186 48
            $this->outputWriter->write("\n" . sprintf('  <info>++</info> migrating <comment>%s</comment>', $version) . "\n");
187
        } else {
188 9
            $this->outputWriter->write("\n" . sprintf('  <info>--</info> reverting <comment>%s</comment>', $version) . "\n");
189
        }
190
191 51
        $version->setState(Version::STATE_EXEC);
192
193 51
        $toSchema = $this->schemaProvider->createToSchema($fromSchema);
194
195 51
        $migration->$direction($toSchema);
196
197 50
        foreach ($this->schemaProvider->getSqlDiffToMigrate($fromSchema, $toSchema) as $sql) {
198 13
            $this->addSql($sql);
199
        }
200
201 50
        if (count($this->sql) !== 0) {
202 39
            if (! $dryRun) {
203 21
                $this->executeVersionExecutionResult($version, $dryRun, $timeAllQueries);
204
            } else {
205 18
                foreach ($this->sql as $idx => $query) {
206 39
                    $this->outputSqlQuery($idx, $query);
207
                }
208
            }
209
        } else {
210 11
            $this->outputWriter->write(sprintf(
211 11
                '<error>Migration %s was executed but did not result in any SQL statements.</error>',
212 11
                $version
213
            ));
214
        }
215
216 50
        $version->setState(Version::STATE_POST);
217
218 50
        $migration->{'post' . ucfirst($direction)}($toSchema);
219
220 50
        if (! $dryRun) {
221 32
            $version->markVersion($direction);
222
        }
223
224 50
        $migrationEnd = microtime(true);
225
226 50
        $time = round($migrationEnd - $migrationStart, 2);
227
228 50
        $versionExecutionResult->setTime($time);
229
230 50
        if ($direction === Version::DIRECTION_UP) {
231 47
            $this->outputWriter->write(sprintf("\n  <info>++</info> migrated (%ss)", $time));
232
        } else {
233 9
            $this->outputWriter->write(sprintf("\n  <info>--</info> reverted (%ss)", $time));
234
        }
235
236 50
        if ($migration->isTransactional()) {
237
            //commit only if running in transactional mode
238 50
            $this->connection->commit();
239
        }
240
241 50
        $version->setState(Version::STATE_NONE);
242
243 50
        $this->configuration->dispatchVersionEvent(
244 50
            $version,
245 50
            Events::onMigrationsVersionExecuted,
246 50
            $direction,
247 50
            $dryRun
248
        );
249
250 50
        return $versionExecutionResult;
251
    }
252
253 6
    private function skipMigration(
254
        SkipMigration $e,
255
        Version $version,
256
        AbstractMigration $migration,
257
        string $direction,
258
        bool $dryRun
259
    ) : void {
260 6
        if ($migration->isTransactional()) {
261
            //only rollback transaction if in transactional mode
262 6
            $this->connection->rollBack();
263
        }
264
265 6
        if ($dryRun === false) {
266 5
            $version->markVersion($direction);
267
        }
268
269 6
        $this->outputWriter->write(sprintf("\n  <info>SS</info> skipped (Reason: %s)", $e->getMessage()));
270
271 6
        $version->setState(Version::STATE_NONE);
272
273 6
        $this->configuration->dispatchVersionEvent(
274 6
            $version,
275 6
            Events::onMigrationsVersionSkipped,
276 6
            $direction,
277 6
            $dryRun
278
        );
279 6
    }
280
281
    /**
282
     * @throws Throwable
283
     */
284 1
    private function migrationError(Throwable $e, Version $version, AbstractMigration $migration) : void
285
    {
286 1
        $this->outputWriter->write(sprintf(
287 1
            '<error>Migration %s failed during %s. Error %s</error>',
288 1
            $version,
289 1
            $version->getExecutionState(),
290 1
            $e->getMessage()
291
        ));
292
293 1
        if ($migration->isTransactional()) {
294
            //only rollback transaction if in transactional mode
295 1
            $this->connection->rollBack();
296
        }
297
298 1
        $version->setState(Version::STATE_NONE);
299 1
    }
300
301 21
    private function executeVersionExecutionResult(
302
        Version $version,
303
        bool $dryRun = false,
304
        bool $timeAllQueries = false
305
    ) : void {
306 21
        foreach ($this->sql as $key => $query) {
307 21
            $queryStart = microtime(true);
308
309 21
            $this->outputSqlQuery($key, $query);
310
311 21
            if (! isset($this->params[$key])) {
312 18
                $this->connection->executeQuery($query);
313
            } else {
314 10
                $this->connection->executeQuery($query, $this->params[$key], $this->types[$key]);
315
            }
316
317 21
            $this->outputQueryTime($queryStart, $timeAllQueries);
318
        }
319 21
    }
320
321
    /**
322
     * @param mixed[]|int $params
323
     * @param mixed[]|int $types
324
     */
325 23
    private function addQueryParams($params, $types) : void
326
    {
327 23
        $index                = count($this->sql) - 1;
328 23
        $this->params[$index] = $params;
329 23
        $this->types[$index]  = $types;
330 23
    }
331
332 21
    private function outputQueryTime(float $queryStart, bool $timeAllQueries = false) : void
333
    {
334 21
        if ($timeAllQueries === false) {
335 19
            return;
336
        }
337
338 2
        $queryEnd  = microtime(true);
339 2
        $queryTime = round($queryEnd - $queryStart, 4);
340
341 2
        $this->outputWriter->write(sprintf('  <info>%ss</info>', $queryTime));
342 2
    }
343
344 39
    private function outputSqlQuery(int $idx, string $query) : void
345
    {
346 39
        $params = $this->parameterFormatter->formatParameters(
347 39
            $this->params[$idx] ?? [],
348 39
            $this->types[$idx] ?? []
349
        );
350
351 39
        $this->outputWriter->write(rtrim(sprintf(
352 39
            '     <comment>-></comment> %s %s',
353 39
            $query,
354 39
            $params
355
        )));
356 39
    }
357
}
358