Writing relations

The backend form sends relations as lists: the uids of the related records for an MM relation, the child records for an inline relation and the file references for a file field. The DataHandler turns these lists into relation rows and keeps their order. Each scenario below changes the same relation once through the DataHandler, the way the form sends it, and once through Extbase, and compares the relation rows and the counters.

Provenance

Tests ran on main (15.0-dev), which is assumed to behave as TYPO3 14.3.

Summary

9 scenarios, by Extbase status:

Comparison

ScenarioCoreExtbase
Adding tags writes mm rows in order The tags 1 and 2 are set on item 1 through DataHandler, as the backend form sends them: the field tags holds the uid list "1,2". DataHandler writes one row per tag into the relation table with uid_local 1 and the sorting 1 and 2 in the order of the list, leaves sorting_foreign at 0 and writes the number of tags, 2, into the field tags of the item. Same as coreExtbase adds the tags 1 and 2 to item 1 and persists it with update() and persistAll(). Extbase writes the same relation rows with the sorting 1 and 2 and sorting_foreign 0 and writes the number of tags, 2, into the item, like DataHandler.
Reordering tags rewrites the sorting The tags of item 1 are sent in the order 2, 1 through DataHandler, as the backend form sends them after the editor moved a tag: the field tags holds the uid list "2,1". DataHandler keeps both relation rows and rewrites their sorting: tag 2 gets the sorting 1, tag 1 gets the sorting 2. Same as coreExtbase detaches both tags from item 1, attaches them again in the order 2, 1 and persists the item with update() and persistAll(). Extbase keeps both relation rows and rewrites their sorting like DataHandler: tag 2 gets the sorting 1, tag 1 gets the sorting 2.
Removing one tag removes its mm row Only tag 2 is sent for item 1 through DataHandler, as the backend form sends the remaining tags after the editor removed tag 1. DataHandler deletes the relation row of tag 1, renumbers the sorting of the remaining row of tag 2 to 1 and writes the number of tags, 1, into the item. DeviatesExtbase removes tag 1 from item 1 and persists the item with update() and persistAll(). Extbase deletes the relation row of tag 1 and writes the number of tags, 1, into the item, but leaves the sorting of the remaining row of tag 2 at 2 instead of renumbering it to 1.
Adding a tag to a translation Tag 1 is set on the German translation 2 of item 1 through DataHandler, as the backend form sends it: the field tags of the translation holds the uid list "1". DataHandler writes the relation row with the uid of the translation, uid_local 2, writes the number of tags, 1, into the translation and leaves the relation row of the default record 1 untouched. Same as coreExtbase reads item 1 with the language German, adds tag 1 and persists the item with update() and persistAll(). Extbase writes the new relation row with the uid of the translation, uid_local 2, and the number of tags, 1, into the translation, like DataHandler.
Reordering tags of a translation The tags of the German translation 2 are sent in the order 2, 1 through DataHandler, as the backend form sends them after the editor moved a tag. DataHandler rewrites the sorting of the relation rows of the translation, uid_local 2, and leaves the relation rows of the default record 1 untouched. DeviatesExtbase reads item 1 with the language German, detaches both tags, attaches them again in the order 2, 1 and persists the item with update() and persistAll(). Extbase swaps the sorting of the relation rows of the default record 1, uid_local 1, and leaves the relation rows of the translation 2 unchanged, because it updates the relation rows with the uid of the default record.
Removing a tag from a translation Only tag 2 is sent for the German translation 2 through DataHandler, as the backend form sends the remaining tags after the editor removed tag 1. DataHandler deletes the relation row of the translation for tag 1, renumbers the remaining row of the translation to the sorting 1, writes the number of tags, 1, into the translation and leaves the relation rows of the default record 1 untouched. DeviatesExtbase reads item 1 with the language German, removes tag 1 and persists the item with update() and persistAll(). Extbase deletes the relation row of the default record 1 for tag 1 and leaves both relation rows of the translation 2 in place; the field tags of the translation stays 2, because Extbase deletes the relation rows with the uid of the default record.
Adding inline children keeps their order Two new remarks are sent as inline children of item 1 through DataHandler, as the backend form sends them: the field ordered_notes of the item holds "NEW1,NEW2" and each remark is a NEW record with its pid and the uid of the item in its field item. DataHandler creates both remarks with the uid of item 1, the sorting 1 and 2 (foreign_sortby) and the current time as crdate and tstamp, and writes the number of remarks, 2, into the item. Same as coreExtbase attaches two new remarks to item 1 and persists the item with update() and persistAll(). Extbase creates both remarks with the uid of item 1, the sorting 1 and 2 and the current time as crdate and tstamp, and writes the number of remarks, 2, into the item, like DataHandler.
Reordering inline children The remarks of item 1 are sent in the order 2, 1 through DataHandler, as the backend form sends them after the editor moved a remark: the field ordered_notes holds the uid list "2,1". DataHandler rewrites the sorting of the remarks: remark 2 gets the sorting 1, remark 1 gets the sorting 2. It sets tstamp of both remarks and of the item to the current time. Same as coreExtbase detaches both remarks from item 1, attaches them again in the order 2, 1 and persists the item with update() and persistAll(). Extbase rewrites the sorting of the remarks like DataHandler, remark 2 gets the sorting 1 and remark 1 the sorting 2, and sets tstamp of both remarks and of the item to the current time.
Adding a file reference A new reference to the file 1 is sent as the image of item 1 through DataHandler, as the backend form sends it: the field images of the item holds "NEW1" and the reference is a NEW sys_file_reference record with its pid, uid_local 1 and the uid of the item as uid_foreign. DataHandler completes the row with tablenames and fieldname images, the sorting_foreign 1 and the current time as crdate and tstamp, and writes the number of references, 1, into the item. Same as coreExtbase attaches a new Extbase file reference, built from a core file reference object for the file 1, to item 1 and persists the item with update() and persistAll(). Extbase writes the same sys_file_reference row as DataHandler, with tablenames, fieldname images, sorting_foreign 1 and the current time as crdate and tstamp, and writes the number of references, 1, into the item.

