Failed Conditions
Pull Request — 4.0 (#4439)
by
unknown
04:42
created

InstallerCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
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
        // 以下環境変数に規定済の設定値があれば利用する
102
        // APP_ENV
103
        $appEnv = env('APP_ENV', 'dev');
104
        // .envが存在しない状態では規定値'install'となっているため、
105
        if ($appEnv === 'install') {
106
            $appEnv = 'dev';
107
        }
108
109
        // APP_DEBUG
110
        $appDebug = env('APP_DEBUG','1');
111
112
        // ECCUBE_ADMIN_ROUTE
113
        $adminRoute = $this->container->getParameter('eccube_admin_route');
114
        if (empty($adminRoute)) {
115
            $adminRoute = 'admin';
116
        }
117
118
        // ECCUBE_TEMPLATE_CODE
119
        $templateCode = $this->container->getParameter('eccube_theme_code');
120
        if (empty($templateCode)) {
121
            $templateCode = 'default';
122
        }
123
124
        // ECCUBE_LOCALE
125
        $locale = $this->container->getParameter('locale');
126
        if (empty($locale)) {
127
            $locale = 'ja';
128
        }
129
130
        $this->io->caution('Execute the installation process. All data is initialized.');
131
        $question = new ConfirmationQuestion('Is it OK?');
132
        if (!$this->io->askQuestion($question)) {
133
            // `no`の場合はキャンセルメッセージを出力して終了する
134
            $this->setCode(function () {
135
                $this->io->success('EC-CUBE installation stopped.');
136
            });
137
138
            return;
139
        }
140
141
        $envParameters = [
142
            'APP_ENV' => $appEnv,
143
            'APP_DEBUG' => $appDebug,
144
            'DATABASE_URL' => $databaseUrl,
145
            'DATABASE_SERVER_VERSION' => $serverVersion,
146
            'MAILER_URL' => $mailerUrl,
147
            'ECCUBE_AUTH_MAGIC' => $authMagic,
148
            'ECCUBE_ADMIN_ROUTE' => $adminRoute,
149
            'ECCUBE_TEMPLATE_CODE' => $templateCode,
150
            'ECCUBE_LOCALE' => $locale,
151
        ];
152
153
        $envDir = $this->container->getParameter('kernel.project_dir');
154
        $envFile = $envDir.'/.env';
155
        $envDistFile = $envDir.'/.env.dist';
156
157
        $env = file_exists($envFile)
158
            ? file_get_contents($envFile)
159
            : file_get_contents($envDistFile);
160
161
        $env = StringUtil::replaceOrAddEnv($env, $envParameters);
162
163
        file_put_contents($envFile, $env);
164
    }
165
166
    protected function initialize(InputInterface $input, OutputInterface $output)
167
    {
168
        $this->io = new SymfonyStyle($input, $output);
169
    }
170
171
    protected function execute(InputInterface $input, OutputInterface $output)
172
    {
173
        // Process実行時に, APP_ENV/APP_DEBUGが子プロセスに引き継がれてしまうため,
174
        // 生成された.envをロードして上書きする.
175
        if ($input->isInteractive()) {
176
            $envDir = $this->container->getParameter('kernel.project_dir');
177
            if (file_exists($envDir.'/.env')) {
178
                (new Dotenv($envDir))->overload();
179
            }
180
        }
181
182
        // 対話モード実行時, container->getParameter('eccube_database_url')では
183
        // 更新後の値が取得できないため, getenv()を使用する.
184
        $databaseUrl = getenv('DATABASE_URL');
185
        $databaseName = $this->getDatabaseName($databaseUrl);
186
        $ifNotExists = $databaseName === 'sqlite' ? '' : ' --if-not-exists';
187
188
        // データベース作成, スキーマ作成, 初期データの投入を行う.
189
        $commands = [
190
            'doctrine:database:create'.$ifNotExists,
191
            'doctrine:schema:drop --force',
192
            'doctrine:schema:create',
193
            'eccube:fixtures:load',
194
            'cache:clear --no-warmup',
195
        ];
196
197
        // コンテナを再ロードするため別プロセスで実行する.
198
        foreach ($commands as $command) {
199
            try {
200
                $this->io->text(sprintf('<info>Run %s</info>...', $command));
201
                $process = new Process('bin/console '.$command);
202
                $process->mustRun();
203
                $this->io->text($process->getOutput());
204
            } catch (ProcessFailedException $e) {
205
                $this->io->error($e->getMessage());
206
207
                return;
208
            }
209
        }
210
211
        $this->io->success('EC-CUBE installation successful.');
212
    }
213
214
    protected function getDatabaseName($databaseUrl)
215
    {
216
        if (0 === strpos($databaseUrl, 'sqlite')) {
217
            return 'sqlite';
218
        }
219
        if (0 === strpos($databaseUrl, 'postgres')) {
220
            return 'postgres';
221
        }
222
        if (0 === strpos($databaseUrl, 'mysql')) {
223
            return 'mysql';
224
        }
225
226
        throw new \LogicException(sprintf('Database Url %s is invalid.', $databaseUrl));
227
    }
228
229
    protected function getDatabaseServerVersion($databaseUrl)
230
    {
231
        try {
232
            $conn = DriverManager::getConnection([
233
                'url' => $databaseUrl,
234
            ]);
235
        } catch (\Exception $e) {
236
            throw new \LogicException(sprintf('Database Url %s is invalid.', $databaseUrl));
237
        }
238
        $platform = $conn->getDatabasePlatform()->getName();
239 View Code Duplication
        switch ($platform) {
240
            case 'sqlite':
241
                $sql = 'SELECT sqlite_version() AS server_version';
242
                break;
243
            case 'mysql':
244
                $sql = 'SELECT version() AS server_version';
245
                break;
246
            case 'postgresql':
247
            default:
248
                $sql = 'SHOW server_version';
249
        }
250
        $stmt = $conn->executeQuery($sql);
251
        $version = $stmt->fetchColumn();
252
253
        if ($platform === 'postgresql') {
254
            preg_match('/\A([\d+\.]+)/', $version, $matches);
255
            $version = $matches[1];
256
        }
257
258
        return $version;
259
    }
260
}
261