Problem/Motivation
When creating a block, that block is required to have a presence in the database when creating a view (short of two notable exceptions, which I'll come back to) due to the way lazy building operates.
My use case is this: I'm extending the
Insert Block module β
to create short codes the will render block_content
entities as blocks inline. To do this I need to actually generate a block (so that I get all of the lovely templating hooked in) which can easily be done in memory using something like $block = \Drupal::service('entity.manager')->getStorage('block')->create($config);
From there I move to generate the view of the block using $block_view = \Drupal::service('entity.manager')->getViewBuilder('block')->view($block);
. Provided my $config
variable had all the relevant settings correct, I get a renderable array.
Unfortunately the array does not render. The BlockViewBuilder::viewMultiple()
function by default adds a lazyBuilder instead of a renderable array of content. The lazyBuilder then tries to load the content using entity_load(), which of course comes up empty because the block only exists in memory. The only two exceptions are blocks of the plugin MainContentBlockPluginInterface
and TitleBlockPluginInterface
which are immediately given pre-renderable blocks.
This issue is compounded by the fact that BlockViewBuilder::buildPreRenderableBlock()
, the function that creates the renderable block array, is protected in the class. It is certainly possible to generate this renderable array outside of the function, but it's additional code that may not stay up to date with changes in how blocks are rendered.
Proposed resolution
I suggest that lazyBuildability should not be determined by the class of the block plugin. Instead I suggest there be more than one way to prevent a block being lazyBuilt:
- Entire classes that need to skip the process such as those already in use should be able to set a lazyBuild property, defined (and override-able) from BlockBase. This makes new block definitions able to allow themselves to opt out of lazyBuilding if needed and makes the whole situation that much more extensible.
- Block entities should be able to pass properties allowing them to opt out of lazyBuilding.
- I don't like the additional DB request overhead of that so I don't think it's a viable option (defeats most of the purpose of lazyBuilding), but if there is genuine interest in being able to build blocks stored only in memory, then this may be a good choice.
Remaining tasks
Code needs review and perhaps discussion.
API changes
This does introduce a skip_lazy_build
block entity property that goes largely undocumented. Unsure if this needs to be introduced into the block entity model properly or even stored in the configuration.