Commit e5dbc1e7 authored by Christian Kuhn's avatar Christian Kuhn Committed by Benni Mack
Browse files

[BUGFIX] No MM relations when localizing categories

"True" MM relations (those tables that have a "uid_local"
and "uid_foreign" db column and NO TCA) have a "local" and
a "foreign" side. For instance with categories, the category
table is the "local" side, and the referencing table "pages",
"tt_content", or whatever table, is the foreign side.

Without the patch, MM table rows when localizing the local
side of an MM relation is buggy, scenario:

A default language tt_content record references
a default language category. This gives one row in the mm
table. If now the category is localized, a second entry
from the localized category to the default language content
element is added. This is wrong.

The patch fixes this in the DataHandler by setting a
dedicated override for this "local side localization" scenario,
so the RelationHandler omits MM processing in this case. A
functional test is added for non-workspace that exists
for workspace already to verify a new relation can still
be added when creating the local side.

Note this is only half of the picture - MM relation should
still be set and updated when a localized foreign side exists
for the just localized local side. This does not happen
currently and leads to broken MM rows even with the patch. This
scenario however needs a bigger refactoring and further
increased coverage and will be handled with further patches.

Still, this patch is relatively straight forward, increases
test coverage for future patches and already solves various
long standing forge issues.

Change-Id: Ieee8b5a4c101065c03bc7e90c8a4aa36b1bdf6a7
Resolves: #89659
Resolves: #89620
Resolves: #91842
Resolves: #77902
Related: #70460
Related: #62727
Releases: master
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/71094

Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Jochen's avatarJochen <rothjochen@gmail.com>
Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Jochen's avatarJochen <rothjochen@gmail.com>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent a034c620
......@@ -4583,6 +4583,12 @@ class DataHandler implements LoggerAwareInterface
}
}
}
if (($fCfg['config']['MM'] ?? false) && !empty($fCfg['config']['MM_oppositeUsage'])) {
// We are localizing the 'local' side of an MM relation. (eg. localizing a category).
// In this case, MM relations connected to the default lang record should not be copied,
// so we set an override here to not trigger mm handling of 'items' field for this.
$overrideValues[$fN] = 0;
}
}
if ($table !== 'pages') {
......
......@@ -66,6 +66,16 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
);
}
public function createCategoryAndAddRelation()
{
$newTableIds = $this->actionService->createNewRecord(
self::TABLE_Category,
0,
['title' => 'Testing #1', 'items' => 'tt_content_' . self::VALUE_ContentIdFirst]
);
$this->recordIds['newCategoryId'] = $newTableIds[self::TABLE_Category][0];
}
public function deleteCategoryRelation()
{
$this->actionService->modifyReferences(
......@@ -126,6 +136,7 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
/**
* See DataSet/copyContentToLanguageOfRelation.csv
* @todo: does not exist in workspaces
*/
public function copyContentToLanguageOfRelation()
{
......@@ -134,6 +145,7 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
/**
* See DataSet/copyCategoryToLanguageOfRelation.csv
* @todo: does not exist in workspaces
*/
public function copyCategoryToLanguageOfRelation()
{
......@@ -146,6 +158,9 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
$this->recordIds['localizedContentId'] = $localizedTableIds[self::TABLE_Content][self::VALUE_ContentIdLast];
}
/**
* @todo: does not exist in workspaces
*/
public function localizeContentOfRelationWithLanguageSynchronization()
{
$GLOBALS['TCA'][self::TABLE_Content]['columns'][self::FIELD_Categories]['config']['behaviour']['allowLanguageSynchronization'] = true;
......@@ -153,6 +168,9 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
$this->recordIds['localizedContentId'] = $localizedTableIds[self::TABLE_Content][self::VALUE_ContentIdLast];
}
/**
* @todo: does not exist in workspaces
*/
public function localizeContentOfRelationAndAddCategoryWithLanguageSynchronization()
{
self::localizeContentOfRelationWithLanguageSynchronization();
......@@ -164,6 +182,9 @@ abstract class AbstractActionTestCase extends AbstractDataHandlerActionTestCase
);
}
/**
* @todo: does not exist in workspaces
*/
public function localizeContentChainOfRelationAndAddCategoryWithLanguageSynchronization()
{
self::localizeContentOfRelationWithLanguageSynchronization();
......
......@@ -56,6 +56,21 @@ class ActionTest extends AbstractActionTestCase
->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B', 'Category A.A'));
}
/**
* @test
*/
public function createCategoryAndAddRelation()
{
parent::createCategoryAndAddRelation();
$this->assertAssertionDataSet('createCategoryAndAddRelation');
$response = $this->executeFrontendSubRequest((new InternalRequest())->withPageId(self::VALUE_PageId));
$responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B', 'Testing #1'));
}
/**
* @test
* See DataSet/deleteCategoryRelation.csv
......@@ -195,12 +210,6 @@ class ActionTest extends AbstractActionTestCase
{
parent::copyCategoryOfRelation();
$this->assertAssertionDataSet('copyCategoryOfRelation');
$response = $this->executeFrontendSubRequest((new InternalRequest())->withPageId(self::VALUE_PageId));
$responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category A (copy 1)'));
}
/**
......
......@@ -14,14 +14,13 @@
,29,0,512,0,0,0,0,0,0,0,0,"Category B",0,0
,30,0,768,0,0,0,0,0,0,0,0,"Category C",0,0
,31,0,1024,0,0,0,0,0,0,0,0,"Category A.A",28,0
,32,0,384,0,1,0,28,0,0,0,0,"[Translate to Dansk:] Category A",0,1
,32,0,384,0,1,0,28,0,0,0,0,"[Translate to Dansk:] Category A",0,0
"sys_category_record_mm",,,,,,,,,,,,,,
,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,
,28,297,"tt_content",0,1,"categories",,,,,,,,
,29,297,"tt_content",0,2,"categories",,,,,,,,
,29,298,"tt_content",0,1,"categories",,,,,,,,
,30,298,"tt_content",0,2,"categories",,,,,,,,
,32,297,"tt_content",1,0,"categories",,,,,,,,
"tt_content",,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories"
,297,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",0,2
......@@ -33,4 +32,3 @@
,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,
,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,
,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,
,"f80e9fad5422a2c5d2b73765108d053a","sys_category",32,"items",,,,0,0,"tt_content",297,,,
"pages",,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title",,,,
,1,0,256,0,0,0,0,0,0,"FunctionalTest",,,,
,88,1,256,0,0,0,0,0,0,"DataHandlerTest",,,,
,89,88,256,0,0,0,0,0,0,"Relations",,,,
,90,88,512,0,0,0,0,0,0,"Target",,,,
"sys_language",,,,,,,,,,,,,,
,"uid","pid","hidden","title","flag",,,,,,,,,
,1,0,0,"Dansk","dk",,,,,,,,,
,2,0,0,"Deutsch","de",,,,,,,,,
"sys_category",,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l10n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parent","items"
,28,0,256,0,0,0,0,0,0,0,0,"Category A",0,0
,29,0,512,0,0,0,0,0,0,0,0,"Category B",0,0
,30,0,768,0,0,0,0,0,0,0,0,"Category C",0,0
,31,0,1024,0,0,0,0,0,0,0,0,"Category A.A",28,0
,32,0,128,0,0,0,0,0,0,0,0,"Testing #1",0,1
"sys_category_record_mm",,,,,,,,,,,,,,
,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,
,28,297,"tt_content",0,1,"categories",,,,,,,,
,29,297,"tt_content",0,2,"categories",,,,,,,,
,29,298,"tt_content",0,1,"categories",,,,,,,,
,30,298,"tt_content",0,2,"categories",,,,,,,,
,32,297,"tt_content",1,0,"categories",,,,,,,,
"tt_content",,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories"
# @todo: "categories" is still 2 but should be 3
,297,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",0,2
,298,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",0,2
"sys_refindex",,,,,,,,,,,,,,
,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,
,"3c637501ab9c158daa933643bff8cc43","sys_category",28,"items",,,,0,0,"tt_content",297,,,
,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,
,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,
,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,
,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,
,"f80e9fad5422a2c5d2b73765108d053a","sys_category",32,"items",,,,0,0,"tt_content",297,,,
......@@ -15,14 +15,13 @@
,29,0,512,0,0,0,0,0,0,0,0,"Category B",0,0
,30,0,768,0,0,0,0,0,0,0,0,"Category C",0,0
,31,0,1024,0,0,0,0,0,0,0,0,"Category A.A",28,0
,32,0,384,0,1,28,28,0,0,0,0,"[Translate to Dansk:] Category A",0,1
,32,0,384,0,1,28,28,0,0,0,0,"[Translate to Dansk:] Category A",0,0
"sys_category_record_mm",,,,,,,,,,,,,,
,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,
,28,297,"tt_content",0,1,"categories",,,,,,,,
,29,297,"tt_content",0,2,"categories",,,,,,,,
,29,298,"tt_content",0,1,"categories",,,,,,,,
,30,298,"tt_content",0,2,"categories",,,,,,,,
,32,297,"tt_content",1,0,"categories",,,,,,,,
"tt_content",,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories"
,297,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",0,2
......@@ -36,4 +35,3 @@
,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,
,"583b9974d1df1d9efb695cdabfe53a73","pages",91,"l10n_parent",,,,0,0,"pages",89,,,
,"6353f17422ca9ee8ea9f0b18d2b233ce","sys_category",32,"l10n_parent",,,,0,0,"sys_category",28,,,
,"f80e9fad5422a2c5d2b73765108d053a","sys_category",32,"items",,,,0,0,"tt_content",297,,,
......@@ -51,16 +51,6 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
$this->recordIds['newContentId'] = $newTableIds[self::TABLE_Content][0];
}
public function createCategoryAndAddRelation()
{
$newTableIds = $this->actionService->createNewRecord(
self::TABLE_Category,
0,
['title' => 'Testing #1', 'items' => 'tt_content_' . self::VALUE_ContentIdFirst]
);
$this->recordIds['newCategoryId'] = $newTableIds[self::TABLE_Category][0];
}
public function createContentAndCreateRelation()
{
$newTableIds = $this->actionService->createNewRecords(
......
......@@ -22,14 +22,13 @@
,29,0,512,0,0,0,0,0,0,0,"Category B",0,0,,,,
,30,0,768,0,0,0,0,0,0,0,"Category C",0,0,,,,
,31,0,1024,0,0,0,0,0,0,0,"Category A.A",28,0,,,,
,32,0,384,0,1,28,1,1,0,0,"[Translate to Dansk:] Category A",0,1,,,,
,32,0,384,0,1,28,1,1,0,0,"[Translate to Dansk:] Category A",0,0,,,,
"sys_category_record_mm",,,,,,,,,,,,,,,,,
,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,,,,
,28,297,"tt_content",0,1,"categories",,,,,,,,,,,
,29,297,"tt_content",0,2,"categories",,,,,,,,,,,
,29,298,"tt_content",0,1,"categories",,,,,,,,,,,
,30,298,"tt_content",0,2,"categories",,,,,,,,,,,
,32,297,"tt_content",1,0,"categories",,,,,,,,,,,
"tt_content",,,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories",,,,
,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",0,2,,,,
......@@ -44,5 +43,4 @@
,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
,"b49c6be1e8bc66be2da51750dbd56d13","sys_category",32,"l10n_parent",,,,0,1,"sys_category",28,,,,,,
,"cbf63549963077818db9099164f2798d","sys_category",32,"items",,,,0,1,"tt_content",297,,,,,,
,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
......@@ -22,14 +22,13 @@
,29,0,512,0,0,0,0,0,0,0,"Category B",0,0,,,,
,30,0,768,0,0,0,0,0,0,0,"Category C",0,0,,,,
,31,0,1024,0,0,0,0,0,0,0,"Category A.A",28,0,,,,
,32,0,384,0,1,28,0,0,0,0,"[Translate to Dansk:] Category A",0,1,,,,
,32,0,384,0,1,28,0,0,0,0,"[Translate to Dansk:] Category A",0,0,,,,
"sys_category_record_mm",,,,,,,,,,,,,,,,,
,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,,,,
,28,297,"tt_content",0,1,"categories",,,,,,,,,,,
,29,297,"tt_content",0,2,"categories",,,,,,,,,,,
,29,298,"tt_content",0,1,"categories",,,,,,,,,,,
,30,298,"tt_content",0,2,"categories",,,,,,,,,,,
,32,297,"tt_content",1,0,"categories",,,,,,,,,,,
"tt_content",,,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories",,,,
,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",0,2,,,,
......@@ -45,4 +44,3 @@
,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
,"f80e9fad5422a2c5d2b73765108d053a","sys_category",32,"items",,,,0,0,"tt_content",297,,,,,,
......@@ -22,14 +22,13 @@
,29,0,512,0,0,0,0,0,0,0,"Category B",0,0,,,,
,30,0,768,0,0,0,0,0,0,0,"Category C",0,0,,,,
,31,0,1024,0,0,0,0,0,0,0,"Category A.A",28,0,,,,
,32,0,384,0,1,28,0,0,0,0,"[Translate to Dansk:] Category A",0,1,,,,
,32,0,384,0,1,28,0,0,0,0,"[Translate to Dansk:] Category A",0,0,,,,
"sys_category_record_mm",,,,,,,,,,,,,,,,,
,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,,,,
,28,297,"tt_content",0,1,"categories",,,,,,,,,,,
,29,297,"tt_content",0,2,"categories",,,,,,,,,,,
,29,298,"tt_content",0,1,"categories",,,,,,,,,,,
,30,298,"tt_content",0,2,"categories",,,,,,,,,,,
,32,297,"tt_content",1,0,"categories",,,,,,,,,,,
"tt_content",,,,,,,,,,,,,,,,,
,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories",,,,
,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",0,2,,,,
......@@ -45,4 +44,3 @@
,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
,"f80e9fad5422a2c5d2b73765108d053a","sys_category",32,"items",,,,0,0,"tt_content",297,,,,,,
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment