Completed
Push — master ( fb5c6c...3561cd )
by Tom
04:39
created

DatabaseHelper::getTablesStatus()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 28
rs 8.439
cc 5
eloc 18
nc 8
nop 1
1
<?php
2
3
namespace N98\Util\Console\Helper;
4
5
use InvalidArgumentException;
6
use PDO;
7
use PDOException;
8
use PDOStatement;
9
use RuntimeException;
10
use Symfony\Component\Console\Helper\Helper as AbstractHelper;
11
use Symfony\Component\Console\Output\NullOutput;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
/**
15
 * Class DatabaseHelper
16
 *
17
 * @package N98\Util\Console\Helper
18
 */
19
class DatabaseHelper extends AbstractHelper
20
{
21
    /**
22
     * @var array
23
     */
24
    protected $dbSettings = null;
25
26
    /**
27
     * @var bool
28
     */
29
    protected $isSocketConnect = false;
30
31
    /**
32
     * @var PDO
33
     */
34
    protected $_connection = null;
35
36
    /**
37
     * @var array
38
     */
39
    protected $_tables;
40
41
    /**
42
     * @var string
43
     */
44
    private $connectionType = 'default';
45
46
    /**
47
     * Set connection type when several db used.
48
     *
49
     * @param $connectionType
50
     */
51
    public function setConnectionType($connectionType)
52
    {
53
        $this->connectionType = $connectionType;
54
    }
55
56
    /**
57
     * @param OutputInterface $output
58
     *
59
     * @throws RuntimeException
60
     * @return void
61
     */
62
    public function detectDbSettings(OutputInterface $output)
0 ignored issues
show
Unused Code introduced by
The parameter $output is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
63
    {
64
        if (null !== $this->dbSettings) {
65
            return;
66
        }
67
68
        /* @var $magentoHelper MagentoHelper */
69
        $magentoHelper = $this->getHelperSet()->get('magento');
70
        $config = $magentoHelper->getBaseConfig(); // @TODO Use \Magento\Framework\App\DeploymentConfig ?
71
72
        if (!isset($config['db'])) {
73
            throw new RuntimeException('DB settings was not found in app/etc/env.php file');
74
        }
75
76
        if (!isset($config['db']['connection'][$this->connectionType])) {
77
            throw new RuntimeException(
78
                sprintf('Cannot find "%s" connection config in app/etc/env.php', $this->connectionType)
79
            );
80
        }
81
82
        $this->dbSettings = (array) $config['db']['connection'][$this->connectionType];
83
84
        $this->dbSettings['prefix'] = '';
85
        if (isset($config['db']['table_prefix'])) {
86
            $this->dbSettings['prefix'] = (string) $config['db']['table_prefix'];
87
        }
88
89 View Code Duplication
        if (
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...
90
            isset($this->dbSettings['host'])
91
            && strpos($this->dbSettings['host'], ':') !== false
92
        ) {
93
            list($this->dbSettings['host'], $this->dbSettings['port']) = explode(':', $this->dbSettings['host']);
94
        }
95
96
        if (isset($this->dbSettings['comment'])) {
97
            unset($this->dbSettings['comment']);
98
        }
99
100
        if (isset($this->dbSettings['unix_socket'])) {
101
            $this->isSocketConnect = true;
102
        }
103
    }
104
105
    /**
106
     * Connects to the database without initializing magento
107
     *
108
     * @param OutputInterface $output = null
0 ignored issues
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
109
     *
110
     * @return PDO
111
     * @throws RuntimeException pdo mysql extension is not installed
112
     */
113
    public function getConnection(OutputInterface $output = null)
114
    {
115
        $output = $this->fallbackOutput($output);
116
117
        if ($this->_connection) {
118
            return $this->_connection;
119
        }
120
121
        $this->detectDbSettings($output);
122
123
        if (!extension_loaded('pdo_mysql')) {
124
            throw new RuntimeException('pdo_mysql extension is not installed');
125
        }
126
127
        if (strpos($this->dbSettings['host'], '/') !== false) {
128
            $this->dbSettings['unix_socket'] = $this->dbSettings['host'];
129
            unset($this->dbSettings['host']);
130 View Code Duplication
        } elseif (strpos($this->dbSettings['host'], ':') !== false) {
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...
131
            list($this->dbSettings['host'], $this->dbSettings['port']) = explode(':', $this->dbSettings['host']);
132
        }
133
134
        $this->_connection = new PDO(
135
            $this->dsn(),
136
            $this->dbSettings['username'],
137
            $this->dbSettings['password']
138
        );
139
140
        /** @link http://bugs.mysql.com/bug.php?id=18551 */
141
        $this->_connection->query("SET SQL_MODE=''");
142
143
        try {
144
            $this->_connection->query('USE `' . $this->dbSettings['dbname'] . '`');
145
        } catch (PDOException $e) {
146
            if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
147
                $output->writeln(sprintf(
148
                    '<error>Failed to use database <comment>%s</comment>: %s</error>',
149
                    var_export($this->dbSettings['dbname'], true),
150
                    $e->getMessage()
151
                ));
152
            }
153
        }
154
155
        $this->_connection->query("SET NAMES utf8");
156
157
        $this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
158
        $this->_connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
159
160
        return $this->_connection;
161
    }
