5 * Contains \Drupal\AppConsole\Command\Site\InstallCommand.
8 namespace Drupal\Console\Command\Site;
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;
29 class InstallCommand extends Command
31 use ContainerAwareCommandTrait;
37 protected $extensionManager;
45 * @var ConfigurationManager
47 protected $configurationManager;
55 * InstallCommand constructor.
57 * @param Manager $extensionManager
59 * @param ConfigurationManager $configurationManager
60 * @param string $appRoot
62 public function __construct(
63 Manager $extensionManager,
65 ConfigurationManager $configurationManager,
68 $this->extensionManager = $extensionManager;
70 $this->configurationManager = $configurationManager;
71 $this->appRoot = $appRoot;
72 parent::__construct();
75 protected function configure()
78 ->setName('site:install')
79 ->setDescription($this->trans('commands.site.install.description'))
82 InputArgument::OPTIONAL,
83 $this->trans('commands.site.install.arguments.profile')
88 InputOption::VALUE_REQUIRED,
89 $this->trans('commands.site.install.options.langcode')
94 InputOption::VALUE_REQUIRED,
95 $this->trans('commands.site.install.options.db-type')
100 InputOption::VALUE_REQUIRED,
101 $this->trans('commands.site.install.options.db-file')
106 InputOption::VALUE_OPTIONAL,
107 $this->trans('commands.migrate.execute.options.db-host')
112 InputOption::VALUE_OPTIONAL,
113 $this->trans('commands.migrate.execute.options.db-name')
118 InputOption::VALUE_OPTIONAL,
119 $this->trans('commands.migrate.execute.options.db-user')
124 InputOption::VALUE_OPTIONAL,
125 $this->trans('commands.migrate.execute.options.db-pass')
130 InputOption::VALUE_OPTIONAL,
131 $this->trans('commands.migrate.execute.options.db-prefix')
136 InputOption::VALUE_OPTIONAL,
137 $this->trans('commands.migrate.execute.options.db-port')
142 InputOption::VALUE_REQUIRED,
143 $this->trans('commands.site.install.options.site-name')
148 InputOption::VALUE_REQUIRED,
149 $this->trans('commands.site.install.options.site-mail')
154 InputOption::VALUE_REQUIRED,
155 $this->trans('commands.site.install.options.account-name')
160 InputOption::VALUE_REQUIRED,
161 $this->trans('commands.site.install.options.account-mail')
166 InputOption::VALUE_REQUIRED,
167 $this->trans('commands.site.install.options.account-pass')
172 InputOption::VALUE_NONE,
173 $this->trans('commands.site.install.options.force')
180 protected function interact(InputInterface $input, OutputInterface $output)
182 $io = new DrupalStyle($input, $output);
185 $profile = $input->getArgument('profile');
187 $profiles = $this->extensionManager
195 $profiles = array_filter(
197 function ($profile) {
198 return strpos($profile, 'testing') !== 0;
202 $profile = $io->choice(
203 $this->trans('commands.site.install.questions.profile'),
204 array_values($profiles)
207 $input->setArgument('profile', $profile);
211 $langcode = $input->getOption('langcode');
213 $languages = $this->site->getStandardLanguages();
214 $defaultLanguage = $this->configurationManager
216 ->get('application.language');
218 $langcode = $io->choiceNoList(
219 $this->trans('commands.site.install.questions.langcode'),
221 $languages[$defaultLanguage]
224 $input->setOption('langcode', $langcode);
227 // Use default database setting if is available
228 $database = Database::getConnectionInfo();
229 if (empty($database['default'])) {
231 $dbType = $input->getOption('db-type');
233 $databases = $this->site->getDatabaseTypes();
234 $dbType = $io->choice(
235 $this->trans('commands.migrate.setup.questions.db-type'),
236 array_column($databases, 'name')
239 foreach ($databases as $dbIndex => $database) {
240 if ($database['name'] == $dbType) {
245 $input->setOption('db-type', $dbType);
248 if ($dbType === 'sqlite') {
250 $dbFile = $input->getOption('db-file');
253 $this->trans('commands.migrate.execute.questions.db-file'),
254 'sites/default/files/.ht.sqlite'
256 $input->setOption('db-file', $dbFile);
260 $dbHost = $input->getOption('db-host');
262 $dbHost = $this->dbHostQuestion($io);
263 $input->setOption('db-host', $dbHost);
267 $dbName = $input->getOption('db-name');
269 $dbName = $this->dbNameQuestion($io);
270 $input->setOption('db-name', $dbName);
274 $dbUser = $input->getOption('db-user');
276 $dbUser = $this->dbUserQuestion($io);
277 $input->setOption('db-user', $dbUser);
281 $dbPass = $input->getOption('db-pass');
283 $dbPass = $this->dbPassQuestion($io);
284 $input->setOption('db-pass', $dbPass);
288 $dbPort = $input->getOption('db-port');
290 $dbPort = $this->dbPortQuestion($io);
291 $input->setOption('db-port', $dbPort);
296 $dbPrefix = $input->getOption('db-prefix');
298 $dbPrefix = $this->dbPrefixQuestion($io);
299 $input->setOption('db-prefix', $dbPrefix);
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']);
311 $this->trans('commands.site.install.messages.using-current-database'),
312 $database['default']['driver'],
313 $database['default']['database'],
314 $database['default']['username']
319 // --site-name option
320 $siteName = $input->getOption('site-name');
322 $siteName = $io->ask(
323 $this->trans('commands.site.install.questions.site-name'),
326 $input->setOption('site-name', $siteName);
329 // --site-mail option
330 $siteMail = $input->getOption('site-mail');
332 $siteMail = $io->ask(
333 $this->trans('commands.site.install.questions.site-mail'),
336 $input->setOption('site-mail', $siteMail);
339 // --account-name option
340 $accountName = $input->getOption('account-name');
342 $accountName = $io->ask(
343 $this->trans('commands.site.install.questions.account-name'),
346 $input->setOption('account-name', $accountName);
349 // --account-pass option
350 $accountPass = $input->getOption('account-pass');
352 $accountPass = $io->askHidden(
353 $this->trans('commands.site.install.questions.account-pass')
355 $input->setOption('account-pass', $accountPass);
358 // --account-mail option
359 $accountMail = $input->getOption('account-mail');
361 $accountMail = $io->ask(
362 $this->trans('commands.site.install.questions.account-mail'),
365 $input->setOption('account-mail', $accountMail);
372 protected function execute(InputInterface $input, OutputInterface $output)
374 $io = new DrupalStyle($input, $output);
375 $uri = parse_url($input->getParameterOption(['--uri', '-l'], 'default'), PHP_URL_HOST);
377 if ($this->site->multisiteMode($uri)) {
378 if (!$this->site->validMultisite($uri)) {
380 sprintf($this->trans('commands.site.install.messages.invalid-multisite'), $uri, $uri)
385 // Modify $_SERVER environment information to enable
386 // the Drupal installer to use the multi-site configuration.
387 $_SERVER['HTTP_HOST'] = $uri;
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');
401 $databases = $this->site->getDatabaseTypes();
403 if ($dbType === 'sqlite') {
405 'database' => $dbFile,
406 'prefix' => $dbPrefix,
407 'namespace' => $databases[$dbType]['namespace'],
412 $fs = new Filesystem();
413 $fs->remove($dbFile);
417 'database' => $dbName,
418 'username' => $dbUser,
419 'password' => $dbPass,
420 'prefix' => $dbPrefix,
423 'namespace' => $databases[$dbType]['namespace'],
427 if ($force && Database::getConnectionInfo()) {
428 $schema = Database::getConnection()->schema();
429 $tables = $schema->findTables('%');
430 foreach ($tables as $table) {
431 $schema->dropTable($table);
437 $drupalFinder = new DrupalFinder();
438 $drupalFinder->locateRoot(getcwd());
439 $composerRoot = $drupalFinder->getComposerRoot();
440 $drupalRoot = $drupalFinder->getDrupalRoot();
442 $this->runInstaller($io, $input, $database, $uri);
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());
453 $this->restoreSitesFile($io);
457 * Backs up sites.php to backup.sites.php (if needed).
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.
463 * @param DrupalStyle $output
465 protected function backupSitesFile(DrupalStyle $output)
467 if (!file_exists($this->appRoot . '/sites/sites.php')) {
471 rename($this->appRoot . '/sites/sites.php', $this->appRoot . '/sites/backup.sites.php');
473 $output->info($this->trans('commands.site.install.messages.sites-backup'));
477 * Restores backup.sites.php to sites.php (if needed).
479 * @param DrupalStyle $output
481 protected function restoreSitesFile(DrupalStyle $output)
483 if (!file_exists($this->appRoot . '/sites/backup.sites.php')) {
487 rename($this->appRoot . '/sites/backup.sites.php', $this->appRoot . '/sites/sites.php');
489 $output->info($this->trans('commands.site.install.messages.sites-restore'));
492 protected function runInstaller(
494 InputInterface $input,
498 $this->site->loadLegacyFile('/core/includes/install.core.inc');
500 $driver = (string)$database['driver'];
504 'profile' => $input->getArgument('profile') ?: 'standard',
505 'langcode' => $input->getOption('langcode') ?: 'en',
508 'install_settings_form' => [
510 $driver => $database,
511 'op' => 'Save and continue',
513 'install_configure_form' => [
514 'site_name' => $input->getOption('site-name') ?: 'Drupal 8',
515 'site_mail' => $input->getOption('site-mail') ?: 'admin@example.org',
517 'name' => $input->getOption('account-name') ?: 'admin',
518 'mail' => $input->getOption('account-mail') ?: 'admin@example.org',
520 'pass1' => $input->getOption('account-pass') ?: 'admin',
521 'pass2' => $input->getOption('account-pass') ?: 'admin'
524 'update_status_module' => [
529 'op' => 'Save and continue',
534 if (!$this->site->multisiteMode($uri)) {
535 $this->backupSitesFile($io);
539 $io->info($this->trans('commands.site.install.messages.installing'));
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'));
547 } catch (\Exception $e) {
548 $io->error($e->getMessage());
552 if (!$this->site->multisiteMode($uri)) {
553 $this->restoreSitesFile($io);
556 $io->success($this->trans('commands.site.install.messages.installed'));