Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Cli/Command/Install.php
<?php

namespace XF\Cli\Command;

use
Symfony\Component\Console\Command\Command;
use
Symfony\Component\Console\Helper\ProgressBar;
use
Symfony\Component\Console\Helper\QuestionHelper;
use
Symfony\Component\Console\Input\ArrayInput;
use
Symfony\Component\Console\Input\InputInterface;
use
Symfony\Component\Console\Input\InputOption;
use
Symfony\Component\Console\Output\OutputInterface;
use
Symfony\Component\Console\Question\ConfirmationQuestion;
use
Symfony\Component\Console\Question\Question;
use
XF\Install\Data\MySql;

use function
count, strlen;

class
Install extends Command implements CustomAppCommandInterface
{
    use
JobRunnerTrait;

    public static function
getCustomAppClass()
    {
        return
'XF\Install\App';
    }

    protected function
configure()
    {
       
$this
           
->setName('xf:install')
            ->
setDescription('Installs XenForo')
            ->
addOption(
               
'user',
               
null,
               
InputOption::VALUE_REQUIRED,
               
'Name of the administrator user (default: Admin)'
           
)
            ->
addOption(
               
'password',
               
null,
               
InputOption::VALUE_REQUIRED,
               
'Password of the administrator user'
           
)
            ->
addOption(
               
'email',
               
null,
               
InputOption::VALUE_OPTIONAL,
               
'Primary board email and email for administrator user (default: (empty))'
           
)
            ->
addOption(
               
'title',
               
null,
               
InputOption::VALUE_REQUIRED,
               
'Board title (default: XenForo)'
           
)
            ->
addOption(
               
'url',
               
null,
               
InputOption::VALUE_REQUIRED,
               
'Board URL (default: http://localhost)'
           
)
            ->
addOption(
               
'skip-statistics',
               
null,
               
InputOption::VALUE_NONE,
               
'If set, the question to opt into anonymous server statistics collection will be skipped.'
           
)
            ->
addOption(
               
'clear',
               
null,
               
InputOption::VALUE_NONE,
               
'If set, existing application tables will be cleared before installing. If not set and tables are found, an error will be triggered.'
           
);
    }

    protected function
execute(InputInterface $input, OutputInterface $output)
    {
       
// TODO: Should phrase the remainder of the text in this class?

        /** @var \XF\Install\App $app */
       
$app = \XF::app();

       
$data = new MySql();
       
$config = \XF::config();

       
$installHelper = new \XF\Install\Helper($app);

        if (
$installHelper->isInstalled())
        {
           
$output->writeln('<error>' . \XF::phrase('you_have_completed_installation_to_reinstall') . '</error>');
            return
1;
        }

        if (!
$config['exists'])
        {
           
$output->writeln('<error>' . \XF::phrase('config_file_x_could_not_be_found', ['file' => 'src/config.php']) . '</error>');
            return
1;
        }

       
$db = \XF::db();

       
$errors = $installHelper->getRequirementErrors($db);
        if (
$errors)
        {
           
$output->writeln('<error>' . \XF::phrase('following_errors_were_found_when_verifying_requirements:') . '</error>');
            foreach (
$errors AS $error)
            {
               
$output->writeln("<info>\t * " . (string)$error . '</info>');
            }
            return
1;
        }

       
/** @var QuestionHelper $helper */
       
$helper = $this->getHelper('question');

       
$warnings = $installHelper->getRequirementWarnings($db);
        if (
$warnings)
        {
           
$output->writeln('<warning>' . \XF::phrase('following_warnings_were_found_when_verifying_requirements:') . '</warning>');
            foreach (
$warnings AS $warning)
            {
               
$output->writeln("<info>\t * " . (string)$warning . '</info>');
            }
           
$output->writeln("");

           
$warningQ = new ConfirmationQuestion(\XF::phrase('you_sure_you_want_to_continue_cli'));
            if (!
$helper->ask($input, $output, $warningQ))
            {
                return
1;
            }
        }

       
$command = $this->getApplication()->find('xf:file-check');
       
$childInput = new ArrayInput([
           
'command' => 'xf:file-check',
           
'--addon' => 'XF'
       
]);
       
$result = $command->run($childInput, $output);

        if (
$result === 1)
        {
            return
1;
        }

        if (isset(
$config['db']['dbname']))
        {
           
$output->writeln("Database name: " . $config['db']['dbname']);
        }

        if (
$installHelper->hasApplicationTables() && !$input->getOption('clear'))
        {
           
$output->writeln('<error>' . \XF::phrase('you_cannot_proceed_unless_tables_removed_cli') . '</error>');
            return
1;
        }

       
$username = $input->getOption('user');
        if (!
$username)
        {
           
$question = new Question('<question>Name of the administrator user (default: Admin):</question> ', 'Admin');
           
$username = $helper->ask($input, $output, $question);
           
$output->writeln("");
        }

        if (
strlen($username) < 3 || strlen($username) > 25)
        {
           
$output->writeln('<error>Please enter a name that is at least 3 characters long and shorter than 25 characters long.</error>');
            return
1;
        }

       
$password = $input->getOption('password');
        if (!
$password)
        {
           
$confirmedPassword = null;

            do
            {
               
$question = new Question('<question>Password of the administrator user:</question> ');
               
$question->setValidator(function ($value)
                {
                    if (
trim($value) == '')
                    {
                        throw new \
InvalidArgumentException('The password can not be empty');
                    }

                    return
$value;
                });
               
$question->setHidden(true);
               
$password = $helper->ask($input, $output, $question);
               
$output->writeln("");

               
// we can just trust the password input if it was entered when executing the command, otherwise ask:
               
$question = new Question('<question>Re-enter the administrator user password to confirm:</question> ');
               
$question->setHidden(true);
               
$confirmedPassword = $helper->ask($input, $output, $question);

                if (
$confirmedPassword !== $password)
                {
                   
$output->writeLn('<error>Passwords did not match. Please enter the same password.</error>');
                }

               
$output->writeln("");
            }
            while (
$password !== $confirmedPassword);
        }

       
$email = $input->getOption('email');
        if (!
$email)
        {
           
$question = new Question('<question>Primary board email and email for administrator user (default: example@example.com):</question> ', 'example@example.com');
           
$email = $helper->ask($input, $output, $question);
           
$output->writeln("");
        }

       
/** @var \XF\Validator\Email $emailValidator */
       
$emailValidator = $app->validator('Email');
       
$emailValidator->setOption('allow_empty', true);
       
$emailValidator->setOption('check_typos', true);
       
$email = $emailValidator->coerceValue($email);
        if (!
$emailValidator->isValid($email, $errorKey))
        {
            if (
$errorKey == 'typo')
            {
               
$output->writeln('<error>' . \XF::phrase('email_address_you_entered_appears_have_typo') . '</error>');
            }
            else
            {
               
$output->writeln('<error>' . \XF::phrase('please_enter_valid_email') . '</error>');
            }
            return
1;
        }

        if (!
$password)
        {
           
$output->writeln('<error>' . \XF::phrase('please_enter_valid_password') . '</error>');
            return
1;
        }

       
$title = $input->getOption('title');
        if (!
$title)
        {
           
$question = new Question('<question>Board title (default: XenForo):</question> ', 'XenForo');
           
$title = $helper->ask($input, $output, $question);
           
$output->writeln("");
        }

       
$url = $input->getOption('url');
        if (!
$url)
        {
           
$question = new Question('<question>Board URL (default: http://localhost):</question> ', 'http://localhost');
           
$url = $helper->ask($input, $output, $question);
           
$output->writeln("");
        }

        if (
$installHelper->hasApplicationTables() && $input->getOption('clear'))
        {
           
$output->write("Deleting existing tables... ");
           
$installHelper->deleteApplicationTables();
           
$output->writeln("Done.");
        }

       
$sm = $db->getSchemaManager();

       
$tables = $data->getTables();

       
$output->writeln("Creating tables...");

       
$progress = new ProgressBar($output, count($tables));
       
$progress->start();

        foreach (
$tables AS $tableName => $definition)
        {
           
$sm->createTable($tableName, $definition);
           
$progress->advance();
        }

       
$progress->finish();
       
$output->writeln("");
       
$output->writeln("Done.");

       
$output->writeln("Creating default data...");

       
$data = $data->getData();

       
$progress = new ProgressBar($output, count($data));
       
$progress->start();

        foreach (
$data AS $dataQuery)
        {
           
$db->query($dataQuery);
           
$progress->advance();
        }

       
$progress->finish();
       
$output->writeln("");
       
$output->writeln("Done. Importing data...");
       
$output->writeln("");

       
$devOutput = $app->developmentOutput();
        if (
$devOutput->isEnabled() && $devOutput->isCoreXfDataAvailable())
        {
           
$command = $this->getApplication()->find('xf-dev:import');
           
$childInput = new ArrayInput([
               
'command' => 'xf-dev:import',
               
'--addon' => 'XF'
           
]);
           
$command->run($childInput, $output);
        }
        else
        {
           
$command = $this->getApplication()->find('xf:rebuild-master-data');
           
$childInput = new ArrayInput(['command' => 'xf:rebuild-master-data']);
           
$childInput->setInteractive(false);
           
$command->run($childInput, $output);
        }

       
$output->writeln("Done. Apply installation configuration...");
       
$output->writeln("");

       
$installHelper->createInitialUser([
           
'username' => $username,
           
'email' => $email
       
], $password);

       
$serverStats = [
           
'configured' => 1,
           
'enabled' => 0
       
];
        if (!
$input->getOption('skip-statistics'))
        {
           
$question = new ConfirmationQuestion("<question>Send anonymous usage statistics (PHP, MySQL, XF usage)? (y/n)</question> ");
            if (
$helper->ask($input, $output, $question))
            {
               
$serverStats['enabled'] = 1;
            }
        }

       
/** @var \XF\Repository\Option $optionRepo */
       
$optionRepo = \XF::repository('XF:Option');

       
// if applicable, updating collectServerStats will enqueue stats collection automatically
       
$optionRepo->updateOptions([
           
'boardTitle' => $title,
           
'boardUrl' => $url,
           
'contactEmailAddress' => $email,
           
'defaultEmailAddress' => $email,
           
'collectServerStats' => $serverStats
       
]);

       
$installHelper->completeInstallation();

       
$output->writeln("");
       
$output->writeln("All finished. Installation has been completed.");
       
$output->writeln("");
       
$output->writeln("Values set:");
       
$output->writeln("\t* Username: $username");
       
$output->writeln("\t* Email: $email");
       
$output->writeln("\t* Password: " . str_repeat('*', strlen($password)) . ' (Confirmed)');
       
$output->writeln("\t* Title: $title");
       
$output->writeln("\t* URL: $url");

        return
0;
    }
}