162
163
    /**
164
     * Creates a PDO DSN for the adapter from $this->_config settings.
165
     *
166
     * @see Zend_Db_Adapter_Pdo_Abstract
167
     * @return string
168
     */
169
    public function dsn()
170
    {
171
        $this->detectDbSettings($this->fallbackOutput());
172
173
        // baseline of DSN parts
174
        $dsn = $this->dbSettings;
175
176
        // don't pass the username, password, charset, database, persistent and driver_options in the DSN
177
        unset($dsn['username']);
178
        unset($dsn['password']);
179
        unset($dsn['options']);
180
        unset($dsn['charset']);
181
        unset($dsn['persistent']);
182
        unset($dsn['driver_options']);
183
        unset($dsn['dbname']);
184
185
        // use all remaining parts in the DSN
186
        $buildDsn = array();
187
        foreach ($dsn as $key => $val) {
188
            if (is_array($val)) {
189
                continue;
190
            }
191
            $buildDsn[$key] = "$key=$val";
192
        }
193
194
        return 'mysql:' . implode(';', $buildDsn);
195
    }
196
197
    /**
198
     * Check whether current mysql user has $privilege privilege
199
     *
200
     * @param string $privilege
201
     *
202
     * @return bool
203
     */
204
    public function mysqlUserHasPrivilege($privilege)
205
    {
206
        $statement = $this->getConnection()->query('SHOW GRANTS');
207
208
        $result = $statement->fetchAll(PDO::FETCH_COLUMN);
209
        foreach ($result as $row) {
210
            if (preg_match('/^GRANT(.*)' . strtoupper($privilege) . '/', $row)
211
                || preg_match('/^GRANT(.*)ALL/', $row)
212
            ) {
213
                return true;
214
            }
215
        }
216
217
        return false;
218
    }
219
220
    /**
221
     * @return string
222
     */
223
    public function getMysqlClientToolConnectionString()
224
    {
225
        $this->detectDbSettings($this->fallbackOutput());
226
227
        if ($this->isSocketConnect) {
228
            $string = '--socket=' . escapeshellarg($this->dbSettings['unix_socket']);
229
        } else {
230
            $string = '-h' . escapeshellarg($this->dbSettings['host']);
231
        }
232
233
        $string .= ' '
234
            . '-u' . escapeshellarg($this->dbSettings['username'])
235
            . ' '
236
            . (isset($this->dbSettings['port'])
237
                ? '-P' . escapeshellarg($this->dbSettings['port']) . ' ' : '')
238
            . (strlen($this->dbSettings['password'])
239
                ? '--password=' . escapeshellarg($this->dbSettings['password']) . ' ' : '')
240
            . escapeshellarg($this->dbSettings['dbname']);
241
242
        return $string;
243
    }
