Current implementation of Drupal\panels\Plugin\DisplayBuilder\StandardDisplayBuilder::buildRegions()
has a wrong condition which could lead to TypeError
(null
instead of expected array
) in \Drupal\Core\Render\Element::isEmpty()
.
Example:
$content = $block->build();
if ($content !== NULL && !Element::isEmpty($content)) {
foreach (['#attributes', '#contextual_links'] as $property) {
if (isset($content[$property])) {
$block_render_array[$property] += $content[$property];
unset($content[$property]);
}
}
}
// If the block is empty, instead of trying to render the block
// correctly return just #cache, so that the render system knows the
// reasons (cache contexts & tags) why this block is empty.
if (Element::isEmpty($content)) {
The Element::isEmpty($content)
on second execution fails with fatal error when $content
contains null
.
Steps to reproduce described in #2819219: Fatal error when "setMainContent()" method is not called (block module not installed).
@capuleto #8:
This patch also makes Drupal\Core\Render\Element::children() trigger several warnings like
"max-age" is an invalid render array key
@Devin Carlson #9:
This also doesn't check if $content !== NULL, as is done earlier in the function, which causes a fatal error if $content is NULL.
Recoverable fatal error: Argument 1 passed to Drupal\Core\Render\Element::isEmpty() must be of the type array, null given called in panels/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php on line 136.
Comment | File | Size | Author |
---|---|---|---|
#57 | 2819235-StandardDisplayBuild-fatal-error-57.patch | 5.44 KB | metalbote |
#54 | 2819235-StandardDisplayBuild-fatal-error-47.patch | 4.88 KB | cr0ss |
Comments
Comment #2
lauriiiThis should fix both of the issues.
We are now throwing a LogicException if the block builder returns something else than an array. The interface doesn't allow them to return anything else so it seems like a good way to get people fix their code.
Comment #3
tobiberlinThis still is not a solution for views generated blocks as I described in #2781897
Comment #4
lauriii@tobiberlin I have tested the original patch with Views block and I cannot reproduce the patch. Are you sure that the View is fully empty?
Comment #5
tobiberlinIt's a mess... it seems to be a more general problem with blocks/ render arrays. The point is that I use a views block with context filter: term id from url as I placed the block in a panel used for term pages. See #2443457: Views block displayed when no results returned and the following #953034: [meta] Themes improperly check renderable arrays when determining visibility - quite strange
Comment #6
lauriiiComment #7
trwill CreditAttribution: trwill commentedReviewed and tested. Patch works well and does fix render array errors for empty blocks, including empty view blocks, as I posted in https://www.drupal.org/node/2812617 (which was closed as duplicate of this issue). Setting to RTBC.
Comment #8
BR0kENThis patch is nicer because it will not throw any exceptions and will not lead to broken site, because the exception is not caught.
For instance, one of blocks from core can break the things. Read more here: #2819219: Fatal error when "setMainContent()" method is not called (block module not installed).
Comment #9
BR0kENComment #10
lauriiiThe block builder is broken if in case we thrown an exception. If we don't throw an exception there is no way for people to know that their block builder is broken.
Comment #11
BR0kENIf core do not validate described, in PHPDoc comments, types then module must not do this as well. Did you read my comment from referenced issue? I don't want to get broken site and a state which is not depends on my code. By the way,
null
- is more or less acceptable replacer forarray
which could mean that result is empty (does not contain nothing). That's how it works, for instance, as default value for typed arguments for methods/functions.Comment #12
lauriiiI think that core should do this also. Also, we sort of do this for page controllers in Drupal core.
That is not correct. It should be specified that it could return null if it's allowed to return null. See also PHP7 documentation for return type declarations: https://wiki.php.net/rfc/return_types#disallowing_null_on_return_types
I'd let the maintainers decide what is the best approach for this.
Comment #13
BR0kENFair point. Let them decide. We can interpret situation in both ways: your and mine. My only concern to not break site in any case.
Comment #14
Xanonull
is never an acceptable value if that value is documented asarray
. One could discuss nullable types, but an empty list MUST still be a list. In our case, we document the return value asarray
, so any code not following that is wrong and MUST be fixed by a developer. If this breaks site, go fix the root cause of the problem, or support someone else in doing so.@BR0kEN: Your patch unfortunately still allows sites to be broken, as it does nothing to help fix the root cause of the problem. Instead, it just tries not to fail in this one particular case.
The approach in #2 is an excellent one, as it fails as early as possible, and clearly instructs developers how to fix the root problem (useful for other usages of
BlockPluginInterface
as well, as opposed to #8). I do propose not to use the plugin ID, but the class and method name instead, and perhaps reference the interface as well, because that's the documentation we are talking about.Comment #15
lauriiiRe-uploading patch from #2 based on #14.
Comment #16
XanoShowing the class and method name, with potentially a reference to the interface method (which comes with the type documentation) makes it much easier to find the code that needs to be fixed.
Why is this an object? As exceptions are development tools, we usually just use plain strings for their messages.
What is the reason this comment was moved away from the code it documents?
Out of scope?
Out of scope?
#3 reports that
SystemMainBlock
is compromised. I'm not entirely sure why the tests do not catch this (maybe::setMainContent()
is called always in core), but it may be worth fixing this by giving the::$mainContent
property an empty array for its default value as it serves as an example of how to fix the root cause of this problem when people analyze the diff for this issue in the future.Comment #17
lauriii#16.1: Fixed
#16.2: Fixed
#16.3: Definitely not. The original code would cause fatal error.
#16.4: The original code is wrong because the render array should be left fully empty.
Comment #18
XanoGreat! If we use
BlockPluginInterface::class
, we get the full namespace as well, and easy refactorability.Docs++.
Thanks for explaining why those other lines were not out of scope! Do or don't we want to update
SystemMainBlock
as an example fix?Comment #19
BR0kENOkay, @Xano, there is some sense in your words from #14. But very bad when core is in use almost year and has issues like this. I'll add a separate patch, based on @lauriii's approach, and make a review of changes from it.
Comment #20
BR0kENComment #21
BR0kENRemoved since not used, as the similar uses below.
Added, to not use class name as string because, potentially, namespace could be changed.
Moved here, to let developers know about the type where variable appears.
No need to call methods of block instance because, if build result will be empty, the
$block_render_array
variable will be set to empty array and all above methods execution will be redundant.Comment #22
sk33lz CreditAttribution: sk33lz at Zivtech commented#20 resolves the errors for me. It also applies cleanly to 3.0-beta5.
Comment #23
jonathanshawHave we identified a core issue to fix the doc comment?
Would it not break backwards compatibility if core now changed what it actually returned? And therefore isn't it necessary in reality for contrib to be able to handle the null?
#20 works for me, fixes the issue with an empty views block that uses the setting "Hide block if the view output is empty".
Comment #24
XanoCore documents it returns arrays, but not all implementations do so, as they return
NULL
instead. To make debugging easier, the patch throws an exception if no array is returned. The actual fix is that the patch no longer makes the code returnNULL
, but an array instead.Comment #25
BR0kENSet it to RTBC after two positive comments. Feel free to change if needed.
Comment #26
Sebastien M. CreditAttribution: Sebastien M. commentedHi all,
Once this #20 patch applied I still have an issue when
$content = $block->build();
is null.First I tried to add a check to avoid throwing exception if null, but later a new error is thrown due to the
Element::isEmpty
function which requires an array as the first parameter.Here is my interdiff patch:
BR
Comment #27
lauriiiSebastien @Actualys: Please see the discussion above. This is the wanted behavior. There's bug in core which needs to be fixed also: #2819219: Fatal error when "setMainContent()" method is not called (block module not installed). You should help that issue move forward instead of making changes for this patch.
I'm re-uploading patch from #19 which was RTBC.
Comment #28
BR0kEN@lauriii, and for what you've re-uploaded it? To be the author of commit? It's funny.
@Sebastien @Actualys, don't you see anything strange in the lines below (they're from your patch)?
Comment #29
BR0kENComment #30
lauriii@BR0kEN The committer can decide the author of the commit and that's why I said I'm re-posting another patch. I was also already credited for this issue since I've posted patches myself so it didn't affect the credits. The reason for re-posting the patch is to avoid any possibility of a wrong patch being committed. :)
Comment #31
BR0kEN@lauriii, you can just show/hide patches as I did. No need to re-upload the same because it's could confuse people.
Comment #32
Sebastien M. CreditAttribution: Sebastien M. commentedSorry for making confusion.
Comment #33
joelpittetThis patch no longer applies against 3.x-dev
Can someone re-roll against 8.x-3.x?
Comment #34
BR0kENComment #35
Loparev CreditAttribution: Loparev commentedWorks like a charm
Comment #36
Loparev CreditAttribution: Loparev commentedComment #37
welly CreditAttribution: welly at Fat Beehive commentedIt's not working for me. The initial error I was getting was:
I applied the patch at https://www.drupal.org/node/2812721#comment-11952030 and now I get:
LogicException: Drupal\Core\Block\BlockPluginInterface::build() method has to return an array. Class returning non-array value is: Drupal\system\Plugin\Block\SystemMainBlock in Drupal\panels\Plugin\DisplayBuilder\StandardDisplayBuilder->buildRegions() (line 110 of /var/www/drupalvm/web/modules/contrib/panels/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php).
Comment #38
BR0kEN@welly, I know that it's almost impossibly to read whole thread by please, try to start from the #27.
Comment #39
welly CreditAttribution: welly at Fat Beehive commentedThanks @BR0kEN, appreciate you pointing me to that comment which I missed. Not sure snide comments are called for or needed though.
Cheers.
Comment #40
koffer CreditAttribution: koffer as a volunteer and commentedA site with drupal 8.3 broke with this error
Recoverable fatal error: Argument 1 passed to Drupal\Core\Render\Element::isEmpty() must be of the type array, null given, called in /Applications/MAMP/htdocs/escalaexp/modules/panels/src/Plugin/Dis$
#1 /Applications/MAMP/htdocs/escalaexp/core/lib/Drupal/Core/Render/Element.php(198): _drupal_error_handler(4096, 'Argument 1 pass...', '/Applications/M...', 198, Array)
#2 /Applications/MAMP/htdocs/escalaexp/modules/panels/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php(136): Drupal\Core\Render\Element::isEmpty(NULL)
#3 /Applications/MAMP/htdocs/escalaexp/modules/panels/src/Plugin/DisplayBuilder/StandardDisplayBuilder.php(162): Drupal\panels\Plugin\DisplayBuilder\StandardDisplayBuilder->buildRegions(Array, Array)
#4 /Applications/MAMP/htdocs/escalaexp/modules/panels/src/Plugin/DisplayVariant/PanelsDisplayVariant.php(329): Drupal\panels\Plugin\DisplayBuilder\StandardDisplayBuilder->build(Object(Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVa$
#5 /Applications/MAMP/htdocs/escalaexp/modules/page_manager/src/Entity/PageVariantViewBuilder.php(34): Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant->build()
#6 /Applications/MAMP/htdocs/escalaexp/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php(96): Drupal\page_manager\Entity\PageVariantViewBuilder->view(Object(Drupal\page_manager\Entity\PageVariant), 'full')
Comment #41
tim.plunkettThere is no reason to be calling
CacheableMetadata::createFromObject($block_render_array);
1) It is not an object, it is an array.
2) It is an empty array that we create on the line directly above this.
#2825497: SystemMainBlock only functions when used by block.module is a separate issue, and while it is an easy way to reproduce this bug, is separate.
Here is my proposed fix. No interdiff since it is from scratch.
This also needs test coverage.
Comment #42
hamrant CreditAttribution: hamrant at DEWEB Studio, Drupal Ukraine Community, FFW for Drupal Ukraine Community commentedGetting these errors every time the page is reloaded:
Tried the patch from #41 but it didn't help.
Patch from #34 fixed problem, thanks @BR0kEN, great job!
Comment #43
tim.plunkettThis issue still needs test coverage.
Comment #44
arosboro CreditAttribution: arosboro at DropForge Labs commentedPatch #34 re-directs this error by referencing to the block that didn't pass an array from its build method. Regarding the updated error message, in my case it was the system content block, because no content had been set by the HTMLRender class.
Comment #45
Li Huang CreditAttribution: Li Huang commentedReroll.
Comment #46
praveenkakumanu CreditAttribution: praveenkakumanu as a volunteer commentedComment #47
praveenkakumanu CreditAttribution: praveenkakumanu as a volunteer commentedComment #48
praveenkakumanu CreditAttribution: praveenkakumanu as a volunteer commentedComment #49
jiv_e CreditAttribution: jiv_e as a volunteer and commented@arosboro, when the following fix is in core, the patch #45 should work also for empty SystemMainBlock.
https://www.drupal.org/node/2885370
Comment #50
BR0kEN@jiv_e, those won't be in core. See #2819219: Fatal error when "setMainContent()" method is not called (block module not installed).
Comment #51
veerakolagani CreditAttribution: veerakolagani commentedthanks its working fine for me
protected $mainContent = [];
Comment #52
dbjpanda CreditAttribution: dbjpanda commentedI could not go through all the comments. But #45 works for me. It is not fixed yet only due to add some test coverage or something else we are waiting for ? Can any one clearly mention what is going here and what to do next ?
Comment #53
cr0ss CreditAttribution: cr0ss as a volunteer and commentedReroll.
Comment #54
cr0ss CreditAttribution: cr0ss as a volunteer and commentedPrevious patch had a unclosed tag. Fixed it.
Comment #55
Sseto CreditAttribution: Sseto commentedIs there a patch for 9.3x?
Comment #56
metalboteSimple reroll...
Comment #57
metalbote