class TestSiteInstallCommand

Same name in other branches
  1. 9 core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php \Drupal\TestSite\Commands\TestSiteInstallCommand
  2. 8.9.x core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php \Drupal\TestSite\Commands\TestSiteInstallCommand
  3. 10 core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php \Drupal\TestSite\Commands\TestSiteInstallCommand

Command to create a test Drupal site.

@internal

Hierarchy

Expanded class hierarchy of TestSiteInstallCommand

1 file declares its use of TestSiteInstallCommand
TestSiteApplication.php in core/tests/Drupal/TestSite/TestSiteApplication.php

File

core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php, line 27

Namespace

Drupal\TestSite\Commands
View source
class TestSiteInstallCommand extends Command {
    use FunctionalTestSetupTrait {
        installParameters as protected installParametersTrait;
    }
    use RandomGeneratorTrait;
    use TestSetupTrait {
        changeDatabasePrefix as protected changeDatabasePrefixTrait;
    }
    
    /**
     * The theme to install as the default for testing.
     *
     * Defaults to the install profile's default theme, if it specifies any.
     */
    protected string $defaultTheme;
    
    /**
     * The base URL.
     */
    protected string $baseUrl;
    
    /**
     * The original array of shutdown function callbacks.
     */
    protected array $originalShutdownCallbacks = [];
    
    /**
     * The translation file directory for the test environment.
     *
     * This is set in BrowserTestBase::prepareEnvironment().
     */
    protected string $translationFilesDirectory;
    
    /**
     * The config importer that can be used in a test.
     */
    protected ?ConfigImporter $configImporter;
    
    /**
     * The install profile to use.
     *
     * @var string
     */
    protected $profile = 'testing';
    
    /**
     * Time limit in seconds for the test.
     *
     * Used by \Drupal\Core\Test\FunctionalTestSetupTrait::prepareEnvironment().
     *
     * @var int
     */
    protected $timeLimit = 500;
    
    /**
     * The language to install the site in.
     *
     * @var string
     */
    protected $langcode = 'en';
    
    /**
     * {@inheritdoc}
     *
     * @todo Remove and fix test to not rely on super user.
     * @see https://www.drupal.org/project/drupal/issues/3437620
     */
    public function __construct(?string $name = NULL) {
        parent::__construct($name);
        $this->usesSuperUserAccessPolicy = TRUE;
    }
    