244
245
    /**
246
     * Get mysql variable value
247
     *
248
     * @param string $variable
249
     *
250
     * @return bool|array returns array on success, false on failure
251
     */
252
    public function getMysqlVariableValue($variable)
253
    {
254
        $statement = $this->getConnection()->query("SELECT @@{$variable};");
255
        if (false === $statement) {
256
            throw new RuntimeException(sprintf('Failed to query mysql variable %s', var_export($variable, 1)));
257
        }
258
259
        $result = $statement->fetch(PDO::FETCH_ASSOC);
260
        if ($result) {
261
            return $result;
262
        }
263
264
        return false;
265
    }
266
267
    /**
268
     * obtain mysql variable value from the database connection.
269
     *
270
     * in difference to @see getMysqlVariableValue(), this method allows to specify the type of the variable as well
271
     * as to use any variable identifier even such that need quoting.
272
     *
273
     * @param string $name mysql variable name
274
     * @param string $type [optional] variable type, can be a system variable ("@@", default) or a session variable
0 ignored issues
show
Documentation introduced by
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
275
     *                     ("@").
276
     *
277
     * @return string variable value, null if variable was not defined
278
     * @throws RuntimeException in case a system variable is unknown (SQLSTATE[HY000]: 1193: Unknown system variable
279
     *                          'nonexistent')
280
     */
281
    public function getMysqlVariable($name, $type = null)
282
    {
283
        if (null === $type) {
284
            $type = "@@";
285
        } else {
286
            $type = (string) $type;
287
        }
288
289
        if (!in_array($type, array("@@", "@"), true)) {
290
            throw new InvalidArgumentException(
291
                sprintf('Invalid mysql variable type "%s", must be "@@" (system) or "@" (session)', $type)
292
            );
293
        }
294
295
        $quoted = '`' . strtr($name, array('`' => '``')) . '`';
296
        $query = "SELECT {$type}{$quoted};";
297
298
        $connection = $this->getConnection();
299
        $statement = $connection->query($query, PDO::FETCH_COLUMN, 0);
300
        if ($statement instanceof PDOStatement) {
301
            $result = $statement->fetchColumn(0);
302
        } else {
303
            $reason = $connection->errorInfo()
304
                ? vsprintf('SQLSTATE[%s]: %s: %s', $connection->errorInfo())
305
                : 'no error info';
306
307
            throw new RuntimeException(
308
                sprintf('Failed to query mysql variable %s: %s', var_export($name, true), $reason)
309
            );
310
        }
311
312
        return $result;
313
    }
314
315
    /**
316
     * @param array $commandConfig
317
     *
318
     * @throws RuntimeException
319
     * @return array
320
     */
321
    public function getTableDefinitions(array $commandConfig)
322
    {
323
        $tableDefinitions = array();
324
        if (!isset($commandConfig['table-groups'])) {
325
            return $tableDefinitions;
326
        }
327
328
        $tableGroups = $commandConfig['table-groups'];
329
        foreach ($tableGroups as $index => $definition) {
330
            if (!isset($definition['id'])) {
331
                throw new RuntimeException("Invalid definition of table-groups (id missing) at index: $index");
332
            }
333
            $id = $definition['id'];
334
            if (isset($tableDefinitions[$id])) {
335
                throw new RuntimeException("Invalid definition of table-groups (duplicate id) id: $id");
336
            }
337
338
            if (!isset($definition['tables'])) {
339
                throw new RuntimeException("Invalid definition of table-groups (tables missing) id: $id");
340
            }
341
            $tables = $definition['tables'];
342
343
            if (is_string($tables)) {
344
                $tables = preg_split('~\s+~', $tables, -1, PREG_SPLIT_NO_EMPTY);
345
            }
346
            if (!is_array($tables)) {
347
                throw new RuntimeException("Invalid tables definition of table-groups id: $id");
348
            }
349
            $tables = array_map('trim', $tables);
350
351
            $description = isset($definition['description']) ? $definition['description'] : '';
352
353
            $tableDefinitions[$id] = array(
354
                'tables'      => $tables,
355
                'description' => $description,
356
            );
357
        }
358
359
        return $tableDefinitions;
360
    }
