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

DumpCommand::getFileName()   C

Complexity

Conditions 11
Paths 21

Size

Total Lines 43
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 43
rs 5.2653
c 1
b 0
f 0
cc 11
eloc 28
nc 21
nop 3

How to fix   Complexity   

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
namespace N98\Magento\Command\Database;
4
5
use N98\Util\OperatingSystem;
6
use RuntimeException;
7
use Symfony\Component\Console\Helper\DialogHelper;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Output\OutputInterface;
12
13
class DumpCommand extends AbstractDatabaseCommand
14
{
15
    /**
16
     * @var array
17
     */
18
    protected $tableDefinitions = null;
19
20
    /**
21
     * @var array
22
     */
23
    protected $commandConfig = null;
24
25
    protected function configure()
26
    {
27
        $this
28
            ->setName('db:dump')
29
            ->addArgument('filename', InputArgument::OPTIONAL, 'Dump filename')
30
            ->addOption('add-time', 't', InputOption::VALUE_OPTIONAL, 'Adds time to filename (only if filename was not provided)')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 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...
31
            ->addOption('compression', 'c', InputOption::VALUE_REQUIRED, 'Compress the dump file using one of the supported algorithms')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 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...
32
            ->addOption('only-command', null, InputOption::VALUE_NONE, 'Print only mysqldump command. Do not execute')
33
            ->addOption('print-only-filename', null, InputOption::VALUE_NONE, 'Execute and prints no output except the dump filename')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 134 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...
34
            ->addOption('no-single-transaction', null, InputOption::VALUE_NONE, 'Do not use single-transaction (not recommended, this is blocking)')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 148 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...
35
            ->addOption('human-readable', null, InputOption::VALUE_NONE, 'Use a single insert with column names per row. Useful to track database differences. Use db:import --optimize for speeding up the import.')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 213 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...
36
            ->addOption('add-routines', null, InputOption::VALUE_NONE, 'Include stored routines in dump (procedures & functions)')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 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...
37
            ->addOption('stdout', null, InputOption::VALUE_NONE, 'Dump to stdout')
38
            ->addOption('strip', 's', InputOption::VALUE_OPTIONAL, 'Tables to strip (dump only structure of those tables)')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 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...
39
            ->addOption('force', 'f', InputOption::VALUE_NONE, 'Do not prompt if all options are defined')
40
            ->setDescription('Dumps database with mysqldump cli client according to informations from local.xml');
41
42
        $help = <<<HELP
43
Dumps configured magento database with `mysqldump`.
44
You must have installed the MySQL client tools.
45
46
On debian systems run `apt-get install mysql-client` to do that.
47
48
The command reads app/etc/local.xml to find the correct settings.
49
If you like to skip data of some tables you can use the --strip option.
50
The strip option creates only the structure of the defined tables and
51
forces `mysqldump` to skip the data.
52
53
Dumps your database and excludes some tables. This is useful i.e. for development.
54
55
Separate each table to strip by a space.
56
You can use wildcards like * and ? in the table names to strip multiple tables.
57
In addition you can specify pre-defined table groups, that start with an @
58
Example: "dataflow_batch_export unimportant_module_* @log
59
60
   $ n98-magerun.phar db:dump --strip="@stripped"
61
62
Available Table Groups:
63
64
* @log Log tables
65
* @dataflowtemp Temporary tables of the dataflow import/export tool
66
* @stripped Standard definition for a stripped dump (logs and dataflow)
67
* @sales Sales data (orders, invoices, creditmemos etc)
68
* @customers Customer data
69
* @trade Current trade data (customers and orders). You usally do not want those in developer systems.
70
* @development Removes logs and trade data so developers do not have to work with real customer data
71
72
Extended: https://github.com/netz98/n98-magerun/wiki/Stripped-Database-Dumps
73
74
See it in action: http://youtu.be/ttjZHY6vThs
75
76
- If you like to prepend a timestamp to the dump name the --add-time option can be used.
77
78
- The command comes with a compression function. Add i.e. `--compression=gz` to dump directly in
79
 gzip compressed file.
80
81
HELP;
82
        $this->setHelp($help);
83
84
    }
85
86
    /**
87
     * @return bool
88
     */
89
    public function isEnabled()
90
    {
91
        return function_exists('exec') && !OperatingSystem::isWindows();
92
    }
93
94
    /**
95
     * @return array
96
     *
97
     * @deprecated Use database helper
98
     * @throws RuntimeException
99
     */
100
    public function getTableDefinitions()
101
    {
102
        $this->commandConfig = $this->getCommandConfig();
103
104
        if (is_null($this->tableDefinitions)) {
105
            $this->tableDefinitions = array();
106
            if (isset($this->commandConfig['table-groups'])) {
107
                $tableGroups = $this->commandConfig['table-groups'];
108 View Code Duplication
                foreach ($tableGroups as $index=>$definition) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
                    $description = isset($definition['description']) ? $definition['description'] : '';
110
                    if (!isset($definition['id'])) {
111
                        throw new RuntimeException('Invalid definition of table-groups (id missing) Index: ' . $index);
112
                    }
113
                    if (!isset($definition['id'])) {
114
                        throw new RuntimeException('Invalid definition of table-groups (tables missing) Id: '
115
                            . $definition['id']
116
                        );
117
                    }
118
119
                    $this->tableDefinitions[$definition['id']] = array(
120
                        'tables'      => $definition['tables'],
121
                        'description' => $description,
122
                    );
123
                }
124
            };
125
        }
126
127
        return $this->tableDefinitions;
128
    }
