Support from Acquia helps fund testing for Drupal Acquia logo

Comments

cilefen’s picture

Assigned: Unassigned » cilefen
colbol’s picture

Assigned: cilefen » Unassigned
Status: Active » Needs review
FileSize
2.82 KB

The problem is this creates a circular service reference:

exception 'Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException' with message 'Circular reference detected for service[error]
"theme.manager", path: "theme.manager -> renderer -> theme.manager".'

Status: Needs review » Needs work

The last submitted patch, 2: inject_the_renderer-2529438-2.patch, failed testing.

plach’s picture

Nice, at very least let's use Drupal::service() :)

dawehner’s picture

Did you tried using setter injection?

cilefen’s picture

Setter injection results in a different circular reference:

exception 'Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException' with message 'Circular reference detected for service[error]
"plugin.manager.element_info", path: "plugin.cache_clearer -> plugin.manager.element_info -> theme.manager -> renderer".'

We'll have to to with #4 without a major refactoring.

cilefen’s picture

Status: Needs work » Needs review
FileSize
624 bytes
cilefen’s picture

Title: Inject the Renderer into the ThemeManager » Remove usages of drupal_render() in ThemeManager
plach’s picture

Status: Needs review » Reviewed & tested by the community

Thanks

dawehner’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
7.46 KB

Here is an alternative idea ... as ThemeManagerInterface::render is already meant to be internal.

plach’s picture

+++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php
@@ -25,11 +27,15 @@
+  public function render($hook, array $variables, RendererInterface $renderer);

What about making $renderer default to NULL so we can have a BC change? Otherwise not sure we can justify this issue in the beta evaluation.

dawehner’s picture

What about making $renderer default to NULL so we can have a BC change? Otherwise not sure we can justify this issue in the beta evaluation.

Well, for sure we could do that, but on the other hand we really pushed hard to make theme() => _theme() internal.

Mile23’s picture

Version: 8.0.x-dev » 8.1.x-dev
Status: Needs review » Needs work
Issue tags: +@deprecated

I think #10 is the way to go, especially in 8.1.x.

-1 on #11. Even if it weren't @internal, we should still inject all dependencies. We want to leave the seam so that the problem from #6 is visible and eventually gets fixed.

One thing though:

