Skip to content
Snippets Groups Projects
Unverified Commit eebe8645 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3143096 by jedihe, jyotimishra123, shetpooja04, alexpott, mradcliffe:...

Issue #3143096 by jedihe, jyotimishra123, shetpooja04, alexpott, mradcliffe: [DX]: throw an exception if #lazy_builder callback does not return a (renderable) array

(cherry picked from commit e9a53cb2)
parent 7898708d
Branches
Tags
22 merge requests!10011Issue #3200534 by quietone, longwave, Kristen Pol: Use dataprovider for...,!3134Issue #3222236: Lighthouse SEO: Uncrawlable Link a#main-content,!2571Issue #3000717: Missing mapping for "nodereference_url" widget,!2521Issue #3185775: Place Views preview on the side on large monitors,!1803Issue #2329253: Allow the ChangedItem to skip updating when synchronizing (f.e. when migrating),!1603Issue #3231707: mxr576's core patch playground,!1479Issue #3250298: Return empty string "" with JSON Serializer instead of FALSE,!1478Issue #3250298: Return empty string "" with JSON Serializer instead of FALSE,!1356Issue #3076171: Provide a new library to replace jQuery UI autocomplete,!1203Issue #3236191 Wrong group exposed form widgets and multiple selection error.,!1076Issue #2903336 Added node context for tokens.,!1015Issue #3226944: REST's Request handler doesn't resolve $data argument for put method,!810Issue #3219541: Remove redudante call $this->requestStack->getCurrentRequest() in FormBuilder::buildForm,!803Issue #3219167: webchick test issue of all time turbo edition super star 20000 NG,!740Issue #3216088: Update Symfony 5 components to 5.3,!657Draft: Remove alpha-stability experimental modules and themes from 9.2.x only, prior...,!577Issue #3209779: Create new database storage for the tracker module,!526Update block module to use once library,!516Issue #3207782: Figure out BC for jquery once by @drupal/once,!413most recent patch to gitlab branch,!400Issue #3051766: Deprecate and replace jQuery Joyride (for tours),!35Issue #3164686 WebAssert::addressEquals() and AssertLegacyTrait::assertUrl() fail to check the querystring
...@@ -353,6 +353,23 @@ protected function doRender(&$elements, $is_root_call = FALSE) { ...@@ -353,6 +353,23 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
// Build the element if it is still empty. // Build the element if it is still empty.
if (isset($elements['#lazy_builder'])) { if (isset($elements['#lazy_builder'])) {
$new_elements = $this->doCallback('#lazy_builder', $elements['#lazy_builder'][0], $elements['#lazy_builder'][1]); $new_elements = $this->doCallback('#lazy_builder', $elements['#lazy_builder'][0], $elements['#lazy_builder'][1]);
// Throw an exception if #lazy_builder callback does not return an array;
// provide helpful details for troubleshooting.
if (!is_array($new_elements)) {
$callable = $elements['#lazy_builder'][0];
$callable_name = '[unknown]';
if ($callable instanceof \Closure) {
$callable_name = '[closure]';
}
elseif (is_array($callable)) {
$callable_name = implode('::', $callable);
}
elseif (is_string($callable)) {
$callable_name = $callable;
}
$wrong_type = gettype($new_elements);
throw new \LogicException("#lazy_builder callbacks must return a valid renderable array, got $wrong_type from $callable_name");
}
// Retain the original cacheability metadata, plus cache keys. // Retain the original cacheability metadata, plus cache keys.
CacheableMetadata::createFromRenderArray($elements) CacheableMetadata::createFromRenderArray($elements)
->merge(CacheableMetadata::createFromRenderArray($new_elements)) ->merge(CacheableMetadata::createFromRenderArray($new_elements))
......
...@@ -962,6 +962,54 @@ public function testCreatePlaceholderPropertyWithoutLazyBuilder() { ...@@ -962,6 +962,54 @@ public function testCreatePlaceholderPropertyWithoutLazyBuilder() {
$this->renderer->renderRoot($element); $this->renderer->renderRoot($element);
} }
/**
* Tests lazy builders (string callable) that do not return a renderable.
*
* @covers ::render
* @covers ::doRender
*/
public function testNonArrayReturnFromLazyBuilderStringCallable() {
$element = [];
$element['#lazy_builder'] = ['Drupal\Tests\Core\Render\PlaceholdersTest::callbackNonArrayReturn', []];
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('#lazy_builder callbacks must return a valid renderable array, got boolean from Drupal\Tests\Core\Render\PlaceholdersTest::callbackNonArrayReturn');
$this->renderer->renderRoot($element);
}
/**
* Tests lazy builders (array callable) that do not return a renderable.
*
* @covers ::render
* @covers ::doRender
*/
public function testNonArrayReturnFromLazyBuilderArrayCallable() {
$element = [];
$element['#lazy_builder'] = [['Drupal\Tests\Core\Render\PlaceholdersTest', 'callbackNonArrayReturn'], []];
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('#lazy_builder callbacks must return a valid renderable array, got boolean from Drupal\Tests\Core\Render\PlaceholdersTest::callbackNonArrayReturn');
$this->renderer->renderRoot($element);
}
/**
* Tests lazy builders (closure) that do not return a renderable.
*
* @covers ::render
* @covers ::doRender
*/
public function testNonArrayReturnFromLazyBuilderClosure() {
$element = [];
$closure = function () {
return NULL;
};
$element['#lazy_builder'] = [$closure, []];
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('#lazy_builder callbacks must return a valid renderable array, got NULL from [closure]');
$this->renderer->renderRoot($element);
}
/** /**
* Create an element with a child and subchild. Each element has the same * Create an element with a child and subchild. Each element has the same
* #lazy_builder callback, but with different contexts. They don't modify * #lazy_builder callback, but with different contexts. They don't modify
......
...@@ -317,11 +317,21 @@ public static function callbackTagCurrentTemperature($animal) { ...@@ -317,11 +317,21 @@ public static function callbackTagCurrentTemperature($animal) {
return $build; return $build;
} }
/**
* Returns invalid renderable to #lazy_builder callback.
*
* @return bool
* TRUE.
*/
public static function callbackNonArrayReturn() {
return TRUE;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public static function trustedCallbacks() { public static function trustedCallbacks() {
return ['callbackTagCurrentTemperature', 'callbackPerUser', 'callback']; return ['callbackTagCurrentTemperature', 'callbackPerUser', 'callback', 'callbackNonArrayReturn'];
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment