diff --git a/core/core.services.yml b/core/core.services.yml index f767c313f09d932a0d51bc63c5218fff1a720ac7..1a5a621e75dfd30ebf6555b33302446c7a36d331 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1735,7 +1735,7 @@ services: Drupal\Core\Render\RenderCacheInterface: '@render_cache' renderer: class: Drupal\Core\Render\Renderer - arguments: ['@controller_resolver', '@theme.manager', '@plugin.manager.element_info', '@render_placeholder_generator', '@render_cache', '@request_stack', '%renderer.config%'] + arguments: ['@callable_resolver', '@theme.manager', '@plugin.manager.element_info', '@render_placeholder_generator', '@render_cache', '@request_stack', '%renderer.config%'] Drupal\Core\Render\RendererInterface: '@renderer' early_rendering_controller_wrapper_subscriber: class: Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index afd993bee701f9cf32f74670201407c1b10348e5..5a7fc05dd5466c6471344ad406437fac87a30387 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -15,6 +15,7 @@ use Drupal\Core\Security\TrustedCallbackInterface; use Drupal\Core\Security\DoTrustedCallbackTrait; use Drupal\Core\Theme\ThemeManagerInterface; +use Drupal\Core\Utility\CallableResolver; use Symfony\Component\HttpFoundation\RequestStack; /** @@ -31,11 +32,11 @@ class Renderer implements RendererInterface { protected $theme; /** - * The controller resolver. + * The callable resolver. * - * @var \Drupal\Core\Controller\ControllerResolverInterface + * @var \Drupal\Core\Utility\CallableResolver */ - protected $controllerResolver; + protected CallableResolver $callableResolver; /** * The element info. @@ -99,8 +100,8 @@ class Renderer implements RendererInterface { /** * Constructs a new Renderer. * - * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver - * The controller resolver. + * @param \Drupal\Core\Utility\CallableResolver|\Drupal\Core\Controller\ControllerResolverInterface $callable_resolver + * The callable resolver. * @param \Drupal\Core\Theme\ThemeManagerInterface $theme * The theme manager. * @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info @@ -114,8 +115,12 @@ class Renderer implements RendererInterface { * @param array $renderer_config * The renderer configuration array. */ - public function __construct(ControllerResolverInterface $controller_resolver, ThemeManagerInterface $theme, ElementInfoManagerInterface $element_info, PlaceholderGeneratorInterface $placeholder_generator, RenderCacheInterface $render_cache, RequestStack $request_stack, array $renderer_config) { - $this->controllerResolver = $controller_resolver; + public function __construct(ControllerResolverInterface|CallableResolver $callable_resolver, ThemeManagerInterface $theme, ElementInfoManagerInterface $element_info, PlaceholderGeneratorInterface $placeholder_generator, RenderCacheInterface $render_cache, RequestStack $request_stack, array $renderer_config) { + if ($callable_resolver instanceof ControllerResolverInterface) { + @trigger_error('Calling ' . __METHOD__ . '() with an argument of ControllerResolverInterface is deprecated in drupal:10.2.0 and is removed in drupal:11.0.0. Use \Drupal\Core\Utility\CallableResolver instead. See https://www.drupal.org/node/3369969', E_USER_DEPRECATED); + $callable_resolver = \Drupal::service('callable_resolver'); + } + $this->callableResolver = $callable_resolver; $this->theme = $theme; $this->elementInfo = $element_info; $this->placeholderGenerator = $placeholder_generator; @@ -843,22 +848,14 @@ protected function ensureMarkupIsSafe(array $elements) { * @see \Drupal\Core\Security\TrustedCallbackInterface */ protected function doCallback($callback_type, $callback, array $args) { - if (is_string($callback)) { - $double_colon = strpos($callback, '::'); - if ($double_colon === FALSE) { - $callback = $this->controllerResolver->getControllerFromDefinition($callback); - } - elseif ($double_colon > 0) { - $callback = explode('::', $callback, 2); - } - } + $callable = $this->callableResolver->getCallableFromDefinition($callback); $message = sprintf('Render %s callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', $callback_type, '%s'); // Add \Drupal\Core\Render\Element\RenderCallbackInterface as an extra // trusted interface so that: // - All public methods on Render elements are considered trusted. // - Helper classes that contain only callback methods can implement this // instead of TrustedCallbackInterface. - return $this->doTrustedCallback($callback, $args, $message, TrustedCallbackInterface::THROW_EXCEPTION, RenderCallbackInterface::class); + return $this->doTrustedCallback($callable, $args, $message, TrustedCallbackInterface::THROW_EXCEPTION, RenderCallbackInterface::class); } /** diff --git a/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php b/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php index b20448c26cfc1c0e000c5f56d8c0ac822ce63d0e..c342a48d93d1201ea49c96faa66feff74f5e86d5 100644 --- a/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php +++ b/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php @@ -4,6 +4,7 @@ use Drupal\Core\Render\RenderContext; use Drupal\Core\Render\Renderer; +use Drupal\Core\Utility\CallableResolver; use Drupal\Tests\UnitTestCase; use Drupal\views\Ajax\ViewAjaxResponse; use Drupal\views\Controller\ViewAjaxController; @@ -102,7 +103,7 @@ protected function setUp(): void { $request_stack = new RequestStack(); $request_stack->push(new Request()); $this->renderer = new Renderer( - $this->createMock('\Drupal\Core\Controller\ControllerResolverInterface'), + $this->createMock(CallableResolver::class), $this->createMock('\Drupal\Core\Theme\ThemeManagerInterface'), $element_info_manager, $this->createMock('\Drupal\Core\Render\PlaceholderGeneratorInterface'), diff --git a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php index 8a86bb72fed0851144f05c6b39a1070a0f97178c..8ff0ddb6a2eb07d36b0532e1d9ae449d6e3a7019 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php @@ -452,9 +452,6 @@ public function testBubblingWithPrerender($test_element) { // Mock the State service. $memory_state = new State(new KeyValueMemoryFactory()); \Drupal::getContainer()->set('state', $memory_state); - $this->controllerResolver->expects($this->any()) - ->method('getControllerFromDefinition') - ->willReturnArgument(0); // Simulate the theme system/Twig: a recursive call to Renderer::render(), // just like the theme system or a Twig template would have done. diff --git a/core/tests/Drupal/Tests/Core/Render/RendererCallbackTest.php b/core/tests/Drupal/Tests/Core/Render/RendererCallbackTest.php index 4462f987993c4fa99d1944ff530d0269d03dabaf..ca63dee68e1bad442d762674d61245f06e772ccf 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererCallbackTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererCallbackTest.php @@ -15,8 +15,8 @@ class RendererCallbackTest extends RendererTestBase { */ protected function setUp(): void { parent::setUp(); - $this->controllerResolver->expects($this->any()) - ->method('getControllerFromDefinition') + $this->callableResolver->expects($this->any()) + ->method('getCallableFromDefinition') ->willReturnArgument(0); } diff --git a/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php b/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php index 72623ac60b339a15278c403fbb504834a1a116d2..b2ad8d8c97359accc3dd33d7abefd4e99d7f2bdf 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php @@ -12,8 +12,8 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Render\Markup; -use Drupal\Core\Security\TrustedCallbackInterface; use Drupal\Core\Render\RenderContext; +use Drupal\Core\Security\TrustedCallbackInterface; /** * @coversDefaultClass \Drupal\Core\Render\Renderer @@ -960,8 +960,8 @@ public function testRenderChildrenPlaceholdersDifferentArguments() { $this->cacheContextsManager->expects($this->any()) ->method('convertTokensToKeys') ->willReturnArgument(0); - $this->controllerResolver->expects($this->any()) - ->method('getControllerFromDefinition') + $this->callableResolver->expects($this->any()) + ->method('getCallableFromDefinition') ->willReturnArgument(0); $this->setupThemeManagerForDetails(); @@ -1141,7 +1141,7 @@ public static function callback($animal) { return [ 'another' => [ '#create_placeholder' => TRUE, - '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', [$animal]], + '#lazy_builder' => [PlaceholdersTest::class . '::callback', [$animal]], ], ]; } diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php index fb05980236deba0627a52e45d960be62e0245079..1257ca4da8a105c692505fdccc6cead54088bf21 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php @@ -16,6 +16,7 @@ use Drupal\Core\Render\PlaceholderingRenderCache; use Drupal\Core\Render\Renderer; use Drupal\Core\Security\TrustedCallbackInterface; +use Drupal\Core\Utility\CallableResolver; use Drupal\Tests\UnitTestCase; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpFoundation\Request; @@ -65,9 +66,9 @@ abstract class RendererTestBase extends UnitTestCase { /** * The mocked controller resolver. * - * @var \Drupal\Core\Controller\ControllerResolverInterface|\PHPUnit\Framework\MockObject\MockObject + * @var \Drupal\Core\Utility\CallableResolver|\PHPUnit\Framework\MockObject\MockObject */ - protected $controllerResolver; + protected $callableResolver; /** * The mocked theme manager. @@ -119,7 +120,10 @@ abstract class RendererTestBase extends UnitTestCase { protected function setUp(): void { parent::setUp(); - $this->controllerResolver = $this->createMock('Drupal\Core\Controller\ControllerResolverInterface'); + $this->callableResolver = $this->createMock(CallableResolver::class); + $this->callableResolver->expects($this->any()) + ->method('getCallableFromDefinition') + ->willReturnArgument(0); $this->themeManager = $this->createMock('Drupal\Core\Theme\ThemeManagerInterface'); $this->elementInfo = $this->createMock('Drupal\Core\Render\ElementInfoManagerInterface'); $this->elementInfo->expects($this->any()) @@ -181,7 +185,7 @@ protected function setUp(): void { }); $this->placeholderGenerator = new PlaceholderGenerator($this->cacheContextsManager, $this->rendererConfig); $this->renderCache = new PlaceholderingRenderCache($this->requestStack, $this->cacheFactory, $this->cacheContextsManager, $this->placeholderGenerator); - $this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->placeholderGenerator, $this->renderCache, $this->requestStack, $this->rendererConfig); + $this->renderer = new Renderer($this->callableResolver, $this->themeManager, $this->elementInfo, $this->placeholderGenerator, $this->renderCache, $this->requestStack, $this->rendererConfig); $container = new ContainerBuilder(); $container->set('cache_contexts_manager', $this->cacheContextsManager);