Follow-up to / Helper for #2407195: Move attachment processing to services and per-type response subclasses

Problem/Motivation

renderRoot() returns a 'string', but that is wrong, because this is the root of the tree and hence we must take cacheable meta data into account.

Proposed resolution

Before:

$this->renderer->renderRoot($html);
$content = $this->renderCache->getCacheableRenderArray($html);

After:

$content = $this->renderer->renderRootReplacementNeedsAName($html);

If someone still needs to use the markup directly, they can do:

print $content['#markup']

on their own risk.

Remaining tasks

  1. Decide the new method name (it should not actually be renderRootReplacementNeedsAName()) and add it. Add documentation to renderRoot() about the new method as well as about the workaround above that is required for it to be cacheable.
  2. Convert those core uses that should be renderPlain() already to renderPlain() (i.e. simple renderables with no assets or caching requirements).
  3. Convert remaining core usages to the new method.
  4. Deprecate renderRoot().

User interface changes

- None

API changes

- New method returns a cacheable render array.

BETA EVAL:

It is a major bug, because if you get back a string, you expect to use that => cacheability metadata lost => security issues.

Comments

Fabianx’s picture

Status: Needs review » Postponed

Postponing on #2407195: Move attachment processing to services and per-type response subclasses, there is more work involved than I thought ...

Fabianx’s picture

dawehner’s picture

Issue tags: +API change
Wim Leers’s picture

Component: request processing system » render system
Assigned: Unassigned » Fabianx
Issue tags: +Needs issue summary update

Is this really major? I think you marked it as major based on your discussions with Crell, where you concluded that if every bit of rendering that Renderer does returns such a thin render array, that we enable significant clean-up/simplification elsewhere?

If so, could you please explain that in the IS? Currently, this issue looks like it's a minor nice-to-have.

Fabianx’s picture

Yes, it is major, because if you get back a string, you expect to use that => cacheability metadata lost => security issues.

Wim Leers’s picture

Aha :) Could you update the IS with that? Thanks!

Fabianx’s picture

Issue summary: View changes
serg2’s picture

Status: Postponed » Needs work

This was postponed on #2407195: Move attachment processing to services and per-type response subclasses which is now fixed so marking as needs work. (hope that is correct & okay!)

star-szr’s picture

Is this still possible to do now? It feels like too big of an API change but maybe I'm misunderstanding something…

dawehner’s picture

I have to agree with @Cottser. Even you are supposed to not call renderRoot() directly, we still have 80 calls to it, so the chance is not unlikely that people use it.

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

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should 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.

xjm’s picture

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

So the "correct" replacement for most renderRoot() usages is probably renderPlain(), correct? Would it be correct to mark renderRoot() internal? The docs say:

Renders final HTML given a structured array tree.

Calls ::render() in such a way that placeholders are replaced.

Should therefore only be used in occasions where the final rendering is happening, just before sending a Response:

  • system internals that are responsible for rendering the final HTML
  • render arrays for non-HTML responses, such as feeds

(Cannot be executed within another render context.)

So the first case is clearly internal, but the second makes it sound like public API. And the second case is not a scenario where cacheability metadata matters anyway, is it? Or is it?

This change definitely could not happen in a patch release, but I can see the case for treating it as a security hardening and allowing the small BC break in a minor, with CR etc.

joelpittet’s picture

With value objects this would kinda make sense/work. But It seems very strange to me that a 'render' function would produce yet another array. Also a huge API change, IMO. When working with the system it just feeds like another barrier to use this API. #death_to_arrays_as_value_objects

alexpott’s picture

If book export broken because of this?

  public function bookExport($type, NodeInterface $node) {
    $method = 'bookExport' . Container::camelize($type);

    // @todo Convert the custom export functionality to serializer.
    if (!method_exists($this->bookExport, $method)) {
      drupal_set_message(t('Unknown export format.'));
      throw new NotFoundHttpException();
    }

    $exported_book = $this->bookExport->{$method}($node);
    return new Response($this->renderer->renderRoot($exported_book));
  }

Or does a something come and grab the cacheable metadata later?

lauriii’s picture

I suggest that we create a new method, remove all usages of the old method in core and finally deprecate it.

xjm’s picture

Title: Make renderRoot() return a cacheable render array instead of a string » [meta] Add a replacement for renderRoot() that returns a cacheable render array instead of a string
Category: Bug report » Plan
Issue summary: View changes
Issue tags: +Triaged core major

We discussed this issue with @alexpott, @Cottser, @lauriii, and @joelpittet at DrupalCon New Orleans. We discussed that the original proposal is probably too disruptive to change in a minor release, because it is a non-BC change to the return value of an API method that we can't really call internal based on its current usage. However, we agreed that it is a major issue. The path forward is:

  1. Decide the new method name (it should not actually be renderRootReplacementNeedsAName()) and add it. Add documentation to renderRoot() about the new method as well as about the workaround above that is required for it to be cacheable.
  2. Convert those core uses that should be renderPlain() already to renderPlain() (i.e. simple renderables with no assets or caching requirements).
  3. Convert remaining core usages to the new method.
  4. Deprecate renderRoot().

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.

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.

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.

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.