Commit 562fc1a5 authored by Sebastian Fischer's avatar Sebastian Fischer Committed by Morton Jonuschat
Browse files

[BUGFIX] isOnSymetricSide must be set by dataprovider

Add a data provider to set isOnSymetricSide on data aggregation
and change all calculations to use the new flag in result array.

Add parent and topmost parent uid, field and table to result
to replace as many InlineStackProcessor calls as possible.

Resolves: #71193
Releases: master
Change-Id: I8d4ec0b2c855cc42b0d03cb34f0b87f5a08a256a
Reviewed-on: https://review.typo3.org/44435

Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: default avatarMorton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: default avatarMorton Jonuschat <m.jonuschat@mojocode.de>
parent e323cd5d
......@@ -486,6 +486,12 @@ class FormInlineAjaxController
{
$parentConfig = $parentData['processedTca']['columns'][$parentFieldName]['config'];
$childTableName = $parentConfig['foreign_table'];
/** @var InlineStackProcessor $inlineStackProcessor */
$inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
$inlineStackProcessor->initializeByGivenStructure($inlineStructure);
$inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
/** @var TcaDatabaseRecord $formDataGroup */
$formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
/** @var FormDataCompiler $formDataCompiler */
......@@ -499,6 +505,17 @@ class FormInlineAjaxController
'inlineFirstPid' => $parentData['inlineFirstPid'],
'inlineParentConfig' => $parentConfig,
'isInlineAjaxOpeningContext' => true,
// values of the current parent element
// it is always a string either an id or new...
'inlineParentUid' => $parentData['databaseRow']['uid'],
'inlineParentTableName' => $parentData['tableName'],
'inlineParentFieldName' => $parentFieldName,
// values of the top most parent element set on first level and not overridden on following levels
'inlineTopMostParentUid' => $parentData['inlineTopMostParentUid'] ?: $inlineTopMostParent['uid'],
'inlineTopMostParentTableName' => $parentData['inlineTopMostParentTableName'] ?: $inlineTopMostParent['table'],
'inlineTopMostParentFieldName' => $parentData['inlineTopMostParentFieldName'] ?: $inlineTopMostParent['field'],
];
// For foreign_selector with useCombination $mainChild is the mm record
// and $combinationChild is the child-child. For "normal" relations, $mainChild
......
......@@ -303,9 +303,8 @@ class InlineRecordContainer extends AbstractContainer
$objectId = $domObjectId . '-' . $foreign_table . '-' . $rec['uid'];
// We need the returnUrl of the main script when loading the fields via AJAX-call (to correct wizard code, so include it as 3rd parameter)
// Pre-Processing:
$isOnSymmetricSide = RelationHandler::isOnSymmetricSide($parentUid, $config, $rec);
$hasForeignLabel = (bool)(!$isOnSymmetricSide && $config['foreign_label']);
$hasSymmetricLabel = (bool)$isOnSymmetricSide && $config['symmetric_label'];
$hasForeignLabel = (bool)(!$data['isOnSymmetricSide'] && $config['foreign_label']);
$hasSymmetricLabel = (bool)$data['isOnSymmetricSide'] && $config['symmetric_label'];
// Get the record title/label for a record:
// Try using a self-defined user function only for formatted labels
......@@ -314,7 +313,7 @@ class InlineRecordContainer extends AbstractContainer
'table' => $foreign_table,
'row' => $rec,
'title' => '',
'isOnSymmetricSide' => $isOnSymmetricSide,
'isOnSymmetricSide' => $data['isOnSymmetricSide'],
'options' => isset($GLOBALS['TCA'][$foreign_table]['ctrl']['formattedLabel_userFunc_options'])
? $GLOBALS['TCA'][$foreign_table]['ctrl']['formattedLabel_userFunc_options']
: array(),
......@@ -432,8 +431,8 @@ class InlineRecordContainer extends AbstractContainer
$tcaTableCols = &$GLOBALS['TCA'][$foreign_table]['columns'];
$isPagesTable = $foreign_table === 'pages';
$isSysFileReferenceTable = $foreign_table === 'sys_file_reference';
$isOnSymmetricSide = RelationHandler::isOnSymmetricSide($parentUid, $config, $rec);
$enableManualSorting = $tcaTableCtrl['sortby'] || $config['MM'] || !$isOnSymmetricSide && $config['foreign_sortby'] || $isOnSymmetricSide && $config['symmetric_sortby'];
$enableManualSorting = $tcaTableCtrl['sortby'] || $config['MM'] || !$data['isOnSymmetricSide']
&& $config['foreign_sortby'] || $data['isOnSymmetricSide'] && $config['symmetric_sortby'];
$nameObject = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
$nameObjectFt = $nameObject . '-' . $foreign_table;
$nameObjectFtId = $nameObjectFt . '-' . $rec['uid'];
......
......@@ -486,7 +486,7 @@ class SingleFieldContainer extends AbstractContainer
// Get the parent record from structure stack
$level = $inlineStackProcessor->getStructureLevel(-1);
// If we have symmetric fields, check on which side we are and hide fields, that are set automatically:
if (RelationHandler::isOnSymmetricSide($level['uid'], $level['config'], $row)) {
if ($this->data['isOnSymmetricSide']) {
$searchArray['%OR']['config'][0]['%AND']['%OR']['symmetric_field'] = $fieldName;
$searchArray['%OR']['config'][0]['%AND']['%OR']['symmetric_sortby'] = $fieldName;
} else {
......
......@@ -564,10 +564,11 @@ abstract class AbstractFormElement extends AbstractNode
/** @var InlineStackProcessor $inlineStackProcessor */
$inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
$inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
$inlineParent = $inlineStackProcessor->getStructureLevel(-1);
$aOnClickInline = '';
if (is_array($inlineParent) && $inlineParent['uid']) {
if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
if ($this->data['isInlineChild'] && $this->data['inlineParentUid']) {
if ($this->data['inlineParentConfig']['foreign_table'] === $table
&& $this->data['inlineParentConfig']['foreign_unique'] === $field
) {
$objectPrefix = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']) . '-' . $table;
$aOnClickInline = $objectPrefix . '|inline.checkUniqueElement|inline.setUniqueElement';
$rOnClickInline = 'inline.revertUnique(' . GeneralUtility::quoteJSvalue($objectPrefix) . ',null,' . GeneralUtility::quoteJSvalue($uid) . ');';
......
......@@ -52,12 +52,13 @@ class SelectSingleElement extends AbstractFormElement
/** @var InlineStackProcessor $inlineStackProcessor */
$inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
$inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
$inlineParent = $inlineStackProcessor->getStructureLevel(-1);
$uniqueIds = null;
if (is_array($inlineParent) && $inlineParent['uid']) {
if ($this->data['isInlineChild'] && $this->data['inlineParentUid']) {
$inlineObjectName = $inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
$inlineFormName = $inlineStackProcessor->getCurrentStructureFormPrefix();
if ($inlineParent['config']['foreign_table'] == $table && $inlineParent['config']['foreign_unique'] == $field) {
if ($this->data['inlineParentConfig']['foreign_table'] === $table
&& $this->data['inlineParentConfig']['foreign_unique'] === $field
) {
$uniqueIds = $this->data['inlineData']['unique'][$inlineObjectName . '-' . $table]['used'];
$parameterArray['fieldChangeFunc']['inlineUnique'] = 'inline.updateUnique(this,'
. GeneralUtility::quoteJSvalue($inlineObjectName . '-' . $table) . ','
......@@ -65,11 +66,13 @@ class SelectSingleElement extends AbstractFormElement
. GeneralUtility::quoteJSvalue($row['uid']) . ');';
}
// hide uid of parent record for symmetric relations
if (
$inlineParent['config']['foreign_table'] == $table
&& ($inlineParent['config']['foreign_field'] == $field || $inlineParent['config']['symmetric_field'] == $field)
if ($this->data['inlineParentConfig']['foreign_table'] === $table
&& (
$this->data['inlineParentConfig']['foreign_field'] === $field
|| $this->data['inlineParentConfig']['symmetric_field'] === $field
)
) {
$uniqueIds[] = $inlineParent['uid'];
$uniqueIds[] = $this->data['inlineParentUid'];
}
}
......
......@@ -207,6 +207,25 @@ class FormDataCompiler
'isInlineChildExpanded' => false,
// Flag if the inline is in an ajax context that wants to expand the element
'isInlineAjaxOpeningContext' => false,
// Uid of the direct parent of the inline element. Handled as string since it may be a "NEW123" string
'inlineParentUid' => '',
// Table name of the direct parent of the inline element
'inlineParentTableName' => '',
// Field name of the direct parent of the inline element
'inlineParentFieldName' => '',
// Uid of the top most parent element. Handled as string since it may be a "NEW123" string
'inlineTopMostParentUid' => '',
// Table name of the top most parent element
'inlineTopMostParentTableName' => '',
// Field name of the top most parent element
'inlineTopMostParentFieldName' => '',
// If is on symetric side of an inline child parent reference.
// symmetric side can be achieved in case of an mm relation to the same table. If record A has a relation
// to record B, the symmetric side is set in case that record B gets edited.
// Record A (table1) <=> mm <=> Record B (table1)
'isOnSymmetricSide' => false,
// Uid of a "child-child" if a new record of an intermediate table is compiled to an existing child. This
// happens if foreign_selector in parent inline config is set. It will be used by default database row
// data providers to set this as value for the foreign_selector field on the intermediate table. One use
......
......@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Database\RelationHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Versioning\VersionState;
use TYPO3\CMS\Backend\Form\InlineStackProcessor;
/**
* Resolve and prepare inline data.
......@@ -258,6 +259,12 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid
{
$parentConfig = $result['processedTca']['columns'][$parentFieldName]['config'];
$childTableName = $parentConfig['foreign_table'];
/** @var InlineStackProcessor $inlineStackProcessor */
$inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
$inlineStackProcessor->initializeByGivenStructure($result['inlineStructure']);
$inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
/** @var TcaDatabaseRecord $formDataGroup */
$formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
/** @var FormDataCompiler $formDataCompiler */
......@@ -271,7 +278,19 @@ class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProvid
'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
'inlineFirstPid' => $result['inlineFirstPid'],
'inlineParentConfig' => $parentConfig,
// values of the current parent element
// it is always a string either an id or new...
'inlineParentUid' => $result['databaseRow']['uid'],
'inlineParentTableName' => $result['tableName'],
'inlineParentFieldName' => $parentFieldName,
// values of the top most parent element set on first level and not overridden on following levels
'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: $inlineTopMostParent['uid'],
'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: $inlineTopMostParent['table'],
'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: $inlineTopMostParent['field'],
];
// For foreign_selector with useCombination $mainChild is the mm record
// and $combinationChild is the child-child. For "normal" relations, $mainChild
// is just the normal child record and $combinationChild is empty.
......
<?php
namespace TYPO3\CMS\Backend\Form\FormDataProvider;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
use TYPO3\CMS\Core\Utility\MathUtility;
/**
* Determine the wether the child is on symmetric side or not.
*
* TCA ctrl fields like label and label_alt are evaluated and their
* current values from databaseRow used to create the title.
*/
class TcaInlineIsOnSymmetricSide implements FormDataProviderInterface
{
/**
* Enrich the processed record information with the resolved title
*
* @param array $result Incoming result array
* @return array Modified array
*/
public function addData(array $result)
{
if (!$result['isInlineChild']) {
return $result;
}
$result['isOnSymmetricSide'] = MathUtility::canBeInterpretedAsInteger($result['databaseRow']['uid'])
&& $result['inlineParentConfig']['symmetric_field']
// non-strict comparison by intention
&& $result['inlineParentUid'] == $result['databaseRow'][$result['inlineParentConfig']['symmetric_field']][0];
return $result;
}
}
<?php
namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Backend\Form\FormDataProvider\TcaInlineIsOnSymmetricSide;
use TYPO3\CMS\Core\Tests\UnitTestCase;
/**
* Test case
*/
class TcaInlineIsOnSymmetricSideTest extends UnitTestCase
{
/**
* @var TcaInlineIsOnSymmetricSide
*/
protected $subject;
/**
* Initializes the mock object.
*/
public function setUp()
{
$this->subject = new TcaInlineIsOnSymmetricSide();
}
/**
* @test
*/
public function addDataSetsIsOnSymmetricSideToTrue()
{
$input = [
'databaseRow' => [
'uid' => 5,
'theSymmetricField' => [
23,
],
],
'isInlineChild' => true,
'inlineParentUid' => 23,
'inlineParentConfig' => [
'symmetric_field' => 'theSymmetricField',
],
];
$expected = $input;
$expected['isOnSymmetricSide'] = true;
$this->assertEquals($expected, $this->subject->addData($input));
}
}
......@@ -513,9 +513,15 @@ return array(
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaInlineConfiguration::class,
),
),
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaInlineIsOnSymmetricSide::class => array(
'depends' => array(
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders::class,
),
),
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaRecordTitle::class => array(
'depends' => array(
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaInline::class,
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaInlineIsOnSymmetricSide::class,
),
),
\TYPO3\CMS\Backend\Form\FormDataProvider\EvaluateDisplayConditions::class => array(
......
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