Passed
Branch master (056094)
by Andreas
04:47
created

schema   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 154
rs 10
wmc 30

4 Methods

Rating   Name   Duplication   Size   Complexity  
A generate_proxyfiles() 0 12 3
F execute() 0 77 17
C process_updates() 0 47 9
A configure() 0 7 1
1
<?php
2
/**
3
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
4
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
6
 */
7
8
namespace midgard\portable\command;
9
10
use midgard\portable\storage\connection;
11
use midgard\portable\classgenerator;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Input\InputArgument;
15
use Symfony\Component\Console\Output\OutputInterface;
16
use Symfony\Component\Console\Helper\ProgressBar;
17
use Symfony\Component\Console\Question\Question;
18
use midgard_storage;
19
use midgard_connection;
20
use Doctrine\ORM\Tools\SchemaTool;
21
use Doctrine\DBAL\Schema\Comparator;
22
use Symfony\Component\Console\Input\InputOption;
23
use Doctrine\Common\Proxy\ProxyGenerator;
24
25
/**
26
 * (Re)generate mapping information from MgdSchema XMLs
27
 */
28
class schema extends Command
29
{
30
    public $connected = false;
31
32
    protected function configure()
33
    {
34
        $this->setName('schema')
35
            ->setDescription('(Re)generate mapping information from MgdSchema XMLs')
36
            ->addArgument('config', InputArgument::OPTIONAL, 'Full path to midgard-portable config file')
37
            ->addOption('force', null, InputOption::VALUE_NONE, 'Ignore errors from DB')
38
            ->addOption('delete', null, InputOption::VALUE_NONE, 'Delete columns/tables that are not defined in mgdschema');
39
    }
40
41
    protected function execute(InputInterface $input, OutputInterface $output)
42
    {
43
        if (!$this->connected) {
44
            $path = $input->getArgument('config');
45
            if (empty($path)) {
46
                if (file_exists(OPENPSA_PROJECT_BASEDIR . 'config/midgard-portable.inc.php')) {
0 ignored issues
show
Bug introduced by
The constant midgard\portable\command\OPENPSA_PROJECT_BASEDIR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
47
                    $path = OPENPSA_PROJECT_BASEDIR . 'config/midgard-portable.inc.php';
48
                } else {
49
                    $dialog = $this->getHelper('question');
50
                    $path = $dialog->ask($input, $output, new Question('<question>Enter path to config file</question>'));
51
                }
52
            }
53
            if (!file_exists($path)) {
54
                throw new \RuntimeException('Config file ' . $path . ' not found');
55
            }
56
            //we have to delay startup so that we can delete the entity class file before it gets included
57
            connection::set_autostart(false);
58
            require $path;
59
        }
60
61
        $mgd_config = midgard_connection::get_instance()->config;
62
        $mgdschema_file = $mgd_config->vardir . '/mgdschema_classes.php';
63
        if (   file_exists($mgdschema_file)
64
            && !unlink($mgdschema_file)) {
65
            throw new \RuntimeException('Could not unlink ' . $mgdschema_file);
66
        }
67
        if (connection::get_parameter('dev_mode') !== true) {
68
            $driver = connection::get_parameter('driver');
69
            $classgenerator = new classgenerator($driver->get_manager(), $mgdschema_file);
70
            $classgenerator->write($driver->get_namespace());
71
        }
72
        if (!file_exists($mgd_config->blobdir . '/0/0')) {
73
            $mgd_config->create_blobdir();
74
        }
75
        connection::startup();
76
        $em = connection::get_em();
77
        connection::invalidate_cache();
78
        $cms = $em->getMetadataFactory()->getAllMetadata();
79
80
        // create storage
81
        if (    !midgard_storage::create_base_storage()
82
             && midgard_connection::get_instance()->get_error_string() != 'MGD_ERR_OK') {
83
            throw new \Exception("Failed to create base database structures" . midgard_connection::get_instance()->get_error_string());
84
        }
85
        $force = $input->getOption('force');
86
        $to_update = [];
87
        $to_create = [];
88
89
        foreach ($cms as $cm) {
90
            if (!$em->getConnection()->getSchemaManager()->tablesExist([$cm->getTableName()])) {
91
                $to_create[] = $cm;
92
            } else {
93
                $to_update[] = $cm;
94
            }
95
        }
96
97
        if (!empty($to_create)) {
98
            $output->writeln('Creating <info>' . count($to_create) . '</info> new tables');
99
            $tool = new SchemaTool($em);
100
            try {
101
                $tool->createSchema($to_create);
102
            } catch (\Exception $e) {
103
                if (!$force) {
104
                    throw $e;
105
                } else {
106
                    $output->writeln('<error>' . $e->getMessage() . '</error>');
107
                }
108
            }
109
        }
110
        if (!empty($to_update)) {
111
            $delete = $input->getOption('delete');
112
            $this->process_updates($to_update, $output, $force, $delete);
113
        }
114
        $output->writeln('Generating proxies');
115
        $this->generate_proxyfiles($cms);
116
117
        $output->writeln('Done');
118
    }
119
120
    private function generate_proxyfiles(array $cms)
121
    {
122
        $em = connection::get_em();
123
        $generator = new ProxyGenerator($em->getConfiguration()->getProxyDir(), $em->getConfiguration()->getProxyNamespace());
124
        $generator->setPlaceholder('baseProxyInterface', 'Doctrine\ORM\Proxy\Proxy');
125
126
        foreach ($cms as $cm) {
127
            $filename = $generator->getProxyFileName($cm->getName());
128
            if (file_exists($filename)) {
129
                unlink($filename);
130
            }
131
            $generator->generateProxyClass($cm, $filename);
132
        }
133
    }
134
135
    private function process_updates(array $to_update, OutputInterface $output, $force, $delete)
136
    {
137
        $em = connection::get_em();
138
        $conn = $em->getConnection();
139
        $tool = new SchemaTool($em);
140
        $from = $conn->getSchemaManager()->createSchema();
141
        $to = $tool->getSchemaFromMetadata($to_update);
142
143
        $comparator = new Comparator;
144
        $diff = $comparator->compare($from, $to);
145
146
        if (!$delete) {
147
            foreach ($diff->changedTables as $changed_table) {
148
                if (!empty($changed_table->removedColumns)) {
149
                    $changed_table->removedColumns = [];
150
                }
151
            }
152
            $sql = $diff->toSaveSql($conn->getDatabasePlatform());
153
        } else {
154
            $sql = $diff->toSql($conn->getDatabasePlatform());
155
        }
156
        if (count($sql) == 0) {
157
            return;
158
        }
159
160
        $output->writeln('Executing <info>' . count($sql) . '</info> updates');
161
        $progress = new ProgressBar($output);
162
        $progress->start(count($sql));
163
164
        foreach ($sql as $sql_line) {
165
            if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
166
                $output->writeln(' Executing <info>' . $sql_line . '</info>');
167
            }
168
            try {
169
                $conn->executeQuery($sql_line);
170
            } catch (\Exception $e) {
171
                if (!$force) {
172
                    throw $e;
173
                } else {
174
                    $output->writeln('<error>' . $e->getMessage() . '</error>');
175
                }
176
            }
177
178
            $progress->advance();
179
        }
180
        $progress->finish();
181
        $output->writeln('');
182
    }
183
}
184