Completed
Push — master ( 75748b...36048b )
by Michael
06:58
created

AbstractDatabaseCommon::executeSqlStatements()   C

Complexity

Conditions 8
Paths 36

Size

Total Lines 63
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 11
Bugs 2 Features 0
Metric Value
c 11
b 2
f 0
dl 0
loc 63
rs 6.8825
cc 8
eloc 45
nc 36
nop 3

How to fix   Long Method   

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
 * Contains AbstractDatabaseCommon class.
4
 *
5
 * PHP version 5.5
6
 *
7
 * LICENSE:
8
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
9
 * which can be used to access the Eve Online API data and place it into a
10
 * database.
11
 * Copyright (C) 2014-2016 Michael Cummings
12
 *
13
 * This program is free software: you can redistribute it and/or modify it
14
 * under the terms of the GNU Lesser General Public License as published by the
15
 * Free Software Foundation, either version 3 of the License, or (at your
16
 * option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful, but WITHOUT
19
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
21
 * for more details.
22
 *
23
 * You should have received a copy of the GNU Lesser General Public License
24
 * along with this program. If not, see
25
 * <http://www.gnu.org/licenses/>.
26
 *
27
 * You should be able to find a copy of this license in the LICENSE.md file. A
28
 * copy of the GNU GPL should also be available in the GNU-GPL.md file.
29
 *
30
 * @copyright 2014-2016 Michael Cummings
31
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
32
 * @author    Michael Cummings <[email protected]>
33
 */
34
namespace Yapeal\Console\Command;
35
36
use FilePathNormalizer\FilePathNormalizerTrait;
37
use Symfony\Component\Console\Command\Command;
38
use Symfony\Component\Console\Helper\ProgressBar;
39
use Symfony\Component\Console\Input\InputInterface;
40
use Symfony\Component\Console\Input\InputOption;
41
use Symfony\Component\Console\Output\OutputInterface;
42
use Yapeal\CommonToolsTrait;
43
use Yapeal\Exception\YapealDatabaseException;
44
45
/**
46
 * Class AbstractDatabaseCommon
47
 */
48
abstract class AbstractDatabaseCommon extends Command
49
{
50
    use CommonToolsTrait, FilePathNormalizerTrait;
51
    /**
52
     * Sets the help message and all the common options used by the Database:* commands.
53
     *
54
     * @param string $help Command help text.
55
     */
56
    protected function addOptions($help)
57
    {
58
        $this->addOption('configFile', 'c', InputOption::VALUE_REQUIRED, 'Configuration file to get settings from.')
59
             ->addOption('database', 'd', InputOption::VALUE_REQUIRED, 'Name of the database.')
60
             ->addOption('hostName', 'o', InputOption::VALUE_REQUIRED, 'Host name for database server.')
61
             ->addOption('password', 'p', InputOption::VALUE_REQUIRED, 'Password used to access database.')
62
             ->addOption('platform', null, InputOption::VALUE_REQUIRED,
63
                 'Platform of database driver. Currently only "mysql" can be used.')
64
             ->addOption('port', null, InputOption::VALUE_REQUIRED,
65
                 'Port number for remote server. Only needed if using http connection.')
66
             ->addOption('tablePrefix', 't', InputOption::VALUE_REQUIRED, 'Prefix for database table names.')
67
             ->addOption('userName', 'u', InputOption::VALUE_REQUIRED, 'User name used to access database.')
68
             ->setHelp($help);
69
    }
70
    /** @noinspection PhpMissingParentCallCommonInspection */
71
    /**
72
     * Executes the current command.
73
     *
74
     * This method is not abstract because you can use this class
75
     * as a concrete class. In this case, instead of defining the
76
     * execute() method, you set the code to execute by passing
77
     * a Closure to the setCode() method.
78
     *
79
     * @param InputInterface  $input  An InputInterface instance
80
     * @param OutputInterface $output An OutputInterface instance
81
     *
82
     * @return int|null null or 0 if everything went fine, or an error code
83
     * @throws \LogicException
84
     *
85
     * @see    setCode()
86
     */
87
    protected function execute(InputInterface $input, OutputInterface $output)
88
    {
89
        $this->processCliOptions($input->getOptions());
90
        return $this->processSql($output);
91
    }
92
    /**
93
     * @param string          $sqlStatements
94
     * @param string          $fileName
95
     * @param OutputInterface $output
96
     *
97
     * @throws \InvalidArgumentException
98
     * @throws \LogicException
99
     * @throws \Symfony\Component\Console\Exception\LogicException
100
     * @throws \Yapeal\Exception\YapealDatabaseException
101
     */
102
    protected function executeSqlStatements($sqlStatements, $fileName, OutputInterface $output)
103
    {
104
        $replacements = [
105
            ';' => '',
106
            '{database}' => $this->getDic()['Yapeal.Sql.database'],
107
            '{engine}' => $this->getDic()['Yapeal.Sql.engine'],
108
            '{ engine}' => $this->getDic()['Yapeal.Sql.engine'],
109
            '{table_prefix}' => $this->getDic()['Yapeal.Sql.tablePrefix'],
110
            '$$' => ';'
111
        ];
112
        $pdo = $this->getPdo();
113
        // Split up SQL into statements on ';'.
114
        // Replace {database}, {table_prefix}, {engine}, ';', and '$$' in statements.
115
        /**
116
         * @var string[] $statements
117
         */
118
        $statements = str_replace(array_keys($replacements), array_values($replacements), explode(';', $sqlStatements));
119
        // 5 is a 'magic' number that I think is shorter than any legal SQL statement.
120
        $statements = array_filter($statements, function ($value) {
121
            return 5 <= strlen(trim($value));
122
        });
123
        $progress = null;
124
        if ($output::VERBOSITY_QUIET !== $output->getVerbosity()) {
125
            if (false === strpos($fileName, '::')) {
126
                $mess = sprintf('<info>Execute %1$s/%2$s</info>', basename(dirname($fileName)),
127
                    basename($fileName, '.sql'));
128
            } else {
129
                $mess = sprintf('<info>Execute %s</info>', $fileName);
130
            }
131
            $output->writeln($mess);
132
            $progress = $this->createProgressBar($output, count($statements));
133
        }
134
        foreach ($statements as $statement => $sql) {
135
            $sql = trim($sql);
136
            try {
137
                $pdo->exec($sql);
138
                if (null !== $progress) {
139
                    $progress->setMessage('<comment>executing</comment>');
140
                    $progress->advance();
141
                }
142
            } catch (\PDOException $exc) {
143
                if (null !== $progress) {
144
                    $progress->setMessage('<error>Failed</error>');
145
                    $progress->finish();
146
                    $output->writeln('');
147
                }
148
                $mess = $sql . PHP_EOL;
149
                $mess .= sprintf(
150
                    'Sql failed in %1$s on statement %2$s with (%3$s) %4$s',
151
                    $fileName,
152
                    $statement,
153
                    $exc->getCode(),
154
                    $exc->getMessage()
155
                );
156
                throw new YapealDatabaseException($mess, 2);
157
            }
158
        }
159
        if (null !== $progress) {
160
            $progress->setMessage('');
161
            $progress->finish();
162
            $output->writeln('');
163
        }
164
    }
165
    /**
166
     * @param array $options
167
     *
168
     * @return AbstractDatabaseCommon
169
     * @throws \LogicException
170
     */
171
    protected function processCliOptions(array $options)
172
    {
173
        $base = 'Yapeal.Sql.';
174
        foreach (['class', 'database', 'hostName', 'password', 'platform', 'tablePrefix', 'userName'] as $option) {
175
            if (!empty($options[$option])) {
176
                $this->getDic()[$base . $option] = $options[$option];
177
            }
178
        }
179
        if (!empty($options['configFile'])) {
180
            $this->getDic()['Yapeal.Config.configDir'] = dirname($options['configFile']);
181
            $this->getDic()['Yapeal.Config.fileName'] = basename($options['configFile']);
182
        }
183
        return $this;
184
    }
185
    /**
186
     * @param OutputInterface $output
187
     */
188
    abstract protected function processSql(OutputInterface $output);
189
    /**
190
     * @param OutputInterface $output
191
     * @param int             $statementCount
192
     *
193
     * @return ProgressBar
194
     */
195
    private function createProgressBar(OutputInterface $output, $statementCount)
196
    {
197
        $progress = new ProgressBar($output);
198
        $progress->setRedrawFrequency(1);
199
        $progress->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s% %message%');
200
        $progress->setMessage('<info>starting</info>');
201
        $progress->start($statementCount);
202
        $progress->setBarWidth(min(4 * $statementCount + 2, 50));
203
        return $progress;
204
    }
205
}
206