Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / tests / Drupal / TestSite / Commands / TestSiteTearDownCommand.php
1 <?php
2
3 namespace Drupal\TestSite\Commands;
4
5 use Drupal\Core\Database\Database;
6 use Drupal\Core\Test\TestDatabase;
7 use Drupal\Tests\BrowserTestBase;
8 use Symfony\Component\Console\Command\Command;
9 use Symfony\Component\Console\Input\InputArgument;
10 use Symfony\Component\Console\Input\InputInterface;
11 use Symfony\Component\Console\Input\InputOption;
12 use Symfony\Component\Console\Output\OutputInterface;
13 use Symfony\Component\Console\Style\SymfonyStyle;
14
15 /**
16  * Command to tear down a test Drupal site.
17  *
18  * @internal
19  */
20 class TestSiteTearDownCommand extends Command {
21
22   /**
23    * {@inheritdoc}
24    */
25   protected function configure() {
26     $this->setName('tear-down')
27       ->setDescription('Removes a test site added by the install command')
28       ->setHelp('All the database tables and files will be removed.')
29       ->addArgument('db-prefix', InputArgument::REQUIRED, 'The database prefix for the test site.')
30       ->addOption('db-url', NULL, InputOption::VALUE_OPTIONAL, 'URL for database. Defaults to the environment variable SIMPLETEST_DB.', getenv('SIMPLETEST_DB'))
31       ->addOption('keep-lock', NULL, InputOption::VALUE_NONE, 'Keeps the database prefix lock. Useful for ensuring test isolation when running concurrent tests.')
32       ->addUsage('test12345678')
33       ->addUsage('test12345678 --db-url "mysql://username:password@localhost/databasename#table_prefix"')
34       ->addUsage('test12345678 --keep-lock');
35   }
36
37   /**
38    * {@inheritdoc}
39    */
40   protected function execute(InputInterface $input, OutputInterface $output) {
41     $db_prefix = $input->getArgument('db-prefix');
42     // Validate the db_prefix argument.
43     try {
44       $test_database = new TestDatabase($db_prefix);
45     }
46     catch (\InvalidArgumentException $e) {
47       $io = new SymfonyStyle($input, $output);
48       $io->getErrorStyle()->error("Invalid database prefix: $db_prefix\n\nValid database prefixes match the regular expression '/test(\d+)$/'. For example, 'test12345678'.");
49       // Display the synopsis of the command like Composer does.
50       $output->writeln(sprintf('<info>%s</info>', sprintf($this->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
51       return 1;
52     }
53
54     $db_url = $input->getOption('db-url');
55     putenv("SIMPLETEST_DB=$db_url");
56
57     // Handle the cleanup of the test site.
58     $this->tearDown($test_database, $db_url);
59
60     // Release the test database prefix lock.
61     if (!$input->getOption('keep-lock')) {
62       $test_database->releaseLock();
63     }
64
65     $output->writeln("<info>Successfully uninstalled $db_prefix test site</info>");
66   }
67
68   /**
69    * Removes a given instance by deleting all the database tables and files.
70    *
71    * @param \Drupal\Core\Test\TestDatabase $test_database
72    *   The test database object.
73    * @param string $db_url
74    *   The database URL.
75    *
76    * @see \Drupal\Tests\BrowserTestBase::cleanupEnvironment()
77    */
78   protected function tearDown(TestDatabase $test_database, $db_url) {
79     // Connect to the test database.
80     $root = dirname(dirname(dirname(dirname(dirname(__DIR__)))));
81     $database = Database::convertDbUrlToConnectionInfo($db_url, $root);
82     $database['prefix'] = ['default' => $test_database->getDatabasePrefix()];
83     Database::addConnectionInfo(__CLASS__, 'default', $database);
84
85     // Remove all the tables.
86     $schema = Database::getConnection('default', __CLASS__)->schema();
87     $tables = $schema->findTables('%');
88     array_walk($tables, [$schema, 'dropTable']);
89
90     // Delete test site directory.
91     $this->fileUnmanagedDeleteRecursive($root . DIRECTORY_SEPARATOR . $test_database->getTestSitePath(), [BrowserTestBase::class, 'filePreDeleteCallback']);
92   }
93
94   /**
95    * Deletes all files and directories in the specified path recursively.
96    *
97    * Note this method has no dependencies on Drupal core to ensure that the
98    * test site can be torn down even if something in the test site is broken.
99    *
100    * @param string $path
101    *   A string containing either an URI or a file or directory path.
102    * @param callable $callback
103    *   (optional) Callback function to run on each file prior to deleting it and
104    *   on each directory prior to traversing it. For example, can be used to
105    *   modify permissions.
106    *
107    * @return bool
108    *   TRUE for success or if path does not exist, FALSE in the event of an
109    *   error.
110    *
111    * @see file_unmanaged_delete_recursive()
112    */
113   protected function fileUnmanagedDeleteRecursive($path, $callback = NULL) {
114     if (isset($callback)) {
115       call_user_func($callback, $path);
116     }
117     if (is_dir($path)) {
118       $dir = dir($path);
119       while (($entry = $dir->read()) !== FALSE) {
120         if ($entry == '.' || $entry == '..') {
121           continue;
122         }
123         $entry_path = $path . '/' . $entry;
124         $this->fileUnmanagedDeleteRecursive($entry_path, $callback);
125       }
126       $dir->close();
127
128       return rmdir($path);
129     }
130     return unlink($path);
131   }
132
133 }