Version 1
[yaffs-website] / vendor / drupal / console / src / Command / Site / InstallCommand.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\AppConsole\Command\Site\InstallCommand.
6  */
7
8 namespace Drupal\Console\Command\Site;
9
10 use Symfony\Component\Filesystem\Filesystem;
11 use Symfony\Component\Config\Definition\Exception\Exception;
12 use Symfony\Component\Console\Input\ArgvInput;
13 use Symfony\Component\Console\Input\InputArgument;
14 use Symfony\Component\Console\Input\InputOption;
15 use Symfony\Component\Console\Input\InputInterface;
16 use Symfony\Component\Console\Output\OutputInterface;
17 use Symfony\Component\Console\Command\Command;
18 use Drupal\Core\Database\Database;
19 use Drupal\Core\Installer\Exception\AlreadyInstalledException;
20 use Drupal\Console\Core\Command\Shared\ContainerAwareCommandTrait;
21 use Drupal\Console\Command\Shared\DatabaseTrait;
22 use Drupal\Console\Core\Utils\ConfigurationManager;
23 use Drupal\Console\Extension\Manager;
24 use Drupal\Console\Core\Style\DrupalStyle;
25 use Drupal\Console\Bootstrap\Drupal;
26 use Drupal\Console\Utils\Site;
27 use DrupalFinder\DrupalFinder;
28
29 class InstallCommand extends Command
30 {
31     use ContainerAwareCommandTrait;
32     use DatabaseTrait;
33
34     /**
35      * @var Manager
36      */
37     protected $extensionManager;
38
39     /**
40      * @var Site
41      */
42     protected $site;
43
44     /**
45      * @var  ConfigurationManager
46      */
47     protected $configurationManager;
48
49     /**
50      * @var string
51      */
52     protected $appRoot;
53
54     /**
55      * InstallCommand constructor.
56      *
57      * @param Manager              $extensionManager
58      * @param Site                 $site
59      * @param ConfigurationManager $configurationManager
60      * @param string               $appRoot
61      */
62     public function __construct(
63         Manager $extensionManager,
64         Site $site,
65         ConfigurationManager $configurationManager,
66         $appRoot
67     ) {
68         $this->extensionManager = $extensionManager;
69         $this->site = $site;
70         $this->configurationManager = $configurationManager;
71         $this->appRoot = $appRoot;
72         parent::__construct();
73     }
74
75     protected function configure()
76     {
77         $this
78             ->setName('site:install')
79             ->setDescription($this->trans('commands.site.install.description'))
80             ->addArgument(
81                 'profile',
82                 InputArgument::OPTIONAL,
83                 $this->trans('commands.site.install.arguments.profile')
84             )
85             ->addOption(
86                 'langcode',
87                 '',
88                 InputOption::VALUE_REQUIRED,
89                 $this->trans('commands.site.install.options.langcode')
90             )
91             ->addOption(
92                 'db-type',
93                 '',
94                 InputOption::VALUE_REQUIRED,
95                 $this->trans('commands.site.install.options.db-type')
96             )
97             ->addOption(
98                 'db-file',
99                 '',
100                 InputOption::VALUE_REQUIRED,
101                 $this->trans('commands.site.install.options.db-file')
102             )
103             ->addOption(
104                 'db-host',
105                 '',
106                 InputOption::VALUE_OPTIONAL,
107                 $this->trans('commands.migrate.execute.options.db-host')
108             )
109             ->addOption(
110                 'db-name',
111                 '',
112                 InputOption::VALUE_OPTIONAL,
113                 $this->trans('commands.migrate.execute.options.db-name')
114             )
115             ->addOption(
116                 'db-user',
117                 '',
118                 InputOption::VALUE_OPTIONAL,
119                 $this->trans('commands.migrate.execute.options.db-user')
120             )
121             ->addOption(
122                 'db-pass',
123                 '',
124                 InputOption::VALUE_OPTIONAL,
125                 $this->trans('commands.migrate.execute.options.db-pass')
126             )
127             ->addOption(
128                 'db-prefix',
129                 '',
130                 InputOption::VALUE_OPTIONAL,
131                 $this->trans('commands.migrate.execute.options.db-prefix')
132             )
133             ->addOption(
134                 'db-port',
135                 '',
136                 InputOption::VALUE_OPTIONAL,
137                 $this->trans('commands.migrate.execute.options.db-port')
138             )
139             ->addOption(
140                 'site-name',
141                 '',
142                 InputOption::VALUE_REQUIRED,
143                 $this->trans('commands.site.install.options.site-name')
144             )
145             ->addOption(
146                 'site-mail',
147                 '',
148                 InputOption::VALUE_REQUIRED,
149                 $this->trans('commands.site.install.options.site-mail')
150             )
151             ->addOption(
152                 'account-name',
153                 '',
154                 InputOption::VALUE_REQUIRED,
155                 $this->trans('commands.site.install.options.account-name')
156             )
157             ->addOption(
158                 'account-mail',
159                 '',
160                 InputOption::VALUE_REQUIRED,
161                 $this->trans('commands.site.install.options.account-mail')
162             )
163             ->addOption(
164                 'account-pass',
165                 '',
166                 InputOption::VALUE_REQUIRED,
167                 $this->trans('commands.site.install.options.account-pass')
168             )
169             ->addOption(
170                 'force',
171                 '',
172                 InputOption::VALUE_NONE,
173                 $this->trans('commands.site.install.options.force')
174             );
175     }
176
177     /**
178      * {@inheritdoc}
179      */
180     protected function interact(InputInterface $input, OutputInterface $output)
181     {
182         $io = new DrupalStyle($input, $output);
183
184         // --profile option
185         $profile = $input->getArgument('profile');
186         if (!$profile) {
187             $profiles = $this->extensionManager
188                 ->discoverProfiles()
189                 ->showCore()
190                 ->showNoCore()
191                 ->showInstalled()
192                 ->showUninstalled()
193                 ->getList(true);
194
195             $profiles = array_filter(
196                 $profiles,
197                 function ($profile) {
198                     return strpos($profile, 'testing') !== 0;
199                 }
200             );
201
202             $profile = $io->choice(
203                 $this->trans('commands.site.install.questions.profile'),
204                 array_values($profiles)
205             );
206
207             $input->setArgument('profile', $profile);
208         }
209
210         // --langcode option
211         $langcode = $input->getOption('langcode');
212         if (!$langcode) {
213             $languages = $this->site->getStandardLanguages();
214             $defaultLanguage = $this->configurationManager
215                 ->getConfiguration()
216                 ->get('application.language');
217
218             $langcode = $io->choiceNoList(
219                 $this->trans('commands.site.install.questions.langcode'),
220                 $languages,
221                 $languages[$defaultLanguage]
222             );
223
224             $input->setOption('langcode', $langcode);
225         }
226
227         // Use default database setting if is available
228         $database = Database::getConnectionInfo();
229         if (empty($database['default'])) {
230             // --db-type option
231             $dbType = $input->getOption('db-type');
232             if (!$dbType) {
233                 $databases = $this->site->getDatabaseTypes();
234                 $dbType = $io->choice(
235                     $this->trans('commands.migrate.setup.questions.db-type'),
236                     array_column($databases, 'name')
237                 );
238
239                 foreach ($databases as $dbIndex => $database) {
240                     if ($database['name'] == $dbType) {
241                         $dbType = $dbIndex;
242                     }
243                 }
244
245                 $input->setOption('db-type', $dbType);
246             }
247
248             if ($dbType === 'sqlite') {
249                 // --db-file option
250                 $dbFile = $input->getOption('db-file');
251                 if (!$dbFile) {
252                     $dbFile = $io->ask(
253                         $this->trans('commands.migrate.execute.questions.db-file'),
254                         'sites/default/files/.ht.sqlite'
255                     );
256                     $input->setOption('db-file', $dbFile);
257                 }
258             } else {
259                 // --db-host option
260                 $dbHost = $input->getOption('db-host');
261                 if (!$dbHost) {
262                     $dbHost = $this->dbHostQuestion($io);
263                     $input->setOption('db-host', $dbHost);
264                 }
265
266                 // --db-name option
267                 $dbName = $input->getOption('db-name');
268                 if (!$dbName) {
269                     $dbName = $this->dbNameQuestion($io);
270                     $input->setOption('db-name', $dbName);
271                 }
272
273                 // --db-user option
274                 $dbUser = $input->getOption('db-user');
275                 if (!$dbUser) {
276                     $dbUser = $this->dbUserQuestion($io);
277                     $input->setOption('db-user', $dbUser);
278                 }
279
280                 // --db-pass option
281                 $dbPass = $input->getOption('db-pass');
282                 if (!$dbPass) {
283                     $dbPass = $this->dbPassQuestion($io);
284                     $input->setOption('db-pass', $dbPass);
285                 }
286
287                 // --db-port prefix
288                 $dbPort = $input->getOption('db-port');
289                 if (!$dbPort) {
290                     $dbPort = $this->dbPortQuestion($io);
291                     $input->setOption('db-port', $dbPort);
292                 }
293             }
294
295             // --db-prefix
296             $dbPrefix = $input->getOption('db-prefix');
297             if (!$dbPrefix) {
298                 $dbPrefix = $this->dbPrefixQuestion($io);
299                 $input->setOption('db-prefix', $dbPrefix);
300             }
301         } else {
302             $input->setOption('db-type', $database['default']['driver']);
303             $input->setOption('db-host', $database['default']['host']);
304             $input->setOption('db-name', $database['default']['database']);
305             $input->setOption('db-user', $database['default']['username']);
306             $input->setOption('db-pass', $database['default']['password']);
307             $input->setOption('db-port', $database['default']['port']);
308             $input->setOption('db-prefix', $database['default']['prefix']['default']);
309             $io->info(
310                 sprintf(
311                     $this->trans('commands.site.install.messages.using-current-database'),
312                     $database['default']['driver'],
313                     $database['default']['database'],
314                     $database['default']['username']
315                 )
316             );
317         }
318
319         // --site-name option
320         $siteName = $input->getOption('site-name');
321         if (!$siteName) {
322             $siteName = $io->ask(
323                 $this->trans('commands.site.install.questions.site-name'),
324                 'Drupal 8'
325             );
326             $input->setOption('site-name', $siteName);
327         }
328
329         // --site-mail option
330         $siteMail = $input->getOption('site-mail');
331         if (!$siteMail) {
332             $siteMail = $io->ask(
333                 $this->trans('commands.site.install.questions.site-mail'),
334                 'admin@example.com'
335             );
336             $input->setOption('site-mail', $siteMail);
337         }
338
339         // --account-name option
340         $accountName = $input->getOption('account-name');
341         if (!$accountName) {
342             $accountName = $io->ask(
343                 $this->trans('commands.site.install.questions.account-name'),
344                 'admin'
345             );
346             $input->setOption('account-name', $accountName);
347         }
348
349         // --account-pass option
350         $accountPass = $input->getOption('account-pass');
351         if (!$accountPass) {
352             $accountPass = $io->askHidden(
353                 $this->trans('commands.site.install.questions.account-pass')
354             );
355             $input->setOption('account-pass', $accountPass);
356         }
357
358         // --account-mail option
359         $accountMail = $input->getOption('account-mail');
360         if (!$accountMail) {
361             $accountMail = $io->ask(
362                 $this->trans('commands.site.install.questions.account-mail'),
363                 $siteMail
364             );
365             $input->setOption('account-mail', $accountMail);
366         }
367     }
368
369     /**
370      * {@inheritdoc}
371      */
372     protected function execute(InputInterface $input, OutputInterface $output)
373     {
374         $io = new DrupalStyle($input, $output);
375         $uri =  parse_url($input->getParameterOption(['--uri', '-l'], 'default'), PHP_URL_HOST);
376
377         if ($this->site->multisiteMode($uri)) {
378             if (!$this->site->validMultisite($uri)) {
379                 $io->error(
380                     sprintf($this->trans('commands.site.install.messages.invalid-multisite'), $uri, $uri)
381                 );
382                 exit(1);
383             }
384
385             // Modify $_SERVER environment information to enable
386             // the Drupal installer to use the multi-site configuration.
387             $_SERVER['HTTP_HOST'] = $uri;
388         }
389
390         // Database options
391         $dbType = $input->getOption('db-type')?:'mysql';
392         $dbFile = $input->getOption('db-file');
393         $dbHost = $input->getOption('db-host')?:'127.0.0.1';
394         $dbName = $input->getOption('db-name')?:'drupal_'.time();
395         $dbUser = $input->getOption('db-user')?:'root';
396         $dbPass = $input->getOption('db-pass');
397         $dbPrefix = $input->getOption('db-prefix');
398         $dbPort = $input->getOption('db-port')?:'3306';
399         $force = $input->getOption('force');
400
401         $databases = $this->site->getDatabaseTypes();
402
403         if ($dbType === 'sqlite') {
404             $database = [
405               'database' => $dbFile,
406               'prefix' => $dbPrefix,
407               'namespace' => $databases[$dbType]['namespace'],
408               'driver' => $dbType,
409             ];
410
411             if ($force) {
412                 $fs = new Filesystem();
413                 $fs->remove($dbFile);
414             }
415         } else {
416             $database = [
417               'database' => $dbName,
418               'username' => $dbUser,
419               'password' => $dbPass,
420               'prefix' => $dbPrefix,
421               'port' => $dbPort,
422               'host' => $dbHost,
423               'namespace' => $databases[$dbType]['namespace'],
424               'driver' => $dbType,
425             ];
426
427             if ($force && Database::getConnectionInfo()) {
428                 $schema = Database::getConnection()->schema();
429                 $tables = $schema->findTables('%');
430                 foreach ($tables as $table) {
431                     $schema->dropTable($table);
432                 }
433             }
434         }
435
436         try {
437             $drupalFinder = new DrupalFinder();
438             $drupalFinder->locateRoot(getcwd());
439             $composerRoot = $drupalFinder->getComposerRoot();
440             $drupalRoot = $drupalFinder->getDrupalRoot();
441
442             $this->runInstaller($io, $input, $database, $uri);
443
444             $autoload = $this->container->get('class_loader');
445             $drupal = new Drupal($autoload, $composerRoot, $drupalRoot);
446             $container = $drupal->boot();
447             $this->getApplication()->setContainer($container);
448         } catch (Exception $e) {
449             $io->error($e->getMessage());
450             return;
451         }
452
453         $this->restoreSitesFile($io);
454     }
455
456     /**
457      * Backs up sites.php to backup.sites.php (if needed).
458      *
459      * This is needed because of a bug with install_drupal() that causes the
460      * install files to be placed directly under /sites instead of the
461      * appropriate subdir when run from a script and a sites.php file exists.
462      *
463      * @param DrupalStyle $output
464      */
465     protected function backupSitesFile(DrupalStyle $output)
466     {
467         if (!file_exists($this->appRoot . '/sites/sites.php')) {
468             return;
469         }
470
471         rename($this->appRoot . '/sites/sites.php', $this->appRoot . '/sites/backup.sites.php');
472
473         $output->info($this->trans('commands.site.install.messages.sites-backup'));
474     }
475
476     /**
477      * Restores backup.sites.php to sites.php (if needed).
478      *
479      * @param DrupalStyle $output
480      */
481     protected function restoreSitesFile(DrupalStyle $output)
482     {
483         if (!file_exists($this->appRoot . '/sites/backup.sites.php')) {
484             return;
485         }
486
487         rename($this->appRoot . '/sites/backup.sites.php', $this->appRoot . '/sites/sites.php');
488
489         $output->info($this->trans('commands.site.install.messages.sites-restore'));
490     }
491
492     protected function runInstaller(
493         DrupalStyle $io,
494         InputInterface $input,
495         $database,
496         $uri
497     ) {
498         $this->site->loadLegacyFile('/core/includes/install.core.inc');
499
500         $driver = (string)$database['driver'];
501
502         $settings = [
503             'parameters' => [
504                 'profile' => $input->getArgument('profile') ?: 'standard',
505                 'langcode' => $input->getOption('langcode') ?: 'en',
506             ],
507             'forms' => [
508                 'install_settings_form' => [
509                     'driver' => $driver,
510                     $driver => $database,
511                     'op' => 'Save and continue',
512                 ],
513                 'install_configure_form' => [
514                     'site_name' => $input->getOption('site-name') ?: 'Drupal 8',
515                     'site_mail' => $input->getOption('site-mail') ?: 'admin@example.org',
516                     'account' => [
517                         'name' => $input->getOption('account-name') ?: 'admin',
518                         'mail' => $input->getOption('account-mail') ?: 'admin@example.org',
519                         'pass' => [
520                             'pass1' => $input->getOption('account-pass') ?: 'admin',
521                             'pass2' => $input->getOption('account-pass') ?: 'admin'
522                         ],
523                     ],
524                     'update_status_module' => [
525                         1 => true,
526                         2 => true,
527                     ],
528                     'clean_url' => true,
529                     'op' => 'Save and continue',
530                 ],
531             ]
532         ];
533
534         if (!$this->site->multisiteMode($uri)) {
535             $this->backupSitesFile($io);
536         }
537
538         $io->newLine();
539         $io->info($this->trans('commands.site.install.messages.installing'));
540
541         try {
542             $autoload = $this->site->getAutoload();
543             install_drupal($autoload, $settings);
544         } catch (AlreadyInstalledException $e) {
545             $io->error($this->trans('commands.site.install.messages.already-installed'));
546             return;
547         } catch (\Exception $e) {
548             $io->error($e->getMessage());
549             return;
550         }
551
552         if (!$this->site->multisiteMode($uri)) {
553             $this->restoreSitesFile($io);
554         }
555
556         $io->success($this->trans('commands.site.install.messages.installed'));
557     }
558 }