Loading core/lib/Drupal/Core/Render/Renderer.php +74 −9 Original line number Diff line number Diff line Loading @@ -162,22 +162,43 @@ public function renderPlain(&$elements) { } /** * {@inheritdoc} * Renders a placeholder into markup. * * @param array $placeholder_element * The placeholder element by reference. * * @return \Drupal\Component\Render\MarkupInterface|string * The rendered HTML. */ public function renderPlaceholder($placeholder, array $elements) { // Get the render array for the given placeholder $placeholder_elements = $elements['#attached']['placeholders'][$placeholder]; protected function doRenderPlaceholder(array &$placeholder_element): MarkupInterface|string { // Prevent the render array from being auto-placeholdered again. $placeholder_elements['#create_placeholder'] = FALSE; $placeholder_element['#create_placeholder'] = FALSE; // Render the placeholder into markup. $markup = $this->renderPlain($placeholder_elements); $markup = $this->renderPlain($placeholder_element); return $markup; } /** * Replaces a placeholder with its markup. * * @param string $placeholder * The placeholder HTML. * @param \Drupal\Component\Render\MarkupInterface|string $markup * The markup to replace the placeholder with. * @param array $elements * The render array that the placeholder is from. * @param array $placeholder_element * The placeholder element render array. * * @return \Drupal\Component\Render\MarkupInterface|string * The rendered HTML. */ protected function doReplacePlaceholder(string $placeholder, string|MarkupInterface $markup, array $elements, array $placeholder_element): array { // Replace the placeholder with its rendered markup, and merge its // bubbleable metadata with the main elements'. $elements['#markup'] = Markup::create(str_replace($placeholder, $markup, $elements['#markup'])); $elements = $this->mergeBubbleableMetadata($elements, $placeholder_elements); $elements = $this->mergeBubbleableMetadata($elements, $placeholder_element); // Remove the placeholder that we've just rendered. unset($elements['#attached']['placeholders'][$placeholder]); Loading @@ -185,6 +206,16 @@ public function renderPlaceholder($placeholder, array $elements) { return $elements; } /** * {@inheritdoc} */ public function renderPlaceholder($placeholder, array $elements) { // Get the render array for the given placeholder $placeholder_element = $elements['#attached']['placeholders'][$placeholder]; $markup = $this->doRenderPlaceholder($placeholder_element); return $this->doReplacePlaceholder($placeholder, $markup, $elements, $placeholder_element); } /** * {@inheritdoc} */ Loading Loading @@ -665,13 +696,47 @@ protected function replacePlaceholders(array &$elements) { // First render all placeholders except 'status messages' placeholders. $message_placeholders = []; $fibers = []; foreach ($elements['#attached']['placeholders'] as $placeholder => $placeholder_element) { if (isset($placeholder_element['#lazy_builder']) && $placeholder_element['#lazy_builder'][0] === 'Drupal\Core\Render\Element\StatusMessages::renderMessages') { $message_placeholders[] = $placeholder; } else { $elements = $this->renderPlaceholder($placeholder, $elements); // Get the render array for the given placeholder $fibers[$placeholder] = new \Fiber(function () use ($placeholder_element) { return [$this->doRenderPlaceholder($placeholder_element), $placeholder_element]; }); } } while (count($fibers) > 0) { $iterations = 0; foreach ($fibers as $placeholder => $fiber) { if (!$fiber->isStarted()) { $fiber->start(); } elseif ($fiber->isSuspended()) { $fiber->resume(); } // If the Fiber hasn't terminated by this point, move onto the next // placeholder, we'll resume this fiber again when we get back here. if (!$fiber->isTerminated()) { // If we've gone through the placeholders once already, and they're // still not finished, then start to allow code higher up the stack to // get on with something else. if ($iterations) { $fiber = \Fiber::getCurrent(); if ($fiber !== NULL) { $fiber->suspend(); } } continue; } [$markup, $placeholder_element] = $fiber->getReturn(); $elements = $this->doReplacePlaceholder($placeholder, $markup, $elements, $placeholder_element); unset($fibers[$placeholder]); } $iterations++; } // Then render 'status messages' placeholders. Loading core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +5 −0 Original line number Diff line number Diff line Loading @@ -314,6 +314,11 @@ public static function callback($animal, $use_animal_as_array_key = FALSE) { * A renderable array. */ public static function callbackPerUser($animal) { // As well as adding the user cache context, additionally suspend the // current Fiber if there is one. if ($fiber = \Fiber::getCurrent()) { $fiber->suspend(); } $build = static::callback($animal); $build['#cache']['contexts'][] = 'user'; return $build; Loading Loading
core/lib/Drupal/Core/Render/Renderer.php +74 −9 Original line number Diff line number Diff line Loading @@ -162,22 +162,43 @@ public function renderPlain(&$elements) { } /** * {@inheritdoc} * Renders a placeholder into markup. * * @param array $placeholder_element * The placeholder element by reference. * * @return \Drupal\Component\Render\MarkupInterface|string * The rendered HTML. */ public function renderPlaceholder($placeholder, array $elements) { // Get the render array for the given placeholder $placeholder_elements = $elements['#attached']['placeholders'][$placeholder]; protected function doRenderPlaceholder(array &$placeholder_element): MarkupInterface|string { // Prevent the render array from being auto-placeholdered again. $placeholder_elements['#create_placeholder'] = FALSE; $placeholder_element['#create_placeholder'] = FALSE; // Render the placeholder into markup. $markup = $this->renderPlain($placeholder_elements); $markup = $this->renderPlain($placeholder_element); return $markup; } /** * Replaces a placeholder with its markup. * * @param string $placeholder * The placeholder HTML. * @param \Drupal\Component\Render\MarkupInterface|string $markup * The markup to replace the placeholder with. * @param array $elements * The render array that the placeholder is from. * @param array $placeholder_element * The placeholder element render array. * * @return \Drupal\Component\Render\MarkupInterface|string * The rendered HTML. */ protected function doReplacePlaceholder(string $placeholder, string|MarkupInterface $markup, array $elements, array $placeholder_element): array { // Replace the placeholder with its rendered markup, and merge its // bubbleable metadata with the main elements'. $elements['#markup'] = Markup::create(str_replace($placeholder, $markup, $elements['#markup'])); $elements = $this->mergeBubbleableMetadata($elements, $placeholder_elements); $elements = $this->mergeBubbleableMetadata($elements, $placeholder_element); // Remove the placeholder that we've just rendered. unset($elements['#attached']['placeholders'][$placeholder]); Loading @@ -185,6 +206,16 @@ public function renderPlaceholder($placeholder, array $elements) { return $elements; } /** * {@inheritdoc} */ public function renderPlaceholder($placeholder, array $elements) { // Get the render array for the given placeholder $placeholder_element = $elements['#attached']['placeholders'][$placeholder]; $markup = $this->doRenderPlaceholder($placeholder_element); return $this->doReplacePlaceholder($placeholder, $markup, $elements, $placeholder_element); } /** * {@inheritdoc} */ Loading Loading @@ -665,13 +696,47 @@ protected function replacePlaceholders(array &$elements) { // First render all placeholders except 'status messages' placeholders. $message_placeholders = []; $fibers = []; foreach ($elements['#attached']['placeholders'] as $placeholder => $placeholder_element) { if (isset($placeholder_element['#lazy_builder']) && $placeholder_element['#lazy_builder'][0] === 'Drupal\Core\Render\Element\StatusMessages::renderMessages') { $message_placeholders[] = $placeholder; } else { $elements = $this->renderPlaceholder($placeholder, $elements); // Get the render array for the given placeholder $fibers[$placeholder] = new \Fiber(function () use ($placeholder_element) { return [$this->doRenderPlaceholder($placeholder_element), $placeholder_element]; }); } } while (count($fibers) > 0) { $iterations = 0; foreach ($fibers as $placeholder => $fiber) { if (!$fiber->isStarted()) { $fiber->start(); } elseif ($fiber->isSuspended()) { $fiber->resume(); } // If the Fiber hasn't terminated by this point, move onto the next // placeholder, we'll resume this fiber again when we get back here. if (!$fiber->isTerminated()) { // If we've gone through the placeholders once already, and they're // still not finished, then start to allow code higher up the stack to // get on with something else. if ($iterations) { $fiber = \Fiber::getCurrent(); if ($fiber !== NULL) { $fiber->suspend(); } } continue; } [$markup, $placeholder_element] = $fiber->getReturn(); $elements = $this->doReplacePlaceholder($placeholder, $markup, $elements, $placeholder_element); unset($fibers[$placeholder]); } $iterations++; } // Then render 'status messages' placeholders. Loading
core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +5 −0 Original line number Diff line number Diff line Loading @@ -314,6 +314,11 @@ public static function callback($animal, $use_animal_as_array_key = FALSE) { * A renderable array. */ public static function callbackPerUser($animal) { // As well as adding the user cache context, additionally suspend the // current Fiber if there is one. if ($fiber = \Fiber::getCurrent()) { $fiber->suspend(); } $build = static::callback($animal); $build['#cache']['contexts'][] = 'user'; return $build; Loading