Commit b05e119b authored by Oliver Hader's avatar Oliver Hader Committed by Georg Ringer
Browse files

[BUGFIX] allowLanguageSynchronization fails for 2nd level translations

2nd level translations are not considered yet with the feature to
synchronize languages either from parent or source language records.
This change modifies the creation of the language state as well as
switches "custom" states to "source" states of a new second level
translation is being created.

Resolves: #79755
Releases: master
Change-Id: I860d87a1b305966a9caa5cbd17bc5bf7229f5704
Reviewed-on: https://review.typo3.org/51644


Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: Susanne Moog's avatarSusanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog's avatarSusanne Moog <susanne.moog@typo3.org>
Reviewed-by: Georg Ringer's avatarGeorg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer's avatarGeorg Ringer <georg.ringer@gmail.com>
parent cd1f5284
......@@ -53,7 +53,7 @@ class LocalizationStateSelector extends AbstractNode
$sourceLanguageTitle = '';
$fieldValueInParentRow = '';
$fieldValueInSourceRow = '';
$fieldValueInSourceRow = null;
if ($l10nParentFieldName && $this->data['databaseRow'][$l10nParentFieldName] > 0) {
if ($l10nSourceFieldName && $this->data['databaseRow'][$l10nSourceFieldName] > 0) {
$languageField = $this->data['processedTca']['ctrl']['languageField'] ?? null;
......@@ -111,7 +111,7 @@ class LocalizationStateSelector extends AbstractNode
$html[] = $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:localizationStateSelector.defaultLanguageValue');
$html[] = '</label>';
$html[] = '</div>';
if ($fieldValueInSourceRow) {
if ($fieldValueInSourceRow !== null) {
$html[] = '<div class="radio radio-inline">';
$html[] = '<label>';
$html[] = '<input';
......
......@@ -312,13 +312,7 @@ class DataMapItem
public function getState(): State
{
if ($this->state === null && !$this->isParentType()) {
$this->state = State::fromJSON(
$this->tableName,
$this->persistedValues['l10n_state'] ?? null
);
$this->state->update(
$this->suggestedValues['l10n_state'] ?? []
);
$this->state = $this->buildState();
}
return $this->state;
}
......@@ -427,4 +421,38 @@ class DataMapItem
$scopes[] = static::SCOPE_EXCLUDE;
return $scopes;
}
/**
* @return null|State
*/
protected function buildState()
{
// build from persisted states
if (!$this->isNew()) {
$state = State::fromJSON(
$this->tableName,
$this->persistedValues['l10n_state'] ?? null
);
// use provided states for a new and copied element
} elseif (is_string($this->suggestedValues['l10n_state'] ?? null)) {
$state = State::fromJSON(
$this->tableName,
$this->suggestedValues['l10n_state']
);
// provide the default states
} else {
$state = State::create($this->tableName);
}
// switch "custom" to "source" state for 2nd level translations
if ($this->isNew() && $this->isGrandChildType()) {
$state->updateStates(State::STATE_CUSTOM, State::STATE_SOURCE);
}
// apply any provided updates to the states
if (is_array($this->suggestedValues['l10n_state'] ?? null)) {
$state->update(
$this->suggestedValues['l10n_state'] ?? []
);
}
return $state;
}
}
......@@ -92,8 +92,10 @@ class DataMapProcessor
foreach ($this->dataMap as $tableName => $idValues) {
$this->collectItems($tableName, $idValues);
}
$this->sanitize();
$this->enrich();
if (!empty($this->items)) {
$this->sanitize();
$this->enrich();
}
return $this->dataMap;
}
......@@ -488,10 +490,10 @@ class DataMapProcessor
$localDataHandler->process_cmdmap();
// update copied or localized ids
foreach ($createAncestorIds as $createAncestorId) {
if (empty($localDataHandler->copyMappingArray[$foreignTableName][$createAncestorId])) {
if (empty($localDataHandler->copyMappingArray_merged[$foreignTableName][$createAncestorId])) {
throw new \RuntimeException('Child record was not processed', 1486233164);
}
$newLocalizationId = $localDataHandler->copyMappingArray[$foreignTableName][$createAncestorId];
$newLocalizationId = $localDataHandler->copyMappingArray_merged[$foreignTableName][$createAncestorId];
$newLocalizationId = $localDataHandler->getAutoVersionId($foreignTableName, $newLocalizationId) ?? $newLocalizationId;
$desiredLocalizationIdMap[$createAncestorId] = $newLocalizationId;
}
......@@ -597,6 +599,7 @@ class DataMapProcessor
$dependencyMap[$dependentItem->getParent()][State::STATE_PARENT][] = $dependentItem;
}
if ($dependentItem->isGrandChildType()) {
$dependencyMap[$dependentItem->getParent()][State::STATE_PARENT][] = $dependentItem;
$dependencyMap[$dependentItem->getSource()][State::STATE_SOURCE][] = $dependentItem;
}
}
......@@ -665,20 +668,21 @@ class DataMapProcessor
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$zeroParameter = $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT);
$idsParameter = $queryBuilder->createNamedParameter($ids, Connection::PARAM_INT_ARRAY);
$predicates = [
$queryBuilder->expr()->in(
$fieldNames['parent'],
$queryBuilder->createNamedParameter($ids, Connection::PARAM_INT_ARRAY)
$idsParameter
)
];
if (!empty($fieldNames['source'])) {
$predicates = [
$queryBuilder->expr()->in(
$fieldNames['source'],
$queryBuilder->createNamedParameter($ids, Connection::PARAM_INT_ARRAY)
)
];
$predicates[] = $queryBuilder->expr()->in(
$fieldNames['source'],
$idsParameter
);
}
$statement = $queryBuilder
......@@ -688,12 +692,12 @@ class DataMapProcessor
// must be any kind of localization
$queryBuilder->expr()->gt(
$fieldNames['language'],
$queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
$zeroParameter
),
// must be in connected mode
$queryBuilder->expr()->gt(
$fieldNames['parent'],
$queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
$zeroParameter
),
// any parent or source pointers
$queryBuilder->expr()->orX(...$predicates)
......
......@@ -163,6 +163,23 @@ class State
);
}
/**
* Updates field names having a particular state to a target state.
*
* @param string $currentState
* @param string $targetState
*/
public function updateStates(string $currentState, string $targetState)
{
$states = [];
foreach ($this->filterFieldNames($currentState) as $fieldName) {
$states[$fieldName] = $targetState;
}
if (!empty($states)) {
$this->update($states);
}
}
/**
* @return string|null
*/
......
......@@ -134,13 +134,15 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
*/
public function localizeContent()
{
$this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdSecond, self::VALUE_LanguageId);
$localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdSecond, self::VALUE_LanguageId);
$this->recordIds['localizedContentId'] = $localizedTableIds[self::TABLE_Content][self::VALUE_ContentIdSecond];
}
public function localizeContentWithLanguageSynchronization()
{
$GLOBALS['TCA']['tt_content']['columns']['header']['config']['behaviour']['allowLanguageSynchronization'] = true;
$this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdSecond, self::VALUE_LanguageId);
$localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdSecond, self::VALUE_LanguageId);
$this->recordIds['localizedContentId'] = $localizedTableIds[self::TABLE_Content][self::VALUE_ContentIdSecond];
$this->actionService->modifyRecord(self::TABLE_Content, self::VALUE_ContentIdSecond, ['header' => 'Testing #1']);
}
......@@ -150,7 +152,16 @@ abstract class AbstractActionTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
*/
public function localizeContentFromNonDefaultLanguage()
{
$this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdThirdLocalized, self::VALUE_LanguageIdSecond);
$localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdThirdLocalized, self::VALUE_LanguageIdSecond);
$this->recordIds['localizedContentId'] = $localizedTableIds[self::TABLE_Content][self::VALUE_ContentIdThirdLocalized];
}
public function localizeContentFromNonDefaultLanguageWithLanguageSynchronizationDefault()
{
$GLOBALS['TCA']['tt_content']['columns']['header']['config']['behaviour']['allowLanguageSynchronization'] = true;
$localizedTableIds = $this->actionService->localizeRecord(self::TABLE_Content, self::VALUE_ContentIdThirdLocalized, self::VALUE_LanguageIdSecond);
$this->recordIds['localizedContentId'] = $localizedTableIds[self::TABLE_Content][self::VALUE_ContentIdThirdLocalized];
$this->actionService->modifyRecord(self::TABLE_Content, self::VALUE_ContentIdThird, ['header' => 'Testing #1']);
}
/**
......
......@@ -193,6 +193,21 @@ class ActionTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\Regular\A
->setTable(self::TABLE_Content)->setField('header')->setValues('[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', '[Translate to Deutsch:] [Translate to Dansk:] Regular Element #3'));
}
/**
* @test
* @see DataSet/localizeContentFromNonDefaultLanguageWSynchronizationDefault.csv
*/
public function localizeContentFromNonDefaultLanguageWithLanguageSynchronizationDefault()
{
parent::localizeContentFromNonDefaultLanguageWithLanguageSynchronizationDefault();
$this->assertAssertionDataSet('localizeContentFromNonDefaultLanguageWSynchronizationDefault');
$responseSections = $this->getFrontendResponse(self::VALUE_PageId, self::VALUE_LanguageIdSecond)->getResponseSections();
$this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
->setTable(self::TABLE_Content)->setField('header')->setValues('[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Testing #1'));
}
/**
* @test
* @see DataSet/changeContentRecordSorting.csv
......
tt_content,,,,,,,,,,,,,,
,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l10n_source,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header,l10n_state
,297,89,256,0,0,0,0,0,0,0,0,0,0,Regular Element #1,
,298,89,512,0,0,0,0,0,0,0,0,0,0,Regular Element #2,
,299,89,768,0,0,0,0,0,0,0,0,0,0,Testing #1,
,300,89,1024,0,1,299,299,299,0,0,0,0,0,Testing #1,\NULL
,301,89,384,0,1,297,297,297,0,0,0,0,0,[Translate to Dansk:] Regular Element #1,
,302,89,448,0,2,297,301,301,0,0,0,0,0,[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1,
,303,89,1280,0,2,299,300,300,0,0,0,0,0,Testing #1,"{""header"":""parent""}"
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