Scenarios

Adding tags writes mm rows in order

Same as core

In 14.3

Core: The tags 1 and 2 are set on item 1 through DataHandler, as the backend form sends them: the field tags holds the uid list "1,2". DataHandler writes one row per tag into the relation table with uid_local 1 and the sorting 1 and 2 in the order of the list, leaves sorting_foreign at 0 and writes the number of tags, 2, into the field tags of the item.

Extbase: Extbase adds the tags 1 and 2 to item 1 and persists it with update() and persistAll(). Extbase writes the same relation rows with the sorting 1 and 2 and sorting_foreign 0 and writes the number of tags, 2, into the item, like DataHandler.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:88 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:106 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/AddedTags.csv (local)

Reordering tags rewrites the sorting

Same as core

In 14.3

Core: The tags of item 1 are sent in the order 2, 1 through DataHandler, as the backend form sends them after the editor moved a tag: the field tags holds the uid list "2,1". DataHandler keeps both relation rows and rewrites their sorting: tag 2 gets the sorting 1, tag 1 gets the sorting 2.

Extbase: Extbase detaches both tags from item 1, attaches them again in the order 2, 1 and persists the item with update() and persistAll(). Extbase keeps both relation rows and rewrites their sorting like DataHandler: tag 2 gets the sorting 1, tag 1 gets the sorting 2.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:128 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:146 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/ReorderedTags.csv (local)

Removing one tag removes its mm row

Deviates

In 14.3

Core: Only tag 2 is sent for item 1 through DataHandler, as the backend form sends the remaining tags after the editor removed tag 1. DataHandler deletes the relation row of tag 1, renumbers the sorting of the remaining row of tag 2 to 1 and writes the number of tags, 1, into the item.

Extbase: Extbase removes tag 1 from item 1 and persists the item with update() and persistAll(). Extbase deletes the relation row of tag 1 and writes the number of tags, 1, into the item, but leaves the sorting of the remaining row of tag 2 at 2 instead of renumbering it to 1.

Target for 15.x

Extbase behaves as the core.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:167 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:185 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/RemovedTag.csv (local)
SkipExtbase differs from core: it deletes the relation row of the removed tag but leaves the remaining row at the sorting 2 instead of renumbering it to 1.
TestRelationsTest::removingOneTagRemovesItsMmRowByExtbase (Failure without skip)
Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '1',
   'uid_foreign' => '2',
   'sorting' => '1',
   'sorting_foreign' => '0'
)

Not asserted record found for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '1',
   'uid_foreign' => '2',
   'sorting' => '2',
   'sorting_foreign' => '0'
)

Adding a tag to a translation

Same as core

In 14.3

Core: Tag 1 is set on the German translation 2 of item 1 through DataHandler, as the backend form sends it: the field tags of the translation holds the uid list "1". DataHandler writes the relation row with the uid of the translation, uid_local 2, writes the number of tags, 1, into the translation and leaves the relation row of the default record 1 untouched.

Extbase: Extbase reads item 1 with the language German, adds tag 1 and persists the item with update() and persistAll(). Extbase writes the new relation row with the uid of the translation, uid_local 2, and the number of tags, 1, into the translation, like DataHandler.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:209 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:227 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/AddedTagToTranslation.csv (local)

Reordering tags of a translation

Deviates

In 14.3

Core: The tags of the German translation 2 are sent in the order 2, 1 through DataHandler, as the backend form sends them after the editor moved a tag. DataHandler rewrites the sorting of the relation rows of the translation, uid_local 2, and leaves the relation rows of the default record 1 untouched.

Extbase: Extbase reads item 1 with the language German, detaches both tags, attaches them again in the order 2, 1 and persists the item with update() and persistAll(). Extbase swaps the sorting of the relation rows of the default record 1, uid_local 1, and leaves the relation rows of the translation 2 unchanged, because it updates the relation rows with the uid of the default record.

Target for 15.x

