Completed
Push — master ( 023585...214513 )
by Dominik
02:05
created

SchemaUpdateCommand::update()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.2
c 0
b 0
f 0
cc 4
eloc 7
nc 3
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Model\Doctrine\DBAL\Command;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\Schema\Schema;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Output\OutputInterface;
11
12
final class SchemaUpdateCommand
13
{
14
    /**
15
     * @var Connection
16
     */
17
    protected $connection;
18
19
    /**
20
     * @var
21
     */
22
    protected $schemaPath;
23
24
    /**
25
     * @param Connection $connection
26
     * @param string     $schemaPath
27
     */
28
    public function __construct(Connection $connection, string $schemaPath)
29
    {
30
        $this->connection = $connection;
31
        $this->schemaPath = $schemaPath;
32
    }
33
34
    /**
35
     * @param InputInterface  $input
36
     * @param OutputInterface $output
37
     *
38
     * @return int|null
39
     */
40
    public function __invoke(InputInterface $input, OutputInterface $output)
41
    {
42
        $dump = true === $input->getOption('dump');
43
        $force = true === $input->getOption('force');
44
45
        if ([] === $statements = $this->getStatements()) {
46
            $output->writeln('<info>No schema changes required</info>');
47
48
            return;
49
        }
50
51
        if (!$dump && !$force) {
52
            $output->writeln('<comment>ATTENTION</comment>: Do not execute in production.');
53
            $output->writeln('    Use the incremental update to detect changes during development and use');
54
            $output->writeln('    the SQL provided to manually update your database in production.');
55
            $output->writeln('');
56
            $output->writeln(sprintf('Would execute <info>"%s"</info> queries.', count($statements)));
57
            $output->writeln('Please run the operation by passing one - or both - of the following options:');
58
            $output->writeln('    <info>--force</info> to execute the command');
59
            $output->writeln('    <info>--dump</info> to dump the SQL statements to the screen');
60
61
            return 1;
62
        }
63
64
        $this->update($output, $statements, $dump, $force);
65
66
        return 0;
67
    }
68
69
    /**
70
     * @param OutputInterface $output
71
     * @param array           $statements
72
     * @param bool            $dump
73
     * @param bool            $force
74
     */
75
    private function update(OutputInterface $output, array $statements, bool $dump, bool $force)
76
    {
77
        if ($dump && $force) {
78
            $this->dumpAndForce($output, $statements);
79
        } elseif ($dump) {
80
            $this->dump($output, $statements);
81
        } else {
82
            $this->force($statements);
83
        }
84
    }
85
86
    /**
87
     * @return array
88
     */
89
    private function getStatements(): array
90
    {
91
        $connection = $this->connection;
92
93
        $schemaManager = $connection->getSchemaManager();
94
        $fromSchema = $schemaManager->createSchema();
95
96
        /** @var Schema $schema */
97
        $schema = require $this->schemaPath;
98
99
        return $fromSchema->getMigrateToSql($schema, $connection->getDatabasePlatform());
100
    }
101
102
    /**
103
     * @param OutputInterface $output
104
     * @param array           $statements
105
     */
106
    private function dump(OutputInterface $output, array $statements)
107
    {
108
        $output->writeln('<info>Begin transaction</info>');
109
110
        foreach ($statements as $statement) {
111
            $output->writeln($statement);
112
        }
113
114
        $output->writeln('<info>Commit</info>');
115
    }
116
117
    /**
118
     * @param array $statements
119
     */
120
    private function force(array $statements)
121
    {
122
        $this->connection->beginTransaction();
123
124
        foreach ($statements as $statement) {
125
            $this->connection->exec($statement);
126
        }
127
128
        $this->connection->commit();
129
    }
130
131
    /**
132
     * @param OutputInterface $output
133
     * @param array           $statements
134
     */
135
    private function dumpAndForce(OutputInterface $output, array $statements)
136
    {
137
        $output->writeln('<info>Begin transaction</info>');
138
        $this->connection->beginTransaction();
139
140
        foreach ($statements as $statement) {
141
            $output->writeln($statement);
142
            $this->connection->exec($statement);
143
        }
144
145
        $output->writeln('<info>Commit</info>');
146
        $this->connection->commit();
147
    }
148
}
149