Hidden dependency on block_content in layout_builder

Created on 23 December 2021, over 2 years ago
Updated 5 April 2024, 3 months ago

Problem/Motivation

The \Drupal\layout_builder\Plugin\Block\InlineBlock plugin has a dependency on code from the Block Content module but the Layout module does not have a dependency on block_content.

Steps to reproduce

  1. Install minimal
  2. Enable layout_builder
  3. Use drush php to run $rc = new \ReflectionClass(\Drupal\layout_builder\Plugin\Block\InlineBlock::class);

Output:

PHP Error:  Interface "Drupal\block_content\Access\RefinableDependentAccessInterface" not found in /Volumes/dev/sites/drupal8alt.dev/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php on line 33

This means we can't use reflection during block discovery with blocks πŸ“Œ Use PHP attributes instead of doctrine annotations Fixed .

Proposed resolution

Move Drupal\block_content\Access\* to Drupal\Core\Access

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

πŸ“Œ Task
Status

Needs work

Version

11.0 πŸ”₯

Component
Block contentΒ  β†’

Last updated 2 days ago

Created by

πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

Live updates comments and jobs are added and updated live.
  • Needs change record

    A change record needs to be drafted before an issue is committed. Note: Change records used to be called change notifications.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    Any reason why we don't just make LB depend on block content module?
    It's pretty useless without it

  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland

    We did some rediscovery of the options discussed here in the PHP attribute issue.

    One more option that came up is whether it's actually worth to maintain layout_builders independence of block_content or if we should just not bother, add a dependency and move on. Not sure, I guess there are some arguments to be made that some use cases of layout builder like using it for overriding default view displays or page manager or something can function quite well without it. But it's also not a big hassle to have block_content enabled, although some sites might use alternative options to provide content blocks. Or we introduce a glue module that depends on layout_builder and block_content. Not sure what implications that would have on existing content and dependencies and such.

    It's more of a BC hassle, but I think extracting that access concept out of block_content could actually be useful for others as well, like paragraphs? we struggle with similar issues there when access depends on specific parent revisions.

    Another idea I brought up was providing explicit support for such cases with provider-as-subfolder feature in discovery, in which we traverse if the given provider exists.

  • πŸ‡¬πŸ‡§United Kingdom catch

    If we eventually fix πŸ› block_content block derivatives do not scale to thousands of block_content entities Needs work with the single block plugin + configuration and remove the deriver (which is about 2-3 issues down from that issue), that might work in such a way that it doesn't fatal, and then couldn't we remove the dependency on block_content again then? If so, then I think we should add the dependency now, and remove it again when we've killed off the deriver.

  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland

    I'm not sure.

    This isn't a problem caused by the deriver. Any attribute-based plugin that uses an unknown trait (not catchable) or unknown base class (catchable but we don't do that yet) will trigger that. Quite the opposite in fact, the deriver allows for that workaround, because the deriver can do that class trickery. Without it, that would need to be done in an alter hook, exposing a BC issue if another module's alter hook comes first.

    And this deriver is per block content *type*, so doesn't have the scalability issue, but actually exposes a useful thing for users (you don't need to add a Block, you add a "Hero", or a "Media gallery" or whatever you name your block content types).

    That said, somehow combining the InlineBlock experience and the regular Block experience seems like it *could* be feasible from a technical standpoint, we could even keep the block type deriver, combined with a re-use existing or create new UI similar to media library. Would be a modal-in-a-model UI though in the current case? There is also that issue about allowing to create reusable blocks from within the InlineBlock UI, that's already one step in that direction.

    To summary, yeah maybe, but that sounds like it's many more steps off than dropping the block_content block deriver.

  • πŸ‡¬πŸ‡§United Kingdom catch

    And this deriver is per block content *type*, so doesn't have the scalability issue, but actually exposes a useful thing for users (you don't need to add a Block, you add a "Hero", or a "Media gallery" or whatever you name your block content types).

    Doh I missed that. Even so, I think we should add the dependency, and open a follow-up to remove the dependency, because it's exchanging a fatal error for a minor annoyance (at worst).

  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland
  • Status changed to Needs review 8 months ago
  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland

    So I realized that the dependency approach is going to cause some update problems and had another idea that is not very nice but quite localized to this single file, we just define that trait and the interface on the fly if we need it. Looks a bit ugly, but at least one test that I
    tried worked. Lets see if some of our weirder test coverage doesn't like this.

    There is also a slight variation of this, where we just do:

    if (!trait_exists(RefinableDependentAccessTrait::class)) {
      return;
    }
    

    That kind of works, but the attribute discovery throws an exception then:

    ReflectionException: Class "Drupal\layout_builder\Plugin\Block\InlineBlock" does not exist in ReflectionClass->__construct() (line 125 of core/lib/Drupal/Component/Plugin/Discovery/AttributeClassDiscovery.php).

    We *could* handle that or check first with a class exists, which I think makes sense, because annotations didn't cause such a problem, and I expect there will be cases out there with with stuff in plugin folders. But I'm not sure if we really want to do it silently or log something.

  • @berdir opened merge request.
  • Status changed to Needs work 8 months ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Change makes sense. But could we add to the comments link to the CR or this issue and maybe mention this isn't encouraged. So others don't see it and decide they can implement that too.

    Didn't break anything which could be good sign.

  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland

    > Change makes sense. But could we add to the comments link to the CR or this issue and maybe mention this isn't encouraged. So others don't see it and decide they can implement that too.

    Oh, I plan to do the opposite of that. Once approved/commited, I want to add this on the CR record for attribute discovery. This isn't something you do for fun. This is a last resort thing when you have no other good options, and just like layout_builder module, when you run into this during the conversion, you need to do _something_, at least as an intermediate step.

  • First commit to issue fork.
  • @longwave opened merge request.
  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    Possible alternative approach in MR!5276 moving the plugin to block_content, not sure this is any better than @Berdir's approach though.

  • πŸ‡¬πŸ‡§United Kingdom catch

    If we move it to block_content we'd need to ensure block_content is enabled on any site using that plugin. I guess we could do something like:
    - post update to enable block_content if layout_builder is enabled, this could be in layout_builder itself
    - don't make block_content an actual dependency of layout builder.

    There's a potential UX issue when people then install layout_builder and not block_content and can't do what they expect, but could add help text for that.

    Only question is would we run into issues before the post update runs with other post updates hook_update_N() if the plugin provider is 'missing', that seems fairly likely tbh. We might want to quickly get that update into 10.2.x without moving the plugin, then move the plugin itself in 10.3?

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    block_content already *has* to be enabled on any site using the plugin; the deriver returns a derivative for each block content type, so if block_content is not enabled there will not be any inline_block plugins available.

    The only issue here is the discovery issue with attributes, because the class is now loaded at discovery time, whereas with attributes the docblock was parsed without actually loading the class; the deriver then returned nothing and so the plugin itself was never loaded or instantiated.

  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland

    See layout_builder_plugin_filter_block_alter(). inline_block has some special behaviour and *only* exists for us in layout builder. moving it to block_content breaks that, that's the reason it works like this.

    As written in Slack, I can see a future where we merge the two existing block_content plugin implementations into a new one that uses no or block type only derivatives and works for inline and reusable and not reusable block_content items both, but that sounds like quite a bit of discussion and figuring how exactly that would all work together.

    For now, inline_block IMHO either needs to stay in layout_builder or in a new module that depends on both layout_builder and block_content.

  • @longwave opened merge request.
  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    Agree now that moving the plugin to block_content won't work.

    Made another attempt in MR!5276 where the dependent code is moved to a subclass that only the deriver knows about, but also not sure this is any better either.

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    ...but it can't live in the same namespace because discovery will still try to load it.

    I give up, none of these solutions are optimal, but still not sure what the best interim fix is. Do we know of any similar instances in contrib that we could try to analyse for a solution as well?

  • πŸ‡¬πŸ‡§United Kingdom catch

    Apart from the fact it involves an upgrade path, why not making layout builder depend on block content + post update to enable it. And then defer the attributes change to the minor after that update so that most sites will do one solidly before the other? Or am I missing something really obvious/not reading the above properly?

  • πŸ‡¦πŸ‡ΊAustralia acbramley

    Agree with Lee in #9 and others here that I think it makes sense to make layout_builder depend on block_content especially if it's going to make our lives easier!

  • The same issue has come up with MigrateSource plugins using a Trait on from another module: πŸ“Œ Convert MigrateSource plugin discovery to attributes Postponed .

Production build 0.69.0 2024