Problem

  1. It's borderline impossible to fully understand the call chains within drupal_render() in D8.

  2. Hopping back and forth and back in a ~5,000 LoC file doesn't help either.

  3. Primary cause: #2118703: Introduce #post_render_cache callback to allow for personalization without breaking the render cache

  4. Hidden major performance problems: #697760-14: Replace getInfo() in tests with native phpDoc + annotations (following PHPUnit)

Proposed solution

  1. Baby step: Just move all of the related functions into static class methods in a new Drupal\Core\Render\Render class.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sun’s picture

Status: Active » Needs review
FileSize
72.95 KB
0 bytes
sun’s picture

FileSize
20.61 KB

Diff against common.inc in order to prove that no functionality has been changed.

Status: Needs review » Needs work

The last submitted patch, 1: render.1.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
72.99 KB
1.26 KB

Fixed missing/bogus namespace imports.

dawehner’s picture

Baby step: Just move all of the related functions into static class methods in a new Drupal\Core\Render\Render.

Does that mean that the next step could be potentially to have all that as a non-static class in some kind of follow up?

+++ b/core/includes/common.inc
@@ -3897,391 +3579,19 @@ function show(&$element) {
+  return Render::getCacheId($elements);

+++ b/core/lib/Drupal/Core/Render/Render.php
@@ -0,0 +1,733 @@
+  public static function getCacheId(array $elements) {

I wonder whether we should to distinct between just getting something and actually computing the result. Maybe generateCacheId?

sun’s picture

Issue summary: View changes
FileSize
83.26 KB
13.35 KB

Yes, after the code has been moved, we can definitely look into turning the class into a service.

Renamed getCacheId() into generateCacheId() + removed obsolete legacy drupal_render_cid_create().

catch’s picture

sun’s picture

@catch: I think you meant "some", not "most"? — I see a few changes to inner function bodies in the patch over there, but the various call chains for cache tags/post_render/collect/... still exist.

FWIW, I also see a repetition of the condition isset($elements['#cache']) || !$is_recursive_call, which causes this:

cache tag + post render cache in drupal_render() causes every recursion to *additionally* recurse 2x into children of each recursion level.

It's exactly the massive recursion logic that is easier to follow after moving this code.

sun’s picture

Would be great to move forward here, as I'd love to help to debug and fix that exponentially increasing recursion bug — I already tried, but gave up after too much monkey-hopping through common.inc.

dawehner’s picture

that exponentially increasing recursion bug

Do you talk about the two following code snippets?

  if (isset($elements['#cache']) || !$is_recursive_call) {
    $post_render_cache = drupal_render_collect_post_render_cache($elements);
    if ($post_render_cache) {
      $elements['#post_render_cache'] = $post_render_cache;
    }
  }

  // ...

  if (!$is_recursive_call || isset($elements['#cache'])) {
    $elements['#cache']['tags'] = drupal_render_collect_cache_tags($elements);
  }

I guess, all we have to do is to separate the manual setting of tags and the collected data, so we can use the collected data, and no longer recursive for each element again. drupal_render_collect_cache_tags could store the collected tags in each tree vertex while iterating, so there would be no need for additional tree-walking in the future.

sun’s picture

Yes, something like that. (but separate issue)

FWIW, this change here also allows us to add proper PHPUnit tests for the Render class to verify that the recursion works correctly + the right methods are called at the right time — however, just moving/renaming the code is complex enough already (I hope the patch still applies), so we should do that in a follow-up issue.

Wim Leers’s picture

Oh, how I've wished that RenderTest was a PHPUnit test! This will make it possible :)

sun’s picture

6: render.6.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 6: render.6.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
83.26 KB

Merged 8.x. (no conflicts)

sun’s picture

15: render.15.patch queued for re-testing.

sun’s picture

15: render.15.patch queued for re-testing.

jibran’s picture

15: render.15.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 15: render.15.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
77.26 KB
6.91 KB

Status: Needs review » Needs work

The last submitted patch, 20: render.20.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
80.99 KB
5.36 KB

Fixed incomplete generateCacheToken() conversion.

Status: Needs review » Needs work

The last submitted patch, 22: render.22.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
FileSize
85.54 KB
6.54 KB

Updated for new calls to Render::generateCachePlaceholder().

sun’s picture

24: render.24.patch queued for re-testing.

Wim Leers’s picture

+++ b/core/lib/Drupal/Core/Render/Render.php
@@ -445,8 +445,7 @@ protected static function getCachePlaceholder($callback, array $context, $token)
+  public static function generateCacheToken() {

generatePostRenderCacheToken() would be a better name, I think.

sun’s picture

24: render.24.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 24: render.24.patch, failed testing.

effulgentsia’s picture

Adding a related issue link, but what's being discussed there should absolutely not hold up this issue :)

sun’s picture

Status: Needs work » Needs review
FileSize
85.57 KB

Merged 8.x.

@Wim Leers: This is simple move is a pain to merge/re-roll, so I'd prefer to perform renames in a separate issue. Where possible, this patch simply uses the camelized version of the underscored procedural function name.

Status: Needs review » Needs work

The last submitted patch, 30: render.30.patch, failed testing.

Crell’s picture

There's little to no benefit to a big static class for this functionality. If anything it's counter-productive. There is no reason this can't be a normal object just calling $this->someProtectedMethod() as needed. That would let it be injected into other objects, too, thus not polluting them.

Wim Leers’s picture

#32: Let us please at least take baby steps. A big static class would still be a step forward.

After having written the above, I went back to the issue summary, and sun apparently thinks exactly the same:

Proposed solution

  1. Baby step: Just move all of the related functions into static class methods in a new Drupal\Core\Render\Render class.

Crell’s picture

Is there a follow-up to make it a for-reals object? The added work to do should not be that big, but as this is an API-affecting patch we should try to get as close to the "final" public facing API as possible so we don't hit beta and get stuck in a sloppy intermediary state.

Baby steps are all well and good but as long as patches can take around here I worry that we will only get through one step; make it a good one.

Wim Leers’s picture

#34: Let me again quote sun to indicate why this is a very worthwhile baby step:

FWIW, this change here also allows us to add proper PHPUnit tests for the Render class to verify that the recursion works correctly + the right methods are called at the right time — however, just moving/renaming the code is complex enough already (I hope the patch still applies), so we should do that in a follow-up issue.

On top of that, we'll finally be able to get rid of all the wrapper methods for drupal_render() that live in so many classes.

To me, that sounds like a solid single step.

dawehner’s picture

Status: Needs work » Postponed

.

mbrett5062’s picture

@dawehner would it be possible for you to add a short comment stating on what this is postponed. Or will this not get done for 8.0.x-dev now and should be bumped to 8.1.x-dev?

effulgentsia’s picture

Status: Postponed » Fixed

The title of this issue got fixed by #36. Renderer::doRender() is still a 300+ LOC function, but is protected, so refactors can happen any time. I think it makes sense to mark this issue fixed and if someone wants to open new issues for ideas on refactoring protected code in Renderer, go for it.

effulgentsia’s picture

Status: Fixed » Closed (duplicate)

Actually, maybe "duplicate" is the more correct status.