aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/CoreBundle/Command/InstallCommand.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag/CoreBundle/Command/InstallCommand.php')
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php281
1 files changed, 65 insertions, 216 deletions
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index f0738b91..877dbfa2 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -2,19 +2,17 @@
2 2
3namespace Wallabag\CoreBundle\Command; 3namespace Wallabag\CoreBundle\Command;
4 4
5use Craue\ConfigBundle\Entity\Setting;
5use FOS\UserBundle\Event\UserEvent; 6use FOS\UserBundle\Event\UserEvent;
6use FOS\UserBundle\FOSUserEvents; 7use FOS\UserBundle\FOSUserEvents;
7use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; 8use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
8use Symfony\Component\Console\Helper\Table;
9use Symfony\Component\Console\Input\ArrayInput; 9use Symfony\Component\Console\Input\ArrayInput;
10use Symfony\Component\Console\Input\InputInterface; 10use Symfony\Component\Console\Input\InputInterface;
11use Symfony\Component\Console\Input\InputOption; 11use Symfony\Component\Console\Input\InputOption;
12use Symfony\Component\Console\Output\BufferedOutput; 12use Symfony\Component\Console\Output\BufferedOutput;
13use Symfony\Component\Console\Output\OutputInterface; 13use Symfony\Component\Console\Output\OutputInterface;
14use Symfony\Component\Console\Question\ConfirmationQuestion;
15use Symfony\Component\Console\Question\Question; 14use Symfony\Component\Console\Question\Question;
16use Wallabag\CoreBundle\Entity\Config; 15use Symfony\Component\Console\Style\SymfonyStyle;
17use Craue\ConfigBundle\Entity\Setting;
18 16
19class InstallCommand extends ContainerAwareCommand 17class InstallCommand extends ContainerAwareCommand
20{ 18{
@@ -24,9 +22,9 @@ class InstallCommand extends ContainerAwareCommand
24 protected $defaultInput; 22 protected $defaultInput;
25 23
26 /** 24 /**
27 * @var OutputInterface 25 * @var SymfonyStyle
28 */ 26 */
29 protected $defaultOutput; 27 protected $io;
30 28
31 /** 29 /**
32 * @var array 30 * @var array
@@ -53,25 +51,27 @@ class InstallCommand extends ContainerAwareCommand
53 protected function execute(InputInterface $input, OutputInterface $output) 51 protected function execute(InputInterface $input, OutputInterface $output)
54 { 52 {
55 $this->defaultInput = $input; 53 $this->defaultInput = $input;
56 $this->defaultOutput = $output;
57 54
58 $output->writeln('<info>Installing wallabag...</info>'); 55 $this->io = new SymfonyStyle($input, $output);
59 $output->writeln(''); 56
57 $this->io->title('Wallabag installer');
60 58
61 $this 59 $this
62 ->checkRequirements() 60 ->checkRequirements()
63 ->setupDatabase() 61 ->setupDatabase()
64 ->setupAdmin() 62 ->setupAdmin()
65 ->setupConfig() 63 ->setupConfig()
64 ->runMigrations()
66 ; 65 ;
67 66
68 $output->writeln('<info>wallabag has been successfully installed.</info>'); 67 $this->io->success('Wallabag has been successfully installed.');
69 $output->writeln('<comment>Just execute `php bin/console server:run --env=prod` for using wallabag: http://localhost:8000</comment>'); 68 $this->io->note('Just execute `php bin/console server:run --env=prod` for using wallabag: http://localhost:8000');
70 } 69 }
71 70
72 protected function checkRequirements() 71 protected function checkRequirements()
73 { 72 {
74 $this->defaultOutput->writeln('<info><comment>Step 1 of 4.</comment> Checking system requirements.</info>'); 73 $this->io->section('Step 1 of 5: Checking system requirements.');
74
75 $doctrineManager = $this->getContainer()->get('doctrine')->getManager(); 75 $doctrineManager = $this->getContainer()->get('doctrine')->getManager();
76 76
77 $rows = []; 77 $rows = [];
@@ -85,7 +85,7 @@ class InstallCommand extends ContainerAwareCommand
85 if (!extension_loaded($this->getContainer()->getParameter('database_driver'))) { 85 if (!extension_loaded($this->getContainer()->getParameter('database_driver'))) {
86 $fulfilled = false; 86 $fulfilled = false;
87 $status = '<error>ERROR!</error>'; 87 $status = '<error>ERROR!</error>';
88 $help = 'Database driver "'.$this->getContainer()->getParameter('database_driver').'" is not installed.'; 88 $help = 'Database driver "' . $this->getContainer()->getParameter('database_driver') . '" is not installed.';
89 } 89 }
90 90
91 $rows[] = [sprintf($label, $this->getContainer()->getParameter('database_driver')), $status, $help]; 91 $rows[] = [sprintf($label, $this->getContainer()->getParameter('database_driver')), $status, $help];
@@ -100,10 +100,10 @@ class InstallCommand extends ContainerAwareCommand
100 $conn->connect(); 100 $conn->connect();
101 } catch (\Exception $e) { 101 } catch (\Exception $e) {
102 if (false === strpos($e->getMessage(), 'Unknown database') 102 if (false === strpos($e->getMessage(), 'Unknown database')
103 && false === strpos($e->getMessage(), 'database "'.$this->getContainer()->getParameter('database_name').'" does not exist')) { 103 && false === strpos($e->getMessage(), 'database "' . $this->getContainer()->getParameter('database_name') . '" does not exist')) {
104 $fulfilled = false; 104 $fulfilled = false;
105 $status = '<error>ERROR!</error>'; 105 $status = '<error>ERROR!</error>';
106 $help = 'Can\'t connect to the database: '.$e->getMessage(); 106 $help = 'Can\'t connect to the database: ' . $e->getMessage();
107 } 107 }
108 } 108 }
109 109
@@ -122,7 +122,7 @@ class InstallCommand extends ContainerAwareCommand
122 if (false === version_compare($version, $minimalVersion, '>')) { 122 if (false === version_compare($version, $minimalVersion, '>')) {
123 $fulfilled = false; 123 $fulfilled = false;
124 $status = '<error>ERROR!</error>'; 124 $status = '<error>ERROR!</error>';
125 $help = 'Your MySQL version ('.$version.') is too old, consider upgrading ('.$minimalVersion.'+).'; 125 $help = 'Your MySQL version (' . $version . ') is too old, consider upgrading (' . $minimalVersion . '+).';
126 } 126 }
127 } 127 }
128 128
@@ -136,50 +136,44 @@ class InstallCommand extends ContainerAwareCommand
136 if (isset($matches[1]) & version_compare($matches[1], '9.2.0', '<')) { 136 if (isset($matches[1]) & version_compare($matches[1], '9.2.0', '<')) {
137 $fulfilled = false; 137 $fulfilled = false;
138 $status = '<error>ERROR!</error>'; 138 $status = '<error>ERROR!</error>';
139 $help = 'PostgreSQL should be greater than 9.1 (actual version: '.$matches[1].')'; 139 $help = 'PostgreSQL should be greater than 9.1 (actual version: ' . $matches[1] . ')';
140 } 140 }
141 } 141 }
142 142
143 $rows[] = [$label, $status, $help]; 143 $rows[] = [$label, $status, $help];
144 144
145 foreach ($this->functionExists as $functionRequired) { 145 foreach ($this->functionExists as $functionRequired) {
146 $label = '<comment>'.$functionRequired.'</comment>'; 146 $label = '<comment>' . $functionRequired . '</comment>';
147 $status = '<info>OK!</info>'; 147 $status = '<info>OK!</info>';
148 $help = ''; 148 $help = '';
149 149
150 if (!function_exists($functionRequired)) { 150 if (!function_exists($functionRequired)) {
151 $fulfilled = false; 151 $fulfilled = false;
152 $status = '<error>ERROR!</error>'; 152 $status = '<error>ERROR!</error>';
153 $help = 'You need the '.$functionRequired.' function activated'; 153 $help = 'You need the ' . $functionRequired . ' function activated';
154 } 154 }
155 155
156 $rows[] = [$label, $status, $help]; 156 $rows[] = [$label, $status, $help];
157 } 157 }
158 158
159 $table = new Table($this->defaultOutput); 159 $this->io->table(['Checked', 'Status', 'Recommendation'], $rows);
160 $table
161 ->setHeaders(['Checked', 'Status', 'Recommendation'])
162 ->setRows($rows)
163 ->render();
164 160
165 if (!$fulfilled) { 161 if (!$fulfilled) {
166 throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.'); 162 throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.');
167 } 163 }
168 164
169 $this->defaultOutput->writeln('<info>Success! Your system can run wallabag properly.</info>'); 165 $this->io->success('Success! Your system can run wallabag properly.');
170
171 $this->defaultOutput->writeln('');
172 166
173 return $this; 167 return $this;
174 } 168 }
175 169
176 protected function setupDatabase() 170 protected function setupDatabase()
177 { 171 {
178 $this->defaultOutput->writeln('<info><comment>Step 2 of 4.</comment> Setting up database.</info>'); 172 $this->io->section('Step 2 of 5: Setting up database.');
179 173
180 // user want to reset everything? Don't care about what is already here 174 // user want to reset everything? Don't care about what is already here
181 if (true === $this->defaultInput->getOption('reset')) { 175 if (true === $this->defaultInput->getOption('reset')) {
182 $this->defaultOutput->writeln('Droping database, creating database and schema, clearing the cache'); 176 $this->io->text('Dropping database, creating database and schema, clearing the cache');
183 177
184 $this 178 $this
185 ->runCommand('doctrine:database:drop', ['--force' => true]) 179 ->runCommand('doctrine:database:drop', ['--force' => true])
@@ -188,13 +182,13 @@ class InstallCommand extends ContainerAwareCommand
188 ->runCommand('cache:clear') 182 ->runCommand('cache:clear')
189 ; 183 ;
190 184
191 $this->defaultOutput->writeln(''); 185 $this->io->newLine();
192 186
193 return $this; 187 return $this;
194 } 188 }
195 189
196 if (!$this->isDatabasePresent()) { 190 if (!$this->isDatabasePresent()) {
197 $this->defaultOutput->writeln('Creating database and schema, clearing the cache'); 191 $this->io->text('Creating database and schema, clearing the cache');
198 192
199 $this 193 $this
200 ->runCommand('doctrine:database:create') 194 ->runCommand('doctrine:database:create')
@@ -202,16 +196,13 @@ class InstallCommand extends ContainerAwareCommand
202 ->runCommand('cache:clear') 196 ->runCommand('cache:clear')
203 ; 197 ;
204 198
205 $this->defaultOutput->writeln(''); 199 $this->io->newLine();
206 200
207 return $this; 201 return $this;
208 } 202 }
209 203
210 $questionHelper = $this->getHelper('question'); 204 if ($this->io->confirm('It appears that your database already exists. Would you like to reset it?', false)) {
211 $question = new ConfirmationQuestion('It appears that your database already exists. Would you like to reset it? (y/N)', false); 205 $this->io->text('Dropping database, creating database and schema...');
212
213 if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) {
214 $this->defaultOutput->writeln('Droping database, creating database and schema');
215 206
216 $this 207 $this
217 ->runCommand('doctrine:database:drop', ['--force' => true]) 208 ->runCommand('doctrine:database:drop', ['--force' => true])
@@ -219,9 +210,8 @@ class InstallCommand extends ContainerAwareCommand
219 ->runCommand('doctrine:schema:create') 210 ->runCommand('doctrine:schema:create')
220 ; 211 ;
221 } elseif ($this->isSchemaPresent()) { 212 } elseif ($this->isSchemaPresent()) {
222 $question = new ConfirmationQuestion('Seems like your database contains schema. Do you want to reset it? (y/N)', false); 213 if ($this->io->confirm('Seems like your database contains schema. Do you want to reset it?', false)) {
223 if ($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { 214 $this->io->text('Dropping schema and creating schema...');
224 $this->defaultOutput->writeln('Droping schema and creating schema');
225 215
226 $this 216 $this
227 ->runCommand('doctrine:schema:drop', ['--force' => true]) 217 ->runCommand('doctrine:schema:drop', ['--force' => true])
@@ -229,29 +219,27 @@ class InstallCommand extends ContainerAwareCommand
229 ; 219 ;
230 } 220 }
231 } else { 221 } else {
232 $this->defaultOutput->writeln('Creating schema'); 222 $this->io->text('Creating schema...');
233 223
234 $this 224 $this
235 ->runCommand('doctrine:schema:create') 225 ->runCommand('doctrine:schema:create')
236 ; 226 ;
237 } 227 }
238 228
239 $this->defaultOutput->writeln('Clearing the cache'); 229 $this->io->text('Clearing the cache...');
240 $this->runCommand('cache:clear'); 230 $this->runCommand('cache:clear');
241 231
242 $this->defaultOutput->writeln(''); 232 $this->io->newLine();
233 $this->io->text('<info>Database successfully setup.</info>');
243 234
244 return $this; 235 return $this;
245 } 236 }
246 237
247 protected function setupAdmin() 238 protected function setupAdmin()
248 { 239 {
249 $this->defaultOutput->writeln('<info><comment>Step 3 of 4.</comment> Administration setup.</info>'); 240 $this->io->section('Step 3 of 5: Administration setup.');
250
251 $questionHelper = $this->getHelperSet()->get('question');
252 $question = new ConfirmationQuestion('Would you like to create a new admin user (recommended) ? (Y/n)', true);
253 241
254 if (!$questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)) { 242 if (!$this->io->confirm('Would you like to create a new admin user (recommended)?', true)) {
255 return $this; 243 return $this;
256 } 244 }
257 245
@@ -260,14 +248,13 @@ class InstallCommand extends ContainerAwareCommand
260 $userManager = $this->getContainer()->get('fos_user.user_manager'); 248 $userManager = $this->getContainer()->get('fos_user.user_manager');
261 $user = $userManager->createUser(); 249 $user = $userManager->createUser();
262 250
263 $question = new Question('Username (default: wallabag) :', 'wallabag'); 251 $user->setUsername($this->io->ask('Username', 'wallabag'));
264 $user->setUsername($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question));
265 252
266 $question = new Question('Password (default: wallabag) :', 'wallabag'); 253 $question = new Question('Password', 'wallabag');
267 $user->setPlainPassword($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question)); 254 $question->setHidden(true);
255 $user->setPlainPassword($this->io->askQuestion($question));
268 256
269 $question = new Question('Email:', ''); 257 $user->setEmail($this->io->ask('Email', ''));
270 $user->setEmail($questionHelper->ask($this->defaultInput, $this->defaultOutput, $question));
271 258
272 $user->setEnabled(true); 259 $user->setEnabled(true);
273 $user->addRole('ROLE_SUPER_ADMIN'); 260 $user->addRole('ROLE_SUPER_ADMIN');
@@ -278,168 +265,20 @@ class InstallCommand extends ContainerAwareCommand
278 $event = new UserEvent($user); 265 $event = new UserEvent($user);
279 $this->getContainer()->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event); 266 $this->getContainer()->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
280 267
281 $this->defaultOutput->writeln(''); 268 $this->io->text('<info>Administration successfully setup.</info>');
282 269
283 return $this; 270 return $this;
284 } 271 }
285 272
286 protected function setupConfig() 273 protected function setupConfig()
287 { 274 {
288 $this->defaultOutput->writeln('<info><comment>Step 4 of 4.</comment> Config setup.</info>'); 275 $this->io->section('Step 4 of 5: Config setup.');
289 $em = $this->getContainer()->get('doctrine.orm.entity_manager'); 276 $em = $this->getContainer()->get('doctrine.orm.entity_manager');
290 277
291 // cleanup before insert new stuff 278 // cleanup before insert new stuff
292 $em->createQuery('DELETE FROM CraueConfigBundle:Setting')->execute(); 279 $em->createQuery('DELETE FROM CraueConfigBundle:Setting')->execute();
293 280
294 $settings = [ 281 foreach ($this->getContainer()->getParameter('wallabag_core.default_internal_settings') as $setting) {
295 [
296 'name' => 'share_public',
297 'value' => '1',
298 'section' => 'entry',
299 ],
300 [
301 'name' => 'carrot',
302 'value' => '1',
303 'section' => 'entry',
304 ],
305 [
306 'name' => 'share_diaspora',
307 'value' => '1',
308 'section' => 'entry',
309 ],
310 [
311 'name' => 'diaspora_url',
312 'value' => 'http://diasporapod.com',
313 'section' => 'entry',
314 ],
315 [
316 'name' => 'share_unmark',
317 'value' => '1',
318 'section' => 'entry',
319 ],
320 [
321 'name' => 'unmark_url',
322 'value' => 'https://unmark.it',
323 'section' => 'entry',
324 ],
325 [
326 'name' => 'share_shaarli',
327 'value' => '1',
328 'section' => 'entry',
329 ],
330 [
331 'name' => 'shaarli_url',
332 'value' => 'http://myshaarli.com',
333 'section' => 'entry',
334 ],
335 [
336 'name' => 'share_mail',
337 'value' => '1',
338 'section' => 'entry',
339 ],
340 [
341 'name' => 'share_twitter',
342 'value' => '1',
343 'section' => 'entry',
344 ],
345 [
346 'name' => 'export_epub',
347 'value' => '1',
348 'section' => 'export',
349 ],
350 [
351 'name' => 'export_mobi',
352 'value' => '1',
353 'section' => 'export',
354 ],
355 [
356 'name' => 'export_pdf',
357 'value' => '1',
358 'section' => 'export',
359 ],
360 [
361 'name' => 'export_csv',
362 'value' => '1',
363 'section' => 'export',
364 ],
365 [
366 'name' => 'export_json',
367 'value' => '1',
368 'section' => 'export',
369 ],
370 [
371 'name' => 'export_txt',
372 'value' => '1',
373 'section' => 'export',
374 ],
375 [
376 'name' => 'export_xml',
377 'value' => '1',
378 'section' => 'export',
379 ],
380 [
381 'name' => 'import_with_redis',
382 'value' => '0',
383 'section' => 'import',
384 ],
385 [
386 'name' => 'import_with_rabbitmq',
387 'value' => '0',
388 'section' => 'import',
389 ],
390 [
391 'name' => 'show_printlink',
392 'value' => '1',
393 'section' => 'entry',
394 ],
395 [
396 'name' => 'wallabag_support_url',
397 'value' => 'https://www.wallabag.org/pages/support.html',
398 'section' => 'misc',
399 ],
400 [
401 'name' => 'wallabag_url',
402 'value' => '',
403 'section' => 'misc',
404 ],
405 [
406 'name' => 'piwik_enabled',
407 'value' => '0',
408 'section' => 'analytics',
409 ],
410 [
411 'name' => 'piwik_host',
412 'value' => 'v2.wallabag.org',
413 'section' => 'analytics',
414 ],
415 [
416 'name' => 'piwik_site_id',
417 'value' => '1',
418 'section' => 'analytics',
419 ],
420 [
421 'name' => 'demo_mode_enabled',
422 'value' => '0',
423 'section' => 'misc',
424 ],
425 [
426 'name' => 'demo_mode_username',
427 'value' => 'wallabag',
428 'section' => 'misc',
429 ],
430 [
431 'name' => 'download_images_enabled',
432 'value' => '0',
433 'section' => 'misc',
434 ],
435 [
436 'name' => 'restricted_access',
437 'value' => '0',
438 'section' => 'entry',
439 ],
440 ];
441
442 foreach ($settings as $setting) {
443 $newSetting = new Setting(); 282 $newSetting = new Setting();
444 $newSetting->setName($setting['name']); 283 $newSetting->setName($setting['name']);
445 $newSetting->setValue($setting['value']); 284 $newSetting->setValue($setting['value']);
@@ -449,7 +288,19 @@ class InstallCommand extends ContainerAwareCommand
449 288
450 $em->flush(); 289 $em->flush();
451 290
452 $this->defaultOutput->writeln(''); 291 $this->io->text('<info>Config successfully setup.</info>');
292
293 return $this;
294 }
295
296 protected function runMigrations()
297 {
298 $this->io->section('Step 5 of 5: Run migrations.');
299
300 $this
301 ->runCommand('doctrine:migrations:migrate', ['--no-interaction' => true]);
302
303 $this->io->text('<info>Migrations successfully executed.</info>');
453 304
454 return $this; 305 return $this;
455 } 306 }
@@ -480,20 +331,18 @@ class InstallCommand extends ContainerAwareCommand
480 $output = new BufferedOutput(); 331 $output = new BufferedOutput();
481 $exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output); 332 $exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output);
482 333
334 // PDO does not always close the connection after Doctrine commands.
335 // See https://github.com/symfony/symfony/issues/11750.
336 $this->getContainer()->get('doctrine')->getManager()->getConnection()->close();
337
483 if (0 !== $exitCode) { 338 if (0 !== $exitCode) {
484 $this->getApplication()->setAutoExit(true); 339 $this->getApplication()->setAutoExit(true);
485 340
486 $this->defaultOutput->writeln(''); 341 throw new \RuntimeException(
487 $this->defaultOutput->writeln('<error>The command "'.$command.'" generates some errors: </error>'); 342 'The command "' . $command . "\" generates some errors: \n\n"
488 $this->defaultOutput->writeln($output->fetch()); 343 . $output->fetch());
489
490 die();
491 } 344 }
492 345
493 // PDO does not always close the connection after Doctrine commands.
494 // See https://github.com/symfony/symfony/issues/11750.
495 $this->getContainer()->get('doctrine')->getManager()->getConnection()->close();
496
497 return $this; 346 return $this;
498 } 347 }
499 348
@@ -535,7 +384,7 @@ class InstallCommand extends ContainerAwareCommand
535 } 384 }
536 385
537 try { 386 try {
538 return in_array($databaseName, $schemaManager->listDatabases()); 387 return in_array($databaseName, $schemaManager->listDatabases(), true);
539 } catch (\Doctrine\DBAL\Exception\DriverException $e) { 388 } catch (\Doctrine\DBAL\Exception\DriverException $e) {
540 // it means we weren't able to get database list, assume the database doesn't exist 389 // it means we weren't able to get database list, assume the database doesn't exist
541 390