129
130
    /**
131
     * Generate help for table definitions
132
     *
133
     * @return string
134
     */
135
    public function getTableDefinitionHelp()
136
    {
137
        $messages = array();
138
        $this->commandConfig = $this->getCommandConfig();
139
        $messages[] = '';
140
        $messages[] = '<comment>Strip option</comment>';
141
        $messages[] = ' Separate each table to strip by a space.';
142
        $messages[] = ' You can use wildcards like * and ? in the table names to strip multiple tables.';
143
        $messages[] = ' In addition you can specify pre-defined table groups, that start with an @';
144
        $messages[] = ' Example: "dataflow_batch_export unimportant_module_* @log';
145
        $messages[] = '';
146
        $messages[] = '<comment>Available Table Groups</comment>';
147
148
        $definitions = $this->getTableDefinitions();
0 ignored issues
show
Deprecated Code introduced by
The method N98\Magento\Command\Data...::getTableDefinitions() has been deprecated with message: Use database helper

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
149
        foreach ($definitions as $id => $definition) {
150
            $description = isset($definition['description']) ? $definition['description'] : '';
151
            /** @TODO:
152
             * Column-Wise formatting of the options, see InputDefinition::asText for code to pad by the max length,
153
             * but I do not like to copy and paste ..
154
             */
155
            $messages[] = ' <info>@' . $id . '</info> ' . $description;
156
        }
157
158
        return implode(PHP_EOL, $messages);
159
    }
160
161
    public function getHelp()
162
    {
163
        return parent::getHelp() . PHP_EOL
164
            . $this->getCompressionHelp() . PHP_EOL
165
            . $this->getTableDefinitionHelp();
166
    }
167
168
    /**
169
     * @param \Symfony\Component\Console\Input\InputInterface $input
170
     * @param \Symfony\Component\Console\Output\OutputInterface $output
171
     * @return int|void
172
     */
173
    protected function execute(InputInterface $input, OutputInterface $output)
174
    {
175
        $this->detectDbSettings($output);
176
177
        if (!$input->getOption('stdout') && !$input->getOption('only-command')
178
            && !$input->getOption('print-only-filename')
179
        ) {
180
            $this->writeSection($output, 'Dump MySQL Database');
181
        }
182
183
        $compressor = $this->getCompressor($input->getOption('compression'));
184
        $fileName   = $this->getFileName($input, $output, $compressor);
185
186
        $stripTables = false;
187
        if ($input->getOption('strip')) {
188
            $stripTables = $this->getHelper('database')->resolveTables(explode(' ', $input->getOption('strip')), $this->getTableDefinitions());
0 ignored issues
show
Deprecated Code introduced by
The method N98\Magento\Command\Data...::getTableDefinitions() has been deprecated with message: Use database helper

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 143 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...
189
            if (!$input->getOption('stdout') && !$input->getOption('only-command')
190
                && !$input->getOption('print-only-filename')
191
            ) {
192
                $output->writeln('<comment>No-data export for: <info>' . implode(' ', $stripTables)
193
                    . '</info></comment>'
194
                );
195
            }
196
        }
197
198
        $dumpOptions = '';
199
        if (!$input->getOption('no-single-transaction')) {
200
            $dumpOptions = '--single-transaction --quick ';
201
        }
202
203
        if ($input->getOption('human-readable')) {
204
            $dumpOptions .= '--complete-insert --skip-extended-insert ';
205
        }
206
207
        if ($input->getOption('add-routines')) {
208
            $dumpOptions .= '--routines ';
209
        }
210
        $execs = array();
211
212
        if (!$stripTables) {
213
            $exec = 'mysqldump ' . $dumpOptions . $this->getHelper('database')->getMysqlClientToolConnectionString();
214
            $exec .= $this->postDumpPipeCommands();
215
            $exec = $compressor->getCompressingCommand($exec);
216
            if (!$input->getOption('stdout')) {
217
                $exec .= ' > ' . escapeshellarg($fileName);
218
            }
219
            $execs[] = $exec;
220
        } else {
221
            // dump structure for strip-tables
222
            $exec = 'mysqldump ' . $dumpOptions . '--no-data ' . $this->getHelper('database')->getMysqlClientToolConnectionString();
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 132 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...
223
            $exec .= ' ' . implode(' ', $stripTables);
224
            $exec .= $this->postDumpPipeCommands();
225
            $exec = $compressor->getCompressingCommand($exec);
226
            if (!$input->getOption('stdout')) {
227
                $exec .= ' > ' . escapeshellarg($fileName);
228
            }
229
            $execs[] = $exec;
230
231
            $ignore = '';
232
            foreach ($stripTables as $stripTable) {
233
                $ignore .= '--ignore-table=' . $this->dbSettings['dbname'] . '.' . $stripTable . ' ';
234
            }
235
236
            // dump data for all other tables
237
            $exec = 'mysqldump ' . $dumpOptions . $ignore . $this->getHelper('database')->getMysqlClientToolConnectionString();
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 127 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...
238
            $exec .= $this->postDumpPipeCommands();
239
            $exec = $compressor->getCompressingCommand($exec);
240
            if (!$input->getOption('stdout')) {
241
                $exec .= ' >> ' . escapeshellarg($fileName);
242
            }
243
            $execs[] = $exec;
244
        }
245
246
        $this->runExecs($execs, $fileName, $input, $output);
247
    }