+++ b/core/modules/system/src/Tests/Theme/ThemeTest.php
@@ -63,13 +63,13 @@ function testThemeDataTypes() {
+      $output = \Drupal::theme()->render('theme_test_foo', array('foo' => $example), \Drupal::service('renderer'));
...
+    $output = \Drupal::theme()->render(array('suggestionnotimplemented'), array(), \Drupal::service('renderer'));

+++ b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php
@@ -50,7 +50,7 @@ public function testInfoStylesheets() {
+    return ['#markup' => \Drupal::theme()->render('theme_test_template_test', array(), \Drupal::service('renderer'))];

@@ -76,7 +76,7 @@ public function testInlineTemplate() {
+    return ['#markup' => \Drupal::theme()->render(array('theme_test__suggestion', 'theme_test'), array(), \Drupal::service('renderer'))];

+++ b/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php
@@ -18,7 +18,7 @@ class TwigThemeTestController {
+    return ['#markup' => \Drupal::theme()->render('twig_theme_test_php_variables', array(), \Drupal::service('renderer'))];

Change those to $this->container->service() instead of \Drupal.

Also need a followup to properly inject all the \Drupal dependencies in the rest of ThemeManager.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joelpittet’s picture

I agree with @plach in #11. To preserve BC we shouldn't change the public interface on ThemeManager. Maybe it leaves a bit of cruft in there but with a bit of comments it will be obvious to remove in D9.

Mile23’s picture

Title: Remove usages of drupal_render() in ThemeManager » Inject renderer service into ThemeManager, disuse drupal_render()
Parent issue: » #2729597: [meta] Replace \Drupal with injected services where appropriate in core

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Mile23’s picture

After #2704871: Replace usages of deprecated method drupal_render(), ThemeManager does not have references to drupal_render() within it. However, it does use \Drupal::service('render')->render(), which doesn't count as injecting the service.

I haven't experimented, but it's likely still a circular reference between the two services.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

eelkeblok’s picture

I am running into some issues trying to render stuff for embedding in an email, and encounter this issue where things go pear-shaped. It looks like the render context is not being passed on. I've rerolled #10 and squashed some more uses of themeManager->render(). Hopefully it's all this impacts.

Status: Needs review » Needs work

The last submitted patch, 24: drupal-inject_renderer_into_thememanager-2529438-24-d8.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

eelkeblok’s picture

This fixes the two test failures (silly misplacement of brackets) and actually uses the passed renderer instance instead of asking for it from the Drupal global object, which is what originally led me to this issue.

eelkeblok’s picture

FileSize
4.41 KB

Here's an interdiff, basically for 10 to 26 (24 was not only a reroll, it also contained fixes for some additional uses of themeManager::render()).

andypost’s picture

markhalliwell’s picture

Status: Needs review » Needs work

I'm not entirely sure this issue is still relevant. Its primary use was to get rid of drupal_render() usage, which has already been done.

Yes, it still uses \Drupal::service('renderer'), but that's a semi-by product of the circular dependency created by the Renderer service.

I'm also really not a huge fan of DI methods like the latest patches are doing.

I think something simliar to #6 can still be accomplished.

Instead of setting the renderer via the service definition, we could still create a ThemeManager::setRenderer() method that can be invoked when setting the $this->theme property in Renderer::__construct:

$this->theme = $theme->setRenderer($this);

An additional ThemeManager::getRenderer() method should be created and used so, if the renderer isn't set (for whatever reason), it can be set using \Drupal::service('renderer') for BC reasons; so the line in ThemeManager::render should read as:

$this->getRenderer()->render($preprocess_bubbleable);

This kind of approach avoids changing method signatures and essentially creating BC breaks with existing interfaces.

The only way to not break the signatures is to do what #11 suggested and use NULL. However, this is essentially no different from creating ThemeManager::getRenderer(), without the unnecessary extra parameter.

I really don't think there is any way to avoid \Drupal::service('renderer') in cases where ThemeManager::render is invoked before the Renderer service is constructed. While this use case isn't likely to be very common, it is still technically possible given the current architecture of Renderer and ThemeManager.

eelkeblok’s picture

Well, I wish I had a better way of reproducing my problem, but it seems that somehow themeManager may end up with a different instance of the renderer than other parts of the system. I have some custom code that gets the renderer from the container and then calls renderPlain, because it needs to produce some HTML for use in an email. Somewhere down the render chain, the render context goes AWOL, resulting in "Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy_builder/#pre_render instead." With the patch from #26, I don't get this, presumably because it ensures the renderer is preserved through the render chain.

I'll take a shot at producing a patch using your proposed resolution, which does sound better from a BC point of view.

eelkeblok’s picture

So, something like this. This too solves my problem, btw.

markhalliwell’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests
  1. +++ b/core/lib/Drupal/Core/Render/Renderer.php
    @@ -111,6 +111,7 @@ class Renderer implements RendererInterface {
         $this->theme = $theme;
    +    $theme->setRenderer($this);
    
    +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -458,4 +469,30 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
    +  public function setRenderer(RendererInterface $renderer) {
    +    $this->renderer = $renderer;
    +  }
    

    Set methods typically return $this to allow chaining.

    Would also allow this to be a one-liner in Renderer::__construct as I mentioned in #29:

    $this->theme = $theme->setRenderer($this);
    
  2. I wish I had a better way of reproducing my problem, but it seems that somehow themeManager may end up with a different instance of the renderer than other parts of the system

    This means this needs a test to reliably reproduce this issue and semi-justify this change.

eelkeblok’s picture

Agreed. It does feel like I am fighting symptoms instead of the actual cause. The render context going missing doesn't make a lot of sense, and there really should not be a functional difference between using \Drupal::service('renderer') or pseudo-injecting the renderer when it is constructed itself.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andypost’s picture

The drupal_render() is deprecated since 8.0 and already removed in 9.0 (only mentions in comments exist) so summary and title needs work

Meantime here's re-roll and fix for #32.1

andypost’s picture

andypost’s picture

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.