    /**
     * {@inheritdoc}
     */
    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/database_name#table_prefix"');
    }
    
    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output) : int {
        // Determines and validates the setup class prior to installing a database
        // to avoid creating unnecessary sites.
        $root = dirname(__DIR__, 5);
        chdir($root);
        $class_name = $this->getSetupClass($input->getOption('setup-file'));
        // Ensure we can install a site in the sites/simpletest directory.
        $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}");
        // Manage site fixture.
        $this->setup($input->getOption('install-profile'), $class_name, $input->getOption('langcode'));
        // Make sure there is an entry in sites.php for the new site.
        $fs = new Filesystem();
        if (!$fs->exists($root . '/sites/sites.php')) {
            $fs->copy($root . '/sites/example.sites.php', $root . '/sites/sites.php');
        }
        $parsed = parse_url($base_url);
        $port = $parsed['port'] ?? 80;
        $host = $parsed['host'] ?? 'localhost';
        // Remove 'sites/' from the beginning of the path.
        $site_path = substr($this->siteDirectory, 6);
        $fs->appendToFile($root . '/sites/sites.php', "\$sites['{$port}.{$host}'] = '{$site_path}';");
        $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;
    }
    
    /**
     * Gets the setup class.
     *
     * @param string|null $file
     *   The file to get the setup class from.
     *
     * @return string|null
     *   The setup class contained in the provided $file.
     *
     * @throws \InvalidArgumentException
     *   Thrown if the file does not exist, does not contain a class or the class
     *   does not implement \Drupal\TestSite\TestSetupInterface or
     *   \Drupal\TestSite\TestPreinstallInterface.
     */
    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;
    }
    
    /**
     * Ensures that the sites/simpletest directory exists and is writable.
     *
     * @param string $root
     *   The Drupal root.
     */
    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');
            }
        }
    }
    
    /**
     * Creates a test drupal installation.
     *
     * @param string $profile
     *   (optional) The installation profile to use.
     * @param string $setup_class
     *   (optional) Setup class. A PHP class to setup configuration used by the
     *   test.
     * @param string $langcode
     *   (optional) The language to install the site in.
     */
    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);
    }
    
    /**
     * Installs Drupal into the test site.
     */
    protected function installDrupal() {
        $this->initUserSession();
        $this->prepareSettings();
        $this->doInstall();
        $this->initSettings();
        $container = $this->initKernel(\Drupal::request());
        $this->initConfig($container);
    }
    
    /**
     * Uses the setup file to configure Drupal.
     *
     * @param string $class
     *   The fully qualified class name, which should set up Drupal for tests. For
     *   example this class could create content types and fields or install
     *   modules. The class needs to implement TestSetupInterface.
     *
     * @see \Drupal\TestSite\TestSetupInterface
     */
    protected function executeSetupClass($class) {
        if (is_subclass_of($class, TestSetupInterface::class)) {
            
            /** @var \Drupal\TestSite\TestSetupInterface $instance */
            $instance = new $class();
            $instance->setup();
        }
    }
    
    /**
     * Uses the setup file to configure the environment prior to install.
     *
     * @param string $class
     *   The fully qualified class name, which should set up the environment prior
     *   to installing Drupal for tests. For example this class could create
     *   translations that are used during the installer.
     *
     * @see \Drupal\TestSite\TestPreinstallInterface
     */
    protected function executePreinstallClass($class) {
        if (is_subclass_of($class, TestPreinstallInterface::class)) {
            
            /** @var \Drupal\TestSite\TestPreinstallInterface $instance */
            $instance = new $class();
            $instance->preinstall($this->databasePrefix, $this->siteDirectory);
        }
    }
    
    /**
     * {@inheritdoc}
     */
    protected function installParameters() {
        $parameters = $this->installParametersTrait();
        $parameters['parameters']['langcode'] = $this->langcode;
        return $parameters;
    }
    
    /**
     * {@inheritdoc}
     */
    protected function changeDatabasePrefix() {
        // Ensure that we use the database from SIMPLETEST_DB environment variable.
        Database::removeConnection('default');
        $this->changeDatabasePrefixTrait();
    }
    
    /**
     * {@inheritdoc}
     */
    protected function prepareDatabasePrefix() {
        // Override this method so that we can force a lock to be created.
        $test_db = new TestDatabase(NULL, TRUE);
        $this->siteDirectory = $test_db->getTestSitePath();
        $this->databasePrefix = $test_db->getDatabasePrefix();
    }

}

Members

