Skip to content

[BUGFIX] do not copy children twice if container is in same cmdmap - #779

Open
Scopestyle wants to merge 1 commit into
b13:masterfrom
Scopestyle:bugfix/770-copy-container-with-children-in-cmdmap
Open

Scopestyle wants to merge 1 commit into
b13:masterfrom
Scopestyle:bugfix/770-copy-container-with-children-in-cmdmap

Conversation

@Scopestyle

Copy link
Copy Markdown

Fixes #770

When a container and its children end up in the same DataHandler cmdmap with copy (for example in the Record module: select all, copy, paste into another page), every child ends up on the target page three times. In the nested case the inner element even ends up seven times.

Cause

  1. SimpleDataHandlerController::setPasteCmd() reverses the clipboard order, so the children are processed before their container. Each child is copied on its own. Its update is empty, so the copy keeps tx_container_parent of the original container.
  2. Then the container is copied. CommandMapPostProcessingHook::copyOrMoveChildren() collects the children through Database::fetchRecordsByParentAndLanguage(), which has no pid restriction. So it picks up the original children and the copies from step 1, and copies all of them into the new container.

This is not specific to the Record module. Any cmdmap that contains a container together with its children triggers it, for example custom modules, imports, or CLI code.

Fix

CommandMapBeforeStartHook now removes copy/move commands of records whose container (at any nesting level) has an identical command in the same cmdmap. The container already copies or moves its children, so the child's own command is redundant.

  • The command must be identical. A child with its own target or update is left untouched.
  • The tx_container_parent chain is read with a workspace overlay. A child that was moved out of its container in a workspace is therefore not dropped.
  • It runs after unsetInconsistentCopyOrMoveCommands(). If a container's command was already removed, its children keep their own commands.

Tests

New: Tests/Functional/Datahandler/DefaultLanguage/ContainerWithChildrenInCmdmapTest.php and one test in Workspace/ContainerTest.php. Each cmdmap is in clipboard order (children first):

Test Without fix With fix
copyContainerWithChildrenInCmdmapCopiesChildrenOnlyOnce each child 3× 1×
copyNestedContainerWithChildrenInCmdmapCopiesChildrenOnlyOnce inner child 7×, child container 3× 1×
moveContainerWithChildrenInCmdmapKeepsChildrenInContainer children stay in the container; only the sorting values differ (each child is moved separately first) children are moved only with their container
Workspace\…::copyContainerWithChildrenInCmdmapCopiesChildMovedOutOfContainerInWorkspace child 3× 1×; the child moved out in the workspace is copied once on its own, and fails if the workspace overlay is removed

Run locally with Build/Scripts/runTests.sh:

  • TYPO3 13 / PHP 8.3 / sqlite, -s functional -- --do-not-fail-on-deprecation --exclude-group v14-only: 511 tests, OK
  • TYPO3 14 / PHP 8.3 / sqlite, -s functional: 535 tests, OK
  • cgl -n and phpstan (13 and 14): OK

Not covered

  • No test checks that a child command with its own target is kept. With current master, a cmdmap like "container → page X, child → container B / colPos 0 on page X" already ignores the child's target. The child ends up in the copied/moved container whether or not this change is applied, so no test can tell the two apart. That behaviour is separate from this PR.
  • Related but separate: fetchRecordsByParentAndLanguage() has no pid restriction. Records on other pages that still point to a container (see [BUG] Pasting in List View does not reset the container parent #662) are therefore copied into each copy of that container. This PR does not change that.

Tested in a real project on TYPO3 13.4.35 / container 3.2.3 with the same logic as a standalone hook. Copying whole pages (41, 35 and 28 elements) produced exactly one copy per element, each in the correct container.

🤖 Generated with Claude Code

If a container and its children are copied or moved with one cmdmap
(e.g. Record module: select all, copy, paste into other page), the
children are processed first (clipboard reverses the order) and keep
tx_container_parent of the original container. Copying the container
afterwards also copies these copies, so every child ends up three
times on the target page.

Copy/move commands of records are now removed if one of their
containers has an identical command in the same cmdmap, the container
copies/moves its children anyway. The container chain is resolved
with workspace overlay.

Fixes: b13#770

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Scopestyle
Scopestyle marked this pull request as ready for review October 2, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copying items in the list view triples the number of items in a container.

1 participant