Completed
Push — 4.0 ( 5cd1ec...87d096 )
by
unknown
07:08 queued 11s
created

InstallerCommand   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 204
Duplicated Lines 5.39 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
dl 11
loc 204
rs 10
c 0
b 0
f 0
wmc 26
lcom 1
cbo 11

7 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 4 1
B execute() 0 42 6
A getDatabaseName() 0 14 4
A __construct() 0 6 1
A configure() 0 5 1
B interact() 0 76 7
B getDatabaseServerVersion() 11 31 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Command;
15
16
use Doctrine\DBAL\DriverManager;
17
use Dotenv\Dotenv;
18
use Eccube\Util\StringUtil;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Console\Question\ConfirmationQuestion;
23
use Symfony\Component\Console\Style\SymfonyStyle;
24
use Symfony\Component\DependencyInjection\ContainerInterface;
25
use Symfony\Component\Process\Exception\ProcessFailedException;
26
use Symfony\Component\Process\Process;
27
28
class InstallerCommand extends Command
29
{
30
    protected static $defaultName = 'eccube:install';
31
32
    /**
33
     * @var ContainerInterface
34
     */
35
    protected $container;
36
37
    /**
38
     * @var SymfonyStyle
39
     */
40
    protected $io;
41
42
    /**
43
     * @var string
44
     */
45
    protected $databaseUrl;
46
47
    public function __construct(ContainerInterface $container)
48
    {
49
        parent::__construct();
50
51
        $this->container = $container;
52
    }
53
54
    protected function configure()
55
    {
56
        $this
57
            ->setDescription('Install EC-CUBE');
58
    }
59
60
    protected function interact(InputInterface $input, OutputInterface $output)
61
    {
62
        $this->io->title('EC-CUBE Installer Interactive Wizard');
63
        $this->io->text([
64
            'If you prefer to not use this interactive wizard, define the environment valiables as follows:',
65
            '',
66
            ' $ export APP_ENV=dev',
67
            ' $ export APP_DEBUG=1',
68
            ' $ export DATABASE_URL=database_url',
69
            ' $ export DATABASE_SERVER_VERSION=server_version',
70
            ' $ export MAILER_URL=mailer_url',
71
            ' $ export ECCUBE_AUTH_MAGIC=auth_magic',
72
            ' ... and more',
73
            ' $ php bin/console eccube:install --no-interaction',
74
            '',
75
        ]);
76
77
        // DATABASE_URL
78
        $databaseUrl = $this->container->getParameter('eccube_database_url');
79
        if (empty($databaseUrl)) {
80
            $databaseUrl = 'sqlite:///var/eccube.db';
81
        }
82
        $databaseUrl = $this->io->ask('Database Url', $databaseUrl);
83
84
        // DATABASE_SERVER_VERSION
85
        $serverVersion = $this->getDatabaseServerVersion($databaseUrl);
86
87
        // MAILER_URL
88
        $mailerUrl = $this->container->getParameter('eccube_mailer_url');
89
        if (empty($mailerUrl)) {
90
            $mailerUrl = 'null://localhost';
91
        }
92
        $mailerUrl = $this->io->ask('Mailer Url', $mailerUrl);
93
94
        // ECCUBE_AUTH_MAGIC
95
        $authMagic = $this->container->getParameter('eccube_auth_magic');
96
        if (empty($authMagic) || $authMagic === '<change.me>') {
97
            $authMagic = StringUtil::random();
98
        }
99
        $authMagic = $this->io->ask('Auth Magic', $authMagic);
100
101
        $this->io->caution('Execute the installation process. All data is initialized.');
102
        $question = new ConfirmationQuestion('Is it OK?');
103
        if (!$this->io->askQuestion($question)) {
104
            // `no`の場合はキャンセルメッセージを出力して終了する
105
            $this->setCode(function () {
106
                $this->io->success('EC-CUBE installation stopped.');
107
            });
108
109
            return;
110
        }
111
112
        $envParameters = [
113
            'APP_ENV' => 'dev',
114
            'APP_DEBUG' => '1',
115
            'DATABASE_URL' => $databaseUrl,
116
            'DATABASE_SERVER_VERSION' => $serverVersion,
117
            'MAILER_URL' => $mailerUrl,
118
            'ECCUBE_AUTH_MAGIC' => $authMagic,
119
            'ECCUBE_ADMIN_ROUTE' => 'admin',
120
            'ECCUBE_TEMPLATE_CODE' => 'default',
121
            'ECCUBE_LOCALE' => 'ja',
122
        ];
123
124
        $envDir = $this->container->getParameter('kernel.project_dir');
125
        $envFile = $envDir.'/.env';
126
        $envDistFile = $envDir.'/.env.dist';
127
128
        $env = file_exists($envFile)
129
            ? file_get_contents($envFile)
130
            : file_get_contents($envDistFile);
131
132
        $env = StringUtil::replaceOrAddEnv($env, $envParameters);
133
134
        file_put_contents($envFile, $env);
135
    }
136
137
    protected function initialize(InputInterface $input, OutputInterface $output)
138
    {
139
        $this->io = new SymfonyStyle($input, $output);
140
    }
141
142
    protected function execute(InputInterface $input, OutputInterface $output)
143
    {
144
        // Process実行時に, APP_ENV/APP_DEBUGが子プロセスに引き継がれてしまうため,
145
        // 生成された.envをロードして上書きする.
146
        if ($input->isInteractive()) {
147
            $envDir = $this->container->getParameter('kernel.project_dir');
148
            if (file_exists($envDir.'/.env')) {
149
                (new Dotenv($envDir))->overload();
150
            }
151
        }
152
153
        // 対話モード実行時, container->getParameter('eccube_database_url')では
154
        // 更新後の値が取得できないため, getenv()を使用する.
155
        $databaseUrl = getenv('DATABASE_URL');
156
        $databaseName = $this->getDatabaseName($databaseUrl);
157
        $ifNotExists = $databaseName === 'sqlite' ? '' : ' --if-not-exists';
158
159
        // データベース作成, スキーマ作成, 初期データの投入を行う.
160
        $commands = [
161
            'doctrine:database:create'.$ifNotExists,
162
            'doctrine:schema:drop --force',
163
            'doctrine:schema:create',
164
            'eccube:fixtures:load',
165
            'cache:clear --no-warmup',
166
        ];
167
168
        // コンテナを再ロードするため別プロセスで実行する.
169
        foreach ($commands as $command) {
170
            try {
171
                $this->io->text(sprintf('<info>Run %s</info>...', $command));
172
                $process = new Process('bin/console '.$command);
173
                $process->mustRun();
174
                $this->io->text($process->getOutput());
175
            } catch (ProcessFailedException $e) {
176
                $this->io->error($e->getMessage());
177
178
                return;
179
            }
180
        }
181
182
        $this->io->success('EC-CUBE installation successful.');
183
    }
184
185
    protected function getDatabaseName($databaseUrl)
186
    {
187
        if (0 === strpos($databaseUrl, 'sqlite')) {
188
            return 'sqlite';
189
        }
190
        if (0 === strpos($databaseUrl, 'postgres')) {
191
            return 'postgres';
192
        }
193
        if (0 === strpos($databaseUrl, 'mysql')) {
194
            return 'mysql';
195
        }
196
197
        throw new \LogicException(sprintf('Database Url %s is invalid.', $databaseUrl));
198
    }
199
200
    protected function getDatabaseServerVersion($databaseUrl)
201
    {
202
        try {
203
            $conn = DriverManager::getConnection([
204
                'url' => $databaseUrl,
205
            ]);
206
        } catch (\Exception $e) {
207
            throw new \LogicException(sprintf('Database Url %s is invalid.', $databaseUrl));
208
        }
209
        $platform = $conn->getDatabasePlatform()->getName();
210 View Code Duplication
        switch ($platform) {
211
            case 'sqlite':
212
                $sql = 'SELECT sqlite_version() AS server_version';
213
                break;
214
            case 'mysql':
215
                $sql = 'SELECT version() AS server_version';
216
                break;
217
            case 'postgresql':
218
            default:
219
                $sql = 'SHOW server_version';
220
        }
221
        $stmt = $conn->executeQuery($sql);
222
        $version = $stmt->fetchColumn();
223
224
        if ($platform === 'postgresql') {
225
            preg_match('/\A([\d+\.]+)/', $version, $matches);
226
            $version = $matches[1];
227
        }
228
229
        return $version;
230
    }
231
}
232