Title Sort descending Modifiers Object type Summary Member alias Overriden Title Overrides
FunctionalTestSetupTrait::$apcuEnsureUniquePrefix protected property The flag to set &#039;apcu_ensure_unique_prefix&#039; setting. 1
FunctionalTestSetupTrait::$classLoader protected property The class loader to use for installation and initialization of setup.
FunctionalTestSetupTrait::$rootUser protected property The &quot;#1&quot; admin user.
FunctionalTestSetupTrait::$usesSuperUserAccessPolicy protected property Set to TRUE to make user 1 a super user. 3
FunctionalTestSetupTrait::doInstall protected function Execute the non-interactive installer. 1
FunctionalTestSetupTrait::getDatabaseTypes protected function Returns all supported database driver installer objects.
FunctionalTestSetupTrait::initConfig protected function Initialize various configurations post-installation. 1
FunctionalTestSetupTrait::initKernel protected function Initializes the kernel after installation.
FunctionalTestSetupTrait::initSettings protected function Initialize settings created during install.
FunctionalTestSetupTrait::initUserSession protected function Initializes user 1 for the site to be installed.
FunctionalTestSetupTrait::installDefaultThemeFromClassProperty protected function Installs the default theme defined by `static::$defaultTheme` when needed. 1
FunctionalTestSetupTrait::installModulesFromClassProperty protected function Install modules defined by `static::$modules`. 1
FunctionalTestSetupTrait::installParameters protected function Returns the parameters that will be used when the test installs Drupal. Aliased as: installParametersTrait 8
FunctionalTestSetupTrait::prepareEnvironment protected function Prepares the current environment for running the test. 29
FunctionalTestSetupTrait::prepareRequestForGenerator protected function Creates a mock request and sets it on the generator.
FunctionalTestSetupTrait::prepareSettings protected function Prepares site settings and services before installation. 4
FunctionalTestSetupTrait::rebuildAll protected function Resets and rebuilds the environment after setup.
FunctionalTestSetupTrait::rebuildContainer protected function Rebuilds \Drupal::getContainer().
FunctionalTestSetupTrait::resetAll protected function Resets all data structures after having enabled new modules.
FunctionalTestSetupTrait::setContainerParameter protected function Changes parameters in the services.yml file.
FunctionalTestSetupTrait::setupBaseUrl protected function Sets up the base URL based upon the environment variable.
FunctionalTestSetupTrait::writeSettings protected function Rewrites the settings.php file of the test site. 1
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
RefreshVariablesTrait::refreshVariables protected function Refreshes in-memory configuration and state information. 2
SessionTestTrait::$sessionName protected property The name of the session cookie.
SessionTestTrait::generateSessionName protected function Generates a session cookie name.
SessionTestTrait::getSessionName protected function Returns the session name in use on the child site.
TestSetupTrait::$configSchemaCheckerExclusions protected static property An array of config object names that are excluded from schema checking. 3
TestSetupTrait::$container protected property The dependency injection container used in the test.
TestSetupTrait::$databasePrefix protected property The database prefix of this test run.
TestSetupTrait::$kernel protected property The DrupalKernel instance used in the test.
TestSetupTrait::$originalSite protected property The site directory of the original parent site.
TestSetupTrait::$privateFilesDirectory protected property The private file directory for the test environment.
TestSetupTrait::$publicFilesDirectory protected property The public file directory for the test environment.
TestSetupTrait::$root protected property The app root.
TestSetupTrait::$siteDirectory protected property The site directory of this test run.
TestSetupTrait::$strictConfigSchema protected property Set to TRUE to strict check all configuration saved. 4
TestSetupTrait::$tempFilesDirectory protected property The temporary file directory for the test environment.
TestSetupTrait::$testId protected property The test run ID.
TestSetupTrait::changeDatabasePrefix protected function Changes the database connection to the prefixed one. Aliased as: changeDatabasePrefixTrait
TestSetupTrait::getConfigSchemaExclusions protected function Gets the config schema exclusions for this test.
TestSiteInstallCommand::$baseUrl protected property The base URL.
TestSiteInstallCommand::$configImporter protected property The config importer that can be used in a test.
TestSiteInstallCommand::$defaultTheme protected property The theme to install as the default for testing.
TestSiteInstallCommand::$langcode protected property The language to install the site in.
TestSiteInstallCommand::$originalShutdownCallbacks protected property The original array of shutdown function callbacks.
TestSiteInstallCommand::$profile protected property The install profile to use.
TestSiteInstallCommand::$timeLimit protected property Time limit in seconds for the test.
TestSiteInstallCommand::$translationFilesDirectory protected property The translation file directory for the test environment.
TestSiteInstallCommand::changeDatabasePrefix protected function
TestSiteInstallCommand::configure protected function
TestSiteInstallCommand::ensureDirectory protected function Ensures that the sites/simpletest directory exists and is writable.
TestSiteInstallCommand::execute protected function
TestSiteInstallCommand::executePreinstallClass protected function Uses the setup file to configure the environment prior to install.
TestSiteInstallCommand::executeSetupClass protected function Uses the setup file to configure Drupal.
TestSiteInstallCommand::getSetupClass protected function Gets the setup class.
TestSiteInstallCommand::installDrupal protected function Installs Drupal into the test site.
TestSiteInstallCommand::installParameters protected function
TestSiteInstallCommand::prepareDatabasePrefix protected function Generates a database prefix for running tests. Overrides TestSetupTrait::prepareDatabasePrefix
TestSiteInstallCommand::setup public function Creates a test drupal installation.
TestSiteInstallCommand::__construct public function @todo Remove and fix test to not rely on super user.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.