ApiLayoutController::getRegionForComponentInstance doesn't work well with nested components if there are multiple regions.

Created on 9 July 2025, 3 days ago

Overview

We recently faced an issue where we couldn't use nested components in an XB page that has multiple regions.

Steps to reproduce

  1. Have multiple regions set up.
  2. Place two components one with a prop and another one with a slot in a component with slots.
  3. Place another component with a prop inside the nested component.
  4. Fill the value of prop in first component. This one works.
  5. Fill the value of prop in 2nd component.(The one in nested component).
  6. See that the network call for this last one fails with 5xx error.

Expected result

Nested components should work well.

This fails at ApiLayoutController::267 because `$regionForComponentId` is null and it's not able to get the region even though content region exists under which this component is placed.

Proposed resolution

User interface changes

🐛 Bug report
Status

Active

Version

0.0

Component

… to be triaged

Created by

🇮🇳India amangrover90

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

Merge Requests

Comments & Activities

  • Issue created by @amangrover90
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    This fails at ApiLayoutController::267 because $regionForComponentId is null and it's not able to get the region even though content region exists under which this component is placed.

    That's

          if ($regionForComponentId !== XbPageVariant::MAIN_CONTENT_REGION) {
            if (!$page_regions[$regionForComponentId]->access('edit')) {
              throw new AccessDeniedHttpException(sprintf('Access denied for region %s', $regionForComponentId));
            }
    

    So … this would mean that $page_regions[$regionForComponentId] resolves to NULL, meaning that $regionForComponentId is NOT one of the existing PageRegion config entities?! 😱

    Can you please apply this patch to get a more precise error message?

    $ git diff
    diff --git a/src/Controller/ApiLayoutController.php b/src/Controller/ApiLayoutController.php
    index f34ce46cc..570082478 100644
    --- a/src/Controller/ApiLayoutController.php
    +++ b/src/Controller/ApiLayoutController.php
    @@ -264,6 +264,9 @@ final class ApiLayoutController {
         if (!empty($page_regions)) {
           $regionForComponentId = $this->getRegionForComponentInstance($data['layout'], $componentInstanceUuid);
           if ($regionForComponentId !== XbPageVariant::MAIN_CONTENT_REGION) {
    +        if (!array_key_exists($regionForComponentId, $page_regions)) {
    +          throw new \LogicException(sprintf("Component instance %s is in a region (%s) for which no PageRegion config entity exists. Existing PageRegions: %s.", $componentInstanceUuid, $regionForComponentId, implode(', ', array_keys($page_regions))));
    +        }
             if (!$page_regions[$regionForComponentId]->access('edit')) {
               throw new AccessDeniedHttpException(sprintf('Access denied for region %s', $regionForComponentId));
             }
    
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Oh wait:

    because $regionForComponentId is null

    If true, this would most likely be a bug in \Drupal\experience_builder\Controller\ApiLayoutController::getRegionForComponentInstance()?

    What would be really helpful is you sharing the full request body that triggered that 500 response 🙏 That would allow us to easily write a failing test case to ApiLayoutControllerPatchTest.

  • 🇺🇸United States mglaman WI, USA

    I walked through the xdebug of this. The component was in the `content` region. I think the bug is in the `slots` code

              // Maybe it's not a component, but a slot inside a component.
              foreach ($componentData['slots'] as $slotData) {
                foreach ($slotData['components'] as $slotComponentData) {
                  if ($slotComponentData['uuid'] === $componentInstanceUuid) {
                    return TRUE;
                  }
                }
              }
    

    It was nested 2 or 3 levels deep.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Bumping priority and tagging , because AFAICT 🐛 Created XB Pattern didn’t include all components Active is a duplicate bug report!

    Tom, could you take a look at this today? 🙏

  • 🇮🇳India amangrover90

    Uploaded the payload for which there was 500 error. It fails trying to calculate the regionForComponentId.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    This blocks #3535078, see #3535078-9: [PP-1] Created XB Pattern didn’t include all components . More likely: that is a duplicate of this issue: different symptom, same root cause. Still, let's double-check there after this lands 👍

  • First commit to issue fork.
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • Pipeline finished with Failed
    2 days ago
    Total: 681s
    #543967
  • Pipeline finished with Success
    2 days ago
    Total: 742s
    #543995
  • 🇪🇸Spain isholgueras

    This is ready with all tests green. Let me know if we can create a follow-up ticket for tests or if we should include here the tests

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Yes, we do, hence the tag 😇

    See #9 for a sample payload, but it sounds like you were able to reproduce this yourself already :)

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • First commit to issue fork.
  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    I think this should be a beta blocker, its pretty easy to get this error.

    Pushed a failing test and rebased off 0.x

    If you checkout 185d8c32 and run ApiLayoutControllerPatchTest it fails.

    We already had most of the required structure in XbTestSetup, just needed to do some fernangling to mirror the nesting.

    Adding the tag, asking for forgiveness not permission etc

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    2 questions on the MR — one about a remaining @todo, one about something I don't understand.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • Pipeline finished with Failed
    1 day ago
    Total: 783s
    #544967
  • 🇪🇸Spain isholgueras

    … but let's land !1204 first, that is much harder to reroll.

    Sure! feel free to throw it back to me if we need a reroll here.

  • 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    🐛 Add rudimentary conflict prevention to the Config Auto-save end-point Active is in! Merging this as soon as CI passes.

    @penyaskito THAT WAS FAST 😱

  • Pipeline finished with Skipped
    1 day ago
    #545061
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Production build 0.71.5 2024