1. 8.2.x core/modules/simpletest/src/KernelTestBase.php
  2. 8.2.x core/tests/Drupal/KernelTests/KernelTestBase.php
  3. 8.0.x core/tests/Drupal/KernelTests/KernelTestBase.php
  4. 8.0.x core/modules/simpletest/src/KernelTestBase.php
  5. 8.1.x core/tests/Drupal/KernelTests/KernelTestBase.php
  6. 8.1.x core/modules/simpletest/src/KernelTestBase.php
  7. 8.3.x core/tests/Drupal/KernelTests/KernelTestBase.php
  8. 8.3.x core/modules/simpletest/src/KernelTestBase.php

Namespace

Drupal\simpletest

File

core/modules/simpletest/src/KernelTestBase.php
View source
  1. <?php
  2. namespace Drupal\simpletest;
  3. use Drupal\Component\Utility\Html;
  4. use Drupal\Component\Utility\SafeMarkup;
  5. use Drupal\Component\Utility\Variable;
  6. use Drupal\Core\Database\Database;
  7. use Drupal\Core\DependencyInjection\ContainerBuilder;
  8. use Drupal\Core\DrupalKernel;
  9. use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
  10. use Drupal\Core\Extension\ExtensionDiscovery;
  11. use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
  12. use Drupal\Core\Language\Language;
  13. use Drupal\Core\Site\Settings;
  14. use Symfony\Component\DependencyInjection\Parameter;
  15. use Drupal\Core\StreamWrapper\StreamWrapperInterface;
  16. use Symfony\Component\DependencyInjection\Reference;
  17. use Symfony\Component\HttpFoundation\Request;
  18. /**
  19. * Base class for integration tests.
  20. *
  21. * Tests extending this base class can access files and the database, but the
  22. * entire environment is initially empty. Drupal runs in a minimal mocked
  23. * environment, comparable to the one in the early installer.
  24. *
  25. * The module/hook system is functional and operates on a fixed module list.
  26. * Additional modules needed in a test may be loaded and added to the fixed
  27. * module list.
  28. *
  29. * @deprecated in Drupal 8.0.x, will be removed before Drupal 9.0.0. Use
  30. * \Drupal\KernelTests\KernelTestBase instead.
  31. *
  32. * @see \Drupal\simpletest\KernelTestBase::$modules
  33. * @see \Drupal\simpletest\KernelTestBase::enableModules()
  34. *
  35. * @ingroup testing
  36. */
  37. abstract class KernelTestBase extends TestBase {
  38. use AssertContentTrait;
  39. /**
  40. * Modules to enable.
  41. *
  42. * Test classes extending this class, and any classes in the hierarchy up to
  43. * this class, may specify individual lists of modules to enable by setting
  44. * this property. The values of all properties in all classes in the hierarchy
  45. * are merged.
  46. *
  47. * Any modules specified in the $modules property are automatically loaded and
  48. * set as the fixed module list.
  49. *
  50. * Unlike WebTestBase::setUp(), the specified modules are loaded only, but not
  51. * automatically installed. Modules need to be installed manually, if needed.
  52. *
  53. * @see \Drupal\simpletest\KernelTestBase::enableModules()
  54. * @see \Drupal\simpletest\KernelTestBase::setUp()
  55. *
  56. * @var array
  57. */
  58. public static $modules = array();
  59. private $moduleFiles;
  60. private $themeFiles;
  61. /**
  62. * The configuration directories for this test run.
  63. *
  64. * @var array
  65. */
  66. protected $configDirectories = array();
  67. /**
  68. * A KeyValueMemoryFactory instance to use when building the container.
  69. *
  70. * @var \Drupal\Core\KeyValueStore\KeyValueMemoryFactory.
  71. */
  72. protected $keyValueFactory;
  73. /**
  74. * Array of registered stream wrappers.
  75. *
  76. * @var array
  77. */
  78. protected $streamWrappers = array();
  79. /**
  80. * {@inheritdoc}
  81. */
  82. function __construct($test_id = NULL) {
  83. parent::__construct($test_id);
  84. $this->skipClasses[__CLASS__] = TRUE;
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. protected function beforePrepareEnvironment() {
  90. // Copy/prime extension file lists once to avoid filesystem scans.
  91. if (!isset($this->moduleFiles)) {
  92. $this->moduleFiles = \Drupal::state()->get('system.module.files') ?: array();
  93. $this->themeFiles = \Drupal::state()->get('system.theme.files') ?: array();
  94. }
  95. }
  96. /**
  97. * Create and set new configuration directories.
  98. *
  99. * @see config_get_config_directory()
  100. *
  101. * @throws \RuntimeException
  102. * Thrown when CONFIG_SYNC_DIRECTORY cannot be created or made writable.
  103. */
  104. protected function prepareConfigDirectories() {
  105. $this->configDirectories = array();
  106. include_once DRUPAL_ROOT . '/core/includes/install.inc';
  107. // Assign the relative path to the global variable.
  108. $path = $this->siteDirectory . '/config_' . CONFIG_SYNC_DIRECTORY;
  109. $GLOBALS['config_directories'][CONFIG_SYNC_DIRECTORY] = $path;
  110. // Ensure the directory can be created and is writeable.
  111. if (!install_ensure_config_directory(CONFIG_SYNC_DIRECTORY)) {
  112. throw new \RuntimeException("Failed to create '" . CONFIG_SYNC_DIRECTORY . "' config directory $path");
  113. }
  114. // Provide the already resolved path for tests.
  115. $this->configDirectories[CONFIG_SYNC_DIRECTORY] = $path;
  116. }
  117. /**
  118. * {@inheritdoc}
  119. */
  120. protected function setUp() {
  121. $this->keyValueFactory = new KeyValueMemoryFactory();
  122. // Back up settings from TestBase::prepareEnvironment().
  123. $settings = Settings::getAll();
  124. // Allow for test-specific overrides.
  125. $directory = DRUPAL_ROOT . '/' . $this->siteDirectory;
  126. $settings_services_file = DRUPAL_ROOT . '/' . $this->originalSite . '/testing.services.yml';
  127. $container_yamls = [];
  128. if (file_exists($settings_services_file)) {
  129. // Copy the testing-specific service overrides in place.
  130. $testing_services_file = $directory . '/services.yml';
  131. copy($settings_services_file, $testing_services_file);
  132. $container_yamls[] = $testing_services_file;
  133. }
  134. $settings_testing_file = DRUPAL_ROOT . '/' . $this->originalSite . '/settings.testing.php';
  135. if (file_exists($settings_testing_file)) {
  136. // Copy the testing-specific settings.php overrides in place.
  137. copy($settings_testing_file, $directory . '/settings.testing.php');
  138. }
  139. if (file_exists($directory . '/settings.testing.php')) {
  140. // Add the name of the testing class to settings.php and include the
  141. // testing specific overrides
  142. $hash_salt = Settings::getHashSalt();
  143. $test_class = get_class($this);
  144. $container_yamls_export = Variable::export($container_yamls);
  145. $php = <<<EOD
  146. <?php
  147. \$settings['hash_salt'] = '$hash_salt';
  148. \$settings['container_yamls'] = $container_yamls_export;
  149. \$test_class = '$test_class';
  150. include DRUPAL_ROOT . '/' . \$site_path . '/settings.testing.php';
  151. EOD;
  152. file_put_contents($directory . '/settings.php', $php);
  153. }
  154. // Add this test class as a service provider.
  155. // @todo Remove the indirection; implement ServiceProviderInterface instead.
  156. $GLOBALS['conf']['container_service_providers']['TestServiceProvider'] = 'Drupal\simpletest\TestServiceProvider';
  157. // Bootstrap a new kernel.
  158. $class_loader = require DRUPAL_ROOT . '/autoload.php';
  159. $this->kernel = new DrupalKernel('testing', $class_loader, FALSE);
  160. $request = Request::create('/');
  161. $site_path = DrupalKernel::findSitePath($request);
  162. $this->kernel->setSitePath($site_path);
  163. if (file_exists($directory . '/settings.testing.php')) {
  164. Settings::initialize(DRUPAL_ROOT, $site_path, $class_loader);
  165. }
  166. $this->kernel->boot();
  167. // Ensure database install tasks have been run.
  168. require_once __DIR__ . '/../../../includes/install.inc';
  169. $connection = Database::getConnection();
  170. $errors = db_installer_object($connection->driver())->runTasks();
  171. if (!empty($errors)) {
  172. $this->fail('Failed to run installer database tasks: ' . implode(', ', $errors));
  173. }
  174. // Reboot the kernel because the container might contain a connection to the
  175. // database that has been closed during the database install tasks. This
  176. // prevents any services created during the first boot from having stale
  177. // database connections, for example, \Drupal\Core\Config\DatabaseStorage.
  178. $this->kernel->shutdown();
  179. $this->kernel->boot();
  180. // Save the original site directory path, so that extensions in the
  181. // site-specific directory can still be discovered in the test site
  182. // environment.
  183. // @see \Drupal\Core\Extension\ExtensionDiscovery::scan()
  184. $settings['test_parent_site'] = $this->originalSite;
  185. // Restore and merge settings.
  186. // DrupalKernel::boot() initializes new Settings, and the containerBuild()
  187. // method sets additional settings.
  188. new Settings($settings + Settings::getAll());
  189. // Create and set new configuration directories.
  190. $this->prepareConfigDirectories();
  191. // Set the request scope.
  192. $this->container = $this->kernel->getContainer();
  193. $this->container->get('request_stack')->push($request);
  194. // Re-inject extension file listings into state, unless the key/value
  195. // service was overridden (in which case its storage does not exist yet).
  196. if ($this->container->get('keyvalue') instanceof KeyValueMemoryFactory) {
  197. $this->container->get('state')->set('system.module.files', $this->moduleFiles);
  198. $this->container->get('state')->set('system.theme.files', $this->themeFiles);
  199. }
  200. // Create a minimal core.extension configuration object so that the list of
  201. // enabled modules can be maintained allowing
  202. // \Drupal\Core\Config\ConfigInstaller::installDefaultConfig() to work.
  203. // Write directly to active storage to avoid early instantiation of
  204. // the event dispatcher which can prevent modules from registering events.
  205. \Drupal::service('config.storage')->write('core.extension', array('module' => array(), 'theme' => array()));
  206. // Collect and set a fixed module list.
  207. $class = get_class($this);
  208. $modules = array();
  209. while ($class) {
  210. if (property_exists($class, 'modules')) {
  211. // Only add the modules, if the $modules property was not inherited.
  212. $rp = new \ReflectionProperty($class, 'modules');
  213. if ($rp->class == $class) {
  214. $modules[$class] = $class::$modules;
  215. }
  216. }
  217. $class = get_parent_class($class);
  218. }
  219. // Modules have been collected in reverse class hierarchy order; modules
  220. // defined by base classes should be sorted first. Then, merge the results
  221. // together.
  222. $modules = array_reverse($modules);
  223. $modules = call_user_func_array('array_merge_recursive', $modules);
  224. if ($modules) {
  225. $this->enableModules($modules);
  226. }
  227. // Tests based on this class are entitled to use Drupal's File and
  228. // StreamWrapper APIs.
  229. // @todo Move StreamWrapper management into DrupalKernel.
  230. // @see https://www.drupal.org/node/2028109
  231. file_prepare_directory($this->publicFilesDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
  232. $this->settingsSet('file_public_path', $this->publicFilesDirectory);
  233. $this->streamWrappers = array();
  234. $this->registerStreamWrapper('public', 'Drupal\Core\StreamWrapper\PublicStream');
  235. // The temporary stream wrapper is able to operate both with and without
  236. // configuration.
  237. $this->registerStreamWrapper('temporary', 'Drupal\Core\StreamWrapper\TemporaryStream');
  238. // Manually configure the test mail collector implementation to prevent
  239. // tests from sending out emails and collect them in state instead.
  240. // While this should be enforced via settings.php prior to installation,
  241. // some tests expect to be able to test mail system implementations.
  242. $GLOBALS['config']['system.mail']['interface']['default'] = 'test_mail_collector';
  243. }
  244. /**
  245. * {@inheritdoc}
  246. */
  247. protected function tearDown() {
  248. if ($this->kernel instanceof DrupalKernel) {
  249. $this->kernel->shutdown();
  250. }
  251. // Before tearing down the test environment, ensure that no stream wrapper
  252. // of this test leaks into the parent environment. Unlike all other global
  253. // state variables in Drupal, stream wrappers are a global state construct
  254. // of PHP core, which has to be maintained manually.
  255. // @todo Move StreamWrapper management into DrupalKernel.
  256. // @see https://www.drupal.org/node/2028109
  257. foreach ($this->streamWrappers as $scheme => $type) {
  258. $this->unregisterStreamWrapper($scheme, $type);
  259. }
  260. parent::tearDown();
  261. }
  262. /**
  263. * Sets up the base service container for this test.
  264. *
  265. * Extend this method in your test to register additional service overrides
  266. * that need to persist a DrupalKernel reboot. This method is called whenever
  267. * the kernel is rebuilt.
  268. *
  269. * @see \Drupal\simpletest\KernelTestBase::setUp()
  270. * @see \Drupal\simpletest\KernelTestBase::enableModules()
  271. * @see \Drupal\simpletest\KernelTestBase::disableModules()
  272. */
  273. public function containerBuild(ContainerBuilder $container) {
  274. // Keep the container object around for tests.
  275. $this->container = $container;
  276. // Set the default language on the minimal container.
  277. $this->container->setParameter('language.default_values', $this->defaultLanguageData());
  278. $container->register('lock', 'Drupal\Core\Lock\NullLockBackend');
  279. $container->register('cache_factory', 'Drupal\Core\Cache\MemoryBackendFactory');
  280. $container
  281. ->register('config.storage', 'Drupal\Core\Config\DatabaseStorage')
  282. ->addArgument(Database::getConnection())
  283. ->addArgument('config');
  284. if ($this->strictConfigSchema) {
  285. $container
  286. ->register('simpletest.config_schema_checker', 'Drupal\Core\Config\Testing\ConfigSchemaChecker')
  287. ->addArgument(new Reference('config.typed'))
  288. ->addArgument($this->getConfigSchemaExclusions())
  289. ->addTag('event_subscriber');
  290. }
  291. $keyvalue_options = $container->getParameter('factory.keyvalue') ?: array();
  292. $keyvalue_options['default'] = 'keyvalue.memory';
  293. $container->setParameter('factory.keyvalue', $keyvalue_options);
  294. $container->set('keyvalue.memory', $this->keyValueFactory);
  295. if (!$container->has('keyvalue')) {
  296. // TestBase::setUp puts a completely empty container in
  297. // $this->container which is somewhat the mirror of the empty
  298. // environment being set up. Unit tests need not to waste time with
  299. // getting a container set up for them. Drupal Unit Tests might just get
  300. // away with a simple container holding the absolute bare minimum. When
  301. // a kernel is overridden then there's no need to re-register the keyvalue
  302. // service but when a test is happy with the superminimal container put
  303. // together here, it still might a keyvalue storage for anything using
  304. // \Drupal::state() -- that's why a memory service was added in the first
  305. // place.
  306. $container->register('settings', 'Drupal\Core\Site\Settings')
  307. ->setFactoryClass('Drupal\Core\Site\Settings')
  308. ->setFactoryMethod('getInstance');
  309. $container
  310. ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory')
  311. ->addArgument(new Reference('service_container'))
  312. ->addArgument(new Parameter('factory.keyvalue'));
  313. $container->register('state', 'Drupal\Core\State\State')
  314. ->addArgument(new Reference('keyvalue'));
  315. }
  316. if ($container->hasDefinition('path_processor_alias')) {
  317. // Prevent the alias-based path processor, which requires a url_alias db
  318. // table, from being registered to the path processor manager. We do this
  319. // by removing the tags that the compiler pass looks for. This means the
  320. // url generator can safely be used within tests.
  321. $definition = $container->getDefinition('path_processor_alias');
  322. $definition->clearTag('path_processor_inbound')->clearTag('path_processor_outbound');
  323. }
  324. if ($container->hasDefinition('password')) {
  325. $container->getDefinition('password')->setArguments(array(1));
  326. }
  327. // Register the stream wrapper manager.
  328. $container
  329. ->register('stream_wrapper_manager', 'Drupal\Core\StreamWrapper\StreamWrapperManager')
  330. ->addArgument(new Reference('module_handler'))
  331. ->addMethodCall('setContainer', array(new Reference('service_container')));
  332. $request = Request::create('/');
  333. $container->get('request_stack')->push($request);
  334. }
  335. /**
  336. * Provides the data for setting the default language on the container.
  337. *
  338. * @return array
  339. * The data array for the default language.
  340. */
  341. protected function defaultLanguageData() {
  342. return Language::$defaultValues;
  343. }
  344. /**
  345. * Installs default configuration for a given list of modules.
  346. *
  347. * @param array $modules
  348. * A list of modules for which to install default configuration.
  349. *
  350. * @throws \RuntimeException
  351. * Thrown when any module listed in $modules is not enabled.
  352. */
  353. protected function installConfig(array $modules) {
  354. foreach ($modules as $module) {
  355. if (!$this->container->get('module_handler')->moduleExists($module)) {
  356. throw new \RuntimeException("'$module' module is not enabled");
  357. }
  358. \Drupal::service('config.installer')->installDefaultConfig('module', $module);
  359. }
  360. $this->pass(format_string('Installed default config: %modules.', array(
  361. '%modules' => implode(', ', $modules),
  362. )));
  363. }
  364. /**
  365. * Installs a specific table from a module schema definition.
  366. *
  367. * @param string $module
  368. * The name of the module that defines the table's schema.
  369. * @param string|array $tables
  370. * The name or an array of the names of the tables to install.
  371. *
  372. * @throws \RuntimeException
  373. * Thrown when $module is not enabled or when the table schema cannot be
  374. * found in the module specified.
  375. */
  376. protected function installSchema($module, $tables) {
  377. // drupal_get_module_schema() is technically able to install a schema
  378. // of a non-enabled module, but its ability to load the module's .install
  379. // file depends on many other factors. To prevent differences in test
  380. // behavior and non-reproducible test failures, we only allow the schema of
  381. // explicitly loaded/enabled modules to be installed.
  382. if (!$this->container->get('module_handler')->moduleExists($module)) {
  383. throw new \RuntimeException("'$module' module is not enabled");
  384. }
  385. $tables = (array) $tables;
  386. foreach ($tables as $table) {
  387. $schema = drupal_get_module_schema($module, $table);
  388. if (empty($schema)) {
  389. // BC layer to avoid some contrib tests to fail.
  390. // @todo Remove the BC layer before 8.1.x release.
  391. // @see https://www.drupal.org/node/2670360
  392. // @see https://www.drupal.org/node/2670454
  393. if ($module == 'system') {
  394. continue;
  395. }
  396. throw new \RuntimeException("Unknown '$table' table schema in '$module' module.");
  397. }
  398. $this->container->get('database')->schema()->createTable($table, $schema);
  399. }
  400. $this->pass(format_string('Installed %module tables: %tables.', array(
  401. '%tables' => '{' . implode('}, {', $tables) . '}',
  402. '%module' => $module,
  403. )));
  404. }
  405. /**
  406. * Installs the storage schema for a specific entity type.
  407. *
  408. * @param string $entity_type_id
  409. * The ID of the entity type.
  410. */
  411. protected function installEntitySchema($entity_type_id) {
  412. /** @var \Drupal\Core\Entity\EntityManagerInterface $entity_manager */
  413. $entity_manager = $this->container->get('entity.manager');
  414. $entity_type = $entity_manager->getDefinition($entity_type_id);
  415. $entity_manager->onEntityTypeCreate($entity_type);
  416. // For test runs, the most common storage backend is a SQL database. For
  417. // this case, ensure the tables got created.
  418. $storage = $entity_manager->getStorage($entity_type_id);
  419. if ($storage instanceof SqlEntityStorageInterface) {
  420. $tables = $storage->getTableMapping()->getTableNames();
  421. $db_schema = $this->container->get('database')->schema();
  422. $all_tables_exist = TRUE;
  423. foreach ($tables as $table) {
  424. if (!$db_schema->tableExists($table)) {
  425. $this->fail(SafeMarkup::format('Installed entity type table for the %entity_type entity type: %table', array(
  426. '%entity_type' => $entity_type_id,
  427. '%table' => $table,
  428. )));
  429. $all_tables_exist = FALSE;
  430. }
  431. }
  432. if ($all_tables_exist) {
  433. $this->pass(SafeMarkup::format('Installed entity type tables for the %entity_type entity type: %tables', array(
  434. '%entity_type' => $entity_type_id,
  435. '%tables' => '{' . implode('}, {', $tables) . '}',
  436. )));
  437. }
  438. }
  439. }
  440. /**
  441. * Enables modules for this test.
  442. *
  443. * To install test modules outside of the testing environment, add
  444. * @code
  445. * $settings['extension_discovery_scan_tests'] = TRUE;
  446. * @endcode
  447. * to your settings.php.
  448. *
  449. * @param array $modules
  450. * A list of modules to enable. Dependencies are not resolved; i.e.,
  451. * multiple modules have to be specified with dependent modules first.
  452. * The new modules are only added to the active module list and loaded.
  453. */
  454. protected function enableModules(array $modules) {
  455. // Perform an ExtensionDiscovery scan as this function may receive a
  456. // profile that is not the current profile, and we don't yet have a cached
  457. // way to receive inactive profile information.
  458. // @todo Remove as part of https://www.drupal.org/node/2186491
  459. $listing = new ExtensionDiscovery(\Drupal::root());
  460. $module_list = $listing->scan('module');
  461. // In ModuleHandlerTest we pass in a profile as if it were a module.
  462. $module_list += $listing->scan('profile');
  463. // Set the list of modules in the extension handler.
  464. $module_handler = $this->container->get('module_handler');
  465. // Write directly to active storage to avoid early instantiation of
  466. // the event dispatcher which can prevent modules from registering events.
  467. $active_storage = \Drupal::service('config.storage');
  468. $extensions = $active_storage->read('core.extension');
  469. foreach ($modules as $module) {
  470. $module_handler->addModule($module, $module_list[$module]->getPath());
  471. // Maintain the list of enabled modules in configuration.
  472. $extensions['module'][$module] = 0;
  473. }
  474. $active_storage->write('core.extension', $extensions);
  475. // Update the kernel to make their services available.
  476. $module_filenames = $module_handler->getModuleList();
  477. $this->kernel->updateModules($module_filenames, $module_filenames);
  478. // Ensure isLoaded() is TRUE in order to make
  479. // \Drupal\Core\Theme\ThemeManagerInterface::render() work.
  480. // Note that the kernel has rebuilt the container; this $module_handler is
  481. // no longer the $module_handler instance from above.
  482. $this->container->get('module_handler')->reload();
  483. $this->pass(format_string('Enabled modules: %modules.', array(
  484. '%modules' => implode(', ', $modules),
  485. )));
  486. }
  487. /**
  488. * Disables modules for this test.
  489. *
  490. * @param array $modules
  491. * A list of modules to disable. Dependencies are not resolved; i.e.,
  492. * multiple modules have to be specified with dependent modules first.
  493. * Code of previously active modules is still loaded. The modules are only
  494. * removed from the active module list.
  495. */
  496. protected function disableModules(array $modules) {
  497. // Unset the list of modules in the extension handler.
  498. $module_handler = $this->container->get('module_handler');
  499. $module_filenames = $module_handler->getModuleList();
  500. $extension_config = $this->config('core.extension');
  501. foreach ($modules as $module) {
  502. unset($module_filenames[$module]);
  503. $extension_config->clear('module.' . $module);
  504. }
  505. $extension_config->save();
  506. $module_handler->setModuleList($module_filenames);
  507. $module_handler->resetImplementations();
  508. // Update the kernel to remove their services.
  509. $this->kernel->updateModules($module_filenames, $module_filenames);
  510. // Ensure isLoaded() is TRUE in order to make
  511. // \Drupal\Core\Theme\ThemeManagerInterface::render() work.
  512. // Note that the kernel has rebuilt the container; this $module_handler is
  513. // no longer the $module_handler instance from above.
  514. $module_handler = $this->container->get('module_handler');
  515. $module_handler->reload();
  516. $this->pass(format_string('Disabled modules: %modules.', array(
  517. '%modules' => implode(', ', $modules),
  518. )));
  519. }
  520. /**
  521. * Registers a stream wrapper for this test.
  522. *
  523. * @param string $scheme
  524. * The scheme to register.
  525. * @param string $class
  526. * The fully qualified class name to register.
  527. * @param int $type
  528. * The Drupal Stream Wrapper API type. Defaults to
  529. * StreamWrapperInterface::NORMAL.
  530. */
  531. protected function registerStreamWrapper($scheme, $class, $type = StreamWrapperInterface::NORMAL) {
  532. $this->container->get('stream_wrapper_manager')->registerWrapper($scheme, $class, $type);
  533. }
  534. /**
  535. * Renders a render array.
  536. *
  537. * @param array $elements
  538. * The elements to render.
  539. *
  540. * @return string
  541. * The rendered string output (typically HTML).
  542. */
  543. protected function render(array &$elements) {
  544. // Use the bare HTML page renderer to render our links.
  545. $renderer = $this->container->get('bare_html_page_renderer');
  546. $response = $renderer->renderBarePage($elements, '', 'maintenance_page');
  547. // Glean the content from the response object.
  548. $content = $response->getContent();
  549. $this->setRawContent($content);
  550. $this->verbose('<pre style="white-space: pre-wrap">' . Html::escape($content));
  551. return $content;
  552. }
  553. }

Classes

Namesort descending Description
KernelTestBase Deprecated Base class for integration tests.