From 515f49224004a70a6754906b14e89b29f956e903 Mon Sep 17 00:00:00 2001 From: Achim Fritz Date: Tue, 15 Sep 2020 15:07:47 +0200 Subject: [PATCH] [BUGFIX] moved records Resolves: #83 --- Classes/DataProcessing/ContainerProcessor.php | 6 +- Classes/Domain/Factory/ContainerFactory.php | 49 +-- Classes/Domain/Factory/Database.php | 75 +++- Classes/Hooks/Datahandler/Database.php | 23 ++ .../DatamapAfterDatabaseOperationHook.php | 35 +- .../Datahandler/Workspace/ContainerTest.php | 333 ++++++++++++++++++ .../Domain/Factory/ContainerFactoryTest.php | 85 +++++ .../Fixture/copiedChildrenInWorkspace.xml | 37 ++ .../Fixture/movedChildrenInWorkspaceAjax.xml | 28 ++ .../movedChildrenInWorkspaceClipboard.xml | 37 ++ ...ovedChildrenInWorkspaceWithTranslation.xml | 67 ++++ 11 files changed, 726 insertions(+), 49 deletions(-) create mode 100644 Tests/Functional/Domain/Factory/Fixture/copiedChildrenInWorkspace.xml create mode 100644 Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceAjax.xml create mode 100644 Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceClipboard.xml create mode 100644 Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceWithTranslation.xml diff --git a/Classes/DataProcessing/ContainerProcessor.php b/Classes/DataProcessing/ContainerProcessor.php index 242816df..2e8d87a2 100644 --- a/Classes/DataProcessing/ContainerProcessor.php +++ b/Classes/DataProcessing/ContainerProcessor.php @@ -110,11 +110,7 @@ protected function processColPos( 'tables' => 'tt_content' ]; foreach ($children as &$child) { - if ($child['t3ver_oid'] > 0) { - $conf['source'] = $child['t3ver_oid']; - } else { - $conf['source'] = $child['uid']; - } + $conf['source'] = $child['uid']; $child['renderedContent'] = $cObj->render($contentRecordRenderer, $conf); } $processedData[$as] = $children; diff --git a/Classes/Domain/Factory/ContainerFactory.php b/Classes/Domain/Factory/ContainerFactory.php index 325a1832..eb12597c 100644 --- a/Classes/Domain/Factory/ContainerFactory.php +++ b/Classes/Domain/Factory/ContainerFactory.php @@ -32,14 +32,18 @@ class ContainerFactory implements SingletonInterface protected $tcaRegistry; /** - * ContainerFactory constructor. - * @param Database|null $database - * @param Registry|null $tcaRegistry + * @var int */ - public function __construct(Database $database = null, Registry $tcaRegistry = null) + protected $workspaceId = 0; + + public function __construct(Database $database = null, Registry $tcaRegistry = null, Context $context = null) { $this->database = $database ?? GeneralUtility::makeInstance(Database::class); $this->tcaRegistry = $tcaRegistry ?? GeneralUtility::makeInstance(Registry::class); + if ($context === null) { + $context = GeneralUtility::makeInstance(Context::class); + } + $this->workspaceId = (int)$context->getPropertyFromAspect('workspace', 'id'); } /** @@ -77,6 +81,7 @@ public function buildContainer(int $uid): Container } else { // connected mode $defaultRecords = $this->database->fetchRecordsByParentAndLanguage($defaultRecord['uid'], 0); + $defaultRecords = $this->doWorkspaceOverlay($defaultRecords); $localizedRecords = $this->database->fetchOverlayRecords($defaultRecords, $language); $childRecords = $this->sortLocalizedRecordsByDefaultRecords($defaultRecords, $localizedRecords); } @@ -100,24 +105,20 @@ public function buildContainer(int $uid): Container */ protected function doWorkspaceOverlay(array $defaultRecords): array { - $workspaceId = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('workspace', 'id'); - if ($workspaceId > 0) { - $workspaceRecords = $this->database->fetchWorkspaceRecords($defaultRecords, $workspaceId); - $overlayed = []; + if (empty($defaultRecords)) { + return []; + } + if ($this->workspaceId > 0) { + $filtered = []; + $uidsHavingWorkspaceVersion = $this->database->fetchUidsHavingWorkspaceVersion($defaultRecords, $this->workspaceId); foreach ($defaultRecords as $defaultRecord) { - $foundOverlay = null; - foreach ($workspaceRecords as $workspaceRecord) { - if ($workspaceRecord['t3ver_oid'] === $defaultRecord['uid']) { - $foundOverlay = $workspaceRecord; - } - } - if ($foundOverlay !== null) { - $overlayed[] = $foundOverlay; - } else { - $overlayed[] = $defaultRecord; + if ($defaultRecord['t3ver_wsid'] === $this->workspaceId) { + $filtered[] = $defaultRecord; + } elseif (in_array($defaultRecord['uid'], $uidsHavingWorkspaceVersion, true) === false) { + $filtered[] = $defaultRecord; } } - return $overlayed; + return $filtered; } // filter workspace placeholders $filtered = []; @@ -164,6 +165,7 @@ protected function buildContainerWithOverlay(int $uid, LanguageAspect $languageA // connected mode $childRecords = $this->database->fetchRecordsByParentAndLanguage($defaultRecord['uid'], 0); if ($languageAspect->doOverlays()) { + $childRecords = $this->doWorkspaceOverlay($childRecords); $childRecordsOverlays = $this->database->fetchOverlayRecords($childRecords, $language); $childRecords = $this->doOverlay($childRecords, $childRecordsOverlays); } @@ -171,6 +173,7 @@ protected function buildContainerWithOverlay(int $uid, LanguageAspect $languageA } else { $childRecords = $this->database->fetchRecordsByParentAndLanguage($record['uid'], 0); if ($languageAspect->doOverlays()) { + $childRecords = $this->doWorkspaceOverlay($childRecords); $childRecordsOverlays = $this->database->fetchOverlayRecords($childRecords, $language); $childRecords = $this->doOverlay($childRecords, $childRecordsOverlays); } @@ -196,7 +199,9 @@ protected function sortLocalizedRecordsByDefaultRecords(array $defaultRecords, a $sorted = []; foreach ($defaultRecords as $defaultRecord) { foreach ($localizedRecords as $localizedRecord) { - if ($localizedRecord['l18n_parent'] === $defaultRecord['uid']) { + if ($localizedRecord['l18n_parent'] === $defaultRecord['uid'] || + $localizedRecord['l18n_parent'] === $defaultRecord['t3ver_oid'] + ) { $sorted[] = $localizedRecord; } } @@ -215,7 +220,9 @@ protected function doOverlay(array $defaultRecords, array $localizedRecords): ar foreach ($defaultRecords as $defaultRecord) { $foundOverlay = null; foreach ($localizedRecords as $localizedRecord) { - if ($localizedRecord['l18n_parent'] === $defaultRecord['uid']) { + if ($localizedRecord['l18n_parent'] === $defaultRecord['uid'] || + $localizedRecord['l18n_parent'] === $defaultRecord['t3ver_oid'] + ) { $foundOverlay = $localizedRecord; } } diff --git a/Classes/Domain/Factory/Database.php b/Classes/Domain/Factory/Database.php index 5f1bc047..bef7d445 100644 --- a/Classes/Domain/Factory/Database.php +++ b/Classes/Domain/Factory/Database.php @@ -12,16 +12,37 @@ * of the License, or any later version. */ +use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\QueryBuilder; use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer; +use TYPO3\CMS\Core\Database\Query\Restriction\FrontendWorkspaceRestriction; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Versioning\VersionState; class Database implements SingletonInterface { + /** + * @var int + */ + protected $backendUserId = 0; + + /** + * @var int + */ + protected $workspaceId = 0; + + public function __construct(Context $context = null) + { + if ($context === null) { + $context = GeneralUtility::makeInstance(Context::class); + } + $this->backendUserId = (int)$context->getPropertyFromAspect('backend.user', 'id', 0); + $this->workspaceId = (int)$context->getPropertyFromAspect('workspace', 'id'); + } /** * @return QueryBuilder @@ -31,8 +52,11 @@ protected function getQueryBuilder(): QueryBuilder $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content'); if (TYPO3_MODE === 'BE') { $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class)); - } else { + } elseif (TYPO3_MODE === 'FE') { $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class)); + if ($this->backendUserId > 0) { + $queryBuilder->getRestrictions()->removeByType(FrontendWorkspaceRestriction::class); + } } return $queryBuilder; } @@ -91,7 +115,8 @@ public function fetchOneDefaultRecord(array $record): ?array public function fetchRecordsByParentAndLanguage(int $parent, int $language): array { $queryBuilder = $this->getQueryBuilder(); - $records = (array)$queryBuilder->select('*') + + return (array)$queryBuilder->select('*') ->from('tt_content') ->where( $queryBuilder->expr()->eq( @@ -102,15 +127,21 @@ public function fetchRecordsByParentAndLanguage(int $parent, int $language): arr 'sys_language_uid', $queryBuilder->createNamedParameter($language, \PDO::PARAM_INT) ), - $queryBuilder->expr()->eq( - 't3ver_oid', - $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + $queryBuilder->expr()->notIn( + 't3ver_state', + $queryBuilder->createNamedParameter( + [VersionState::NEW_PLACEHOLDER, VersionState::MOVE_PLACEHOLDER], + Connection::PARAM_INT_ARRAY + ) + ), + $queryBuilder->expr()->in( + 't3ver_wsid', + $queryBuilder->createNamedParameter([0, $this->workspaceId], Connection::PARAM_INT_ARRAY) ) ) ->orderBy('sorting', 'ASC') ->execute() ->fetchAll(); - return $records; } /** @@ -123,6 +154,9 @@ public function fetchOverlayRecords(array $records, int $language): array $uids = []; foreach ($records as $record) { $uids[] = $record['uid']; + if ($record['t3ver_oid'] > 0) { + $uids[] = $record['t3ver_oid']; + } } $queryBuilder = $this->getQueryBuilder(); $records = (array)$queryBuilder->select('*') @@ -136,30 +170,34 @@ public function fetchOverlayRecords(array $records, int $language): array 'sys_language_uid', $queryBuilder->createNamedParameter($language, \PDO::PARAM_INT) ), - $queryBuilder->expr()->eq( - 't3ver_oid', - $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + $queryBuilder->expr()->notIn( + 't3ver_state', + $queryBuilder->createNamedParameter( + [VersionState::NEW_PLACEHOLDER, VersionState::MOVE_PLACEHOLDER], + Connection::PARAM_INT_ARRAY + ) + ), + $queryBuilder->expr()->in( + 't3ver_wsid', + $queryBuilder->createNamedParameter([0, $this->workspaceId], Connection::PARAM_INT_ARRAY) ) ) ->execute() ->fetchAll(); - return $records; } - /** - * @param array $records - * @param int $workspaceId - * @return array - */ - public function fetchWorkspaceRecords(array $records, int $workspaceId): array + public function fetchUidsHavingWorkspaceVersion(array $records, int $workspaceId): array { + if (empty($records)) { + return []; + } $uids = []; foreach ($records as $record) { $uids[] = $record['uid']; } $queryBuilder = $this->getQueryBuilder(); - $records = (array)$queryBuilder->select('*') + return (array)$queryBuilder->select('t3ver_oid') ->from('tt_content') ->where( $queryBuilder->expr()->in( @@ -172,8 +210,7 @@ public function fetchWorkspaceRecords(array $records, int $workspaceId): array ) ) ->execute() - ->fetchAll(); - return $records; + ->fetchAll(\PDO::FETCH_COLUMN); } /** diff --git a/Classes/Hooks/Datahandler/Database.php b/Classes/Hooks/Datahandler/Database.php index aaed1c7a..ca4bb12a 100644 --- a/Classes/Hooks/Datahandler/Database.php +++ b/Classes/Hooks/Datahandler/Database.php @@ -55,6 +55,29 @@ public function fetchOneRecord(int $uid): ?array return $record; } + /** + * @param int $uid + * @return array|null + */ + public function fetchOneMovedRecord(int $uid): ?array + { + $queryBuilder = $this->getQueryBuilder(); + $record = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3ver_move_id', + $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetch(); + if ($record === false) { + return null; + } + return $record; + } + /** * @param array $record * @return array diff --git a/Classes/Hooks/Datahandler/DatamapAfterDatabaseOperationHook.php b/Classes/Hooks/Datahandler/DatamapAfterDatabaseOperationHook.php index 5fe19bf1..f6071716 100644 --- a/Classes/Hooks/Datahandler/DatamapAfterDatabaseOperationHook.php +++ b/Classes/Hooks/Datahandler/DatamapAfterDatabaseOperationHook.php @@ -12,13 +12,24 @@ * of the License, or any later version. */ -use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; class DatamapAfterDatabaseOperationHook { + /** + * @var Database + */ + protected $database; + + /** + * @param Database|null $database + */ + public function __construct(Database $database = null) + { + $this->database = $database ?? GeneralUtility::makeInstance(Database::class); + } /** * @param string $status @@ -33,19 +44,35 @@ public function processDatamap_afterDatabaseOperations(string $status, string $t if ( $table === 'tt_content' && $status === 'update' && + $dataHandler->BE_USER->workspace > 0 && MathUtility::canBeInterpretedAsInteger($id) && is_array($dataHandler->datamap['tt_content']) ) { $datamapForPlaceHolders = ['tt_content' => []]; foreach ($dataHandler->datamap['tt_content'] as $origId => $data) { if (!empty($data['tx_container_parent']) && $data['tx_container_parent'] > 0) { - $workspaceVersion = BackendUtility::getWorkspaceVersionOfRecord($dataHandler->BE_USER->workspace, $table, $origId, 'uid,t3ver_oid'); - if ((int)$workspaceVersion['uid'] === (int)$id && (int)$workspaceVersion['uid'] !== (int)$origId) { + $origRecord = $this->database->fetchOneRecord((int)$origId); + // origRecord is copied placeholder + if ( + (int)$origRecord['t3ver_oid'] === 0 && + (int)$origRecord['tx_container_parent'] !== (int)$data['tx_container_parent'] && + (int)$origRecord['t3ver_wsid'] === (int)$dataHandler->BE_USER->workspace + ) { $datamapForPlaceHolders['tt_content'][$origId] = ['tx_container_parent' => $data['tx_container_parent']]; + } else { + // origRecord is moved placehoder + $origRecord = $this->database->fetchOneMovedRecord((int)$origId); + if ( + (int)$origRecord['t3ver_oid'] === 0 && + (int)$origRecord['tx_container_parent'] !== (int)$data['tx_container_parent'] && + (int)$origRecord['t3ver_wsid'] === (int)$dataHandler->BE_USER->workspace + ) { + $datamapForPlaceHolders['tt_content'][$origRecord['uid']] = ['tx_container_parent' => $data['tx_container_parent']]; + } } } } - if (count($datamapForPlaceHolders['tt_content']) > 0) { + if (!empty($datamapForPlaceHolders['tt_content'])) { $localDataHandler = GeneralUtility::makeInstance(DataHandler::class); $localDataHandler->bypassWorkspaceRestrictions = true; $localDataHandler->start($datamapForPlaceHolders, [], $dataHandler->BE_USER); diff --git a/Tests/Functional/Datahandler/Workspace/ContainerTest.php b/Tests/Functional/Datahandler/Workspace/ContainerTest.php index 1bf10c4c..803a09b4 100644 --- a/Tests/Functional/Datahandler/Workspace/ContainerTest.php +++ b/Tests/Functional/Datahandler/Workspace/ContainerTest.php @@ -25,6 +25,7 @@ protected function setUp(): void parent::setUp(); $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/pages.xml'); $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/tt_content_default_language.xml'); + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/tt_content_default_language_second_container.xml'); $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/Workspace/sys_workspace.xml'); $this->backendUser->setWorkspace(1); } @@ -63,6 +64,331 @@ public function newVersionDoesNotCreateNewVersionsOfChildren(): void self::assertFalse($row); } + /** + * @test + */ + public function moveChildsColPosInContainer(): void + { + $cmdmap = [ + 'tt_content' => [ + 2 => [ + 'move' => [ + 'action' => 'paste', + 'target' => 3, + 'update' => [ + 'colPos' => '1-201', + 'sys_language_uid' => 0 + ] + ] + ] + ] + ]; + $this->dataHandler->start([], $cmdmap, $this->backendUser); + $this->dataHandler->process_cmdmap(); + + // moved record is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->orWhere( + $queryBuilder->expr()->eq( + 't3ver_move_id', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(2, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(201, $row['colPos']); + } + } + + /** + * @test + */ + public function moveChildOutsideContainer(): void + { + $cmdmap = [ + 'tt_content' => [ + 2 => [ + 'move' => [ + 'action' => 'paste', + 'target' => 3, + 'update' => [ + 'colPos' => 0, + 'sys_language_uid' => 0 + + ] + ] + ] + ] + ]; + $this->dataHandler->start([], $cmdmap, $this->backendUser); + $this->dataHandler->process_cmdmap(); + + // moved record is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->orWhere( + $queryBuilder->expr()->eq( + 't3ver_move_id', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(2, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(0, $row['tx_container_parent']); + self::assertSame(0, $row['colPos']); + } + } + + /** + * @test + */ + public function copyChildsColPosInContainer(): void + { + $cmdmap = [ + 'tt_content' => [ + 2 => [ + 'copy' => [ + 'action' => 'paste', + 'target' => 3, + 'update' => [ + 'colPos' => '1-201', + 'sys_language_uid' => 0 + + ] + ] + ] + ] + ]; + $this->dataHandler->start([], $cmdmap, $this->backendUser); + $this->dataHandler->process_cmdmap(); + + // moved record is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(2, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(201, $row['colPos']); + } + } + + /** + * @test + */ + public function copyChildOutsideContainer(): void + { + $cmdmap = [ + 'tt_content' => [ + 2 => [ + 'copy' => [ + 'action' => 'paste', + 'target' => 3, + 'update' => [ + 'colPos' => 0, + 'sys_language_uid' => 0 + + ] + ] + ] + ] + ]; + $this->dataHandler->start([], $cmdmap, $this->backendUser); + $this->dataHandler->process_cmdmap(); + + // copied record is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ), + $queryBuilder->expr()->eq( + 't3ver_oid', + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(1, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(0, $row['colPos']); + } + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ), + $queryBuilder->expr()->neq( + 't3ver_oid', + $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(1, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(0, $row['tx_container_parent']); + self::assertSame(0, $row['colPos']); + } + } + + /** + * @test + */ + public function copyChildsColPosInOtherContainer(): void + { + $cmdmap = [ + 'tt_content' => [ + 2 => [ + 'copy' => [ + 'action' => 'paste', + 'target' => 3, + 'update' => [ + 'colPos' => '91-201', + 'sys_language_uid' => 0 + + ] + ] + ] + ] + ]; + $this->dataHandler->start([], $cmdmap, $this->backendUser); + $this->dataHandler->process_cmdmap(); + + // copied record is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(2, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(91, $row['tx_container_parent']); + self::assertSame(201, $row['colPos']); + } + } + + /** + * @test + */ + public function moveChildsColPosInOtherContainer(): void + { + $cmdmap = [ + 'tt_content' => [ + 2 => [ + 'move' => [ + 'action' => 'paste', + 'target' => 3, + 'update' => [ + 'colPos' => '91-201', + 'sys_language_uid' => 0 + + ] + ] + ] + ] + ]; + $this->dataHandler->start([], $cmdmap, $this->backendUser); + $this->dataHandler->process_cmdmap(); + + // copied record is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + + $queryBuilder = $this->getQueryBuilder(); + $rows = $queryBuilder->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq( + 't3_origuid', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->orWhere( + $queryBuilder->expr()->eq( + 't3ver_move_id', + $queryBuilder->createNamedParameter(2, \PDO::PARAM_INT) + ) + ) + ->execute() + ->fetchAll(); + self::assertSame(2, count($rows)); + foreach ($rows as $row) { + self::assertSame(1, $row['t3ver_wsid']); + self::assertSame(91, $row['tx_container_parent']); + self::assertSame(201, $row['colPos']); + } + } + /** * @test */ @@ -84,6 +410,11 @@ public function copyContainer(): void $this->dataHandler->start([], $cmdmap, $this->backendUser); $this->dataHandler->process_cmdmap(); + // copied child is not modified + $row = $this->fetchOneRecord('uid', 2); + self::assertSame(1, $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); + $queryBuilder = $this->getQueryBuilder(); $containerRow = $queryBuilder->select('*') ->from('tt_content') @@ -111,9 +442,11 @@ public function copyContainer(): void ) ->execute() ->fetchAll(); + self::assertSame(2, count($rows)); foreach ($rows as $row) { self::assertSame(1, $row['t3ver_wsid']); self::assertSame($containerRow['uid'], $row['tx_container_parent']); + self::assertSame(200, $row['colPos']); } } } diff --git a/Tests/Functional/Domain/Factory/ContainerFactoryTest.php b/Tests/Functional/Domain/Factory/ContainerFactoryTest.php index f15208c4..aee9e1ed 100644 --- a/Tests/Functional/Domain/Factory/ContainerFactoryTest.php +++ b/Tests/Functional/Domain/Factory/ContainerFactoryTest.php @@ -11,6 +11,9 @@ */ use B13\Container\Domain\Factory\ContainerFactory; +use TYPO3\CMS\Core\Context\Context; +use TYPO3\CMS\Core\Context\LanguageAspect; +use TYPO3\CMS\Core\Context\WorkspaceAspect; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; @@ -43,4 +46,86 @@ public function localizedContainerChildElementsHasSortingOfDefaultChildElements( $first = $children[0]; self::assertSame(6, $first['uid']); } + + /** + * @test + */ + public function containerHoldsMovedChildrenInWorkspaceClipboard(): void + { + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/Workspace/sys_workspace.xml'); + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceClipboard.xml'); + $workspaceAspect = GeneralUtility::makeInstance(WorkspaceAspect::class, 1); + GeneralUtility::makeInstance(Context::class)->setAspect('workspace', $workspaceAspect); + $containerFactory = GeneralUtility::makeInstance(ContainerFactory::class); + $container = $containerFactory->buildContainer(101); + $children = $container->getChildrenByColPos(200); + self::assertSame(0, count($children)); + $container = $containerFactory->buildContainer(103); + $children = $container->getChildrenByColPos(201); + self::assertSame(1, count($children)); + $first = $children[0]; + self::assertSame(104, $first['uid']); + } + + /** + * @test + */ + public function containerHoldsMovedChildrenInWorkspaceAjax(): void + { + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/Workspace/sys_workspace.xml'); + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceAjax.xml'); + $workspaceAspect = GeneralUtility::makeInstance(WorkspaceAspect::class, 1); + GeneralUtility::makeInstance(Context::class)->setAspect('workspace', $workspaceAspect); + $containerFactory = GeneralUtility::makeInstance(ContainerFactory::class); + $container = $containerFactory->buildContainer(101); + $children = $container->getChildrenByColPos(200); + self::assertSame(0, count($children)); + $container = $containerFactory->buildContainer(103); + $children = $container->getChildrenByColPos(201); + self::assertSame(1, count($children)); + $first = $children[0]; + self::assertSame(104, $first['uid']); + } + + /** + * @test + */ + public function containerHoldsMovedChildrenInWorkspaceWithTranslation(): void + { + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/Workspace/sys_workspace.xml'); + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceWithTranslation.xml'); + $workspaceAspect = GeneralUtility::makeInstance(WorkspaceAspect::class, 1); + $languageAspect = GeneralUtility::makeInstance(LanguageAspect::class, 1); + GeneralUtility::makeInstance(Context::class)->setAspect('workspace', $workspaceAspect); + GeneralUtility::makeInstance(Context::class)->setAspect('language', $languageAspect); + $containerFactory = GeneralUtility::makeInstance(ContainerFactory::class); + $container = $containerFactory->buildContainer(106); + $children = $container->getChildrenByColPos(200); + self::assertSame(0, count($children)); + $container = $containerFactory->buildContainer(104); + $children = $container->getChildrenByColPos(202); + self::assertSame(1, count($children)); + $first = $children[0]; + self::assertSame(110, $first['uid']); + } + + /** + * @test + */ + public function containerHoldsCopiedChildrenInWorkspaceAjax(): void + { + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Fixtures/Workspace/sys_workspace.xml'); + $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/container/Tests/Functional/Domain/Factory/Fixture/copiedChildrenInWorkspace.xml'); + $workspaceAspect = GeneralUtility::makeInstance(WorkspaceAspect::class, 1); + GeneralUtility::makeInstance(Context::class)->setAspect('workspace', $workspaceAspect); + $containerFactory = GeneralUtility::makeInstance(ContainerFactory::class); + $container = $containerFactory->buildContainer(101); + $children = $container->getChildrenByColPos(200); + self::assertSame(1, count($children)); + $container = $containerFactory->buildContainer(103); + $children = $container->getChildrenByColPos(201); + self::assertSame(1, count($children)); + $first = $children[0]; + self::assertSame(105, $first['uid']); + } } diff --git a/Tests/Functional/Domain/Factory/Fixture/copiedChildrenInWorkspace.xml b/Tests/Functional/Domain/Factory/Fixture/copiedChildrenInWorkspace.xml new file mode 100644 index 00000000..378899af --- /dev/null +++ b/Tests/Functional/Domain/Factory/Fixture/copiedChildrenInWorkspace.xml @@ -0,0 +1,37 @@ + + + + 101 + 1 + b13-2cols-with-header-container + + + 102 + 1 + 200 + 101 + + + 103 + 1 + b13-2cols-with-header-container + + + 104 + 1 + 201 + 103 + 1 + 0 + 1 + + + 105 + 1 + 201 + 103 + 1 + 104 + -1 + + diff --git a/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceAjax.xml b/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceAjax.xml new file mode 100644 index 00000000..3aa73c80 --- /dev/null +++ b/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceAjax.xml @@ -0,0 +1,28 @@ + + + + 101 + 1 + b13-2cols-with-header-container + + + 102 + 1 + 200 + 101 + + + 103 + 1 + b13-2cols-with-header-container + + + 104 + 1 + 201 + 103 + 1 + 102 + 0 + + diff --git a/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceClipboard.xml b/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceClipboard.xml new file mode 100644 index 00000000..774032ce --- /dev/null +++ b/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceClipboard.xml @@ -0,0 +1,37 @@ + + + + 101 + 1 + b13-2cols-with-header-container + + + 102 + 1 + 200 + 101 + + + 103 + 1 + b13-2cols-with-header-container + + + 104 + 1 + 201 + 103 + 1 + 102 + 4 + + + 105 + 1 + 201 + 103 + 1 + 0 + 3 + + diff --git a/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceWithTranslation.xml b/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceWithTranslation.xml new file mode 100644 index 00000000..e4d8ac11 --- /dev/null +++ b/Tests/Functional/Domain/Factory/Fixture/movedChildrenInWorkspaceWithTranslation.xml @@ -0,0 +1,67 @@ + + + + 101 + 1 + b13-2cols-with-header-container + + + 102 + 1 + b13-2cols-with-header-container + + + 103 + 1 + 200 + 102 + + + + 104 + 1 + 1 + 101 + b13-2cols-with-header-container + + + 105 + 1 + 200 + 103 + 102 + 1 + + + 106 + 1 + b13-2cols-with-header-container + 1 + 102 + + + + + 109 + 1 + 202 + 101 + 1 + 103 + 0 + + + + 110 + 1 + 202 + 101 + 1 + 105 + 0 + 103 + 1 + + + +