View source
<?php
namespace Drupal\TestSite\Commands;
use Drupal\Core\Database\Database;
use Drupal\Core\Test\FunctionalTestSetupTrait;
use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Test\TestSetupTrait;
use Drupal\TestSite\TestPreinstallInterface;
use Drupal\TestSite\TestSetupInterface;
use Drupal\Tests\RandomGeneratorTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class TestSiteInstallCommand extends Command {
use FunctionalTestSetupTrait {
installParameters as protected installParametersTrait;
}
use RandomGeneratorTrait;
use TestSetupTrait {
changeDatabasePrefix as protected changeDatabasePrefixTrait;
}
protected $profile = 'testing';
protected $timeLimit = 500;
protected $databasePrefix;
protected $langcode = 'en';
protected function configure() {
$this
->setName('install')
->setDescription('Creates a test Drupal site')
->setHelp('The details to connect to the test site created will be displayed upon success. It will contain the database prefix and the user agent.')
->addOption('setup-file', NULL, InputOption::VALUE_OPTIONAL, 'The path to a PHP file containing a class to setup configuration used by the test, for example, core/tests/Drupal/TestSite/TestSiteMultilingualInstallTestScript.php.')
->addOption('db-url', NULL, InputOption::VALUE_OPTIONAL, 'URL for database. Defaults to the environment variable SIMPLETEST_DB.', getenv('SIMPLETEST_DB'))
->addOption('base-url', NULL, InputOption::VALUE_OPTIONAL, 'Base URL for site under test. Defaults to the environment variable SIMPLETEST_BASE_URL.', getenv('SIMPLETEST_BASE_URL'))
->addOption('install-profile', NULL, InputOption::VALUE_OPTIONAL, 'Install profile to install the site in. Defaults to testing.', 'testing')
->addOption('langcode', NULL, InputOption::VALUE_OPTIONAL, 'The language to install the site in. Defaults to en.', 'en')
->addOption('json', NULL, InputOption::VALUE_NONE, 'Output test site connection details in JSON.')
->addUsage('--setup-file core/tests/Drupal/TestSite/TestSiteMultilingualInstallTestScript.php --json')
->addUsage('--install-profile demo_umami --langcode fr')
->addUsage('--base-url "http://example.com" --db-url "mysql://username:password@localhost/databasename#table_prefix"');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$root = dirname(dirname(dirname(dirname(dirname(__DIR__)))));
chdir($root);
$class_name = $this
->getSetupClass($input
->getOption('setup-file'));
$this
->ensureDirectory($root);
$db_url = $input
->getOption('db-url');
$base_url = $input
->getOption('base-url');
putenv("SIMPLETEST_DB={$db_url}");
putenv("SIMPLETEST_BASE_URL={$base_url}");
$this
->setup($input
->getOption('install-profile'), $class_name, $input
->getOption('langcode'));
$user_agent = drupal_generate_test_ua($this->databasePrefix);
if ($input
->getOption('json')) {
$output
->writeln(json_encode([
'db_prefix' => $this->databasePrefix,
'user_agent' => $user_agent,
'site_path' => $this->siteDirectory,
]));
}
else {
$output
->writeln('<info>Successfully installed a test site</info>');
$io = new SymfonyStyle($input, $output);
$io
->table([], [
[
'Database prefix',
$this->databasePrefix,
],
[
'User agent',
$user_agent,
],
[
'Site path',
$this->siteDirectory,
],
]);
}
return 0;
}
protected function getSetupClass($file) {
if ($file === NULL) {
return;
}
if (!file_exists($file)) {
throw new \InvalidArgumentException("The file {$file} does not exist.");
}
$classes = get_declared_classes();
include_once $file;
$new_classes = array_values(array_diff(get_declared_classes(), $classes));
if (empty($new_classes)) {
throw new \InvalidArgumentException("The file {$file} does not contain a class.");
}
$class = array_pop($new_classes);
if (!is_subclass_of($class, TestSetupInterface::class) && !is_subclass_of($class, TestPreinstallInterface::class)) {
throw new \InvalidArgumentException("The class {$class} contained in {$file} needs to implement \\Drupal\\TestSite\\TestSetupInterface or \\Drupal\\TestSite\\TestPreinstallInterface");
}
return $class;
}
protected function ensureDirectory($root) {
if (!is_writable($root . '/sites/simpletest')) {
if (!@mkdir($root . '/sites/simpletest')) {
throw new \RuntimeException($root . '/sites/simpletest must exist and be writable to install a test site');
}
}
}
public function setup($profile = 'testing', $setup_class = NULL, $langcode = 'en') {
$this->profile = $profile;
$this->langcode = $langcode;
$this
->setupBaseUrl();
$this
->prepareEnvironment();
$this
->executePreinstallClass($setup_class);
$this
->installDrupal();
$this
->executeSetupClass($setup_class);
}
protected function installDrupal() {
$this
->initUserSession();
$this
->prepareSettings();
$this
->doInstall();
$this
->initSettings();
$container = $this
->initKernel(\Drupal::request());
$this
->initConfig($container);
}
protected function executeSetupClass($class) {
if (is_subclass_of($class, TestSetupInterface::class)) {
$instance = new $class();
$instance
->setup();
}
}
protected function executePreinstallClass($class) {
if (is_subclass_of($class, TestPreinstallInterface::class)) {
$instance = new $class();
$instance
->preinstall($this->databasePrefix, $this->siteDirectory);
}
}
protected function installParameters() {
$parameters = $this
->installParametersTrait();
$parameters['parameters']['langcode'] = $this->langcode;
return $parameters;
}
protected function changeDatabasePrefix() {
Database::removeConnection('default');
$this
->changeDatabasePrefixTrait();
}
protected function prepareDatabasePrefix() {
$test_db = new TestDatabase(NULL, TRUE);
$this->siteDirectory = $test_db
->getTestSitePath();
$this->databasePrefix = $test_db
->getDatabasePrefix();
}
}