Issue #3143096 by jedihe, jyotimishra123, shetpooja04, alexpott, mradcliffe: [DX]: throw an exception if #lazy_builder callback does not return a (renderable) array
parent
e7d67e912e
commit
e9a53cb2b3
|
@ -353,6 +353,23 @@ class Renderer implements RendererInterface {
|
||||||
// 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 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
||||||
$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 @@ class PlaceholdersTest implements TrustedCallbackInterface {
|
||||||
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'];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue