Problem/Motivation

Following the introduction of SourceWithSlotsInterface in #3531521: Layout plugins support, and related to #3574548: Unexpected properties in ComponentSource data.

When we move a slot source to a slot of an implementation of SourceWithSlotsInterface being, or having as ancestor, a non-ComponentSource implementation of SourceWithSlotsInterface, the uppest (at least) SourceWithSlotsInterface implementation lose some data structure.

Yes, it is a very specific situation :)

For example:

  1. Start a new Page Layout display. It will have the new PageLayouSource at the root. This source implements SourceWithSlotsInterface.
  2. Attach a first ComponentSource to the root
  3. Attach a second ComponentSource to a slot of PageLayouSource
  4. Move the second ComponentSource to a slot of the first ComponentSource
  5. Result: The first ComponentSource lose some data, including the source_id

Proposed resolution

We may have an undetected leftover of hardcoded ComponentSource logic in Instance entity.

For example, in Instance::moveToSlot() has a magic number ("3") which looks suspicious:

    $parent_slot = \array_slice($path, \count($path) - 3, 1)[0

We need to fix that, but also:

  1. Since beta1 we are introducing more and more coupling to SourceInterface in Instance entity. Is it the opportunity to embrace this coupling and to rely less on array primitives in InstanceInterface ?
  2. Can we add a playwright test using PageLayoutSource as the root of the builder? in order to detect those kind of situations in the pipeline?
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

pdureau created an issue. See original summary.

pdureau’s picture

Status: Active » Postponed

We may need to merge #3573805: Empty renderables in regions prevent layouts rendering before completing this work

pdureau’s picture

Issue summary: View changes

mogtofu33 made their first commit to this issue’s fork.

pdureau’s picture

Status: Postponed » Needs work

#3573805: Empty renderables in regions prevent layouts rendering is merged.

I can resume my work. Not ready for merge yet: it seems the bug is fixed, we are also now totally SDC agnostic; and we have a bunch of kernel tests to check this, but it is at the cost of this mechanism:

    // To avoid non consecutive array keys, we rebuild the value list.
    $slot_path = \array_slice($path, 0, \count($path) - 1);
    $slot = NestedArray::getValue($root, $slot_path);
    NestedArray::setValue($root, $slot_path, \array_values($slot));

This may have unfortunate side effects. Let's see if the playwright tests are OK

pdureau’s picture

Assigned: pdureau » mogtofu33
Status: Needs work » Needs review

Hello Jean,

Here are the challenges of the work done here, once we moved from hardcoded SDC logic to SourceWithSlotInterface.

InstanceSlotOperationsTest and array list indexation

If we have this structure:

  • a slot with 2 sources:
    • the source "A" to move, indexed "0"
    • a source "B" with slots (ComponentSource, LayoutSource...), indexed "1"

If we Instance::moveToSlot() the source "A" into a slot of "B" we have this unexpected structure:

[sources] 
  [0] 
    [node_id] => B
    [source_id] => layout
    [source] 
      [plugin_id] => layout_onecol
      [regions] 
            [content] 
  [1] 
    [source] 
      [regions] 
        [content] 
          [0] 
            [node_id] => A
            [source_id] => textfield

Where the source property with the new value is dissociated from the node_id, the source_id and the original source.

Let's take a Instance::moveToSlot() action, it is divided in 2 internal steps:

  1. Instance::doRemove() is reindexing the "B" (from "1" to "0") after the removal of "A":
        // To avoid non consecutive array keys, we rebuild the value list.
        $slot_path = \array_slice($path, 0, \count($path) - 1);
        $slot = NestedArray::getValue($root, $slot_path);
        NestedArray::setValue($root, $slot_path, \array_values($slot));
  2. Instance::doAttachToSlot() is still believing "B" is indexed at "1" and merging the array structure teh wrong way

So, in the MR, we moved the reindexing of list indexes (\array_values($slot));) from ::doRemove() to the beginning of ::buildIndexFromSlot() and now we have a food source structure but badly indexed ("1" instead of "0"):

[sources] 
  [0] 
  [1] 
    [node_id] => B
    [source_id] => layout
    [source] 
      [plugin_id] => layout_onecol
      [regions] 
        [content] 
          [0] 
            [node_id] => A
            [source_id] => textfield

So, in InstanceSlotOperationsTest::testMoveFromComponentToNestedLayoutEmptyRegion) test, we considered this OK because we want to keep consistent indexes during the chain of atomic operation and we expect the values to be correctly indexed at the very end, thanks to ::buildIndexFromSlot().

I hope it was the right bet.

Some change in InstanceHistoryTest

For your information.

mogtofu33’s picture

Assigned: mogtofu33 » Unassigned
Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • mogtofu33 committed 57bc4ea8 on 1.0.x authored by pdureau
    fix: #3574921 Instance::moveToSlot() error when an ancestor is a not a...

Status: Fixed » Closed (fixed)

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