Completed
Pull Request — master (#177)
by
unknown
04:33
created

src/N98/Magento/Command/Database/ImportCommand.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace N98\Magento\Command\Database;
4
5
use Symfony\Component\Console\Input\InputArgument;
6
use Symfony\Component\Console\Input\InputInterface;
7
use Symfony\Component\Console\Input\InputOption;
8
use Symfony\Component\Console\Output\OutputInterface;
9
10
class ImportCommand extends AbstractDatabaseCommand
11
{
12
    protected function configure()
13
    {
14
        $this
15
            ->setName('db:import')
16
            ->addArgument('filename', InputArgument::OPTIONAL, 'Dump filename')
17
            ->addOption('compression', 'c', InputOption::VALUE_REQUIRED, 'The compression of the specified file')
18
            ->addOption('only-command', null, InputOption::VALUE_NONE, 'Print only mysql command. Do not execute')
19
            ->addOption('only-if-empty', null, InputOption::VALUE_NONE, 'Imports only if database is empty')
20
            ->addOption('optimize', null, InputOption::VALUE_NONE, 'Convert verbose INSERTs to short ones before import (not working with compression)')
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 152 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
21
            ->addOption('drop', null, InputOption::VALUE_NONE, 'Drop and recreate database before import')
22
            ->addOption('drop-tables', null, InputOption::VALUE_NONE, 'Drop tables before import')
23
            ->setDescription('Imports database with mysql cli client according to database defined in local.xml');
24
25
        $help = <<<HELP
26
Imports an SQL file with mysql cli client into current configured database.
27
28
You need to have MySQL client tools installed on your system.
29
HELP;
30
        $this->setHelp($help);
31
32
    }
33
34
    /**
35
     * @return bool
36
     */
37
    public function isEnabled()
38
    {
39
        return function_exists('exec');
40
    }
41
42
    /**
43
     * Optimize a dump by converting single INSERTs per line to INSERTs with multiple lines
44
     * @param $fileName
45
     * @return string temporary filename
46
     */
47
    protected function optimize($fileName)
48
    {
49
        $in = fopen($fileName,'r');
50
        $result = tempnam(sys_get_temp_dir(), 'dump') . '.sql';
51
        $out = fopen($result, 'w');
52
53
        $currentTable = '';
54
        $maxlen = 8 * 1024 * 1024; // 8 MB
55
        $len = 0;
56
        while ($line = fgets($in)) {
57
            if (strtolower(substr($line, 0, 11)) == 'insert into') {
58
                preg_match('/^insert into `(.*)` \(.*\) values (.*);/i', $line, $m);
59
60 View Code Duplication
                if (count($m) < 3) { // fallback for very long lines or other cases where the preg_match fails
61
                    if ($currentTable != '') {
62
                        fwrite($out, ";\n");
63
                    }
64
                    fwrite($out, $line);
65
                    $currentTable = '';
66
                    continue;
67
                }
68
69
                $table = $m[1];
70
                $values = $m[2];
71
72
                if ($table != $currentTable or ($len > $maxlen - 1000)) {
73
                    if ($currentTable != '') {
74
                        fwrite($out, ";\n\n");
75
                    }
76
                    $currentTable = $table;
77
                    $insert = 'INSERT INTO `' . $table . '` VALUES ' . $values;
78
                    fwrite($out, $insert);
79
                    $len = strlen($insert);
80
                } else {
81
                    fwrite($out, ',' . $values);
82
                    $len += strlen($values) + 1;
83
                }
84 View Code Duplication
            } else {
85
                if ($currentTable != '') {
86
                    fwrite($out, ";\n");
87
                    $currentTable = '';
88
                }
89
                fwrite($out, $line);
90
            }
91
92
        }
93
        fclose($in);
94
        fclose($out);
95
96
        return $result;
97
98
    }
99
    /**
100
     * @param \Symfony\Component\Console\Input\InputInterface $input
101
     * @param \Symfony\Component\Console\Output\OutputInterface $output
102
     * @return int|void
103
     */
104
    protected function execute(InputInterface $input, OutputInterface $output)
105
    {
106
        $this->detectDbSettings($output);
107
        $this->writeSection($output, 'Import MySQL Database');
108
        $dbHelper = $this->getHelper('database');
109
110
        $fileName = $this->checkFilename($input);
111
112
        $compressor = $this->getCompressor($input->getOption('compression'));
113
114
        // create import command
115
        $exec = $compressor->getDecompressingCommand(
116
            'mysql ' . $dbHelper->getMysqlClientToolConnectionString(),
117
            $fileName
118
        );
119
        if ($input->getOption('only-command')) {
120
            $output->writeln($exec);
121
122
            return;
123
        } else {
124
            if ($input->getOption('only-if-empty')
125
                && count($dbHelper->getTables()) > 0
126
            ) {
127
                $output->writeln('<comment>Skip import. Database is not empty</comment>');
128
129
                return;
130
            }
131
        }
132
133
        if ($input->getOption('optimize')) {
134
            if ($input->getOption('compression')) {
135
                throw new \Exception('Options --compression and --optimize are not compatible');
136
            }
137
            $output->writeln('<comment>Optimizing <info>' . $fileName . '</info> to temporary file');
138
            $fileName = $this->optimize($fileName);
139
        }
140
141
        if( $input->getOption('drop') ) {
142
            $dbHelper->dropDatabase($output);
143
            $dbHelper->createDatabase($output);
144
        }
145
        if( $input->getOption('drop-tables') ) {
146
            $dbHelper->dropTables($output);
147
        }
148
149
150
151
152
            $this->doImport($output, $fileName, $exec);
153
154
        if ($input->getOption('optimize')) {
155
            unlink($fileName);
156
        }
157
    }
158
159
    public function asText() {
160
        return parent::asText() . "\n" .
161
            $this->getCompressionHelp();
162
    }
163
164
    /**
165
     * @param InputInterface $input
166
     *
167
     * @return mixed
168
     * @throws \InvalidArgumentException
169
     */
170
    protected function checkFilename(InputInterface $input)
171
    {
172
        $fileName = $input->getArgument('filename');
173
        if (!file_exists($fileName)) {
174
            throw new \InvalidArgumentException('File does not exist');
175
        }
176
        return $fileName;
177
    }
178
179
    /**
180
     * @param OutputInterface $output
181
     * @param string          $fileName
182
     * @param string          $exec
183
     *
184
     * @return void
185
     */
186
    protected function doImport(OutputInterface $output, $fileName, $exec)
187
    {
188
        $returnValue = null;
189
        $commandOutput = null;
190
        $output->writeln(
191
            '<comment>Importing SQL dump <info>' . $fileName . '</info> to database <info>'
192
            . $this->dbSettings['dbname'] . '</info>'
193
        );
194
        exec($exec, $commandOutput, $returnValue);
195
        if ($returnValue <> 0) {
196
            $output->writeln('<error>' . implode(PHP_EOL, $commandOutput) . '</error>');
197
        }
198
        $output->writeln('<info>Finished</info>');
199
    }
200
}
201