361
362
    /**
363
     * @param array $list to resolve
364
     * @param array $definitions from to resolve
365
     * @param array $resolved Which definitions where already resolved -> prevent endless loops
366
     *
367
     * @return array
368
     * @throws RuntimeException
369
     */
370
    public function resolveTables(array $list, array $definitions = array(), array $resolved = array())
371
    {
372
        if ($this->_tables === null) {
373
            $this->_tables = $this->getTables(true);
374
        }
375
376
        $resolvedList = array();
377
        foreach ($list as $entry) {
378
            if (substr($entry, 0, 1) == '@') {
379
                $code = substr($entry, 1);
380
                if (!isset($definitions[$code])) {
381
                    throw new RuntimeException('Table-groups could not be resolved: ' . $entry);
382
                }
383
                if (!isset($resolved[$code])) {
384
                    $resolved[$code] = true;
385
                    $tables = $this->resolveTables(
386
                        $this->resolveRetrieveDefinitionsTablesByCode($definitions, $code),
387
                        $definitions,
388
                        $resolved
389
                    );
390
                    $resolvedList = array_merge($resolvedList, $tables);
391
                }
392
                continue;
393
            }
394
395
            // resolve wildcards
396
            if (strpos($entry, '*') !== false) {
397
                $connection = $this->getConnection();
398
                $sth = $connection->prepare(
399
                    'SHOW TABLES LIKE :like',
400
                    array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)
401
                );
402
                $sth->execute(
403
                    array(':like' => str_replace('*', '%', $this->dbSettings['prefix'] . $entry))
404
                );
405
                $rows = $sth->fetchAll();
406
                foreach ($rows as $row) {
407
                    $resolvedList[] = $row[0];
408
                }
409
                continue;
410
            }
411
412
            if (in_array($entry, $this->_tables)) {
413
                $resolvedList[] = $this->dbSettings['prefix'] . $entry;
414
            }
415
        }
416
417
        asort($resolvedList);
418
        $resolvedList = array_unique($resolvedList);
419
420
        return $resolvedList;
421
    }
422
423
    /**
424
     * @param array $definitions
425
     * @param string $code
426
     * @return array tables
427
     */
428
    private function resolveRetrieveDefinitionsTablesByCode(array $definitions, $code)
429
    {
430
        $tables = $definitions[$code]['tables'];
431
432
        if (is_string($tables)) {
433
            $tables = preg_split('~\s+~', $tables, -1, PREG_SPLIT_NO_EMPTY);
434
        }
435
        if (!is_array($tables)) {
436
            throw new RuntimeException("Invalid tables definition of table-groups code: @$code");
437
        }
438
439
        $tables = array_reduce((array) $tables, array($this, 'resolveTablesArray'), null);
440
441
        return $tables;
442
    }
443
444
    /**
445
     * @param array|null $carry [optional]
446
     * @param $item [optional]
447
     * @return array
448
     * @throws InvalidArgumentException if item is not an array or string
449
     */
450
    private function resolveTablesArray(array $carry = null, $item = null)
451
    {
452
        if (is_string($item)) {
453
            $item = preg_split('~\s+~', $item, -1, PREG_SPLIT_NO_EMPTY);
454
        }
455
456
        if (is_array($item)) {
457
            if (count($item) > 1) {
458
                $item = array_reduce($item, array($this, 'resolveTablesArray'), (array) $carry);
459
            }
460
        } else {
461
            throw new InvalidArgumentException(sprintf('Unable to handle %s', var_export($item, true)));
462
        }
463
464
        return array_merge((array) $carry, $item);
465
    }
466
467
    /**
468
     * Get list of database tables
469
     *
470
     * @param bool $withoutPrefix [optional] remove prefix from the returned table names. prefix is obtained from
0 ignored issues
show
Documentation introduced by
Should the type for parameter $withoutPrefix not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
471
     *                            magento database configuration. defaults to false.
472
     *
473
     * @return array
474
     * @throws RuntimeException
475
     */
476
    public function getTables($withoutPrefix = null)
