‪TYPO3CMS  ‪main
TcaSelectItemsTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
32 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
33 
34 final class ‪TcaSelectItemsTest extends FunctionalTestCase
35 {
36  protected array ‪$testExtensionsToLoad = ['typo3/sysext/backend/Tests/Functional/Fixtures/Extensions/test_tca_select_items'];
37  protected array $pathsToProvideInTestInstance = ['typo3/sysext/backend/Tests/Functional/Form/Fixtures/TcaSelectItems/files/' => 'fileadmin/'];
38 
39  protected function setUp(): void
40  {
41  parent::setUp();
42  $this->importCSVDataSet(__DIR__ . '/../Fixtures/TcaSelectItems/be_users.csv');
43  $this->importCSVDataSet(__DIR__ . '/../Fixtures/TcaSelectItems/base.csv');
44  $this->importCSVDataSet(__DIR__ . '/../Fixtures/TcaSelectItems/sys_file_storage.csv');
45  ‪$GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create('default');
46  ‪$GLOBALS['BE_USER'] = $this->setUpBackendUser(1);
47  }
48 
49  protected function tearDown(): void
50  {
51  GeneralUtility::purgeInstances();
52  parent::tearDown();
53  }
54 
55  #[Test]
56  public function addDataKeepExistingItems(): void
57  {
58  $input = [
59  'tableName' => 'aTable',
60  'processedTca' => [
61  'columns' => [
62  'aField' => [
63  'config' => [
64  'type' => 'radio',
65  'items' => [
66  0 => [
67  'label' => 'foo',
68  'value' => 'bar',
69  ],
70  ],
71  ],
72  ],
73  'anotherField' => [
74  'config' => [
75  'type' => 'group',
76  'items' => [
77  0 => [
78  'label' => 'foo',
79  'value' => 'bar',
80  ],
81  ],
82  ],
83  ],
84  ],
85  ],
86  ];
87 
88  $expected = $input;
89  self::assertSame($expected, (new TcaSelectItems())->addData($input));
90  }
91 
92  #[Test]
93  public function addDataThrowsExceptionIfAnItemIsNotAnArray(): void
94  {
95  $input = [
96  'tableName' => 'aTable',
97  'processedTca' => [
98  'columns' => [
99  'aField' => [
100  'config' => [
101  'type' => 'select',
102  'renderType' => 'selectSingle',
103  'items' => [
104  'label' => 'foo',
105  ],
106  ],
107  ],
108  ],
109  ],
110  ];
111 
112  $this->expectException(\UnexpectedValueException::class);
113  $this->expectExceptionCode(1439288036);
114 
115  (new TcaSelectItems())->addData($input);
116  }
117 
118  #[Test]
119  public function addDataTranslatesItemLabels(): void
120  {
121  $input = [
122  'tableName' => 'aTable',
123  'databaseRow' => [
124  'aField' => 'aValue',
125  ],
126  'processedTca' => [
127  'columns' => [
128  'aField' => [
129  'config' => [
130  'type' => 'select',
131  'renderType' => 'selectSingle',
132  'items' => [
133  0 => [
134  'label' => 'LLL:EXT:test_tca_select_items/Resources/Private/Language/locallang.xlf:aLabel',
135  'value' => 'aValue',
136  ],
137  ],
138  'maxitems' => 99999,
139  ],
140  ],
141  ],
142  ],
143  ];
144 
145  $expected = $input;
146  $expected['processedTca']['columns']['aField']['config']['items'][0]['label'] = 'translated';
147  $expected['processedTca']['columns']['aField']['config']['items'][0]['icon'] = null;
148  $expected['processedTca']['columns']['aField']['config']['items'][0]['group'] = null;
149  $expected['processedTca']['columns']['aField']['config']['items'][0]['description'] = null;
150 
151  $expected['databaseRow']['aField'] = ['aValue'];
152 
153  self::assertSame($expected, (new TcaSelectItems())->addData($input));
154  }
155 
156  #[Test]
157  public function addDataAddsDividersIfItemGroupsAreDefined(): void
158  {
159  $input = [
160  'tableName' => 'aTable',
161  'databaseRow' => [
162  'aField' => 'aValue',
163  ],
164  'processedTca' => [
165  'columns' => [
166  'aField' => [
167  'config' => [
168  'type' => 'select',
169  'renderType' => 'selectSingle',
170  'items' => [
171  [
172  'label' => 'aLabel',
173  'value' => 'aValue',
174  'icon' => 'an-icon-reference',
175  'group' => 'non-existing-group',
176  'description' => null,
177  ],
178  [
179  'label' => 'anotherLabel',
180  'value' => 'anotherValue',
181  'icon' => 'an-icon-reference',
182  'group' => 'example-group',
183  'description' => null,
184  ],
185  ],
186  'itemGroups' => [
187  'example-group' => 'My Example Group',
188  ],
189  'maxitems' => 99999,
190  ],
191  ],
192  ],
193  ],
194  ];
195 
196  $expected = $input;
197  $expected['databaseRow']['aField'] = ['aValue'];
198  $expected['processedTca']['columns']['aField']['config']['items'] = [
199  [
200  'label' => 'My Example Group',
201  'value' => '--div--',
202  'group' => 'example-group',
203  ],
204  [
205  'label' => 'anotherLabel',
206  'value' => 'anotherValue',
207  'icon' => 'an-icon-reference',
208  'group' => 'example-group',
209  'description' => null,
210  ],
211  [
212  'label' => 'non-existing-group',
213  'value' => '--div--',
214  'group' => 'non-existing-group',
215  ],
216  [
217  'label' => 'aLabel',
218  'value' => 'aValue',
219  'icon' => 'an-icon-reference',
220  'group' => 'non-existing-group',
221  'description' => null,
222  ],
223  ];
224 
225  self::assertSame($expected, (new TcaSelectItems())->addData($input));
226  }
227 
228  #[Test]
229  public function addDataAddsItemGroupsFromForeignTable(): void
230  {
231  $input = [
232  'tableName' => 'aTable',
233  'effectivePid' => 1,
234  'databaseRow' => [
235  'aField' => 'invalid',
236  ],
237  'processedTca' => [
238  'columns' => [
239  'aField' => [
240  'config' => [
241  'type' => 'select',
242  'renderType' => 'selectSingle',
243  'items' => [
244  [
245  'label' => 'anotherLabel',
246  'value' => 'anotherValue',
247  'icon' => 'an-icon-reference',
248  'group' => 'example-group',
249  'description' => null,
250  ],
251  ],
252  'itemGroups' => [
253  'example-group' => 'My Example Group',
254  'itemgroup1' => 'Item group foreign table 1',
255  'itemgroup2' => 'Item group foreign table 2',
256  ],
257  'foreign_table' => 'foreign_table',
258  'foreign_table_item_group' => 'itemgroup',
259  'maxitems' => 99999,
260  ],
261  ],
262  ],
263  ],
264  ];
265 
266  $expectedItemGroups = [
267  'none', // Invalid database value gets special "none" group
268  'example-group', // Header item for 'example-group'
269  'example-group', // Item 'anotherValue'
270  'itemgroup1', // Header item for 'itemgroup1' <- dynamic from database value
271  'itemgroup1', // Item uid=1
272  'itemgroup2', // Header item for 'itemgroup2' <- dynamic from database value
273  'itemgroup2', // Item uid=2
274  'itemgroup2', // Item uid=6
275  'itemgroup3', // Header item for 'itemgroup3' <- dynamic from database value
276  'itemgroup3', // Item uid=3
277  'itemgroup3', // Item uid=4
278  'itemgroup3', // Item uid=5
279  ];
280 
281  $result = (new TcaSelectItems())->addData($input);
282  $resultItems = $result['processedTca']['columns']['aField']['config']['items'];
283  $resultItemGroups = array_column($resultItems, 'group');
284 
285  self::assertSame($expectedItemGroups, $resultItemGroups);
286  }
287 
288  #[Test]
289  public function addDataKeepsIconFromItem(): void
290  {
291  $input = [
292  'tableName' => 'aTable',
293  'databaseRow' => [
294  'aField' => 'aValue',
295  ],
296  'processedTca' => [
297  'columns' => [
298  'aField' => [
299  'config' => [
300  'type' => 'select',
301  'renderType' => 'selectSingle',
302  'items' => [
303  0 => [
304  'label' => 'aLabel',
305  'value' => 'aValue',
306  'icon' => 'an-icon-reference',
307  'group' => null,
308  'description' => null,
309  ],
310  ],
311  'maxitems' => 99999,
312  ],
313  ],
314  ],
315  ],
316  ];
317 
318  $expected = $input;
319  $expected['databaseRow']['aField'] = ['aValue'];
320 
321  self::assertSame($expected, (new TcaSelectItems())->addData($input));
322  }
323 
324  #[Test]
325  public function addDataAddsFileItemsWithConfiguredFileFolder(): void
326  {
327  $directory = ‪Environment::getVarPath() . '/' . ‪StringUtility::getUniqueId('test-') . '/';
328  $input = [
329  'tableName' => 'aTable',
330  'databaseRow' => [],
331  'processedTca' => [
332  'columns' => [
333  'aField' => [
334  'config' => [
335  'type' => 'select',
336  'renderType' => 'selectSingle',
337  'fileFolderConfig' => [
338  'folder' => $directory,
339  'allowedExtensions' => 'gif',
340  'depth' => 1,
341  ],
342  ],
343  ],
344  ],
345  ],
346  ];
347 
348  mkdir($directory);
349  touch($directory . 'anImage.gif');
350  touch($directory . 'aFile.txt');
351  mkdir($directory . '/subdir');
352  touch($directory . '/subdir/anotherImage.gif');
353  mkdir($directory . '/subdir/subsubdir');
354  touch($directory . '/subdir/subsubdir/anotherImage.gif');
355 
356  $expectedItems = [
357  0 => [
358  'label' => 'anImage.gif',
359  'value' => 'anImage.gif',
360  'icon' => $directory . 'anImage.gif',
361  'group' => null,
362  'description' => null,
363  ],
364  1 => [
365  'label' => 'subdir/anotherImage.gif',
366  'value' => 'subdir/anotherImage.gif',
367  'icon' => $directory . 'subdir/anotherImage.gif',
368  'group' => null,
369  'description' => null,
370  ],
371  ];
372 
373  $result = (new TcaSelectItems())->addData($input);
374 
375  self::assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
376  }
377 
378  #[Test]
379  public function addDataAddsFileItemsWithOverwrittenFileFolder(): void
380  {
381  $directory = ‪Environment::getVarPath() . '/' . ‪StringUtility::getUniqueId('test-') . '/';
382  $overriddenDirectory = ‪Environment::getVarPath() . '/' . ‪StringUtility::getUniqueId('test-overridden-') . '/';
383  $input = [
384  'tableName' => 'aTable',
385  'databaseRow' => [],
386  'processedTca' => [
387  'columns' => [
388  'aField' => [
389  'config' => [
390  'type' => 'select',
391  'renderType' => 'selectSingle',
392  'fileFolderConfig' => [
393  'folder' => $directory,
394  'allowedExtensions' => 'gif',
395  'depth' => 1,
396  ],
397  ],
398  ],
399  ],
400  ],
401  'pageTsConfig' => [
402  'TCEFORM.' => [
403  'aTable.' => [
404  'aField.' => [
405  'config.' => [
406  'fileFolderConfig.' => [
407  'folder' => $overriddenDirectory,
408  'allowedExtensions' => 'svg',
409  'depth' => 0,
410  ],
411  ],
412  ],
413  ],
414  ],
415  ],
416  ];
417 
418  mkdir($directory);
419  touch($directory . 'anImage.gif');
420  touch($directory . 'aFile.txt');
421  touch($directory . 'aIcon.svg');
422  mkdir($directory . '/subdir');
423  touch($directory . '/subdir/anotherImage.gif');
424  touch($directory . '/subdir/anotherFile.txt');
425  touch($directory . '/subdir/anotherIcon.txt');
426 
427  mkdir($overriddenDirectory);
428  touch($overriddenDirectory . 'anOverriddenImage.gif');
429  touch($overriddenDirectory . 'anOverriddenFile.txt');
430  touch($overriddenDirectory . 'anOverriddenIcon.svg');
431  mkdir($overriddenDirectory . '/subdir');
432  touch($overriddenDirectory . '/subdir/anotherOverriddenImage.gif');
433  touch($overriddenDirectory . '/subdir/anotherOverriddenFile.txt');
434  touch($overriddenDirectory . '/subdir/anotherOverriddenIcon.svg');
435 
436  $expectedItems = [
437  0 => [
438  'label' => 'anOverriddenIcon.svg',
439  'value' => 'anOverriddenIcon.svg',
440  'icon' => $overriddenDirectory . 'anOverriddenIcon.svg',
441  'group' => null,
442  'description' => null,
443  ],
444  ];
445 
446  $result = (new TcaSelectItems())->addData($input);
447 
448  self::assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
449  }
450 
451  #[Test]
452  public function addDataThrowsExceptionForInvalidFileFolder(): void
453  {
454  $input = [
455  'tableName' => 'aTable',
456  'databaseRow' => [],
457  'processedTca' => [
458  'columns' => [
459  'aField' => [
460  'config' => [
461  'type' => 'select',
462  'renderType' => 'selectSingle',
463  'fileFolderConfig' => [
464  'folder' => 'EXT:non_existing/Resources/Public/',
465  ],
466  ],
467  ],
468  ],
469  ],
470  ];
471 
472  $this->expectException(\RuntimeException::class);
473  $this->expectExceptionCode(1479399227);
474  (new TcaSelectItems())->addData($input);
475  }
476 
477  #[Test]
478  public function addDataAddsItemsByAddItemsFromPageTsConfig(): void
479  {
480  $input = [
481  'databaseRow' => [
482  'aField' => '',
483  ],
484  'tableName' => 'aTable',
485  'processedTca' => [
486  'columns' => [
487  'aField' => [
488  'config' => [
489  'type' => 'select',
490  'renderType' => 'selectSingle',
491  'items' => [
492  0 => [
493  'label' => 'keepMe',
494  'value' => 'keep',
495  'icon' => null,
496  'group' => null,
497  'description' => null,
498  ],
499  ],
500  'maxitems' => 99999,
501  ],
502  ],
503  ],
504  ],
505  'pageTsConfig' => [
506  'TCEFORM.' => [
507  'aTable.' => [
508  'aField.' => [
509  'addItems.' => [
510  '1' => 'addMe',
511  ],
512  ],
513  ],
514  ],
515  ],
516  ];
517 
518  $expected = $input;
519  $expected['databaseRow']['aField'] = [];
520  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
521  'label' => 'addMe',
522  'value' => 1,
523  'icon' => null,
524  'group' => null,
525  'description' => null,
526  ];
527 
528  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
529  }
530 
531  #[Test]
532  public function addDataAddsItemsByAddItemsWithGroupFromPageTsConfig(): void
533  {
534  $input = [
535  'databaseRow' => [
536  'aField' => '',
537  ],
538  'tableName' => 'aTable',
539  'processedTca' => [
540  'columns' => [
541  'aField' => [
542  'config' => [
543  'type' => 'select',
544  'renderType' => 'selectSingle',
545  'items' => [
546  0 => [
547  'label' => 'keepMe',
548  'value' => 'keep',
549  'icon' => null,
550  'group' => 'none',
551  'description' => null,
552  ],
553  ],
554  'maxitems' => 99999,
555  ],
556  ],
557  ],
558  ],
559  'pageTsConfig' => [
560  'TCEFORM.' => [
561  'aTable.' => [
562  'aField.' => [
563  'addItems.' => [
564  '1' => 'addMe',
565  '1.' => [
566  'group' => 'custom-group',
567  ],
568  ],
569  ],
570  ],
571  ],
572  ],
573  ];
574 
575  $expected = $input;
576  $expected['databaseRow']['aField'] = [];
577  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
578  'label' => 'custom-group',
579  'value' => '--div--',
580  'group' => 'custom-group',
581  ];
582  $expected['processedTca']['columns']['aField']['config']['items'][2] = [
583  'label' => 'addMe',
584  'value' => 1,
585  'icon' => null,
586  'group' => 'custom-group',
587  'description' => null,
588  ];
589 
590  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
591  }
592 
593  #[Test]
594  public function addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig(): void
595  {
596  $input = [
597  'databaseRow' => [
598  'aField' => '',
599  ],
600  'tableName' => 'aTable',
601  'processedTca' => [
602  'columns' => [
603  'aField' => [
604  'config' => [
605  'type' => 'select',
606  'renderType' => 'selectSingle',
607  'items' => [
608  0 => [
609  'label' => 'keepMe',
610  'value' => 'keep',
611  'icon' => null,
612  'group' => null,
613  'description' => null,
614  ],
615  ],
616  'maxitems' => 99999,
617  ],
618  ],
619  ],
620  ],
621  'pageTsConfig' => [
622  'TCEFORM.' => [
623  'aTable.' => [
624  'aField.' => [
625  'addItems.' => [
626  'keep' => 'addMe',
627  ],
628  ],
629  ],
630  ],
631  ],
632  ];
633 
634  $expected = $input;
635  $expected['databaseRow']['aField'] = [];
636  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
637  'label' => 'addMe',
638  'value' => 'keep',
639  'icon' => null,
640  'group' => null,
641  'description' => null,
642  ];
643 
644  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
645  }
646 
647  public static function addDataReplacesMarkersInForeignTableClauseDataProvider(): array
648  {
649  return [
650  'replace REC_FIELD' => [
651  'AND foreign_table.title=\'###REC_FIELD_rowField###\'',
652  [
653  [
654  'label' => 'Item 1',
655  'value' => 1,
656  'icon' => 'default-not-found',
657  'group' => null,
658  'description' => null,
659  ],
660  ],
661  [],
662  ],
663  'replace REC_FIELD within FlexForm' => [
664  'AND foreign_table.title=###REC_FIELD_rowFieldFlexForm###',
665  [
666  [
667  'label' => 'Item 2',
668  'value' => 2,
669  'icon' => 'default-not-found',
670  'group' => null,
671  'description' => null,
672  ],
673  ],
674  [
675  'databaseRow' => [
676  'rowFieldThree' => [
677  0 => 'rowFieldThreeValue',
678  ],
679  ],
680  'flexParentDatabaseRow' => [
681  'rowFieldFlexForm' => [
682  0 => 'Item 2',
683  ],
684  ],
685  ],
686  ],
687  'replace REC_FIELD fullQuote' => [
688  'AND foreign_table.title=###REC_FIELD_rowField###',
689  [
690  [
691  'label' => 'Item 1',
692  'value' => 1,
693  'icon' => 'default-not-found',
694  'group' => null,
695  'description' => null,
696  ],
697  ],
698  [],
699  ],
700  'replace REC_FIELD fullQuoteWithArray' => [
701  'AND foreign_table.title=###REC_FIELD_rowFieldThree###',
702  [
703  [
704  'label' => 'Item 3',
705  'value' => 3,
706  'icon' => 'default-not-found',
707  'group' => null,
708  'description' => null,
709  ],
710  ],
711  [
712  'databaseRow' => [
713  'rowFieldThree' => [
714  0 => 'Item 3',
715  ],
716  ],
717  ],
718  ],
719  'replace REC_FIELD multiple markers' => [
720  'AND ( foreign_table.title=\'###REC_FIELD_rowField###\' OR foreign_table.title=###REC_FIELD_rowFieldTwo### )',
721  [
722  [
723  'label' => 'Item 1',
724  'value' => 1,
725  'icon' => 'default-not-found',
726  'group' => null,
727  'description' => null,
728  ],
729  [
730  'label' => 'Item 2',
731  'value' => 2,
732  'icon' => 'default-not-found',
733  'group' => null,
734  'description' => null,
735  ],
736  ],
737  [],
738  ],
739  'replace CURRENT_PID' => [
740  'AND foreign_table.uid=###CURRENT_PID###',
741  [
742  [
743  'label' => 'Item 1',
744  'value' => 1,
745  'icon' => 'default-not-found',
746  'group' => null,
747  'description' => null,
748  ],
749  ],
750  [],
751  ],
752  'replace CURRENT_PID within FlexForm' => [
753  'AND foreign_table.uid=###CURRENT_PID###',
754  [
755  [
756  'label' => 'Item 4',
757  'value' => 4,
758  'icon' => 'default-not-found',
759  'group' => null,
760  'description' => null,
761  ],
762  ],
763  [
764  'flexParentDatabaseRow' => [
765  'pid' => '4',
766  ],
767  ],
768  ],
769  'replace CURRENT_PID integer cast' => [
770  'AND foreign_table.uid=###CURRENT_PID###',
771  [
772  [
773  'label' => 'Item 4',
774  'value' => 4,
775  'icon' => 'default-not-found',
776  'group' => null,
777  'description' => null,
778  ],
779  ],
780  [
781  'effectivePid' => '4string',
782  ],
783  ],
784  'replace THIS_UID' => [
785  'AND foreign_table.uid=###THIS_UID###',
786  [
787  [
788  'label' => 'Item 5',
789  'value' => 5,
790  'icon' => 'default-not-found',
791  'group' => null,
792  'description' => null,
793  ],
794  ],
795  [],
796  ],
797  'replace THIS_UID integer cast' => [
798  'AND foreign_table.uid=###THIS_UID###',
799  [
800  [
801  'label' => 'Item 5',
802  'value' => 5,
803  'icon' => 'default-not-found',
804  'group' => null,
805  'description' => null,
806  ],
807  ],
808  [
809  'databaseRow' => [
810  'uid' => '5string',
811  ],
812  ],
813  ],
814  'replace SITEROOT' => [
815  'AND foreign_table.uid=###SITEROOT###',
816  [
817  [
818  'label' => 'Item 6',
819  'value' => 6,
820  'icon' => 'default-not-found',
821  'group' => null,
822  'description' => null,
823  ],
824  ],
825  [],
826  ],
827  'replace SITEROOT integer cast' => [
828  'AND foreign_table.uid=###SITEROOT###',
829  [
830  [
831  'label' => 'Item 6',
832  'value' => 6,
833  'icon' => 'default-not-found',
834  'group' => null,
835  'description' => null,
836  ],
837  ],
838  [
839  'rootline' => [
840  1 => [
841  'uid' => '6string',
842  ],
843  ],
844  ],
845  ],
846  'replace PAGE_TSCONFIG_ID' => [
847  'AND foreign_table.uid=###PAGE_TSCONFIG_ID###',
848  [
849  [
850  'label' => 'Item 3',
851  'value' => 3,
852  'icon' => 'default-not-found',
853  'group' => null,
854  'description' => null,
855  ],
856  ],
857  [
858  'pageTsConfig' => [
859  'TCEFORM.' => [
860  'tca_select_items.' => [
861  'aField.' => [
862  'PAGE_TSCONFIG_ID' => '3',
863  ],
864  ],
865  ],
866  ],
867  ],
868  ],
869  'replace PAGE_TSCONFIG_ID integer cast' => [
870  'AND foreign_table.uid=###PAGE_TSCONFIG_ID###',
871  [
872  [
873  'label' => 'Item 3',
874  'value' => 3,
875  'icon' => 'default-not-found',
876  'group' => null,
877  'description' => null,
878  ],
879  ],
880  [
881  'pageTsConfig' => [
882  'TCEFORM.' => [
883  'tca_select_items.' => [
884  'aField.' => [
885  'PAGE_TSCONFIG_ID' => '3string',
886  ],
887  ],
888  ],
889  ],
890  ],
891  ],
892  'replace PAGE_TSCONFIG_STR' => [
893  'AND foreign_table.uid=\'###PAGE_TSCONFIG_STR###\'',
894  [
895  [
896  'label' => 'Item 4',
897  'value' => 4,
898  'icon' => 'default-not-found',
899  'group' => null,
900  'description' => null,
901  ],
902  ],
903  [
904  'pageTsConfig' => [
905  'TCEFORM.' => [
906  'tca_select_items.' => [
907  'aField.' => [
908  'PAGE_TSCONFIG_STR' => '4',
909  ],
910  ],
911  ],
912  ],
913  ],
914  ],
915  'replace PAGE_TSCONFIG_IDLIST' => [
916  'AND foreign_table.uid IN (###PAGE_TSCONFIG_IDLIST###)',
917  [
918  [
919  'label' => 'Item 3',
920  'value' => 3,
921  'icon' => 'default-not-found',
922  'group' => null,
923  'description' => null,
924  ],
925  [
926  'label' => 'Item 4',
927  'value' => 4,
928  'icon' => 'default-not-found',
929  'group' => null,
930  'description' => null,
931  ],
932  ],
933  [
934  'pageTsConfig' => [
935  'TCEFORM.' => [
936  'tca_select_items.' => [
937  'aField.' => [
938  'PAGE_TSCONFIG_IDLIST' => '3,4',
939  ],
940  ],
941  ],
942  ],
943  ],
944  ],
945  'replace PAGE_TSCONFIG_IDLIST cleans list' => [
946  'AND foreign_table.uid IN (###PAGE_TSCONFIG_IDLIST###)',
947  [
948  [
949  'label' => 'Item 3',
950  'value' => 3,
951  'icon' => 'default-not-found',
952  'group' => null,
953  'description' => null,
954  ],
955  [
956  'label' => 'Item 4',
957  'value' => 4,
958  'icon' => 'default-not-found',
959  'group' => null,
960  'description' => null,
961  ],
962  ],
963  [
964  'pageTsConfig' => [
965  'TCEFORM.' => [
966  'tca_select_items.' => [
967  'aField.' => [
968  'PAGE_TSCONFIG_IDLIST' => 'a, 3, b, 4, c',
969  ],
970  ],
971  ],
972  ],
973  ],
974  ],
975  'replace SITE:rootPageId' => [
976  'AND foreign_table.uid = ###SITE:rootPageId###',
977  [
978  [
979  'label' => 'Item 6',
980  'value' => 6,
981  'icon' => 'default-not-found',
982  'group' => null,
983  'description' => null,
984  ],
985  ],
986  [],
987  ],
988  'replace SITE:mySetting.foobar' => [
989  'AND foreign_table.title = ###SITE:mySetting.foobar###',
990  [
991  [
992  'label' => 'Item 5',
993  'value' => 5,
994  'icon' => 'default-not-found',
995  'group' => null,
996  'description' => null,
997  ],
998  ],
999  [],
1000  ],
1001  'replace SITE:mySetting.doesNotExist' => [
1002  'AND foreign_table.title = ###SITE:mySetting.doesNotExist###',
1003  [],
1004  [],
1005  ],
1006  'replace SITE:rootPageId, SITE:mySetting.foobar and PAGE_TSCONFIG_IDLIST' => [
1007  'AND ( foreign_table.uid = ###SITE:rootPageId### OR foreign_table.title = ###SITE:mySetting.foobar### OR foreign_table.uid IN (###PAGE_TSCONFIG_IDLIST###) )',
1008  [
1009  [
1010  'label' => 'Item 3',
1011  'value' => 3,
1012  'icon' => 'default-not-found',
1013  'group' => null,
1014  'description' => null,
1015  ],
1016  [
1017  'label' => 'Item 4',
1018  'value' => 4,
1019  'icon' => 'default-not-found',
1020  'group' => null,
1021  'description' => null,
1022  ],
1023  [
1024  'label' => 'Item 5',
1025  'value' => 5,
1026  'icon' => 'default-not-found',
1027  'group' => null,
1028  'description' => null,
1029  ],
1030  [
1031  'label' => 'Item 6',
1032  'value' => 6,
1033  'icon' => 'default-not-found',
1034  'group' => null,
1035  'description' => null,
1036  ],
1037  ],
1038  [
1039  'pageTsConfig' => [
1040  'TCEFORM.' => [
1041  'tca_select_items.' => [
1042  'aField.' => [
1043  'PAGE_TSCONFIG_IDLIST' => 'a, 3, b, 4, c',
1044  ],
1045  ],
1046  ],
1047  ],
1048  ],
1049  ],
1050  ];
1051  }
1052 
1053  #[DataProvider('addDataReplacesMarkersInForeignTableClauseDataProvider')]
1054  #[Test]
1055  public function addDataReplacesMarkersInForeignTableClause(string $foreignTableWhere, array $expectedItems, array $inputOverride): void
1056  {
1057  $input = [
1058  'tableName' => 'tca_select_items',
1059  'effectivePid' => 1,
1060  'databaseRow' => [
1061  'uid' => 5,
1062  'rowField' => 'Item 1',
1063  'rowFieldTwo' => 'Item 2',
1064  ],
1065  'processedTca' => [
1066  'columns' => [
1067  'aField' => [
1068  'config' => [
1069  'type' => 'select',
1070  'renderType' => 'selectSingle',
1071  'foreign_table' => 'foreign_table',
1072  'foreign_table_where' => $foreignTableWhere,
1073  'maxitems' => 1,
1074  ],
1075  ],
1076  ],
1077  ],
1078  'rootline' => [
1079  2 => [
1080  'uid' => 999,
1081  'is_siteroot' => 0,
1082  ],
1083  1 => [
1084  'uid' => 6,
1085  'is_siteroot' => 1,
1086  ],
1087  0 => [
1088  'uid' => 0,
1089  'is_siteroot' => null,
1090  ],
1091  ],
1092  'pageTsConfig' => [],
1093  'site' => new Site('some-site', 6, ['rootPageId' => 6, 'mySetting' => ['foobar' => 'Item 5']]),
1094  ];
1095  ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
1096 
1097  $expected = $input;
1098  $expected['processedTca']['columns']['aField']['config']['items'] = $expectedItems;
1099  $expected['databaseRow']['aField'] = [];
1100 
1101  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1102  }
1103 
1104  #[Test]
1105  public function addDataThrowsExceptionIfForeignTableIsNotDefinedInTca(): void
1106  {
1107  $input = [
1108  'tableName' => 'aTable',
1109  'processedTca' => [
1110  'columns' => [
1111  'aField' => [
1112  'config' => [
1113  'type' => 'select',
1114  'renderType' => 'selectSingle',
1115  'foreign_table' => 'fTableNotDefined',
1116  ],
1117  ],
1118  ],
1119  ],
1120  ];
1121 
1122  $this->expectException(\UnexpectedValueException::class);
1123  $this->expectExceptionCode(1439569743);
1124 
1125  (new TcaSelectItems())->addData($input);
1126  }
1127 
1128  #[Test]
1129  public function addDataForeignTableSplitsGroupOrderAndLimit(): void
1130  {
1131  $input = [
1132  'tableName' => 'aTable',
1133  'effectivePid' => 1,
1134  'databaseRow' => [
1135  'uid' => 1,
1136  ],
1137  'processedTca' => [
1138  'columns' => [
1139  'aField' => [
1140  'config' => [
1141  'type' => 'select',
1142  'renderType' => 'selectSingle',
1143  'maxitems' => 99999,
1144  'foreign_table' => 'foreign_table',
1145  // @todo Using "uid", "pid" and "title" inside GROUP BY to satisfy the `ONLY_FULL_GROUP_BY` rule on
1146  // @todo some dbms. Doing so renders the GROUP statement useless, though.
1147  'foreign_table_where' => '
1148  AND foreign_table.uid > 1
1149  GROUP BY uid, pid, title, groupingfield1, groupingfield2
1150  ORDER BY uid
1151  LIMIT 1,2',
1152  ],
1153  ],
1154  ],
1155  ],
1156  'rootline' => [],
1157  'site' => null,
1158  ];
1159 
1160  $expected = $input;
1161 
1162  $expected['processedTca']['columns']['aField']['config']['items'] = [
1163  [
1164  'label' => 'Item 3',
1165  'value' => 3,
1166  'icon' => 'default-not-found',
1167  'group' => null,
1168  'description' => null,
1169  ],
1170  [
1171  'label' => 'Item 4',
1172  'value' => 4,
1173  'icon' => 'default-not-found',
1174  'group' => null,
1175  'description' => null,
1176  ],
1177  ];
1178 
1179  $expected['databaseRow']['aField'] = [];
1180 
1181  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1182  }
1183 
1184  #[Test]
1185  public function addDataForeignTableQueuesFlashMessageOnDatabaseError(): void
1186  {
1187  $input = [
1188  'databaseRow' => [
1189  'uid' => 1,
1190  'aField' => '',
1191  ],
1192  'tableName' => 'aTable',
1193  'effectivePid' => 1,
1194  'processedTca' => [
1195  'columns' => [
1196  'aField' => [
1197  'config' => [
1198  'type' => 'select',
1199  'renderType' => 'selectSingle',
1200  'foreign_table' => 'non_existing_table',
1201  'items' => [
1202  0 => [
1203  'label' => 'itemLabel',
1204  'value' => 'itemValue',
1205  'icon' => null,
1206  'group' => null,
1207  'description' => null,
1208  ],
1209  ],
1210  'maxitems' => 99999,
1211  ],
1212  ],
1213  ],
1214  ],
1215  'rootline' => [],
1216  ];
1217 
1218  ‪$GLOBALS['TCA']['non_existing_table'] = [];
1219  $expected = $input;
1220  $expected['databaseRow']['aField'] = [];
1221 
1222  $result = (new TcaSelectItems())->addData($input);
1223  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1224  $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1225 
1226  self::assertEquals($expected, $result);
1227  self::assertCount(1, $flashMessageQueue->getAllMessages());
1228  }
1229 
1230  #[Test]
1231  public function addDataForeignTableHandlesForeignTableRows(): void
1232  {
1233  $input = [
1234  'databaseRow' => [
1235  'uid' => 1,
1236  'aField' => '',
1237  ],
1238  'tableName' => 'aTable',
1239  'effectivePid' => 1,
1240  'processedTca' => [
1241  'columns' => [
1242  'aField' => [
1243  'config' => [
1244  'type' => 'select',
1245  'renderType' => 'selectSingle',
1246  'foreign_table' => 'foreign_table',
1247  'foreign_table_prefix' => 'aPrefix',
1248  'foreign_table_where' => 'AND foreign_table.uid = 1',
1249  'items' => [],
1250  'maxitems' => 99999,
1251  ],
1252  ],
1253  ],
1254  ],
1255  'site' => null,
1256  'rootline' => [],
1257  ];
1258 
1259  $expected = $input;
1260  $expected['databaseRow']['aField'] = [];
1261  $expected['processedTca']['columns']['aField']['config']['items'] = [
1262  [
1263  'label' => 'aPrefixItem 1',
1264  'value' => 1,
1265  'icon' => 'default-not-found',
1266  'group' => null,
1267  'description' => null,
1268  ],
1269  ];
1270 
1271  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1272  }
1273 
1274  #[Test]
1275  public function addDataRemovesItemsThatAreRestrictedByUserStorageAddedByForeignTable(): void
1276  {
1277  $input = [
1278  'databaseRow' => [
1279  'uid' => 1,
1280  'aField' => '',
1281  ],
1282  'tableName' => 'aTable',
1283  'effectivePid' => 1,
1284  'processedTca' => [
1285  'columns' => [
1286  'aField' => [
1287  'config' => [
1288  'type' => 'select',
1289  'renderType' => 'selectSingle',
1290  'foreign_table' => 'sys_file_storage',
1291  'items' => [
1292  [
1293  'label' => 'some other file storage',
1294  'value' => 2,
1295  ],
1296  ],
1297  'maxitems' => 99999,
1298  ],
1299  ],
1300  ],
1301  ],
1302  'rootline' => [],
1303  ];
1304 
1305  $expected = $input;
1306  $expected['databaseRow']['aField'] = [];
1307  $expected['processedTca']['columns']['aField']['config']['items'] = [
1308  [
1309  'label' => 'fileadmin/ (auto-created)',
1310  'value' => 1,
1311  'icon' => 'mimetypes-x-sys_file_storage',
1312  'group' => null,
1313  'description' => null,
1314  ],
1315  ];
1316 
1317  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1318  }
1319 
1320  #[Test]
1321  public function addDataForeignTableResolvesIconFromSelicon(): void
1322  {
1323  $input = [
1324  'databaseRow' => [
1325  'uid' => 1,
1326  'aField' => '',
1327  ],
1328  'tableName' => 'aTable',
1329  'effectivePid' => 1,
1330  'processedTca' => [
1331  'columns' => [
1332  'aField' => [
1333  'config' => [
1334  'type' => 'select',
1335  'renderType' => 'selectSingle',
1336  'foreign_table' => 'foreign_table',
1337  'foreign_table_where' => 'AND foreign_table.uid < 3',
1338  'maxitems' => 99999,
1339  ],
1340  ],
1341  ],
1342  ],
1343  'site' => null,
1344  'rootline' => [],
1345  ];
1346 
1347  $expected = $input;
1348  $expected['databaseRow']['aField'] = [];
1349  $expected['processedTca']['columns']['aField']['config']['items'] = [
1350  [
1351  'label' => 'Item 1',
1352  'value' => 1,
1353  'icon' => 'fileadmin/file1.png',
1354  'group' => null,
1355  'description' => null,
1356  ],
1357  [
1358  'label' => 'Item 2',
1359  'value' => 2,
1360  'icon' => 'fileadmin/file2.png',
1361  'group' => null,
1362  'description' => null,
1363  ],
1364  ];
1365 
1366  $this->importCSVDataSet(__DIR__ . '/../Fixtures/TcaSelectItems/sys_file_reference.csv');
1367  ‪$GLOBALS['TCA']['foreign_table']['ctrl']['selicon_field'] = 'fal_field';
1368 
1369  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1370  }
1371 
1372  #[Test]
1373  public function addDataRemovesItemsByKeepItemsPageTsConfig(): void
1374  {
1375  $input = [
1376  'databaseRow' => [
1377  'aField' => '',
1378  ],
1379  'tableName' => 'aTable',
1380  'processedTca' => [
1381  'columns' => [
1382  'aField' => [
1383  'config' => [
1384  'type' => 'select',
1385  'renderType' => 'selectSingle',
1386  'items' => [
1387  0 => [
1388  'label' => 'keepMe',
1389  'value' => 'keep',
1390  'icon' => null,
1391  'group' => null,
1392  'description' => null,
1393  ],
1394  1 => [
1395  'label' => 'removeMe',
1396  'value' => 'remove',
1397  ],
1398  2 => [
1399  'label' => 'removeMe',
1400  'value' => 0,
1401  ],
1402  ],
1403  'maxitems' => 99999,
1404  ],
1405  ],
1406  ],
1407  ],
1408  'pageTsConfig' => [
1409  'TCEFORM.' => [
1410  'aTable.' => [
1411  'aField.' => [
1412  'keepItems' => 'keep',
1413  ],
1414  ],
1415  ],
1416  ],
1417  ];
1418 
1419  $expected = $input;
1420  $expected['databaseRow']['aField'] = [];
1421  unset(
1422  $expected['processedTca']['columns']['aField']['config']['items'][1],
1423  $expected['processedTca']['columns']['aField']['config']['items'][2]
1424  );
1425 
1426  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1427  }
1428 
1429  #[Test]
1430  public function addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig(): void
1431  {
1432  $input = [
1433  'databaseRow' => [
1434  'aField' => '',
1435  ],
1436  'tableName' => 'aTable',
1437  'processedTca' => [
1438  'columns' => [
1439  'aField' => [
1440  'config' => [
1441  'type' => 'select',
1442  'renderType' => 'selectSingle',
1443  'items' => [
1444  0 => [
1445  0 => 'keepMe',
1446  1 => 'keep',
1447  null,
1448  null,
1449  ],
1450  1 => [
1451  0 => 'removeMe',
1452  1 => 'remove',
1453  ],
1454  ],
1455  'maxitems' => 99999,
1456  ],
1457  ],
1458  ],
1459  ],
1460  'pageTsConfig' => [
1461  'TCEFORM.' => [
1462  'aTable.' => [
1463  'aField.' => [
1464  'keepItems' => '',
1465  ],
1466  ],
1467  ],
1468  ],
1469  ];
1470 
1471  $expected = $input;
1472  $expected['databaseRow']['aField'] = [];
1473  $expected['processedTca']['columns']['aField']['config']['items'] = [];
1474 
1475  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1476  }
1477 
1478  #[Test]
1479  public function addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig(): void
1480  {
1481  $input = [
1482  'databaseRow' => [
1483  'aField' => '',
1484  ],
1485  'tableName' => 'aTable',
1486  'processedTca' => [
1487  'columns' => [
1488  'aField' => [
1489  'config' => [
1490  'type' => 'select',
1491  'renderType' => 'selectSingle',
1492  'items' => [
1493  0 => [
1494  'label' => 'keepMe',
1495  'value' => '1',
1496  'icon' => null,
1497  'group' => null,
1498  ],
1499  1 => [
1500  'label' => 'removeMe',
1501  'value' => 'remove',
1502  ],
1503  ],
1504  'maxitems' => 99999,
1505  ],
1506  ],
1507  ],
1508  ],
1509  'pageTsConfig' => [
1510  'TCEFORM.' => [
1511  'aTable.' => [
1512  'aField.' => [
1513  'keepItems' => '1',
1514  'addItems.' => [
1515  '1' => 'addItem #1',
1516  '12' => 'addItem #12',
1517  ],
1518  ],
1519  ],
1520  ],
1521  ],
1522  ];
1523 
1524  $expected = $input;
1525  $expected['databaseRow']['aField'] = [];
1526  $expected['processedTca']['columns']['aField']['config']['items'] = [
1527  0 => [
1528  'label' => 'keepMe',
1529  'value' => '1',
1530  'icon' => null,
1531  'group' => null,
1532  'description' => null,
1533  ],
1534  1 => [
1535  'label' => 'addItem #1',
1536  'value' => '1',
1537  'icon' => null,
1538  'group' => null,
1539  'description' => null,
1540  ],
1541  2 => [
1542  'label' => 'addItem #12',
1543  'value' => '12',
1544  'icon' => null,
1545  'group' => null,
1546  'description' => null,
1547  ],
1548  ];
1549 
1550  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1551  }
1552 
1553  #[Test]
1554  public function addDataRemovesItemsByRemoveItemsPageTsConfig(): void
1555  {
1556  $input = [
1557  'databaseRow' => [
1558  'aField' => '',
1559  ],
1560  'tableName' => 'aTable',
1561  'processedTca' => [
1562  'columns' => [
1563  'aField' => [
1564  'config' => [
1565  'type' => 'select',
1566  'renderType' => 'selectSingle',
1567  'items' => [
1568  0 => [
1569  'label' => 'keepMe',
1570  'value' => 'keep',
1571  'icon' => null,
1572  'group' => null,
1573  'description' => null,
1574  ],
1575  1 => [
1576  'label' => 'removeMe',
1577  'value' => 'remove',
1578  ],
1579  2 => [
1580  'label' => 'keep me',
1581  'value' => 0,
1582  'icon' => null,
1583  'group' => null,
1584  'description' => null,
1585  ],
1586  ],
1587  'maxitems' => 99999,
1588  ],
1589  ],
1590  ],
1591  ],
1592  'pageTsConfig' => [
1593  'TCEFORM.' => [
1594  'aTable.' => [
1595  'aField.' => [
1596  'removeItems' => 'remove',
1597  ],
1598  ],
1599  ],
1600  ],
1601  ];
1602 
1603  $expected = $input;
1604  $expected['databaseRow']['aField'] = [];
1605  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1606  $expected['processedTca']['columns']['aField']['config']['items'] = array_values($expected['processedTca']['columns']['aField']['config']['items']);
1607  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1608  }
1609 
1610  #[Test]
1611  public function addDataRemovesItemsByZeroValueRemoveItemsPageTsConfig(): void
1612  {
1613  $input = [
1614  'databaseRow' => [
1615  'aField' => '',
1616  ],
1617  'tableName' => 'aTable',
1618  'processedTca' => [
1619  'columns' => [
1620  'aField' => [
1621  'config' => [
1622  'type' => 'select',
1623  'renderType' => 'selectSingle',
1624  'items' => [
1625  0 => [
1626  'label' => 'keepMe',
1627  'value' => 'keep',
1628  'icon' => null,
1629  'group' => null,
1630  'description' => null,
1631  ],
1632  1 => [
1633  'label' => 'keepMe',
1634  'value' => 'keepMe2',
1635  'icon' => null,
1636  'group' => null,
1637  'description' => null,
1638  ],
1639  2 => [
1640  'label' => 'remove me',
1641  'value' => 0,
1642  ],
1643  ],
1644  'maxitems' => 99999,
1645  ],
1646  ],
1647  ],
1648  ],
1649  'pageTsConfig' => [
1650  'TCEFORM.' => [
1651  'aTable.' => [
1652  'aField.' => [
1653  'removeItems' => '0',
1654  ],
1655  ],
1656  ],
1657  ],
1658  ];
1659 
1660  $expected = $input;
1661  $expected['databaseRow']['aField'] = [];
1662  unset($expected['processedTca']['columns']['aField']['config']['items'][2]);
1663  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1664  }
1665 
1666  #[Test]
1667  public function addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig(): void
1668  {
1669  $input = [
1670  'databaseRow' => [
1671  'aField' => '',
1672  ],
1673  'tableName' => 'aTable',
1674  'processedTca' => [
1675  'columns' => [
1676  'aField' => [
1677  'config' => [
1678  'type' => 'select',
1679  'renderType' => 'selectSingle',
1680  'items' => [
1681  0 => [
1682  'label' => 'keepMe',
1683  'value' => 'keep',
1684  'icon' => null,
1685  'group' => null,
1686  'description' => null,
1687  ],
1688  1 => [
1689  'label' => 'removeMe',
1690  'value' => 'remove',
1691  ],
1692  ],
1693  'maxitems' => 99999,
1694  ],
1695  ],
1696  ],
1697  ],
1698  'pageTsConfig' => [
1699  'TCEFORM.' => [
1700  'aTable.' => [
1701  'aField.' => [
1702  'removeItems' => 'remove,add',
1703  'addItems.' => [
1704  'add' => 'addMe',
1705  ],
1706  ],
1707  ],
1708  ],
1709  ],
1710  ];
1711 
1712  $expected = $input;
1713  $expected['databaseRow']['aField'] = [];
1714  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1715 
1716  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1717  }
1718 
1719  #[Test]
1720  public function addDataRemovesItemsByLanguageFieldUserRestriction(): void
1721  {
1722  $input = [
1723  'databaseRow' => [
1724  'aField' => '0',
1725  ],
1726  'tableName' => 'aTable',
1727  'processedTca' => [
1728  'ctrl' => [
1729  'languageField' => 'aField',
1730  ],
1731  'columns' => [
1732  'aField' => [
1733  'config' => [
1734  'type' => 'select',
1735  'renderType' => 'selectSingle',
1736  'items' => [
1737  0 => [
1738  'label' => 'Default',
1739  'value' => '0',
1740  ],
1741  1 => [
1742  'label' => 'German',
1743  'value' => '1',
1744  ],
1745  2 => [
1746  'label' => 'Danish',
1747  'value' => '2',
1748  ],
1749  ],
1750  'maxitems' => 99999,
1751  ],
1752  ],
1753  ],
1754  ],
1755  'site' => new Site(
1756  'test',
1757  1,
1758  [
1759  'languages' => [
1760  [
1761  'languageId' => 0,
1762  'title' => 'Default',
1763  'locale' => 'en_US.UTF-8',
1764  ],
1765  [
1766  'languageId' => 1,
1767  'title' => 'German',
1768  'locale' => 'de_DE.UTF-8',
1769  ],
1770  [
1771  'languageId' => 2,
1772  'title' => 'Danish',
1773  'locale' => 'da_DK.UTF-8',
1774  ],
1775  ],
1776  ]
1777  ),
1778  ];
1779 
1780  ‪$GLOBALS['BE_USER']->groupData['allowed_languages'] = '0,1';
1781  $expected = $input;
1782  $expected['databaseRow']['aField'] = [
1783  0 => '0',
1784  ];
1785  $expected['processedTca']['columns']['aField']['config']['items'] = [
1786  0 => [
1787  'label' => 'Default',
1788  'value' => '0',
1789  'icon' => null,
1790  'group' => null,
1791  'description' => null,
1792  ],
1793  1 => [
1794  'label' => 'German',
1795  'value' => '1',
1796  'icon' => null,
1797  'group' => null,
1798  'description' => null,
1799  ],
1800  ];
1801 
1802  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1803  }
1804 
1805  #[Test]
1806  public function addDataKeepsAllPagesDoktypesForAdminUser(): void
1807  {
1808  $input = [
1809  'databaseRow' => [
1810  'doktype' => 'keep',
1811  ],
1812  'tableName' => 'pages',
1813  'processedTca' => [
1814  'columns' => [
1815  'doktype' => [
1816  'config' => [
1817  'type' => 'select',
1818  'renderType' => 'selectSingle',
1819  'items' => [
1820  0 => [
1821  'label' => 'keepMe',
1822  'value' => 'keep',
1823  'icon' => null,
1824  'group' => null,
1825  'description' => null,
1826  ],
1827  ],
1828  'maxitems' => 99999,
1829  ],
1830  ],
1831  ],
1832  ],
1833  ];
1834 
1835  $backendUserMock = $this->createMock(BackendUserAuthentication::class);
1836  ‪$GLOBALS['BE_USER'] = $backendUserMock;
1837  $backendUserMock->expects(self::once())->method('isAdmin')->willReturn(true);
1838 
1839  $expected = $input;
1840  $expected['databaseRow']['doktype'] = ['keep'];
1841 
1842  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1843  }
1844 
1845  #[Test]
1846  public function addDataKeepsAllowedPageTypesForNonAdminUser(): void
1847  {
1848  $input = [
1849  'databaseRow' => [
1850  'doktype' => 'keep',
1851  ],
1852  'tableName' => 'pages',
1853  'processedTca' => [
1854  'columns' => [
1855  'doktype' => [
1856  'config' => [
1857  'type' => 'select',
1858  'renderType' => 'selectSingle',
1859  'items' => [
1860  0 => [
1861  'label' => 'keepMe',
1862  'value' => 'keep',
1863  'icon' => null,
1864  'group' => null,
1865  'description' => null,
1866  ],
1867  1 => [
1868  'label' => 'removeMe',
1869  'value' => 'remove',
1870  ],
1871  ],
1872  'maxitems' => 99999,
1873  ],
1874  ],
1875  ],
1876  ],
1877  ];
1878 
1879  ‪$GLOBALS['BE_USER']->groupData['pagetypes_select'] = 'foo,keep,anotherAllowedDoktype';
1880 
1881  $expected = $input;
1882  $expected['databaseRow']['doktype'] = ['keep'];
1883  unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
1884 
1885  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
1886  }
1887 
1888  #[Test]
1889  public function addDataCallsItemsProcFunc(): void
1890  {
1891  $input = [
1892  'tableName' => 'aTable',
1893  'inlineParentUid' => 1,
1894  'inlineParentTableName' => 'aTable',
1895  'inlineParentFieldName' => 'aField',
1896  'inlineParentConfig' => [],
1897  'inlineTopMostParentUid' => 1,
1898  'inlineTopMostParentTableName' => 'topMostTable',
1899  'inlineTopMostParentFieldName' => 'topMostField',
1900  'databaseRow' => [
1901  'aField' => 'aValue',
1902  ],
1903  'effectivePid' => 42,
1904  'site' => new Site('aSite', 456, []),
1905  'processedTca' => [
1906  'columns' => [
1907  'aField' => [
1908  'config' => [
1909  'type' => 'select',
1910  'renderType' => 'selectSingle',
1911  'items' => [],
1912  'itemsProcFunc' => static function (array $parameters, $pObj) {
1913  $parameters['items'] = [
1914  0 => [
1915  0 => 'aLabel',
1916  1 => 'aValue',
1917  2 => null,
1918  3 => null,
1919  4 => null,
1920  ],
1921  ];
1922  },
1923  ],
1924  ],
1925  ],
1926  ],
1927  ];
1928 
1929  $expected = $input;
1930  $expected['databaseRow']['aField'] = ['aValue'];
1931  $expected['processedTca']['columns']['aField']['config'] = [
1932  'type' => 'select',
1933  'renderType' => 'selectSingle',
1934  'items' => [
1935  0 => [
1936  'label' => 'aLabel',
1937  'value' => 'aValue',
1938  'icon' => null,
1939  'group' => null,
1940  'description' => null,
1941  ],
1942  ],
1943  'maxitems' => 99999,
1944  ];
1945 
1946  self::assertSame($expected, (new TcaSelectItems())->addData($input));
1947  }
1948 
1955  #[Test]
1956  public function addDataItemsProcFuncWillUseItemsFromForeignTable(): void
1957  {
1958  $input = [
1959  'databaseRow' => [
1960  'uid' => 5,
1961  'aField' => '',
1962  ],
1963  'tableName' => 'aTable',
1964  'inlineParentUid' => 1,
1965  'inlineParentTableName' => 'aTable',
1966  'inlineParentFieldName' => 'aField',
1967  'inlineParentConfig' => [],
1968  'inlineTopMostParentUid' => 1,
1969  'inlineTopMostParentTableName' => 'topMostTable',
1970  'inlineTopMostParentFieldName' => 'topMostField',
1971  'effectivePid' => 1,
1972  'site' => new Site('aSite', 456, []),
1973  'processedTca' => [
1974  'columns' => [
1975  'aField' => [
1976  'config' => [
1977  'type' => 'select',
1978  'renderType' => 'selectSingle',
1979  'foreign_table' => 'foreign_table',
1980  'itemsProcFunc' => static function (array $parameters, $pObj) {
1981  $filteredItems = [];
1982  // Iterate over given items to filter them
1983  foreach ($parameters['items'] as $item) {
1984  if ($item[1] === 2) { // uid === 2
1985  $filteredItems[] = [
1986  $item[0], // label
1987  $item[1], // uid
1988  null, // icon
1989  null, // groupID
1990  null, // helpText
1991  ];
1992  }
1993  }
1994  $parameters['items'] = $filteredItems;
1995  },
1996  'maxitems' => 99999,
1997  ],
1998  ],
1999  ],
2000  ],
2001  'rootline' => [],
2002  ];
2003 
2004  $expected = $input;
2005  $expected['processedTca']['columns']['aField']['config'] = [
2006  'type' => 'select',
2007  'renderType' => 'selectSingle',
2008  'foreign_table' => 'foreign_table',
2009  'items' => [
2010  0 => [
2011  'label' => 'Item 2',
2012  'value' => 2,
2013  'icon' => null,
2014  'group' => null,
2015  'description' => null,
2016  ],
2017  ],
2018  'maxitems' => 99999,
2019  ];
2020 
2021  $expected['databaseRow']['aField'] = [];
2022 
2023  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2024  }
2025 
2033  #[Test]
2034  public function addDataItemsProcFuncWillUseItemsFromForeignTableAndRemoveItemsByPageTsConfig(): void
2035  {
2036  $input = [
2037  'databaseRow' => [
2038  'uid' => 5,
2039  'aField' => '',
2040  ],
2041  'tableName' => 'aTable',
2042  'inlineParentUid' => 1,
2043  'inlineParentTableName' => 'aTable',
2044  'inlineParentFieldName' => 'aField',
2045  'inlineParentConfig' => [],
2046  'inlineTopMostParentUid' => 1,
2047  'inlineTopMostParentTableName' => 'topMostTable',
2048  'inlineTopMostParentFieldName' => 'topMostField',
2049  'effectivePid' => 1,
2050  'site' => new Site('aSite', 456, []),
2051  'processedTca' => [
2052  'columns' => [
2053  'aField' => [
2054  'config' => [
2055  'type' => 'select',
2056  'renderType' => 'selectSingle',
2057  'foreign_table' => 'foreign_table',
2058  'itemsProcFunc' => static function (array $parameters, $pObj) {
2059  $filteredItems = [];
2060  // Iterate over given items to filter them
2061  foreach ($parameters['items'] as $item) {
2062  if ($item[1] < 3) { // uid < 2
2063  $filteredItems[] = [
2064  $item[0], // label
2065  $item[1], // uid
2066  null, // icon
2067  null, // groupId
2068  null, // helpText
2069  ];
2070  }
2071  }
2072  $parameters['items'] = $filteredItems;
2073  },
2074  'maxitems' => 99999,
2075  ],
2076  ],
2077  ],
2078  ],
2079  'pageTsConfig' => [
2080  'TCEFORM.' => [
2081  'aTable.' => [
2082  'aField.' => [
2083  'removeItems' => '2',
2084  ],
2085  ],
2086  ],
2087  ],
2088  'rootline' => [],
2089  ];
2090 
2091  $expected = $input;
2092  $expected['processedTca']['columns']['aField']['config'] = [
2093  'type' => 'select',
2094  'renderType' => 'selectSingle',
2095  'foreign_table' => 'foreign_table',
2096  'items' => [
2097  0 => [
2098  'label' => 'Item 1',
2099  'value' => 1,
2100  'icon' => null,
2101  'group' => null,
2102  'description' => null,
2103  ],
2104  ],
2105  'maxitems' => 99999,
2106  ];
2107 
2108  $expected['databaseRow']['aField'] = [];
2109 
2110  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2111  }
2112 
2120  #[Test]
2121  public function addDataItemsProcFuncWillUseItemsFromForeignTableAndAddItemsByPageTsConfig(): void
2122  {
2123  $input = [
2124  'databaseRow' => [
2125  'uid' => 5,
2126  'aField' => '',
2127  ],
2128  'tableName' => 'aTable',
2129  'inlineParentUid' => 1,
2130  'inlineParentTableName' => 'aTable',
2131  'inlineParentFieldName' => 'aField',
2132  'inlineParentConfig' => [],
2133  'inlineTopMostParentUid' => 1,
2134  'inlineTopMostParentTableName' => 'topMostTable',
2135  'inlineTopMostParentFieldName' => 'topMostField',
2136  'effectivePid' => 1,
2137  'site' => new Site('aSite', 456, []),
2138  'processedTca' => [
2139  'columns' => [
2140  'aField' => [
2141  'config' => [
2142  'type' => 'select',
2143  'renderType' => 'selectSingle',
2144  'foreign_table' => 'foreign_table',
2145  'itemsProcFunc' => static function (array $parameters, $pObj) {
2146  $filteredItems = [];
2147  // Iterate over given items to filter them
2148  foreach ($parameters['items'] as $item) {
2149  if ($item[1] === 2) { // uid must be 2
2150  $filteredItems[] = [
2151  $item[0], // label
2152  $item[1], // uid
2153  null, // icon
2154  null, // groupID
2155  null, // helpText
2156  ];
2157  }
2158  }
2159  $parameters['items'] = $filteredItems;
2160  },
2161  'maxitems' => 99999,
2162  ],
2163  ],
2164  ],
2165  ],
2166  'pageTsConfig' => [
2167  'TCEFORM.' => [
2168  'aTable.' => [
2169  'aField.' => [
2170  'addItems.' => [
2171  '12' => 'Label of the added item',
2172  ],
2173  ],
2174  ],
2175  ],
2176  ],
2177  'rootline' => [],
2178  ];
2179 
2180  $expected = $input;
2181  $expected['processedTca']['columns']['aField']['config'] = [
2182  'type' => 'select',
2183  'renderType' => 'selectSingle',
2184  'foreign_table' => 'foreign_table',
2185  'items' => [
2186  0 => [
2187  'label' => 'Item 2',
2188  'value' => 2,
2189  'icon' => null,
2190  'group' => null,
2191  'description' => null,
2192  ],
2193  1 => [
2194  'label' => 'Label of the added item',
2195  'value' => 12,
2196  'icon' => null,
2197  'group' => null,
2198  'description' => null,
2199  ],
2200  ],
2201  'maxitems' => 99999,
2202  ];
2203 
2204  $expected['databaseRow']['aField'] = [];
2205 
2206  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2207  }
2208 
2209  #[Test]
2210  public function addDataItemsProcFuncReceivesParameters(): void
2211  {
2212  $input = [
2213  'tableName' => 'aTable',
2214  'inlineParentUid' => 1,
2215  'inlineParentTableName' => 'aTable',
2216  'inlineParentFieldName' => 'aField',
2217  'inlineParentConfig' => ['config' => 'someValue'],
2218  'inlineTopMostParentUid' => 1,
2219  'inlineTopMostParentTableName' => 'topMostTable',
2220  'inlineTopMostParentFieldName' => 'topMostField',
2221  'databaseRow' => [
2222  'aField' => 'aValue',
2223  ],
2224  'effectivePid' => 42,
2225  'site' => new Site('aSite', 456, []),
2226  'pageTsConfig' => [
2227  'TCEFORM.' => [
2228  'aTable.' => [
2229  'aField.' => [
2230  'itemsProcFunc.' => [
2231  'itemParamKey' => 'itemParamValue',
2232  ],
2233  ],
2234  ],
2235  ],
2236  ],
2237  'processedTca' => [
2238  'columns' => [
2239  'aField' => [
2240  'config' => [
2241  'type' => 'select',
2242  'renderType' => 'selectSingle',
2243  'aKey' => 'aValue',
2244  'items' => [
2245  0 => [
2246  'label' => 'aLabel',
2247  'value' => 'aValue',
2248  ],
2249  ],
2250  'itemsProcFunc' => static function (array $parameters, $pObj) {
2251  if ($parameters['items'][0]['label'] !== 'aLabel'
2252  || $parameters['items'][0]['value'] !== 'aValue'
2253  || $parameters['config']['aKey'] !== 'aValue'
2254  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
2255  || $parameters['table'] !== 'aTable'
2256  || $parameters['row'] !== [ 'aField' => 'aValue' ]
2257  || $parameters['field'] !== 'aField'
2258  || $parameters['inlineParentUid'] !== 1
2259  || $parameters['inlineParentTableName'] !== 'aTable'
2260  || $parameters['inlineParentFieldName'] !== 'aField'
2261  || $parameters['inlineParentConfig'] !== ['config' => 'someValue']
2262  || $parameters['inlineTopMostParentUid'] !== 1
2263  || $parameters['inlineTopMostParentTableName'] !== 'topMostTable'
2264  || $parameters['inlineTopMostParentFieldName'] !== 'topMostField'
2265  ) {
2266  throw new \UnexpectedValueException('broken', 1476109436);
2267  }
2268  },
2269  ],
2270  ],
2271  ],
2272  ],
2273  ];
2274 
2275  (new TcaSelectItems())->addData($input);
2276 
2277  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
2278  $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
2279  self::assertCount(0, $flashMessageQueue->getAllMessages());
2280  }
2281 
2282  #[Test]
2283  public function addDataItemsProcFuncEnqueuesFlashMessageOnException(): void
2284  {
2285  $input = [
2286  'tableName' => 'aTable',
2287  'inlineParentUid' => 1,
2288  'inlineParentTableName' => 'aTable',
2289  'inlineParentFieldName' => 'aField',
2290  'inlineParentConfig' => [],
2291  'inlineTopMostParentUid' => 1,
2292  'inlineTopMostParentTableName' => 'topMostTable',
2293  'inlineTopMostParentFieldName' => 'topMostField',
2294  'databaseRow' => [
2295  'aField' => 'aValue',
2296  ],
2297  'effectivePid' => 42,
2298  'site' => new Site('aSite', 456, []),
2299  'pageTsConfig' => [
2300  'TCEFORM.' => [
2301  'aTable.' => [
2302  'aField.' => [
2303  'itemsProcFunc.' => [
2304  'itemParamKey' => 'itemParamValue',
2305  ],
2306  ],
2307  ],
2308  ],
2309  ],
2310  'processedTca' => [
2311  'columns' => [
2312  'aField' => [
2313  'config' => [
2314  'type' => 'select',
2315  'renderType' => 'selectSingle',
2316  'aKey' => 'aValue',
2317  'items' => [
2318  0 => [
2319  0 => 'aLabel',
2320  1 => 'aValue',
2321  ],
2322  ],
2323  'itemsProcFunc' => static function (array $parameters, $pObj) {
2324  throw new \UnexpectedValueException('anException', 1476109437);
2325  },
2326  ],
2327  ],
2328  ],
2329  ],
2330  ];
2331 
2332  (new TcaSelectItems())->addData($input);
2333 
2334  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
2335  $flashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
2336  self::assertCount(1, $flashMessageQueue->getAllMessages());
2337  }
2338 
2339  #[Test]
2340  public function addDataTranslatesItemLabelsFromPageTsConfig(): void
2341  {
2342  $input = [
2343  'databaseRow' => [
2344  'aField' => 'aValue',
2345  ],
2346  'tableName' => 'aTable',
2347  'processedTca' => [
2348  'columns' => [
2349  'aField' => [
2350  'config' => [
2351  'type' => 'select',
2352  'renderType' => 'selectSingle',
2353  'items' => [
2354  0 => [
2355  'label' => 'aLabel',
2356  'value' => 'aValue',
2357  'icon' => null,
2358  'group' => null,
2359  'description' => null,
2360  ],
2361  ],
2362  'maxitems' => 99999,
2363  ],
2364  ],
2365  ],
2366  ],
2367  'pageTsConfig' => [
2368  'TCEFORM.' => [
2369  'aTable.' => [
2370  'aField.' => [
2371  'altLabels.' => [
2372  'aValue' => 'labelOverride',
2373  ],
2374  ],
2375  ],
2376  ],
2377  ],
2378  ];
2379 
2380  $expected = $input;
2381  $expected['databaseRow']['aField'] = ['aValue'];
2382  $expected['processedTca']['columns']['aField']['config']['items'][0]['label'] = 'labelOverride';
2383 
2384  self::assertSame($expected, (new TcaSelectItems())->addData($input));
2385  }
2386 
2387  #[Test]
2388  public function addDataAddsIconsFromPageTsConfig(): void
2389  {
2390  $input = [
2391  'databaseRow' => [
2392  'aField' => 'aValue',
2393  ],
2394  'tableName' => 'aTable',
2395  'processedTca' => [
2396  'columns' => [
2397  'aField' => [
2398  'config' => [
2399  'type' => 'select',
2400  'renderType' => 'selectSingle',
2401  'items' => [
2402  0 => [
2403  'label' => 'aLabel',
2404  'value' => 'aValue',
2405  'icon' => 'icon-identifier',
2406  'group' => null,
2407  'description' => null,
2408  ],
2409  ],
2410  'maxitems' => 99999,
2411  ],
2412  ],
2413  ],
2414  ],
2415  'pageTsConfig' => [
2416  'TCEFORM.' => [
2417  'aTable.' => [
2418  'aField.' => [
2419  'altIcons.' => [
2420  'aValue' => 'icon-identifier-override',
2421  ],
2422  ],
2423  ],
2424  ],
2425  ],
2426  ];
2427 
2428  $expected = $input;
2429  $expected['databaseRow']['aField'] = ['aValue'];
2430  $expected['processedTca']['columns']['aField']['config']['items'][0]['icon'] = 'icon-identifier-override';
2431 
2432  self::assertSame($expected, (new TcaSelectItems())->addData($input));
2433  }
2434 
2435  #[Test]
2436  public function processSelectFieldValueSetsMmForeignRelationValues(): void
2437  {
2438  $input = [
2439  'command' => 'edit',
2440  'tableName' => 'tca_select_items',
2441  'effectivePid' => 1,
2442  'databaseRow' => [
2443  'uid' => 42,
2444  // Two connected rows
2445  'mm_field' => 2,
2446  ],
2447  'processedTca' => [
2448  'columns' => [
2449  'mm_field' => [
2450  'config' => [
2451  'type' => 'select',
2452  'renderType' => 'selectSingle',
2453  'maxitems' => 999,
2454  'foreign_table' => 'foreign_table',
2455  'MM' => 'select_ftable_mm',
2456  'items' => [],
2457  ],
2458  ],
2459  ],
2460  ],
2461  ];
2462 
2463  self::assertSame(['5', '6'], (new TcaSelectItems())->addData($input)['databaseRow']['mm_field']);
2464  }
2465 
2466  #[Test]
2467  public function processSelectFieldValueSetsForeignRelationValues(): void
2468  {
2469  $input = [
2470  'tableName' => 'tca_select_items',
2471  'effectivePid' => 1,
2472  'databaseRow' => [
2473  'uid' => 42,
2474  'foreign_field' => '1,2,3,4',
2475  ],
2476  'processedTca' => [
2477  'columns' => [
2478  'foreign_field' => [
2479  'config' => [
2480  'type' => 'select',
2481  'renderType' => 'selectSingle',
2482  'maxitems' => 999,
2483  'foreign_table' => 'foreign_table',
2484  'items' => [],
2485  ],
2486  ],
2487  ],
2488  ],
2489  ];
2490 
2491  self::assertSame(['1', '2', '3', '4'], (new TcaSelectItems())->addData($input)['databaseRow']['foreign_field']);
2492  }
2493 
2494  #[Test]
2495  public function processSelectFieldValueRemovesInvalidDynamicValues(): void
2496  {
2497  $input = [
2498  'tableName' => 'tca_select_items',
2499  'effectivePid' => 1,
2500  'databaseRow' => [
2501  'uid' => 5,
2502  'foreign_field' => '1,2,bar,foo',
2503  ],
2504  'processedTca' => [
2505  'columns' => [
2506  'foreign_field' => [
2507  'config' => [
2508  'type' => 'select',
2509  'renderType' => 'selectSingleBox',
2510  'foreign_table' => 'foreign_table',
2511  'maxitems' => 999,
2512  'items' => [
2513  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2514  ],
2515  ],
2516  ],
2517  ],
2518  ],
2519  ];
2520 
2521  self::assertSame(['1', '2', 'foo'], (new TcaSelectItems())->addData($input)['databaseRow']['foreign_field']);
2522  }
2523 
2524  #[Test]
2525  public function processSelectFieldValueKeepsValuesFromStaticItems(): void
2526  {
2527  $input = [
2528  'tableName' => 'aTable',
2529  'databaseRow' => [
2530  'aField' => 'foo,bar',
2531  ],
2532  'processedTca' => [
2533  'columns' => [
2534  'aField' => [
2535  'config' => [
2536  'type' => 'select',
2537  'renderType' => 'selectSingle',
2538  'maxitems' => 999,
2539  'items' => [
2540  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2541  ['label' => 'bar', 'value' => 'bar', 'icon' => null, 'group' => null, 'description' => null],
2542  ],
2543  ],
2544  ],
2545  ],
2546  ],
2547  ];
2548 
2549  $expected = $input;
2550  $expected['databaseRow']['aField'] = [
2551  'foo',
2552  'bar',
2553  ];
2554 
2555  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2556  }
2557 
2558  #[Test]
2559  public function processSelectFieldValueReturnsEmptyValueForSingleSelect(): void
2560  {
2561  $input = [
2562  'tableName' => 'aTable',
2563  'databaseRow' => [
2564  'aField' => '',
2565  ],
2566  'processedTca' => [
2567  'columns' => [
2568  'aField' => [
2569  'config' => [
2570  'type' => 'select',
2571  'renderType' => 'selectSingle',
2572  'maxitems' => 99999,
2573  'items' => [],
2574  ],
2575  ],
2576  ],
2577  ],
2578  ];
2579 
2580  $expected = $input;
2581  $expected['databaseRow']['aField'] = [];
2582 
2583  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2584  }
2585 
2586  #[Test]
2587  public function processSelectFieldValueTrimsEmptyValueForMultiValueSelect(): void
2588  {
2589  $input = [
2590  'tableName' => 'aTable',
2591  'databaseRow' => [
2592  'aField' => 'b,,c',
2593  ],
2594  'processedTca' => [
2595  'columns' => [
2596  'aField' => [
2597  'config' => [
2598  'type' => 'select',
2599  'renderType' => 'selectSingle',
2600  'maxitems' => 999,
2601  'items' => [
2602  ['label' => 'a', 'value' => '', 'icon' => null, 'group' => null, 'description' => null],
2603  ['label' => 'b', 'value' => 'b', 'icon' => null, 'group' => null, 'description' => null],
2604  ['label' => 'c', 'value' => 'c', 'icon' => null, 'group' => null, 'description' => null],
2605  ],
2606  ],
2607  ],
2608  ],
2609  ],
2610  ];
2611 
2612  $expected = $input;
2613  $expected['databaseRow']['aField'] = [
2614  'b',
2615  'c',
2616  ];
2617 
2618  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2619  }
2620 
2621  #[Test]
2622  public function processSelectFieldValueDoesNotCallRelationManagerForStaticOnlyItems(): void
2623  {
2624  $relationHandlerMock = $this->createMock(RelationHandler::class);
2625  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerMock);
2626  $relationHandlerMock->expects(self::never())->method('start');
2627  $relationHandlerMock->expects(self::never())->method('getValueArray');
2628 
2629  $input = [
2630  'tableName' => 'aTable',
2631  'databaseRow' => [
2632  'aField' => 'foo',
2633  ],
2634  'processedTca' => [
2635  'columns' => [
2636  'aField' => [
2637  'config' => [
2638  'type' => 'select',
2639  'renderType' => 'selectSingle',
2640  'maxitems' => 999,
2641  'items' => [
2642  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2643  ],
2644  ],
2645  ],
2646  ],
2647  ],
2648  ];
2649 
2650  $expected = $input;
2651  $expected['databaseRow']['aField'] = ['foo'];
2652 
2653  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2654  }
2655 
2656  #[Test]
2657  public function processSelectFieldValueAddsInvalidValuesToItemsForSingleSelects(): void
2658  {
2659  $relationHandlerMock = $this->createMock(RelationHandler::class);
2660  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerMock);
2661  $relationHandlerMock->expects(self::never())->method('start');
2662  $relationHandlerMock->expects(self::never())->method('getValueArray');
2663 
2664  $input = [
2665  'tableName' => 'aTable',
2666  'databaseRow' => [
2667  'aField' => '1,2,bar,foo',
2668  ],
2669  'processedTca' => [
2670  'columns' => [
2671  'aField' => [
2672  'config' => [
2673  'type' => 'select',
2674  'renderType' => 'selectSingle',
2675  'maxitems' => 99999,
2676  'items' => [
2677  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2678  ],
2679  ],
2680  ],
2681  ],
2682  ],
2683  ];
2684 
2685  $expected = $input;
2686  $expected['databaseRow']['aField'] = ['foo'];
2687  $expected['processedTca']['columns']['aField']['config']['items'] = [
2688  ['label' => '[ INVALID VALUE ("bar") ]', 'value' => 'bar', 'icon' => null, 'group' => 'none', 'description' => null],
2689  ['label' => '[ INVALID VALUE ("2") ]', 'value' => '2', 'icon' => null, 'group' => 'none', 'description' => null],
2690  ['label' => '[ INVALID VALUE ("1") ]', 'value' => '1', 'icon' => null, 'group' => 'none', 'description' => null],
2691  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2692  ];
2693  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2694  }
2695 
2696  #[Test]
2697  public function processSelectFieldValueReturnsDuplicateValuesForMultipleSelect(): void
2698  {
2699  $input = [
2700  'tableName' => 'aTable',
2701  'databaseRow' => [
2702  'aField' => '1,foo,foo,2,bar',
2703  ],
2704  'processedTca' => [
2705  'columns' => [
2706  'aField' => [
2707  'config' => [
2708  'type' => 'select',
2709  'renderType' => 'selectSingle',
2710  'multiple' => true,
2711  'maxitems' => 999,
2712  'items' => [
2713  ['label' => '1', 'value' => '1', 'icon' => null, 'group' => null, 'description' => null],
2714  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2715  ['label' => 'bar', 'value' => 'bar', 'icon' => null, 'group' => null, 'description' => null],
2716  ['label' => '2', 'value' => '2', 'icon' => null, 'group' => null, 'description' => null],
2717  ],
2718  ],
2719  ],
2720  ],
2721  ],
2722  ];
2723 
2724  $expected = $input;
2725  $expected['databaseRow']['aField'] = [
2726  '1',
2727  'foo',
2728  'foo',
2729  '2',
2730  'bar',
2731  ];
2732 
2733  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2734  }
2735 
2736  #[Test]
2737  public function processSelectFieldValueReturnsUniqueValuesForMultipleSelect(): void
2738  {
2739  $input = [
2740  'tableName' => 'aTable',
2741  'databaseRow' => [
2742  'aField' => '1,foo,foo,2,bar',
2743  ],
2744  'processedTca' => [
2745  'columns' => [
2746  'aField' => [
2747  'config' => [
2748  'type' => 'select',
2749  'renderType' => 'selectSingle',
2750  'multiple' => false,
2751  'maxitems' => 999,
2752  'items' => [
2753  ['label' => '1', 'value' => '1', 'icon' => null, 'group' => null, 'description' => null],
2754  ['label' => 'foo', 'value' => 'foo', 'icon' => null, 'group' => null, 'description' => null],
2755  ['label' => 'bar', 'value' => 'bar', 'icon' => null, 'group' => null, 'description' => null],
2756  ['label' => '2', 'value' => '2', 'icon' => null, 'group' => null, 'description' => null],
2757  ],
2758  ],
2759  ],
2760  ],
2761  ],
2762  ];
2763 
2764  $expected = $input;
2765  $expected['databaseRow']['aField'] = [
2766  0 => '1',
2767  1 => 'foo',
2768  3 => '2',
2769  4 => 'bar',
2770  ];
2771 
2772  self::assertEquals($expected, (new TcaSelectItems())->addData($input));
2773  }
2774 
2775  public static function processSelectFieldSetsCorrectValuesForMmRelationsDataProvider(): array
2776  {
2777  return [
2778  'Relation with MM table and new status with default values' => [
2779  [
2780  'tableName' => 'tca_select_items',
2781  'command' => 'new',
2782  'effectivePid' => 1,
2783  'databaseRow' => [
2784  'uid' => 'NEW1234',
2785  'mm_field' => '24,35',
2786  ],
2787  'processedTca' => [
2788  'columns' => [
2789  'mm_field' => [
2790  'config' => [
2791  'type' => 'select',
2792  'renderType' => 'selectSingle',
2793  'maxitems' => 999,
2794  'MM' => 'select_ftable_mm',
2795  'foreign_table' => 'foreign_table',
2796  'items' => [],
2797  ],
2798  ],
2799  ],
2800  ],
2801  ],
2802  [
2803  24, 35,
2804  ],
2805  ],
2806  'Relation with MM table and item array in list but no new status' => [
2807  [
2808  'tableName' => 'tca_select_items',
2809  'command' => 'edit',
2810  'effectivePid' => 42,
2811  'databaseRow' => [
2812  'uid' => 42,
2813  'mm_field' => '2',
2814  ],
2815  'processedTca' => [
2816  'columns' => [
2817  'mm_field' => [
2818  'config' => [
2819  'type' => 'select',
2820  'renderType' => 'selectSingle',
2821  'maxitems' => 999,
2822  'MM' => 'select_ftable_mm',
2823  'foreign_table' => 'foreign_table',
2824  'items' => [],
2825  ],
2826  ],
2827  ],
2828  ],
2829  ],
2830  [5, 6],
2831  ],
2832  'Relation with MM table and maxitems = 1 processes field value (item count)' => [
2833  [
2834  'tableName' => 'tca_select_items',
2835  'command' => 'edit',
2836  'effectivePid' => 42,
2837  'databaseRow' => [
2838  'uid' => 43,
2839  // MM relation with one item has 1 in field value
2840  'mm_field' => 1,
2841  ],
2842  'processedTca' => [
2843  'columns' => [
2844  'mm_field' => [
2845  'config' => [
2846  'type' => 'select',
2847  'renderType' => 'selectSingle',
2848  'maxitems' => 1,
2849  'MM' => 'select_ftable_mm',
2850  'foreign_table' => 'foreign_table',
2851  'items' => [],
2852  ],
2853  ],
2854  ],
2855  ],
2856  ],
2857  [
2858  2,
2859  ],
2860  ],
2861  'Relation with MM table and maxitems = 1 results in empty array if no items are set' => [
2862  [
2863  'tableName' => 'tca_select_items',
2864  'command' => 'edit',
2865  'effectivePid' => 42,
2866  'databaseRow' => [
2867  'uid' => 58,
2868  // MM relation with no items has 0 in field value
2869  'mm_field' => 0,
2870  ],
2871  'processedTca' => [
2872  'columns' => [
2873  'mm_field' => [
2874  'config' => [
2875  'type' => 'select',
2876  'renderType' => 'selectSingle',
2877  'maxitems' => 1,
2878  'MM' => 'select_ftable_mm',
2879  'foreign_table' => 'foreign_table',
2880  'items' => [],
2881  ],
2882  ],
2883  ],
2884  ],
2885  ],
2886  [],
2887  ],
2888  ];
2889  }
2890 
2891  #[DataProvider('processSelectFieldSetsCorrectValuesForMmRelationsDataProvider')]
2892  #[Test]
2893  public function processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $relationHandlerUids): void
2894  {
2895  self::assertEquals($relationHandlerUids, (new TcaSelectItems())->addData($input)['databaseRow']['mm_field']);
2896  }
2897 }
‪TYPO3\CMS\Core\Localization\LanguageServiceFactory
Definition: LanguageServiceFactory.php:25
‪TYPO3\CMS\Core\Database\RelationHandler
Definition: RelationHandler.php:36
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static getVarPath()
Definition: Environment.php:197
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Backend\Tests\Functional\Form\FormDataProvider\TcaSelectItemsTest\$testExtensionsToLoad
‪array $testExtensionsToLoad
Definition: TcaSelectItemsTest.php:36
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Tests\Functional\Form\FormDataProvider\TcaSelectItemsTest
Definition: TcaSelectItemsTest.php:35
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems
Definition: TcaSelectItems.php:28
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Backend\Tests\Functional\Form\FormDataProvider
Definition: TcaCategoryTest.php:18
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57