Problem/Motivation

Currently the LayoutBuilder Render element itself holds the key to the layout preparation, making it difficult for storage plugins or custom code to decide how to ouput a layout

Proposed resolution

Implement an Event for preparing a layout so subscribers can easily alter the sections.

Remaining tasks

  • Create an event/dispatcher for preparing layouts.
  • Subscribe to the event to replicate current functionality.
  • Deprecation notices for changed parameters.
  • Tests? Does this need to be tested outside of current test cases?

User interface changes

None

API changes

New LayoutBuilderEvents::PREPARE_LAYOUT event for modules to interact without layouts during rendering.

Data model changes

None

Release notes snippet

New LayoutBuilderEvents::PREPARE_LAYOUT event for modules to interact without layouts during rendering see https://www.drupal.org/node/3160587

CommentFileSizeAuthor
#37 interdiff-33_37.txt1.44 KBb_sharpe
#37 3143635-layout-event-9.1-combined-37.patch22.92 KBb_sharpe
#37 3143635-layout-event-9.1-tests-only-37.patch17.79 KBb_sharpe
#33 interdiff-26_33.txt1.13 KBb_sharpe
#33 3143635-layout-event-9.1-combined-33.patch22.89 KBb_sharpe
#33 3143635-layout-event-9.1-tests-only-33.patch17.77 KBb_sharpe
#26 interdiff_22_26.txt4.09 KBb_sharpe
#26 3143635-layout-event-9.1-combined-26.patch22.89 KBb_sharpe
#26 3143635-layout-event-9.1-tests-only-26.patch17.77 KBb_sharpe
#22 interdiff_12-22.txt6.82 KBb_sharpe
#22 3143635-layout-event-9.1-combined-22.patch20.77 KBb_sharpe
#22 3143635-layout-event-9.1-tests-only-22.patch15.68 KBb_sharpe
#22 3143635-layout-event-8.9-combined-22.patch20.76 KBb_sharpe
#2 3143635-layout-event.patch10.13 KBb_sharpe
#3 3143635-layout-event-3.patch11 KBb_sharpe
#7 3143635-layout-event-with-tests.patch20.43 KBb_sharpe
#9 3143635-layout-event-tests-only.patch15.26 KBb_sharpe
#9 3143635-layout-event-combined.patch20.33 KBb_sharpe
#9 interdiff.txt4.98 KBb_sharpe
#12 3143635-layout-event-tests-only-2.patch15.26 KBb_sharpe
#12 3143635-layout-event-combined-2.patch20.33 KBb_sharpe
#12 interdiff.txt5.23 KBb_sharpe
#16 3143635-layout-event-tests-only-14.patch20.6 KBb_sharpe
#16 3143635-layout-event-combined-14.patch20.6 KBb_sharpe
#16 interdiff_12-14.txt4.96 KBb_sharpe
#17 3143635-16.patch20.32 KBDeepak Goyal
#17 interdiff_12-16.txt5 KBDeepak Goyal
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

b_sharpe created an issue. See original summary.

b_sharpe’s picture

Status: Active » Needs review
FileSize
10.13 KB

Not sure if this warrants tests as functionality should not have changed. Please review.

NOTE: If using layout_builder_st (or any other module that overrides the LB Element class) then you will get an error since it is expecting different construct.

b_sharpe’s picture

FileSize
11 KB

Updated patch to allow BC for contrib as it seems there are a fair amount of known modules overriding the LB element due to the lack of being able to decorate plugins.

b_sharpe’s picture

Issue summary: View changes

Updated remaining tasks

mahmoud-zayed’s picture

+1

tim.plunkett’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests, +Blocks-Layouts

Looking good! Next up would be a test implementation of an event subscriber, maybe a couple or one with dynamic behavior. Run before core's, after, and one before that stops propagation.

b_sharpe’s picture

Status: Needs work » Needs review
FileSize
20.43 KB

Added tests for before/after default event as well as stopping event propagation.

tim.plunkett’s picture

Issue tags: -Needs tests

