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