From 5e8ffff20bd900dd8fe041a41534d00c15ae106f Mon Sep 17 00:00:00 2001 From: Sebastian Michaelsen Date: Wed, 25 Feb 2026 09:20:24 +0100 Subject: [PATCH] refactor: move InlineItemsHelper ownership to webcomponents --- .github/phpunit.functional.xml | 19 ++ .github/workflows/ci.yml | 25 ++ .../Helpers/InlineItemsHelper.php | 43 +-- .../Helpers/Fixtures/MultipleInlineItems.csv | 8 + .../MultipleInlineItemsInWorkspace.csv | 8 + ...msInWorkspaceWithNewItemAtTheBeginning.csv | 9 + ...ineItemsInWorkspaceWithNewItemAtTheEnd.csv | 9 + ...ItemsInWorkspaceWithNewItemInTheMiddle.csv | 9 + ...eInlineItemsInWorkspaceWithRemovedItem.csv | 9 + ...ltipleInlineItemsRearrangedInWorkspace.csv | 10 + .../Helpers/Fixtures/OneInlineItem.csv | 7 + .../OneInlineItemChangedInWorkspace.csv | 8 + .../OneInlineItemEnabledInWorkspace.csv | 8 + .../Fixtures/OneInlineItemInWorkspace.csv | 7 + ...OneInlineItemWithoutDefaultTranslation.csv | 7 + .../Helpers/Fixtures/TranslatedInlineItem.csv | 8 + .../Helpers/InlineItemsHelperTest.php | 276 ++++++++++++++++++ .../TCA/tx_inlineitemshelperfixture_child.php | 46 +++ .../tx_inlineitemshelperfixture_parent.php | 39 +++ .../inline_items_helper_fixture/composer.json | 11 + .../Helpers/InlineItemsHelperTest.php | 52 ++++ 21 files changed, 599 insertions(+), 19 deletions(-) create mode 100644 .github/phpunit.functional.xml create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItems.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspace.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheBeginning.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheEnd.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemInTheMiddle.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithRemovedItem.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsRearrangedInWorkspace.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItem.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemChangedInWorkspace.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemEnabledInWorkspace.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemInWorkspace.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemWithoutDefaultTranslation.csv create mode 100644 Tests/Functional/DataProviding/Helpers/Fixtures/TranslatedInlineItem.csv create mode 100644 Tests/Functional/DataProviding/Helpers/InlineItemsHelperTest.php create mode 100644 Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_child.php create mode 100644 Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_parent.php create mode 100644 Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/composer.json create mode 100644 Tests/Unit/DataProviding/Helpers/InlineItemsHelperTest.php diff --git a/.github/phpunit.functional.xml b/.github/phpunit.functional.xml new file mode 100644 index 0000000..d1fa385 --- /dev/null +++ b/.github/phpunit.functional.xml @@ -0,0 +1,19 @@ + + + + + ../Classes/ + + + + + ../Tests/Functional/ + ../Tests/Functional/Fixtures/ + + + + + + + + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db07d6e..55d845f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,31 @@ jobs: bootstrap: vendor/autoload.php configuration: .github/phpunit.xml + functional-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: mbstring, intl, pdo_sqlite + tools: composer:v2 + + - name: Composer install + run: composer install --ignore-platform-reqs --no-interaction + + - name: Prepare TYPO3 extension path + run: | + mkdir -p public/typo3conf/ext/ + if [ ! -L public/typo3conf/ext/webcomponents ]; then ln -snvf ../../../. public/typo3conf/ext/webcomponents; fi + + - name: Functional Tests + env: + typo3DatabaseDriver: pdo_sqlite + typo3DatabaseName: typo3 + run: vendor/bin/phpunit -c .github/phpunit.functional.xml + phpstan: runs-on: ubuntu-latest steps: diff --git a/Classes/DataProviding/Helpers/InlineItemsHelper.php b/Classes/DataProviding/Helpers/InlineItemsHelper.php index c5b522f..6814534 100644 --- a/Classes/DataProviding/Helpers/InlineItemsHelper.php +++ b/Classes/DataProviding/Helpers/InlineItemsHelper.php @@ -8,7 +8,6 @@ use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; -use TYPO3\CMS\Core\Database\Query\QueryHelper; use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -25,49 +24,55 @@ public function __construct( ) {} /** - * @param array $parentRecord - * @return list> + * @param array $parentRecord + * @return list> */ public function loadInlineItems(array $parentRecord, string $inlineFieldName, string $parentTable = 'tt_content'): array { // if the field is empty, and we're not in a workspace context, then there are no inline items - /** @var int|string $versioningWorkspaceId */ - $versioningWorkspaceId = $this->context->getPropertyFromAspect('workspace', 'id'); - $versioningWorkspaceId = (int)$versioningWorkspaceId; + $workspaceId = $this->context->getPropertyFromAspect('workspace', 'id'); + $versioningWorkspaceId = is_int($workspaceId) || is_string($workspaceId) ? (int)$workspaceId : 0; if (empty($parentRecord[$inlineFieldName]) && $versioningWorkspaceId === 0) { return []; } $inlineFieldTca = $this->getInlineFieldTca($inlineFieldName, $parentTable); - $foreignTable = $inlineFieldTca['config']['foreign_table'] ?? null; - if ($foreignTable === null) { + $inlineFieldConfig = $inlineFieldTca['config'] ?? []; + $foreignTable = $inlineFieldConfig['foreign_table'] ?? null; + if (!is_string($foreignTable) || $foreignTable === '') { throw new \Exception( sprintf('Could not load inline items for field "%s". Missing \'foreign_table\' in its TCA configuration', $inlineFieldName), 1686299043 ); } - $foreignField = $inlineFieldTca['config']['foreign_field'] ?? null; - $foreignTableTca = $GLOBALS['TCA'][$foreignTable]; - $foreignSortby = $inlineFieldTca['config']['foreign_sortby'] ?? $foreignTableTca['ctrl']['sortby'] ?? null; + $foreignField = $inlineFieldConfig['foreign_field'] ?? null; + if (!is_string($foreignField) || $foreignField === '') { + $foreignField = null; + } + $foreignTableTca = $GLOBALS['TCA'][$foreignTable] ?? []; + $foreignSortby = $inlineFieldConfig['foreign_sortby'] ?? $foreignTableTca['ctrl']['sortby'] ?? null; + if (!is_string($foreignSortby) || $foreignSortby === '') { + $foreignSortby = null; + } $queryBuilder = $this->connectionPool->getQueryBuilderForTable($foreignTable); $queryBuilder->getRestrictions()->removeAll(); $parentRecordId = $parentRecord['_LOCALIZED_UID'] ?? $parentRecord['uid'] ?? 0; - $constraints = []; + $constraints = $this->pageRepository->getDefaultConstraints($foreignTable); if (!empty($foreignField)) { - $constraints[] = $queryBuilder->expr()->eq($foreignField, $queryBuilder->createNamedParameter($parentRecordId, Connection::PARAM_INT)); + $constraints['foreign_field'] = $queryBuilder->expr()->eq($foreignField, $queryBuilder->createNamedParameter($parentRecordId, Connection::PARAM_INT)); } else { $itemsUidList = GeneralUtility::intExplode(',', (string)($parentRecord[$inlineFieldName] ?? ''), true); if (empty($itemsUidList)) { return []; } - $constraints[] = $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($itemsUidList, ArrayParameterType::INTEGER)); + $constraints['uidList'] = $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($itemsUidList, ArrayParameterType::INTEGER)); } - if (isset($foreignTableTca['ctrl']['languageField'])) { - $constraints[] = $queryBuilder->expr()->in($foreignTableTca['ctrl']['languageField'], $queryBuilder->createNamedParameter([-1, $parentRecord['sys_language_uid'] ?? 0], ArrayParameterType::INTEGER)); + $languageField = $foreignTableTca['ctrl']['languageField'] ?? null; + if (is_string($languageField) && $languageField !== '') { + $constraints['language'] = $queryBuilder->expr()->in($languageField, $queryBuilder->createNamedParameter([-1, $parentRecord['sys_language_uid'] ?? 0], ArrayParameterType::INTEGER)); } - $constraints[] = QueryHelper::stripLogicalOperatorPrefix($this->pageRepository->enableFields($foreignTable)); - $queryBuilder->select('*')->from($foreignTable)->where(...$constraints); + $queryBuilder->select('*')->from($foreignTable)->where(...array_values($constraints)); if ($foreignSortby) { $queryBuilder->orderBy($foreignSortby); } @@ -96,7 +101,7 @@ public function loadInlineItems(array $parentRecord, string $inlineFieldName, st } /** - * @return array{config: array{foreign_table?: string, foreign_field?: string, foreign_sortby?: string}, label: string, type: string} + * @return array{config?: array} */ protected function getInlineFieldTca(string $inlineFieldName, string $localTableName = 'tt_content'): array { diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItems.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItems.csv new file mode 100644 index 0000000..e86d597 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItems.csv @@ -0,0 +1,8 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1","sorting" +,"1","1","1","tx_inlineitemshelperfixture_parent","-1","BJB","2" +,"2","1","1","tx_inlineitemshelperfixture_parent","-1","BJB","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspace.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspace.csv new file mode 100644 index 0000000..919e747 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspace.csv @@ -0,0 +1,8 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1","t3ver_wsid","t3ver_state","sorting" +,"1","1","1","tx_inlineitemshelperfixture_parent","-1","BJB","1","1","2" +,"2","1","1","tx_inlineitemshelperfixture_parent","-1","BJB","1","1","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheBeginning.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheBeginning.csv new file mode 100644 index 0000000..bc47cd6 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheBeginning.csv @@ -0,0 +1,9 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","input_1","t3ver_wsid","t3ver_state","sorting" +,"1","1","1","tx_inlineitemshelperfixture_parent","BJB","0","0","2" +,"2","1","1","tx_inlineitemshelperfixture_parent","BJB","0","0","3" +,"3","1","1","tx_inlineitemshelperfixture_parent","BJB","1","1","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheEnd.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheEnd.csv new file mode 100644 index 0000000..f6affcb --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheEnd.csv @@ -0,0 +1,9 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","input_1","t3ver_wsid","t3ver_state","sorting" +,"1","1","1","1","-1","BJB","0","0","2" +,"2","1","1","1","-1","BJB","0","0","3" +,"3","1","1","1","-1","BJB","1","1","4" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemInTheMiddle.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemInTheMiddle.csv new file mode 100644 index 0000000..dda6ee5 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemInTheMiddle.csv @@ -0,0 +1,9 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","input_1","t3ver_wsid","t3ver_state","sorting" +,"1","1","1","tx_inlineitemshelperfixture_parent","BJB","0","0","2" +,"2","1","1","tx_inlineitemshelperfixture_parent","BJB","0","0","5" +,"3","1","1","tx_inlineitemshelperfixture_parent","BJB","1","1","4" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithRemovedItem.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithRemovedItem.csv new file mode 100644 index 0000000..64c6aa0 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsInWorkspaceWithRemovedItem.csv @@ -0,0 +1,9 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","input_1","t3ver_wsid","t3ver_state","t3ver_oid","sorting" +,"1","1","1","tx_inlineitemshelperfixture_parent","BJB","0","0","0","3" +,"2","1","1","tx_inlineitemshelperfixture_parent","BJB","0","0","0","2" +,"3","1","1","tx_inlineitemshelperfixture_parent","BJB","1","2","1","3" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsRearrangedInWorkspace.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsRearrangedInWorkspace.csv new file mode 100644 index 0000000..26479bc --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/MultipleInlineItemsRearrangedInWorkspace.csv @@ -0,0 +1,10 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1","sorting","t3ver_oid","t3ver_wsid" +,"1","1","1","1","-1","BJB/first","1","0","0" +,"2","1","1","1","-1","BJB/second","2","0","0" +,"3","1","1","1","-1","BJB/first","2","1","1" +,"4","1","1","1","-1","BJB/second","1","2","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItem.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItem.csv new file mode 100644 index 0000000..46db3b3 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItem.csv @@ -0,0 +1,7 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1" +,"1","1","1","tx_inlineitemshelperfixture_parent","-1","BJB" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemChangedInWorkspace.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemChangedInWorkspace.csv new file mode 100644 index 0000000..f21a2ed --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemChangedInWorkspace.csv @@ -0,0 +1,8 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1","t3ver_wsid","t3ver_state","t3ver_oid" +,"1","1","1","tx_inlineitemshelperfixture_parent","-1","BJB","0","0","0" +,"2","1","1","tx_inlineitemshelperfixture_parent","-1","BJB/changed","1","0","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemEnabledInWorkspace.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemEnabledInWorkspace.csv new file mode 100644 index 0000000..b0fc83e --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemEnabledInWorkspace.csv @@ -0,0 +1,8 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","hidden","t3ver_wsid","t3ver_state","t3ver_oid" +,"1","1","1","1","-1","1","0","0","0" +,"2","1","1","1","-1","0","1","0","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemInWorkspace.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemInWorkspace.csv new file mode 100644 index 0000000..97c3457 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemInWorkspace.csv @@ -0,0 +1,7 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1","t3ver_wsid","t3ver_state" +,"1","1","1","1","-1","BJB","1","1" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemWithoutDefaultTranslation.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemWithoutDefaultTranslation.csv new file mode 100644 index 0000000..9680443 --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/OneInlineItemWithoutDefaultTranslation.csv @@ -0,0 +1,7 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1" +,"1","1","2","tx_inlineitemshelperfixture_parent","1","BJB" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/Fixtures/TranslatedInlineItem.csv b/Tests/Functional/DataProviding/Helpers/Fixtures/TranslatedInlineItem.csv new file mode 100644 index 0000000..394a7da --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/Fixtures/TranslatedInlineItem.csv @@ -0,0 +1,8 @@ +"tx_inlineitemshelperfixture_child" +,"uid","pid","parentid","parenttable","sys_language_uid","input_1" +,"1","1","1","tx_inlineitemshelperfixture_parent","0","BJB" +,"2","1","2","tx_inlineitemshelperfixture_parent","1","BJB/overlaid" + +"tx_inlineitemshelperfixture_parent" +,"uid" +,"1" diff --git a/Tests/Functional/DataProviding/Helpers/InlineItemsHelperTest.php b/Tests/Functional/DataProviding/Helpers/InlineItemsHelperTest.php new file mode 100644 index 0000000..68e0e7f --- /dev/null +++ b/Tests/Functional/DataProviding/Helpers/InlineItemsHelperTest.php @@ -0,0 +1,276 @@ +setWorkspace(0); + $this->subject = new InlineItemsHelper( + $this->get(ConnectionPool::class), + $this->get(Context::class), + $this->get(PageRepository::class), + ); + } + + #[Test] + public function returnsEmptyArrayForNoData(): void + { + $items = $this->subject->loadInlineItems(['pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertSame([], $items); + } + + #[Test] + public function returnsEmptyArrayForNoDataInWorkspace(): void + { + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertSame([], $items); + } + + #[Test] + public function returnsOneItemForOneRecordInDatabase(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/OneInlineItem.csv'); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1, self::INLINE_FIELD => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(1, $items); + self::assertIsArray($items[0]); + } + + #[Test] + public function returnsRecordFromDatabase(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/OneInlineItem.csv'); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1, self::INLINE_FIELD => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + $connection = $this->getConnectionPool()->getConnectionForTable(self::CHILD_TABLE); + $rows = $connection->executeQuery( + 'SELECT * FROM ' . self::CHILD_TABLE . ' WHERE parentid = :parentid', + ['parentid' => 1] + )->fetchAllAssociative(); + + self::assertIsArray($items); + self::assertCount(1, $items); + self::assertSame($rows, $items); + } + + #[Test] + public function returnsSortedItems(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItems.csv'); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1, self::INLINE_FIELD => 2], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(2, $items); + self::assertSame(2, $items[0]['uid']); + self::assertSame(1, $items[1]['uid']); + } + + #[Test] + public function returnsOneItemWithOneRecordCreatedInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/OneInlineItemInWorkspace.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(1, $items); + self::assertIsArray($items[0]); + } + + #[Test] + public function returnSortedItemsInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItemsInWorkspace.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(2, $items); + self::assertSame(2, $items[0]['uid']); + self::assertSame(1, $items[1]['uid']); + } + + #[Test] + public function returnSortedItemsWithCreatedOneAtTheBeginningInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheBeginning.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(3, $items); + self::assertSame(3, $items[0]['uid']); + self::assertSame(1, $items[1]['uid']); + self::assertSame(2, $items[2]['uid']); + } + + #[Test] + public function returnSortedItemsWithCreatedOneInTheMiddleInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemInTheMiddle.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(3, $items); + self::assertSame(1, $items[0]['uid']); + self::assertSame(3, $items[1]['uid']); + self::assertSame(2, $items[2]['uid']); + } + + #[Test] + public function returnSortedItemsWithCreatedOneAtTheEndInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItemsInWorkspaceWithNewItemAtTheEnd.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(3, $items); + self::assertSame(1, $items[0]['uid']); + self::assertSame(2, $items[1]['uid']); + self::assertSame(3, $items[2]['uid']); + } + + #[Test] + public function returnSortedItemsWithRemovedItemInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItemsInWorkspaceWithRemovedItem.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(1, $items); + self::assertSame(2, $items[0]['uid']); + } + + #[Test] + public function returnsItemChangedInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/OneInlineItemChangedInWorkspace.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(1, $items); + self::assertSame('BJB/changed', $items[0]['input_1']); + } + + #[Test] + public function returnsSortedItemsWithSortingChangedInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/MultipleInlineItemsRearrangedInWorkspace.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertIsArray($items); + self::assertCount(2, $items); + self::assertSame('BJB/second', $items[0]['input_1']); + self::assertSame('BJB/first', $items[1]['input_1']); + } + + #[Test] + public function returnsItemEnabledInWorkspace(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/OneInlineItemEnabledInWorkspace.csv'); + + $this->setWorkspace(1); + + $items = $this->subject->loadInlineItems(['uid' => 1, 'pid' => 1], self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertCount(1, $items); + } + + #[Test] + public function returnsOverlaidItemWhenParentRecordIsTranslated(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/TranslatedInlineItem.csv'); + $record = [ + 'uid' => 1, + 'pid' => 1, + 'sys_language_uid' => 1, + self::INLINE_FIELD => 1, + '_LOCALIZED_UID' => 2, + ]; + + $items = $this->subject->loadInlineItems($record, self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertCount(1, $items); + self::assertSame('BJB/overlaid', $items[0]['input_1']); + } + + #[Test] + public function returnsItemWithoutDefaultTranslationWhenContentElementIsTranslated(): void + { + $this->importCSVDataSet(__DIR__ . '/Fixtures/OneInlineItemWithoutDefaultTranslation.csv'); + $record = [ + 'uid' => 1, + 'pid' => 1, + 'sys_language_uid' => 1, + self::INLINE_FIELD => 1, + '_LOCALIZED_UID' => 2, + ]; + + $items = $this->subject->loadInlineItems($record, self::INLINE_FIELD, self::PARENT_TABLE); + + self::assertCount(1, $items); + self::assertSame('BJB', $items[0]['input_1']); + } + + private function setWorkspace(int $workspaceId): void + { + $context = GeneralUtility::makeInstance(Context::class); + $context->setAspect('workspace', new WorkspaceAspect($workspaceId)); + } +} diff --git a/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_child.php b/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_child.php new file mode 100644 index 0000000..0d0b9b1 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_child.php @@ -0,0 +1,46 @@ + [ + 'title' => 'InlineItemsHelper fixture child', + 'label' => 'input_1', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'delete' => 'deleted', + 'sortby' => 'sorting', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'translationSource' => 'l10n_source', + 'enablecolumns' => [ + 'disabled' => 'hidden', + ], + 'security' => [ + 'ignorePageTypeRestriction' => true, + ], + ], + 'columns' => [ + 'parentid' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'parenttable' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'input_1' => [ + 'label' => 'Input', + 'config' => [ + 'type' => 'input', + ], + ], + ], + 'types' => [ + '0' => [ + 'showitem' => 'input_1', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_parent.php b/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_parent.php new file mode 100644 index 0000000..7f4da08 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/Configuration/TCA/tx_inlineitemshelperfixture_parent.php @@ -0,0 +1,39 @@ + [ + 'title' => 'InlineItemsHelper fixture parent', + 'label' => 'uid', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'delete' => 'deleted', + 'sortby' => 'sorting', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'translationSource' => 'l10n_source', + 'enablecolumns' => [ + 'disabled' => 'hidden', + ], + 'security' => [ + 'ignorePageTypeRestriction' => true, + ], + ], + 'columns' => [ + 'inline_2' => [ + 'label' => 'Inline items', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_inlineitemshelperfixture_child', + 'foreign_field' => 'parentid', + 'foreign_table_field' => 'parenttable', + ], + ], + ], + 'types' => [ + '0' => [ + 'showitem' => 'inline_2', + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/composer.json b/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/composer.json new file mode 100644 index 0000000..98e1271 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/inline_items_helper_fixture/composer.json @@ -0,0 +1,11 @@ +{ + "name": "julius-baer/inline-items-helper-fixture", + "type": "typo3-cms-extension", + "description": "Functional test fixture extension for InlineItemsHelper", + "version": "1.0.0", + "extra": { + "typo3/cms": { + "extension-key": "inline_items_helper_fixture" + } + } +} diff --git a/Tests/Unit/DataProviding/Helpers/InlineItemsHelperTest.php b/Tests/Unit/DataProviding/Helpers/InlineItemsHelperTest.php new file mode 100644 index 0000000..31c4d5e --- /dev/null +++ b/Tests/Unit/DataProviding/Helpers/InlineItemsHelperTest.php @@ -0,0 +1,52 @@ +subject = new InlineItemsHelper( + self::createStub(ConnectionPool::class), + self::createStub(Context::class), + self::createStub(PageRepository::class), + ); + } + + #[Test] + public function throwsExceptionIfTcaIsNotLoadable(): void + { + self::expectExceptionCode(1587038305); + + $this->subject->loadInlineItems(['my_field' => 1], 'my_field', 'my_table'); + } + + #[Test] + public function throwsExceptionIfFieldIsNotInline(): void + { + $GLOBALS['TCA'] = ArrayUtility::setValueByPath($GLOBALS['TCA'] ?? [], 'my_table/columns/my_field/config/type', 'text'); + + self::expectExceptionCode(1686299043); + + $this->subject->loadInlineItems(['my_field' => 1], 'my_field', 'my_table'); + + $GLOBALS['TCA'] = ArrayUtility::removeByPath($GLOBALS['TCA'], 'my_table/columns/my_field/config/type'); + } +}