Layout Builder/preview compatibility

Created on 3 July 2023, 12 months ago
Updated 13 July 2023, 12 months ago

Problem/Motivation

When adding a computed field to a layout builder display, layout builder crashes.

#3371474 πŸ› Responses to ->getSetting() ignore requested setting string, static return value. Fixed Helps resolve some of the issues with layout builder.

However, when layout builder tries to preview a computed entity reference field without a real entity, the lazy builder ends up passing along variables that invoke ComputedFieldBuilder::viewField() with an invalid node ID, resulting in a whitescreen.

Steps to reproduce

Create a reverse entity reference field on a content type, enable layout builder, render the field in the layout using "rendered entity". Save and come back to the layout builder edit screen for the bundle. See a whitescreen showing.

Proposed resolution

I'm not particularly well versed in how the entity preview system works, but it seems reasonable to expect a sensible behavior here. Perhaps we could mimic what entity reference does, whatever that is.

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Fixed

Version

4.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States gcb

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @gcb
  • @gcb opened merge request.
  • Status changed to Needs review 12 months ago
  • πŸ‡ΊπŸ‡ΈUnited States gcb
  • πŸ‡¬πŸ‡§United Kingdom joachim

    I'm confused how we get to the lazy builder callback with no entity. What does this code produce for the $entity->id()?

        $build[$field_name] = [
          '#lazy_builder' => [
            'computed_field.computed_field_builder:viewField',
            [
              $entity->getEntityTypeId(),
              $entity->id(),
              $field_name,
              $display->getMode(),
            ],
          ],
          '#create_placeholder' => TRUE,
        ];
    
  • Status changed to Postponed: needs info 12 months ago
  • πŸ‡¬πŸ‡§United Kingdom joachim

    I'm not managing to reproduce this - when I went to set up the layout for my node type, I added the reverse ER field and it appeared correctly in the preview.

    Could you give precise steps to reproduce please?

    And also turn on error reporting, so you can see the actual error rather than just a whitescreen?

  • πŸ‡ΊπŸ‡ΈUnited States gcb

    I have Commerce products that are used to purchase event registrations. Basically, the Product has an entity reference to an Event node. We want to display some information about the Product on the event automatically. In this case, it's basically a field on the Product for the maximum number of registrations allowed.

    The Product has a view mode that displays this integer field, called "Capacity".

    The Event has a computed field using the reverse entity reference plugin, pointing to the product.

    Events have a view mode, NOT using layout builder, that includes this and some other fields, called "key_details". It renders the computed field using a the Capacity view mode.

    The Event "Full" view mode uses the ctools "Entity view (Content)" block to render the event using the key_details view mode. (Yes, the event view mode renders the same event in a different view mode)"

    I suspect that extra layer of abstraction is unnecessary, and you could get the same thing with the computed field in a block on the Full view mode -- but that field still isn't appearing for me.

    Here's the error, which I get on my event node type's full display mode configuration's layout config page: ("/admin/structure/types/manage/event/display/full/layout")

    TypeError: Drupal\computed_field\ComputedFieldBuilder::viewField(): Argument #2 ($entity_id) must be of type int, null given in Drupal\computed_field\ComputedFieldBuilder->viewField() (line 50 of modules/contrib/computed_field/src/ComputedFieldBuilder.php).
    Drupal\computed_field\ComputedFieldBuilder->viewField('node', NULL, 'computed_registration_product', 'key_details')
    call_user_func_array(Array, Array) (Line: 101)
    Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #lazy_builder callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
    Drupal\Core\Render\Renderer->doCallback('#lazy_builder', Array, Array) (Line: 353)
    Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
    Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
    Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
    Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 161)
    Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
    Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
    Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
    Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
    Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
    Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
    Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 149)
    Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 278)
    Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 127)
    Drupal\Core\Render\HtmlResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
    Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
    call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
    Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
    Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
    Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
    Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
    Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
    Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 50)
    Drupal\ban\BanMiddleware->handle(Object, 1, 1) (Line: 48)
    Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
    Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
    Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 718)
    Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
    
  • Status changed to Needs work 12 months ago
  • πŸ‡ΊπŸ‡ΈUnited States gcb
  • Status changed to Postponed: needs info 12 months ago
  • πŸ‡¬πŸ‡§United Kingdom joachim

    Can you debug in computed_field_entity_view_alter() and see why $entity->id() on line 70 is NULL?

  • Status changed to Needs review 12 months ago
  • πŸ‡ΊπŸ‡ΈUnited States gcb

    Yes -- it's what I expected. The entity is new, and doesn't have an ID. $entity->id() returns NULL. $entity->isNew() returns TRUE.

    I get this all the time with layout builder and various contrib modules that aren't expecting to generate sample content for an entity generated only for the purpose of LB's preview. (If you are trying to reproduce, but editing the layout on a specific entity, you might not be able to -- I think it uses the actual entity in those cases.) This is the layout configuration at the bundle level.

    There's just no entity ID to work with.

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

    Thanks for the explanation.

    So the simplest thing is just to bypass the lazy builder in that circumstance. We don't care about cacheability in preview anyway.

    Can you try the new MR?

  • Status changed to RTBC 12 months ago
  • πŸ‡ΊπŸ‡ΈUnited States gcb

    Sounds good to me, and yes this patch works great for my use case. Thanks!

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

    Fixed.

    Thanks for reporting, debugging, and testing!

    I'm making a new release.

  • Status changed to Fixed 12 months ago
    • joachim β†’ committed cec00533 on 4.0.x
      Issue #3372109 by joachim , gcb: Fixed fields using lazy builder causing...
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.69.0 2024