diff --git a/core/core.services.yml b/core/core.services.yml index 13edc77..ea97a9a 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1225,16 +1225,16 @@ services: - { name: path_processor_inbound, priority: 200 } - { name: path_processor_outbound, priority: 200 } arguments: ['@config.factory'] + path_processor_entity_uuid: + class: Drupal\Core\PathProcessor\PathProcessorEntityUuid + tags: + - { name: path_processor_inbound, priority: 50 } + arguments: ['@entity_type.manager'] route_processor_current: class: Drupal\Core\RouteProcessor\RouteProcessorCurrent arguments: ['@current_route_match'] tags: - { name: route_processor_outbound, priority: 200 } - route_processor_entity_uuid: - class: Drupal\Core\RouteProcessor\RouteProcessorEntityUUID - arguments: ['@entity.manager'] - tags: - - { name: route_processor_outbound, priority: 100 } path_processor_alias: class: Drupal\Core\PathProcessor\PathProcessorAlias tags: diff --git a/core/lib/Drupal/Core/Entity/EntityTypeManager.php b/core/lib/Drupal/Core/Entity/EntityTypeManager.php index 03b0d45..ab7f645 100644 --- a/core/lib/Drupal/Core/Entity/EntityTypeManager.php +++ b/core/lib/Drupal/Core/Entity/EntityTypeManager.php @@ -172,25 +172,20 @@ public function getListBuilder($entity_type) { * {@inheritdoc} */ public function getFormObject($entity_type, $operation) { - if (!isset($this->handlers['form'][$operation][$entity_type])) { - if (!$class = $this->getDefinition($entity_type, TRUE)->getFormClass($operation)) { - throw new InvalidPluginDefinitionException($entity_type, sprintf('The "%s" entity type did not specify a "%s" form class.', $entity_type, $operation)); - } - - $form_object = $this->classResolver->getInstanceFromDefinition($class); - - $form_object - ->setStringTranslation($this->stringTranslation) - ->setModuleHandler($this->moduleHandler) - ->setEntityTypeManager($this) - ->setOperation($operation) - // The entity manager cannot be injected due to a circular dependency. - // @todo Remove this set call in https://www.drupal.org/node/2603542. - ->setEntityManager(\Drupal::entityManager()); - $this->handlers['form'][$operation][$entity_type] = $form_object; + if (!$class = $this->getDefinition($entity_type, TRUE)->getFormClass($operation)) { + throw new InvalidPluginDefinitionException($entity_type, sprintf('The "%s" entity type did not specify a "%s" form class.', $entity_type, $operation)); } - return $this->handlers['form'][$operation][$entity_type]; + $form_object = $this->classResolver->getInstanceFromDefinition($class); + + return $form_object + ->setStringTranslation($this->stringTranslation) + ->setModuleHandler($this->moduleHandler) + ->setEntityTypeManager($this) + ->setOperation($operation) + // The entity manager cannot be injected due to a circular dependency. + // @todo Remove this set call in https://www.drupal.org/node/2603542. + ->setEntityManager(\Drupal::entityManager()); } /** diff --git a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php index a372327..43c4468 100644 --- a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php +++ b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php @@ -135,10 +135,7 @@ public function checkNodeAccess(array $tree) { $nids = array_keys($node_links); $query = $this->queryFactory->get('node'); - $group = $query->orConditionGroup() - ->condition('nid', $nids, 'IN') - ->condition('uuid', $nids, 'IN'); - $query->condition($group); + $query->condition('nid', $nids, 'IN'); // Allows admins to view all nodes, by both disabling node_access // query rewrite as well as not checking for the node status. The @@ -154,11 +151,9 @@ public function checkNodeAccess(array $tree) { } $nids = $query->execute(); - foreach ($node_links as $nid => $links) { - foreach ($links as $key => $link) { - if (isset($nids[$nid])) { - $node_links[$nid][$key]->access = $access_result; - } + foreach ($nids as $nid) { + foreach ($node_links[$nid] as $key => $link) { + $node_links[$nid][$key]->access = $access_result; } } } @@ -179,8 +174,8 @@ public function checkNodeAccess(array $tree) { */ protected function collectNodeLinks(array &$tree, array &$node_links) { foreach ($tree as $key => &$element) { - if (($url = $element->link->getUrlObject()) && !$url->isExternal() && $url->getRouteName() == 'entity.node.canonical') { - $nid = $element->link->getUrlObject()->getRouteParameters()['node']; + if ($element->link->getRouteName() == 'entity.node.canonical') { + $nid = $element->link->getRouteParameters()['node']; $node_links[$nid][$key] = $element; // Deny access by default. checkNodeAccess() will re-add it. $element->access = AccessResult::neutral(); diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php index 0d93051..573cd49 100644 --- a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php +++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php @@ -2,7 +2,6 @@ namespace Drupal\Core\ParamConverter; -use Drupal\Component\Uuid\Uuid; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\TypedData\TranslatableInterface; @@ -63,12 +62,6 @@ public function convert($value, $definition, $name, array $defaults) { $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults); if ($storage = $this->entityManager->getStorage($entity_type_id)) { $entity = $storage->load($value); - // If there is no entity loadable by ID, try to load by UUID. - if (!$entity && Uuid::isValid($value)) { - if ($entities = $storage->loadByProperties(['uuid' => $value])) { - $entity = reset($entities); - } - } // If the entity type is translatable, ensure we return the proper // translation object for the current context. if ($entity instanceof EntityInterface && $entity instanceof TranslatableInterface) { diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorEntityUuid.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorEntityUuid.php new file mode 100644 index 0000000..bbf5223 --- /dev/null +++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorEntityUuid.php @@ -0,0 +1,58 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public function processInbound($path, Request $request) { + $matches = []; + if (preg_match('/^\/([a-z_]+)\/(' . Uuid::VALID_PATTERN . ')$/i', $path, $matches)) { + $entity_type_id = $matches[1]; + $uuid = $matches[2]; + if ($this->entityTypeManager->hasDefinition($entity_type_id)) { + $storage = $this->entityTypeManager->getStorage($entity_type_id); + $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); + if ($entity_type->hasLinkTemplate('canonical') && $entities = $storage->loadByProperties(['uuid' => $uuid])) { + /* @var \Drupal\Core\Entity\EntityInterface $entity */ + $entity = reset($entities); + $path = '/' . ltrim($entity->toUrl()->getInternalPath(), '/'); + } + } + } + return $path; + } + +} diff --git a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php deleted file mode 100644 index 3c5ef78..0000000 --- a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorEntityUUID.php +++ /dev/null @@ -1,51 +0,0 @@ -entityManager = $entity_manager; - } - - /** - * {@inheritdoc} - */ - public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) { - if (strpos($route_name, 'entity.') === 0 && list(, $entity_type, $operation) = explode('.', $route_name)) { - if (isset($parameters[$entity_type]) && strlen($parameters[$entity_type]) === 32) { - if ($entities = $this->entityManager->getStorage($entity_type)->loadByProperties(['uuid' => $parameters[$entity_type]])) { - /** @var \Drupal\Core\Entity\EntityInterface $entity */ - $entity = reset($entities); - $parameters[$entity_type] = $entity->id(); - } - } - } - } - -} diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index 417fc5b..8122e89 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -35,7 +35,8 @@ class Registry implements DestructableInterface { * The complete theme registry. * * @var array - * An associative array keyed by theme hook names, whose values are + * An array of theme registries, keyed by the theme name. Each registry is + * an associative array keyed by theme hook names, whose values are * associative arrays containing the aggregated hook definition: * - type: The type of the extension the original theme hook originates * from; e.g., 'module' for theme hook 'node' of Node module. @@ -74,7 +75,7 @@ class Registry implements DestructableInterface { * - process: An array of theme variable process callbacks to invoke * before invoking the actual theme function or template. */ - protected $registry; + protected $registry = []; /** * The cache backend to use for the complete theme registry data. @@ -91,11 +92,11 @@ class Registry implements DestructableInterface { protected $moduleHandler; /** - * The incomplete, runtime theme registry. + * An array of incomplete, runtime theme registries, keyed by theme name. * - * @var \Drupal\Core\Utility\ThemeRegistry + * @var \Drupal\Core\Utility\ThemeRegistry[] */ - protected $runtimeRegistry; + protected $runtimeRegistry = []; /** * Stores whether the registry was already initialized. @@ -204,20 +205,20 @@ protected function init($theme_name = NULL) { */ public function get() { $this->init($this->themeName); - if (isset($this->registry)) { - return $this->registry; + if (isset($this->registry[$this->theme->getName()])) { + return $this->registry[$this->theme->getName()]; } if ($cache = $this->cache->get('theme_registry:' . $this->theme->getName())) { - $this->registry = $cache->data; + $this->registry[$this->theme->getName()] = $cache->data; } else { - $this->registry = $this->build(); + $this->build(); // Only persist it if all modules are loaded to ensure it is complete. if ($this->moduleHandler->isLoaded()) { $this->setCache(); } } - return $this->registry; + return $this->registry[$this->theme->getName()]; } /** @@ -230,17 +231,17 @@ public function get() { */ public function getRuntime() { $this->init($this->themeName); - if (!isset($this->runtimeRegistry)) { - $this->runtimeRegistry = new ThemeRegistry('theme_registry:runtime:' . $this->theme->getName(), $this->cache, $this->lock, array('theme_registry'), $this->moduleHandler->isLoaded()); + if (!isset($this->runtimeRegistry[$this->theme->getName()])) { + $this->runtimeRegistry[$this->theme->getName()] = new ThemeRegistry('theme_registry:runtime:' . $this->theme->getName(), $this->cache, $this->lock, array('theme_registry'), $this->moduleHandler->isLoaded()); } - return $this->runtimeRegistry; + return $this->runtimeRegistry[$this->theme->getName()]; } /** * Persists the theme registry in the cache backend. */ protected function setCache() { - $this->cache->set('theme_registry:' . $this->theme->getName(), $this->registry, Cache::PERMANENT, array('theme_registry')); + $this->cache->set('theme_registry:' . $this->theme->getName(), $this->registry[$this->theme->getName()], Cache::PERMANENT, array('theme_registry')); } /** @@ -354,9 +355,9 @@ protected function build() { unset($cache[$hook]['preprocess functions']); } } - $this->registry = $cache; + $this->registry[$this->theme->getName()] = $cache; - return $this->registry; + return $this->registry[$this->theme->getName()]; } /** @@ -714,12 +715,12 @@ protected function postProcessExtension(array &$cache, ActiveTheme $theme) { */ public function reset() { // Reset the runtime registry. - if (isset($this->runtimeRegistry) && $this->runtimeRegistry instanceof ThemeRegistry) { - $this->runtimeRegistry->clear(); + foreach ($this->runtimeRegistry as $runtime_registry) { + $runtime_registry->clear(); } - $this->runtimeRegistry = NULL; + $this->runtimeRegistry = []; - $this->registry = NULL; + $this->registry = []; Cache::invalidateTags(array('theme_registry')); return $this; } @@ -728,8 +729,8 @@ public function reset() { * {@inheritdoc} */ public function destruct() { - if (isset($this->runtimeRegistry)) { - $this->runtimeRegistry->destruct(); + foreach ($this->runtimeRegistry as $runtime_registry) { + $runtime_registry->destruct(); } } diff --git a/core/modules/system/tests/themes/test_stable/test_stable.theme b/core/modules/system/tests/themes/test_stable/test_stable.theme new file mode 100644 index 0000000..8498d89 --- /dev/null +++ b/core/modules/system/tests/themes/test_stable/test_stable.theme @@ -0,0 +1,13 @@ +installSchema('system', ['sequences']); + $this->installEntitySchema('node'); + $this->installEntitySchema('user'); + $this->installEntitySchema('contact_message'); + } + + /** + * Tests ::processInbound(). + * + * @covers ::processInbound + */ + public function testProcessInbound() { + $node_type = NodeType::create([ + 'type' => 'article', + 'name' => 'Article', + ]); + $node_type->save(); + $node = Node::create([ + 'type' => 'article', + 'title' => 'Some node', + 'status' => 1, + 'uid' => 1, + ]); + $node->save(); + + $user = User::create([ + 'name' => 'bob', + 'mail' => 'bob@example.com', + ]); + $user->save(); + + $message_type = ContactForm::create([ + 'id' => 'form', + 'label' => 'A form', + ]); + $message_type->save(); + + $message = Message::create([ + 'contact_form' => 'form', + ]); + $message->save(); + + $fake_uuid = '3FA3D516-FCE7-4788-BCCF-CE41B78F8F28'; + + /* @var \Drupal\Core\PathProcessor\PathProcessorEntityUuid $processor */ + $processor = $this->container->get('path_processor_entity_uuid'); + + $request = Request::create(''); + + // Non matching paths are ignored. + $this->assertEquals('/this-does-not-match', $processor->processInbound('/this-does-not-match', $request)); + // Node and user should be processed to their serial ID/canonical route. + $this->assertEquals('/user/' . $user->id(), $processor->processInbound('/user/' . $user->uuid(), $request)); + $this->assertEquals('/node/' . $node->id(), $processor->processInbound('/node/' . $node->uuid(), $request)); + // Taxonomy is not enable so the entity-type should not be processed. + $this->assertEquals('/taxonomy_term/' . $fake_uuid, $processor->processInbound('/taxonomy_term/' . $fake_uuid, $request)); + // This UUID doesn't exist for node, so should not be processed. + $this->assertEquals('/node/' . $fake_uuid, $processor->processInbound('/node/' . $fake_uuid, $request)); + // Contact messages don't have canonical links, so should not be processed. + $this->assertEquals('/contact_message/' . $message->uuid(), $processor->processInbound('/contact_message/' . $message->uuid(), $request)); + } + +} diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php index 2536fd3..ded278e 100644 --- a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php +++ b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php @@ -88,12 +88,6 @@ public function testConvert($value, array $definition, array $defaults, $expecte ['valid_id', (object) ['id' => 'valid_id']], ['invalid_id', NULL], ]); - $entity_storage->expects($this->any()) - ->method('loadByProperties') - ->willReturnMap([ - [['uuid' => 'invalid_id'], NULL], - [['uuid' => $value], [(object) ['uuid' => $value, 'id' => 'valid_id']]], - ]); $this->assertEquals($expected_result, $this->entityConverter->convert($value, $definition, 'foo', $defaults)); } @@ -109,8 +103,6 @@ public function providerTestConvert() { $data[] = ['invalid_id', ['type' => 'entity:entity_test'], ['foo' => 'invalid_id'], NULL]; // Entity type placeholder. $data[] = ['valid_id', ['type' => 'entity:{entity_type}'], ['foo' => 'valid_id', 'entity_type' => 'entity_test'], (object) ['id' => 'valid_id']]; - // UUID. - $data[] = ['1c5217f4-553c-40d8-8389-a3cc3529d79c', ['type' => 'entity:entity_test'], ['foo' => '1c5217f4-553c-40d8-8389-a3cc3529d79c'], (object) ['uuid' => '1c5217f4-553c-40d8-8389-a3cc3529d79c', 'id' => 'valid_id']]; return $data; } diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorEntityUuidTest.php b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorEntityUuidTest.php new file mode 100644 index 0000000..9f70984 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorEntityUuidTest.php @@ -0,0 +1,157 @@ +getMock(EntityTypeManagerInterface::class); + } + $processor = new PathProcessorEntityUuid($entity_type_manager); + $this->assertEquals($expected, $processor->processInbound($inbound_path, Request::create($inbound_path))); + } + + /** + * Data provider for ::testProcessInbound(). + * + * @return array + * Test cases. + */ + public function providerProcessInbound() { + $user_uuid = '03C88CB8-76E1-4358-9BEC-EEF4233ED9F7'; + $node_uuid = '1E69BE45-DF30-40C6-B6AB-82E04084DC9E'; + $pony_uuid = 'EDCB122F-4851-41A5-8A9F-0DF94727E6B9'; + $contact_uuid = '72E91376-C52E-49EA-9F82-C7829463B874'; + $not_found_uuid = '3483E574-57D5-45F6-8D6E-3CFEAE605907'; + + // An entity-type with a canonical link. + $entity_type_with_link = $this->getMock(EntityTypeInterface::class); + $entity_type_with_link->expects($this->any()) + ->method('hasLinkTemplate') + ->willReturn(TRUE); + + // An entity-type without a canonical link. + $entity_type_without_link = $this->getMock(EntityTypeInterface::class); + $entity_type_without_link->expects($this->any()) + ->method('hasLinkTemplate') + ->willReturn(FALSE); + + // Entity-manager. + $entity_type_manager = $this->getMock(EntityTypeManagerInterface::class); + $entity_type_manager->expects($this->any()) + ->method('hasDefinition') + ->willReturnCallback(function($entity_type_id) { + return in_array($entity_type_id, ['user', 'node', 'contact'], TRUE); + }); + $entity_type_manager->expects($this->any()) + ->method('getDefinition') + ->willReturnCallback(function($entity_type_id) use ($entity_type_with_link, $entity_type_without_link) { + if (in_array($entity_type_id, ['user', 'node'], TRUE)) { + return $entity_type_with_link; + } + return $entity_type_without_link; + }); + + // Mock node. + $node_url = $this->getMockBuilder(Url::class) + ->disableOriginalConstructor() + ->getMock(); + $node_url->expects($this->any()) + ->method('getInternalPath') + ->willReturn('node/12'); + $node_mock = $this->getMock(NodeInterface::class); + $node_mock->expects($this->any()) + ->method('toUrl') + ->willReturn($node_url); + + // Mock user. + $user_url = $this->getMockBuilder(Url::class) + ->disableOriginalConstructor() + ->getMock(); + $user_url->expects($this->any()) + ->method('getInternalPath') + ->willReturn('user/1'); + $user_mock = $this->getMock(UserInterface::class); + $user_mock->expects($this->any()) + ->method('toUrl') + ->willReturn($user_url); + + // Mock node storage. + $node_storage = $this->getMockBuilder(NodeStorage::class) + ->disableOriginalConstructor() + ->getMock(); + $node_storage->expects($this->any()) + ->method('loadByProperties') + ->with(['uuid' => $node_uuid]) + ->willReturn([ + $node_mock, + ]); + + // Mock user storage. + $user_storage = $this->getMockBuilder(UserStorage::class) + ->disableOriginalConstructor() + ->getMock(); + $user_storage->expects($this->any()) + ->method('loadByProperties') + ->willReturnCallback(function($conditions) use ($user_mock, $user_uuid) { + if ($conditions['uuid'] == $user_uuid) { + return [$user_mock]; + } + return []; + }); + + // Mock entity-manager. + $entity_type_manager->expects($this->any()) + ->method('getStorage') + ->willReturnMap([ + ['user', $user_storage], + ['node', $node_storage], + ]); + return [ + 'irrelevant' => ['/this-does-not-match', '/this-does-not-match'], + 'user-valid' => ['/user/' . $user_uuid, '/user/1', $entity_type_manager], + 'node-valid' => ['/node/' . $node_uuid, '/node/12', $entity_type_manager], + 'invalid-entity-type' => [ + '/pony/' . $pony_uuid, + '/pony/' . $pony_uuid, + $entity_type_manager, + ], + 'no-such-uuid' => [ + '/user/' . $not_found_uuid, + '/user/' . $not_found_uuid, + $entity_type_manager, + ], + 'no-canonical-link' => [ + '/contact/' . $contact_uuid, + '/contact/' . $contact_uuid, + $entity_type_manager, + ], + ]; + } + +} diff --git a/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php b/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php index e0c20cd..1243118 100644 --- a/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php +++ b/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php @@ -86,8 +86,7 @@ protected function setUp() { * Tests getting the theme registry defined by a module. */ public function testGetRegistryForModule() { - $this->setupTheme('test_theme'); - $this->registry->setTheme(new ActiveTheme([ + $test_theme = new ActiveTheme([ 'name' => 'test_theme', 'path' => 'core/modules/system/tests/themes/test_theme/test_theme.info.yml', 'engine' => 'twig', @@ -98,11 +97,29 @@ public function testGetRegistryForModule() { 'libraries' => [], 'extension' => '.twig', 'base_themes' => [], - ])); + ]); - // Include the module so that hook_theme can be called. + $test_stable = new ActiveTheme([ + 'name' => 'test_stable', + 'path' => 'core/modules/system/tests/themes/test_stable/test_stable.info.yml', + 'engine' => 'twig', + 'owner' => 'twig', + 'stylesheets_remove' => [], + 'libraries_override' => [], + 'libraries_extend' => [], + 'libraries' => [], + 'extension' => '.twig', + 'base_themes' => [], + ]); + + $this->themeManager->expects($this->exactly(2)) + ->method('getActiveTheme') + ->willReturnOnConsecutiveCalls($test_theme, $test_stable); + + // Include the module and theme files so that hook_theme can be called. include_once $this->root . '/core/modules/system/tests/modules/theme_test/theme_test.module'; - $this->moduleHandler->expects($this->once()) + include_once $this->root . '/core/modules/system/tests/themes/test_stable/test_stable.theme'; + $this->moduleHandler->expects($this->exactly(2)) ->method('getImplementations') ->with('theme') ->will($this->returnValue(array('theme_test'))); @@ -126,16 +143,24 @@ public function testGetRegistryForModule() { $this->assertArrayHasKey('theme_test_function_template_override', $registry); $this->assertArrayNotHasKey('test_theme_not_existing_function', $registry); + $this->assertFalse(in_array('test_stable_preprocess_theme_test_render_element', $registry['theme_test_render_element']['preprocess functions'])); $info = $registry['theme_test_function_suggestions']; $this->assertEquals('module', $info['type']); $this->assertEquals('core/modules/system/tests/modules/theme_test', $info['theme path']); $this->assertEquals('theme_theme_test_function_suggestions', $info['function']); $this->assertEquals(array(), $info['variables']); + + // The second call will initialize with the second theme. Ensure that this + // returns a different object and the discovery for the second theme's + // preprocess function worked. + $other_registry = $this->registry->get(); + $this->assertNotSame($registry, $other_registry); + $this->assertTrue(in_array('test_stable_preprocess_theme_test_render_element', $other_registry['theme_test_render_element']['preprocess functions'])); } - protected function setupTheme($theme_name = NULL) { - $this->registry = new TestRegistry($this->root, $this->cache, $this->lock, $this->moduleHandler, $this->themeHandler, $this->themeInitialization, $theme_name); + protected function setupTheme() { + $this->registry = new TestRegistry($this->root, $this->cache, $this->lock, $this->moduleHandler, $this->themeHandler, $this->themeInitialization); $this->registry->setThemeManager($this->themeManager); } @@ -143,23 +168,10 @@ protected function setupTheme($theme_name = NULL) { class TestRegistry extends Registry { - public function setTheme(ActiveTheme $theme) { - $this->theme = $theme; - } - - protected function init($theme_name = NULL) { - } - protected function getPath($module) { if ($module == 'theme_test') { return 'core/modules/system/tests/modules/theme_test'; } } - protected function listThemes() { - } - - protected function initializeTheme() { - } - }