Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
By specification of \Drupal\Core\Block\BlockPluginInterface
, the build()
method must return an array, but in case of \Drupal\system\Plugin\Block\SystemMainBlock
it could not always be respected. If method setMainContent()
of \Drupal\system\Plugin\Block\SystemMainBlock
class will not be called, then build()
method of the same class will return null
which may lead to TypeError
.
- Install Drupal using
minimal
profile. - Install the following modules:
panels
,page_manager
,page_manager_ui
. - Create new custom page using "Page manager", select "Panels" as variant type.
- Add "Main page content" block to content of newly created page, visit it and you'll see
The website encountered an unexpected error. Please try again later.
Comment | File | Size | Author |
---|---|---|---|
#2 | core-fatal_error_main_content_block-2819219-2.patch | 502 bytes | BR0kEN |
Comments
Comment #2
BR0kENComment #3
BR0kENComment #4
BR0kENI'm not sure that in body of issue described correct workflow, because code of
panels
module have the following lines:But what I know exactly - is that we should ensure that return type will be an array.
Comment #5
lauriiiLooks good for me
Comment #6
lauriiiComment #7
alexpottCommitted and pushed 24eeeb1 to 8.3.x and ba6f496 to 8.2.x. Thanks!
I thought about asking for a test but it just does not seem worth it.
Comment #10
Wim LeersThis is very much a non-option. There must be "main content" for a given page.
This resulting in an error/failing ungracefully was great. You would not be able to achieve that with Drupal core itself. If you could, that'd be a bug.
It sounds like something
panels
orpage_manager
are doing is wrong.Comment #11
BR0kEN@Wim Leers, let's abstract from Drupal core: could be a case when, instead of expected
array
,null
will be returned. If it acceptable, then we need to update returned types in\Drupal\Core\Block\BlockPluginInterface::build()
.Nevertheless I'm not thinking that this is mostly issue of Panels, because
SystemMainBlock
- is not a standard block - it implements additionalMainContentBlockPluginInterface
interface.Comment #12
dawehnerThere are some more possible options.
But what we should NOT do is to return NULL, as that makes it harder to debug than needed.
Comment #13
BR0kEN@dawehner, I guess now we have first of the options you've described. Also, if page do not have a content, then it's not a requirement to call
setMainContent()
.I'm pretty sure that
null
-preventing behavior - is a good one.@Wim Leers, I set back the
Fixed
status. Please create a new issue for enhancements.Comment #14
Wim LeersNo, I'm not asking for an enhancement. I'm saying this commit is wrong and should be reverted.
I also asked for detailed reasoning/explanation as to how
SystemMainBlock
can cause any problems when used with Panels/Page Manager, because with Drupal core alone you surely cannot get it to lead to a fatal error.Comment #15
dawehnerWell, code should be correct for itself, outside of arbitrary side effects :)
Comment #18
xjmAfter discussing with @tim.plunkett and @wimleers, it sounds like this is actually a bug in Page Manager (we think). What core should do is throw an explicit exception like this:
https://www.pastery.net/zzwjnv/
(via @tim.plunkett)
Edit: and also document that it can be null.
So we'll open a separate core issue to do that in 8.3.x only (since it is a disruptive change), but in either case there is a bug that will need to be fixed in contrib.
Comment #19
dawehnerIs there a reason we cannot check whether main content !== NULL? The main content should be a render array, so checking for NULL should be enough.
Comment #20
xjmComment #21
BR0kENCould somebody give me a reason why value, equal to empty array by default, - bad approach?
We just will have nothing to render, when
setMainContent()
method will not be called. Easy enough.Comment #22
tim.plunkettIf the system using the main content block does not call setMainContent, the block shouldn't be available to place in that system.
Comment #23
BR0kENSo, do Page Manager needs to implement something like this?
Code above taken from
\Drupal\block\Plugin\DisplayVariant\BlockPageVariant::build()
.Do not it looks a bit harder than just render the emptiness? We can make a lot of specific blocks (via implementing the interfaces) and it's strange for me that we need writing a lot of conditions to handle specific initializations.
Comment #24
tim.plunkettOpened #2825497: SystemMainBlock only functions when used by block.module.
Comment #25
lauriiiAccording to #23 block plugins implementing
TitleBlockPluginInterface
orMessagesBlockPluginInterface
are also not working properly with other modules than block module unless they specifically provide to support them.Edit:
I read the code in
BlockPageVariant::build
and it loks like theMessagesBlockPluginInterface
is used to provide fallback so that the messages are always printed on the page, even if there is no messages block placed. So the issue only exists forMainContentBlockPluginInterface
andTitleBlockPluginInterface
.Comment #26
BR0kEN#22 sounds good, but in real life all code that uses this block must have an additional check, like (taken from https://www.drupal.org/node/2812721#comment-11952030):
Comment #27
jiv_e CreditAttribution: jiv_e as a volunteer and commentedOk.. this is confusing. @BR0kEN guided me here after I added this:
https://www.drupal.org/node/2885370
I don't understand the reason to allow NULL values from SystemMainBlock::build(). Documentation says it shouldn't. Is the documentation incorrect? I have read this thread and I still don't understand.
My patch passed the tests. What does it break? Not enough test coverage?
Comment #28
tim.plunkettI'd prefer something along these lines.
Comment #29
jiv_e CreditAttribution: jiv_e as a volunteer and commentedThanks! I had fragile idea of this.. ok. It seemed obvious that the class was meant to be used like that.
But I don't agree that we should throw an Exception if mainContent is not set. Why should the system fail? Why not just let it go through as an empty array and use drupal_set_message and logger to notify that 'The system_main_block was placed but ::setMainContent was not called'?
Comment #30
jiv_e CreditAttribution: jiv_e as a volunteer and at LilDrop Consulting commentedI'll try to formulate two options I see presented in this thread. Then I will try to argue why the second option is better.
1. SystemMainBlock should be a special block. Instead like all the other blocks in core it's build() method should be called only after some requirements are met. Namely it's setMainContent() method should be called first. Otherwise SystemMainBlock::build() throws an Exception. It is contrib developers responsibility to handle this exception in her code. This special case and the Exception should be mentioned in the documentation of BlockPluginInterface::build().
2. SystemMainBlock behaves as all other blocks in core. It always returns an array. If setMainContent is not called then build() will return an empty array and SystemMainBlock shows no content. It's developers responsibility to call setMainContent if she wishes to have content on the SystemMainBlock.
Optionally we could notify users that setMainContent was not called, as mentioned in #29. But I changed my mind about that, so maybe not.
I think option 2. is better:
I will leave defending of the first option for others. Please correct me if I misrepresented the first option. If there's an option 3. add it in!
Comment #31
BR0kENTo be honest, I've changed my mind about this block and now think that it should throw an exception because otherwise (in a case of emptiness) its usage seems redundant.
Comment #32
jiv_e CreditAttribution: jiv_e as a volunteer and at LilDrop Consulting commented@BR0kEN, I agree that it seems redundant. But I think that the benefits of the option 2. still outweigh this.
I try to list all the reasons for option 1. I have noticed.
The first one has two forms, but they say the same thing. Empty main content block should not be accepted in any circumstance. The second one is just a weaker form of the first. It just says that it seems useless to have an empty main content block. So basically we should first think about the first one. If that does not hold then move to the next.
The problem with the first is that it doesn't really give any practical reasons. It just states that "you shouldn't do that". Please explain why! Explain also why these reasons outweigh the reasons for the 2. option.
For me it's expected to have an empty block if no content is put in it. If a developer/user wants to have content in it then she should put some in. It's not core's job to decide if blocks have content or not. So I would say it's not a bug.
Defender of option 1. is saying that the main content block should not exist on a page without a content. Is this just a philosophical standpoint without real practical reason? I think blocks are containers. Empty container should be able to exist without any content.
Comment #33
jiv_e CreditAttribution: jiv_e as a volunteer and at LilDrop Consulting commentedI'm sorry if my approach was inappropriate! I hope I didn't insult anyone. I admit I teased a little bit, though. ;)
I don't want to stall this issue, if I'm just raving please ignore me! I'm really just trying to understand the reasons behind option 1. and make sure that we make solid decisions for the benefit of Drupal.