Extbase behaves as the core.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:249 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:267 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/ReorderedTagsOfTranslation.csv (local)
SkipExtbase differs from core: it rewrites the sorting of the relation rows of the default record instead of those of the translation.
TestRelationsTest::reorderingTagsOfATranslationByExtbase (Failure without skip)
Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '1',
   'uid_foreign' => '1',
   'sorting' => '1',
   'sorting_foreign' => '0'
)

Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '1',
   'uid_foreign' => '2',
   'sorting' => '2',
   'sorting_foreign' => '0'
)

Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '2',
   'uid_foreign' => '1',
   'sorting' => '2',
   'sorting_foreign' => '0'
)

Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '2',
   'uid_foreign' => '2',
   'sorting' => '1',
   'sorting_foreign' => '0'
)

Not asserted record found for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '1',
   'uid_foreign' => '1',
   'sorting' => '2',
   'sorting_foreign' => '0'
)

[truncated]

Removing a tag from a translation

Deviates

In 14.3

Core: Only tag 2 is sent for the German translation 2 through DataHandler, as the backend form sends the remaining tags after the editor removed tag 1. DataHandler deletes the relation row of the translation for tag 1, renumbers the remaining row of the translation to the sorting 1, writes the number of tags, 1, into the translation and leaves the relation rows of the default record 1 untouched.

Extbase: Extbase reads item 1 with the language German, removes tag 1 and persists the item with update() and persistAll(). Extbase deletes the relation row of the default record 1 for tag 1 and leaves both relation rows of the translation 2 in place; the field tags of the translation stays 2, because Extbase deletes the relation rows with the uid of the default record.

Target for 15.x

Extbase behaves as the core.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:292 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:310 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/RemovedTagFromTranslation.csv (local)
SkipExtbase differs from core: it deletes the relation row of the default record instead of the row of the translation and leaves the translation with its two tags.
TestRelationsTest::removingATagFromATranslationByExtbase (Failure without skip)
Assertion in data-set failed for "tx_extbasefacts_domain_model_item:2":
Fields|Assertion|Record
tags  |1        |2

Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '1',
   'uid_foreign' => '1',
   'sorting' => '1',
   'sorting_foreign' => '0'
)

Assertion in data-set failed for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '2',
   'uid_foreign' => '2',
   'sorting' => '1',
   'sorting_foreign' => '0'
)

Not asserted record found for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '2',
   'uid_foreign' => '1',
   'sorting' => '1',
   'sorting_foreign' => '0'
)

Not asserted record found for "tx_extbasefacts_item_tag_mm":
array(
   'uid_local' => '2',
   'uid_foreign' => '2',
   'sorting' => '2',
   'sorting_foreign' => '0'
)

Adding inline children keeps their order

Same as core

In 14.3

Core: Two new remarks are sent as inline children of item 1 through DataHandler, as the backend form sends them: the field ordered_notes of the item holds "NEW1,NEW2" and each remark is a NEW record with its pid and the uid of the item in its field item. DataHandler creates both remarks with the uid of item 1, the sorting 1 and 2 (foreign_sortby) and the current time as crdate and tstamp, and writes the number of remarks, 2, into the item.

Extbase: Extbase attaches two new remarks to item 1 and persists the item with update() and persistAll(). Extbase creates both remarks with the uid of item 1, the sorting 1 and 2 and the current time as crdate and tstamp, and writes the number of remarks, 2, into the item, like DataHandler.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:335 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:359 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/AddedRemarks.csv (local)

Reordering inline children

Same as core

In 14.3

Core: The remarks of item 1 are sent in the order 2, 1 through DataHandler, as the backend form sends them after the editor moved a remark: the field ordered_notes holds the uid list "2,1". DataHandler rewrites the sorting of the remarks: remark 2 gets the sorting 1, remark 1 gets the sorting 2. It sets tstamp of both remarks and of the item to the current time.

Extbase: Extbase detaches both remarks from item 1, attaches them again in the order 2, 1 and persists the item with update() and persistAll(). Extbase rewrites the sorting of the remarks like DataHandler, remark 2 gets the sorting 1 and remark 1 the sorting 2, and sets tstamp of both remarks and of the item to the current time.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:381 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:399 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/ReorderedRemarks.csv (local)

Adding a file reference

Same as core

In 14.3

Core: A new reference to the file 1 is sent as the image of item 1 through DataHandler, as the backend form sends it: the field images of the item holds "NEW1" and the reference is a NEW sys_file_reference record with its pid, uid_local 1 and the uid of the item as uid_foreign. DataHandler completes the row with tablenames and fieldname images, the sorting_foreign 1 and the current time as crdate and tstamp, and writes the number of references, 1, into the item.

Extbase: Extbase attaches a new Extbase file reference, built from a core file reference object for the file 1, to item 1 and persists the item with update() and persistAll(). Extbase writes the same sys_file_reference row as DataHandler, with tablenames, fieldname images, sorting_foreign 1 and the current time as crdate and tstamp, and writes the number of references, 1, into the item.

Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:426 (Core) (local)
Testtypo3/sysext/extbase/Tests/Functional/Persistence/Facts/RelationsTest.php:447 (Extbase) (local)
Filetypo3/sysext/extbase/Tests/Functional/Persistence/Facts/Fixtures/Relations/AddedFileReference.csv (local)