477
    {
478
        $withoutPrefix = (bool) $withoutPrefix;
479
480
        $db = $this->getConnection();
481
        $prefix = $this->dbSettings['prefix'];
482
        $prefixLength = strlen($prefix);
483
484
        $column = $columnName = 'table_name';
485
486
        $input = array();
487
488
        if ($withoutPrefix && $prefixLength) {
489
            $column = sprintf('SUBSTRING(%1$s FROM 1 + CHAR_LENGTH(:name)) %1$s', $columnName);
490
            $input[':name'] = $prefix;
491
        }
492
493
        $condition = 'table_schema = database()';
494
495
        if ($prefixLength) {
496
            $escape = '=';
497
            $condition .= sprintf(" AND %s LIKE :like ESCAPE '%s'", $columnName, $escape);
498
            $input[':like'] = $this->quoteLike($prefix, $escape) . '%';
499
        }
500
501
        $query = sprintf('SELECT %s FROM information_schema.tables WHERE %s;', $column, $condition);
502
        $statement = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
503
        $result = $statement->execute($input);
504
505
        if (!$result) {
506
            // @codeCoverageIgnoreStart
507
            $this->throwRuntimeException(
508
                $statement,
509
                sprintf('Failed to obtain tables from database: %s', var_export($query, true))
510
            );
511
        } // @codeCoverageIgnoreEnd
512
513
        $result = $statement->fetchAll(PDO::FETCH_COLUMN, 0);
514
515
        return $result;
516
    }
517
518
    /**
519
     * throw a runtime exception and provide error info for the statement if available
520
     *
521
     * @param PDOStatement $statement
522
     * @param string $message
523
     *
524
     * @throws RuntimeException
525
     */
526
    private function throwRuntimeException(PDOStatement $statement, $message = "")
527
    {
528
        $reason = $statement->errorInfo()
529
            ? vsprintf('SQLSTATE[%s]: %s: %s', $statement->errorInfo())
530
            : 'no error info for statement';
531
532
        if (strlen($message)) {
533
            $message .= ': ';
534
        } else {
535
            $message = '';
536
        }
537
538
        throw new RuntimeException($message . $reason);
539
    }
540
541
    /**
542
     * quote a string so that it is safe to use in a LIKE
543
     *
544
     * @param string $string
545
     * @param string $escape character - single us-ascii character
546
     *
547
     * @return string
548
     */
549
    private function quoteLike($string, $escape = '=')
550
    {
551
        $translation = array(
552
            $escape => $escape . $escape,
553
            '%'     => $escape . '%',
554
            '_'     => $escape . '_',
555
        );
556
557
        return strtr($string, $translation);
558
    }
559
560
    /**
561
     * Get list of db tables status
562
     *
563
     * @param bool $withoutPrefix
564
     *
565
     * @return array
566
     */
567
    public function getTablesStatus($withoutPrefix = false)