248
249
    /**
250
     * @param array $execs
251
     * @param string $fileName
252
     * @param InputInterface $input
253
     * @param OutputInterface $output
254
     */
255
    private function runExecs(array $execs, $fileName, InputInterface $input, OutputInterface $output)
256
    {
257
        if ($input->getOption('only-command') && !$input->getOption('print-only-filename')) {
258
            foreach ($execs as $exec) {
259
                $output->writeln($exec);
260
            }
261
        } else {
262
            if (!$input->getOption('stdout') && !$input->getOption('only-command')
263
                && !$input->getOption('print-only-filename')
264
            ) {
265
                $output->writeln('<comment>Start dumping database <info>' . $this->dbSettings['dbname']
266
                    . '</info> to file <info>' . $fileName . '</info>'
267
                );
268
            }
269
270
            foreach ($execs as $exec) {
271
                $commandOutput = '';
272
                if ($input->getOption('stdout')) {
273
                    passthru($exec, $returnValue);
274
                } else {
275
                    exec($exec, $commandOutput, $returnValue);
276
                }
277
                if ($returnValue > 0) {
278
                    $output->writeln('<error>' . implode(PHP_EOL, $commandOutput) . '</error>');
279
                    $output->writeln('<error>Return Code: ' . $returnValue . '. ABORTED.</error>');
280
281
                    return;
282
                }
283
            }
284
285
            if (!$input->getOption('stdout') && !$input->getOption('print-only-filename')) {
286
                $output->writeln('<info>Finished</info>');
287
            }
288
        }
289
290
        if ($input->getOption('print-only-filename')) {
291
            $output->writeln($fileName);
292
        }
293
    }
294
295
    /**
296
     * Commands which filter mysql data. Piped to mysqldump command
297
     *
298
     * @return string
299
     */
300
    protected function postDumpPipeCommands()
301
    {
302
        return ' | sed -e ' . escapeshellarg('s/DEFINER[ ]*=[ ]*[^*]*\*/\*/');
303
    }
304
305
    /**
306
     * @param \Symfony\Component\Console\Input\InputInterface $input
307
     * @param \Symfony\Component\Console\Output\OutputInterface $output
308
     * @param \N98\Magento\Command\Database\Compressor\AbstractCompressor $compressor
309
     * @return string
310
     */
311
    protected function getFileName(InputInterface $input, OutputInterface $output,
312
        Compressor\AbstractCompressor $compressor
313
    ) {
314
        $namePrefix    = '';
315
        $nameSuffix    = '';
316
        $nameExtension = '.sql';
317
318
        if ($input->getOption('add-time') !== false) {
319
            $timeStamp = date('Y-m-d_His');
320
321
            if ($input->getOption('add-time') == 'suffix') {
322
                $nameSuffix = '_' . $timeStamp;
323
            } else {
324
                $namePrefix = $timeStamp . '_';
325
            }
326
        }
327
328
        if ((($fileName = $input->getArgument('filename')) === null || ($isDir = is_dir($fileName))) && !$input->getOption('stdout')) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 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...
329
            /** @var DialogHelper $dialog */
330
            $dialog      = $this->getHelperSet()->get('dialog');
331
            $defaultName = $namePrefix . $this->dbSettings['dbname'] . $nameSuffix . $nameExtension;
332
            if (isset($isDir) && $isDir) {
333
                $defaultName = rtrim($fileName, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $defaultName;
334
            }
335
            if (!$input->getOption('force')) {
336
                $fileName = $dialog->ask($output, '<question>Filename for SQL dump:</question> [<comment>'
337
                    . $defaultName . '</comment>]', $defaultName
338
                );
339
            } else {
340
                $fileName = $defaultName;
341
            }
342
        } else {
343
            if ($input->getOption('add-time')) {
344
                $pathParts = pathinfo($fileName);
345
                $fileName = ($pathParts['dirname'] == '.' ? '' : $pathParts['dirname'] . DIRECTORY_SEPARATOR ) .
346
                    $namePrefix . $pathParts['filename'] . $nameSuffix . '.' . $pathParts['extension'];
347
            }
348
        }
349
350
        $fileName = $compressor->getFileName($fileName);
351
352
        return $fileName;
353
    }
354
}
355