Tests look good!

  1. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -53,15 +62,35 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
    -  public function __construct(array $configuration, $plugin_id, $plugin_definition, LayoutTempstoreRepositoryInterface $layout_tempstore_repository, MessengerInterface $messenger) {
    +  public function __construct(array $configuration, $plugin_id, $plugin_definition, LayoutTempstoreRepositoryInterface $layout_tempstore_repository = NULL, MessengerInterface $messenger = NULL, EventDispatcherInterface $event_dispatcher = NULL) {
    ...
    +    if ($layout_tempstore_repository) {
    +      @trigger_error('Calling LayoutBuilder::__construct() with the $layout_tempstore_repository argument is deprecated in drupal:8.9.0 and will be removed in drupal:10.0.0', E_USER_DEPRECATED);
    +    }
    +
    +    if ($messenger) {
    +      @trigger_error('Calling LayoutBuilder::__construct() with the $messenger argument is deprecated in drupal:8.9.0 and will be removed in drupal:10.0.0', E_USER_DEPRECATED);
    +    }
    +
    +    if (!$event_dispatcher) {
    +      @trigger_error('Calling LayoutBuilder::__construct() without the $event_dispatcher argument is deprecated in drupal:8.9.0. The $event_dispatcher argument will be required in drupal:10.0.0.', E_USER_DEPRECATED);
    +      $event_dispatcher = \Drupal::service('event_dispatcher');
    +    }
    

    This should be something like this

    public function __construct(array $configuration, $plugin_id, $plugin_definition, $event_dispatcher, $messenger = NULL) {
    	parent::__construct($configuration, $plugin_id, $plugin_definition);
    	if (!($event_dispatcher instanceof EventDispatcherInterface)) {
    		@trigger_error('The event_dispatcher service should be passed to LayoutBuilder::__construct() instead of the layout_builder.tempstore_repository service since 9.1.0. This will be required in Drupal 10.0.0. See https://www.drupal.org/node/XXXXX.', E_USER_DEPRECATED);
    		$event_dispatcher = \Drupal::service('event_dispatcher');
    	}
    	$this->eventDispatcher = $event_dispatcher;
    	if ($messenger) {
    		@trigger_error('Calling LayoutBuilder::__construct() with the $messenger argument is deprecated in drupal:9.1.0 and will be removed in drupal:10.0.0', E_USER_DEPRECATED);
    	}
    }
    

    Then in 10.0, it'd get the typehint.
    For example, see this evolution over 3 releases:
    https://git.drupalcode.org/project/drupal/-/blob/8.6.x/core/modules/cont...
    https://git.drupalcode.org/project/drupal/-/blob/8.7.x/core/modules/cont...
    https://git.drupalcode.org/project/drupal/-/blob/9.0.x/core/modules/cont...

  2. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -72,8 +101,9 @@ public static function create(ContainerInterface $container, array $configuratio
    -      $container->get('layout_builder.tempstore_repository'),
    -      $container->get('messenger')
    +      NULL,
    +      NULL,
    +      $container->get('event_dispatcher')
    

    Then this could drop the NULLs

  3. +++ b/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
    @@ -0,0 +1,79 @@
    +    $events[LayoutBuilderEvents::PREPARE_LAYOUT][] = ['onPrepareLayout'];
    

    I think this should set a specific priority higher than 0, since this is our expected behavior. Then any 0 (default) priority subscribers will consistently after this one, unless they purposefully specify

  4. +++ b/core/modules/layout_builder/tests/modules/layout_builder_element_test/src/EventSubscriber/TestPrepareLayout.php
    @@ -0,0 +1,118 @@
    +      if ($entity->id() === '2') {
    +        $event->stopPropagation();
    +      }
    

    Great! (Though very odd that it is a string, not an int, not what I expected 😅)

b_sharpe’s picture

  • Added "Test-only" patch which continues current functionality, but with tests and event/subscribers in place to not fatal.
  • Updated combined patch with changes from feedback above.

The last submitted patch, 9: 3143635-layout-event-tests-only.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 9: 3143635-layout-event-combined.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

b_sharpe’s picture

Whoops, I accidentally reverted the test change before patch. Let's try this again.

The last submitted patch, 12: 3143635-layout-event-tests-only-2.patch, failed testing. View results

tim.plunkett’s picture

Version: 8.9.x-dev » 9.1.x-dev
Status: Needs review » Needs work

All of the implementation and tests look great, into the home stretch which means very nitpicky coding standards fixes :)

  1. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -31,18 +31,11 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
    +   * The Event Dispatcher.
    

    The event dispatcher.

  2. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -53,15 +46,24 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
    +   * @param \Drupal\Core\Messenger\MessengerInterface|NULL $messenger
    

    Lower case null

  3. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -53,15 +46,24 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
    +   *   The messenger service. This is left optional for BC reasons and
    +   *   will be deprecated in drupal:9.1.0.
    

    (optional) The messenger service. This is no longer used and will be removed in drupal:10.0.0.

  4. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -53,15 +46,24 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
    +      @trigger_error('The event_dispatcher service should be passed to LayoutBuilder::__construct() instead of the layout_builder.tempstore_repository service since 9.1.0. This will be required in Drupal 10.0.0.', E_USER_DEPRECATED);
    ...
    +      @trigger_error('Calling LayoutBuilder::__construct() with the $messenger argument is deprecated in drupal:9.1.0 and will be removed in drupal:10.0.0', E_USER_DEPRECATED);
    

    I believe these need a link to a change record. See other trigger_errors in core.

  5. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -72,8 +74,8 @@ public static function create(ContainerInterface $container, array $configuratio
    +      $container->get('event_dispatcher'),
    +      NULL
    

    This NULL can be removed

  6. +++ b/core/modules/layout_builder/src/Event/PrepareLayoutEvent.php
    @@ -0,0 +1,45 @@
    + * Event fired when during preRender() of a LayoutBuilder Element.
    
    +++ b/core/modules/layout_builder/src/LayoutBuilderEvents.php
    @@ -26,4 +26,19 @@ final class LayoutBuilderEvents {
    +   * Name of the event fired when preparing a LayoutBuilder Element.
    ...
    +   * This event allows modules to collabourate on creating the sections used in
    +   * a LayoutBuilder Element during PreRender().
    

    "when during" in the first docblock

    "LayoutBuilder Element" should be \Drupal\layout_builder\Element\LayoutBuilder to not be ambiguous. That can also be added to the @see

    The capitalization on preRender() is inconsistent, as are the parens
    Also while it is a method name, it's only coincidentally the same. I think this should be #pre_render in all cases, as that's where it's actually run.

  7. +++ b/core/modules/layout_builder/src/Event/PrepareLayoutEvent.php
    @@ -0,0 +1,45 @@
    + * Subscribers to this event should manipulate the cacheability object and the
    + * build array in this event.
    

    This seems copy/pasted

  8. +++ b/core/modules/layout_builder/src/Event/PrepareLayoutEvent.php
    @@ -0,0 +1,45 @@
    +   * The Section Storage Plugin.
    

    The section storage plugin.

  9. +++ b/core/modules/layout_builder/src/Event/PrepareLayoutEvent.php
    @@ -0,0 +1,45 @@
    +   * LayoutPrepareEvent constructor.
    
    +++ b/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
    @@ -0,0 +1,79 @@
    +   * PrepareLayout constructor.
    
    +++ b/core/modules/layout_builder/tests/modules/layout_builder_element_test/src/EventSubscriber/TestPrepareLayout.php
    @@ -0,0 +1,118 @@
    +   * PrepareLayout constructor.
    

    Constructs a new _____.

    And make sure it's the right class name

  10. +++ b/core/modules/layout_builder/tests/modules/layout_builder_element_test/layout_builder_element_test.info.yml
    @@ -0,0 +1,8 @@
    +core: 8.x
    

    Not any more!

  11. +++ b/core/modules/layout_builder/tests/modules/layout_builder_element_test/src/EventSubscriber/TestPrepareLayout.php
    @@ -0,0 +1,118 @@
    + * An event subscriber that prepares a LayoutBuilder element for preRender.
    

    More preRender

  12. +++ b/core/modules/layout_builder/tests/modules/layout_builder_element_test/src/EventSubscriber/TestPrepareLayout.php
    @@ -0,0 +1,118 @@
    +    // Act before LB subscriber.
    ...
    +    // Act after LB subscriber.
    ...
    +   * Subscriber to test acting before the LB subscriber.
    

    spell out Layout Builder

Deepak Goyal’s picture

Assigned: Unassigned » Deepak Goyal
b_sharpe’s picture

8.9.x changes here, will post 9.1.x if all looks good.

Deepak Goyal’s picture

Hi @tim.plunkett
updated patch please review.

Status: Needs review » Needs work

The last submitted patch, 17: 3143635-16.patch, failed testing. View results

Deepak Goyal’s picture

Assigned: Deepak Goyal » Unassigned
Webbeh’s picture

Status: Needs work » Needs review

With the repeat of work between #16 and #17, and #16 passing automated testing while #17 fails, marking Needs Review with work of #16.

b_sharpe’s picture

Assigned: Unassigned » b_sharpe
Status: Needs review » Needs work

Assigning to me to not muddy waters here...

I will repost a proper 9.1.x and a backport for original 8.9.x

b_sharpe’s picture

Summary of changes to keep things in order here:

  • 8.9.x Combined patch, back-ported from 9.1.x
  • 9.1.x test only patch, which continues current functionality but with event/subscribers in place to not fatal.
  • 9.1.x combined patch
  • Interdiff of 8.9.x patch in #12 updated to 9.1.x along with notes from comment #14

The last submitted patch, 22: 3143635-layout-event-9.1-tests-only-22.patch, failed testing. View results

tim.plunkett’s picture

Status: Needs review » Needs work

One more pass on the nits should do it.
Also it occurs to me that this is supposed to test the deprecation. You can pass in the things that aren't supposed to be passed anymore, make sure it still all works, and use @expectedDeprecation on that test method.

  1. +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
    @@ -53,15 +46,24 @@ class LayoutBuilder extends RenderElement implements ContainerFactoryPluginInter
    +      @trigger_error('The event_dispatcher service should be passed to LayoutBuilder::__construct() instead of the layout_builder.tempstore_repository service since 9.1.0. This will be required in Drupal 10.0.0. See https://www.drupal.org/node/3152690', E_USER_DEPRECATED);
    ...
    +      @trigger_error('Calling LayoutBuilder::__construct() with the $messenger argument is deprecated in drupal:9.1.0 and will be removed in drupal:10.0.0', E_USER_DEPRECATED);
    

    The CR link should be in both

  2. +++ b/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
    @@ -0,0 +1,83 @@
    +   * PrepareLayout constructor.
    

    Missed one

  3. +++ b/core/modules/layout_builder/src/LayoutBuilderEvents.php
    @@ -26,4 +26,19 @@ final class LayoutBuilderEvents {
    +   * Name of the event fired when preparing a LayoutBuilder Element.
    ...
    +   * This event allows modules to collabourate on creating the sections used in
    +   * a LayoutBuilder Element during PreRender().
    

    no U in collaborate, and missed a #pre_render. Also didn't make the change about not calling LayoutBuilder Element.

  4. +++ b/core/modules/layout_builder/src/LayoutBuilderEvents.php
    @@ -26,4 +26,19 @@ final class LayoutBuilderEvents {
    +   * @EVENT
    

    Not sure what this is supposed to be :D

pyrello’s picture

Very nice work on this update. I think this is going to be a big improvement to the LB system.

I wanted to note that the event, as currently designed, only allows for alterations to the sections and components. The administrative links, such as "Add block" or "Add section" get added after this fires, so it is still necessary to use a '#pre_render' function to alter behavior related to that.

b_sharpe’s picture

  • Tests added for deprecation notices
  • Changes from comments in #24
  • Interdiff from #22

The last submitted patch, 26: 3143635-layout-event-9.1-tests-only-26.patch, failed testing. View results

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

This is a welcome addition, it has great test coverage, and to the best of my knowledge is up to par with how deprecations should be done. Great work @b_sharpe!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 26: 3143635-layout-event-9.1-combined-26.patch, failed testing. View results

tim.plunkett’s picture

Status: Needs work » Reviewed & tested by the community

Random fail in CKEditorIntegrationTest. Requeued/reRTBC'd

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 26: 3143635-layout-event-9.1-combined-26.patch, failed testing. View results

tim.plunkett’s picture

b_sharpe’s picture

The last submitted patch, 33: 3143635-layout-event-9.1-tests-only-33.patch, failed testing. View results

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. It nice seeing the event leading to less dependencies being injected in the LayoutBuilder element. This is looking good.
  2. +++ b/core/modules/layout_builder/src/Event/PrepareLayoutEvent.php
    @@ -0,0 +1,45 @@
    +   * Gets the section storage.
    +   *
    +   * @return \Drupal\layout_builder\SectionStorageInterface
    +   *   The section storage.
    +   */
    +  public function getSectionStorage() {
    +    return $this->sectionStorage;
    +  }
    

    Can use a return typehint in new code.

  3. +++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderPrepareLayoutTest.php
    @@ -0,0 +1,119 @@
    +    // Chack the block is on the node page.
    

    typo Chack

  4. +++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderPrepareLayoutTest.php
    @@ -0,0 +1,119 @@
    +    // When we edit the layout, it get's the static blocks.
    

    typo: get's

b_sharpe’s picture

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

It was news to me that the policy is to add strict return types to code now, and that's not in the coding standards yet.
But as @alexpott clarified on slack, it's much easier to add them now than later...

Also I don't understand cspell, is that not integrated with testbot?

Either way, the patch is good.

The last submitted patch, 37: 3143635-layout-event-9.1-tests-only-37.patch, failed testing. View results

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record

I'm sorry on my last review I missed that we don't have a change record describing the new event and when to use it. Once the change record exists this issue can be set back to rtbc.

b_sharpe’s picture

Status: Needs work » Needs review
tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

per #40

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed

Committed e77ca8b and pushed to 9.1.x. Thanks!

  • alexpott committed e77ca8b on 9.1.x
    Issue #3143635 by b_sharpe, tim.plunkett, alexpott: Change Layout...
vselivanov’s picture

Patch from #26 works with Drupal 8.9.2.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

quietone’s picture

Published change record