568
    {
569
        $db = $this->getConnection();
570
        $prefix = $this->dbSettings['prefix'];
571
        if (strlen($prefix) > 0) {
572
            $statement = $db->prepare('SHOW TABLE STATUS LIKE :like', array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
573
            $statement->execute(
574
                array(':like' => $prefix . '%')
575
            );
576
        } else {
577
            $statement = $db->query('SHOW TABLE STATUS');
578
        }
579
580
        if ($statement) {
581
            $result = $statement->fetchAll(PDO::FETCH_ASSOC);
582
            $return = array();
583
            foreach ($result as $table) {
584
                if (true === $withoutPrefix) {
585
                    $table['Name'] = str_replace($prefix, '', $table['Name']);
586
                }
587
                $return[$table['Name']] = $table;
588
            }
589
590
            return $return;
591
        }
592
593
        return array();
594
    }
595
596
    /**
597
     * @return array
598
     */
599
    public function getDbSettings()
600
    {
601
        return $this->dbSettings;
602
    }
603
604
    /**
605
     * @return boolean
606
     */
607
    public function getIsSocketConnect()
608
    {
609
        return $this->isSocketConnect;
610
    }
611
612
    /**
613
     * Returns the canonical name of this helper.
614
     *
615
     * @return string The canonical name
616
     *
617
     * @api
618
     */
619
    public function getName()
620
    {
621
        return 'database';
622
    }
623
624
    /**
625
     * @param OutputInterface $output
626
     */
627 View Code Duplication
    public function dropDatabase(OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
628
    {
629
        $this->detectDbSettings($output);
630
        $db = $this->getConnection();
631
        $db->query('DROP DATABASE `' . $this->dbSettings['dbname'] . '`');
632
        $output->writeln('<info>Dropped database</info> <comment>' . $this->dbSettings['dbname'] . '</comment>');
633
    }
634
635
    /**
636
     * @param OutputInterface $output
637
     */
638
    public function dropTables(OutputInterface $output)
639
    {
640
        $result = $this->getTables();
641
        $query = 'SET FOREIGN_KEY_CHECKS = 0; ';
642
        $count = 0;
643
        foreach ($result as $tableName) {
644
            $query .= 'DROP TABLE IF EXISTS `' . $tableName . '`; ';
645
            $count++;
646
        }
647
        $query .= 'SET FOREIGN_KEY_CHECKS = 1;';
648
        $this->getConnection()->query($query);
649
        $output->writeln('<info>Dropped database tables</info> <comment>' . $count . ' tables dropped</comment>');
650
    }
651
652
    /**
653
     * @param OutputInterface $output
654
     */
655 View Code Duplication
    public function createDatabase(OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
656
    {
657
        $this->detectDbSettings($output);
658
        $db = $this->getConnection();
659
        $db->query('CREATE DATABASE IF NOT EXISTS `' . $this->dbSettings['dbname'] . '`');
660
        $output->writeln('<info>Created database</info> <comment>' . $this->dbSettings['dbname'] . '</comment>');
661
    }
662
663
    /**
664
     * @param string $command example: 'VARIABLES', 'STATUS'
665
     * @param string|null $variable [optional]
666
     *
667
     * @return array
668
     */
669
    private function runShowCommand($command, $variable = null)
670
    {
671
        $db = $this->getConnection();
672
673
        if (null !== $variable) {
674
            $statement = $db->prepare(
675
                'SHOW /*!50000 GLOBAL */ ' . $command . ' LIKE :like',
676
                array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)
677
            );
678
            $statement->execute(
679
                array(':like' => $variable)
680
            );
681
        } else {
682
            $statement = $db->query('SHOW /*!50000 GLOBAL */ ' . $command);
683
        }
684
685
        if ($statement) {
686
            /** @var array|string[] $result */
687
            $result = $statement->fetchAll(PDO::FETCH_ASSOC);
688
            $return = array();
689
            foreach ($result as $row) {
690
                $return[$row['Variable_name']] = $row['Value'];
691
            }
692
693
            return $return;
694
        }
695
696
        return array();
697
    }
698
699
    /**
700
     * @param string|null $variable [optional]
701
     *
702
     * @return array
703
     */
704
    public function getGlobalVariables($variable = null)
705
    {
706
        return $this->runShowCommand('VARIABLES', $variable);
707
    }
708
709
    /**
710
     * @param string|null $variable [optional]
711
     *
712
     * @return array
713
     */
714
    public function getGlobalStatus($variable = null)
715
    {
716
        return $this->runShowCommand('STATUS', $variable);
717
    }
718
719
    /**
720
     * small helper method to obtain an object of type OutputInterface
721
     *
722
     * @param OutputInterface|null $output
723
     *
724
     * @return OutputInterface
725
     */
726
    private function fallbackOutput(OutputInterface $output = null)
727
    {
728
        if (null !== $output) {
729
            return $output;
730
        }
731
732
        if ($this->getHelperSet()->has('io')) {
733
            /** @var $helper IoHelper */
734
            $helper = $this->getHelperSet()->get('io');
735
            $output = $helper->getOutput();
736
        }
737
738
        if (null === $output) {
739
            $output = new NullOutput();
740
        }
741
742
        return $output;
743
    }
744
}
745