‪TYPO3CMS  11.5
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 Doctrine\DBAL\Exception as DBALException;
21 use Doctrine\DBAL\Result;
22 use Prophecy\Argument;
23 use Prophecy\PhpUnit\ProphecyTrait;
30 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
45 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
46 
50 class ‪TcaSelectItemsTest extends UnitTestCase
51 {
52  use ProphecyTrait;
53 
57  protected function ‪setUp(): void
58  {
59  parent::setUp();
60  // Default LANG prophecy just returns incoming value as label if calling ->sL()
61  $languageServiceProphecy = $this->prophesize(LanguageService::class);
62  $languageServiceProphecy->loadSingleTableDescription(Argument::cetera())->willReturn(null);
63  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
64  ‪$GLOBALS['LANG'] = $languageServiceProphecy->reveal();
65 
66  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
67  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
68 
69  $iconRegistryProphecy = $this->prophesize(IconRegistry::class);
70  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconRegistryProphecy->reveal());
71  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
72  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
73  }
74 
78  protected function ‪tearDown(): void
79  {
80  GeneralUtility::purgeInstances();
81  parent::tearDown();
82  }
83 
91  protected function ‪mockDatabaseConnection(string $tableName = 'fTable'): array
92  {
93  $connectionProphet = $this->prophesize(Connection::class);
94  $connectionProphet->quote(Argument::cetera())->will(static function ($arguments) {
95  return "'" . $arguments[0] . "'";
96  });
97  $connectionProphet->quoteIdentifier(Argument::cetera())->will(static function ($arguments) {
98  return '`' . $arguments[0] . '`';
99  });
100 
101  $restrictionProphet = $this->prophesize(DefaultRestrictionContainer::class);
102  $restrictionProphet->removeAll()->willReturn($restrictionProphet->reveal());
103  $restrictionProphet->add(Argument::cetera())->willReturn($restrictionProphet->reveal());
104 
105  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
106  $queryBuilderProphet->expr()->willReturn(
107  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
108  );
109  $queryBuilderProphet->getRestrictions()->willReturn($restrictionProphet->reveal());
110  $queryBuilderProphet->quoteIdentifier(Argument::cetera())->will(static function ($arguments) {
111  return '`' . $arguments[0] . '`';
112  });
113 
114  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
115  $connectionPoolProphet->getConnectionForTable($tableName)
116  ->willReturn($connectionProphet->reveal());
117  $connectionPoolProphet->getQueryBuilderForTable($tableName)
118  ->shouldBeCalled()
119  ->willReturn($queryBuilderProphet->reveal());
120 
121  return [$queryBuilderProphet, $connectionPoolProphet, $connectionProphet, $restrictionProphet];
122  }
123 
128  protected function ‪mockDatabaseConnectionForProcessSelectField(): void
129  {
130  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection('foreignTable');
131 
132  $statementProphet = $this->prophesize(Result::class);
133  $statementProphet->fetchAllAssociative()->shouldBeCalled();
134 
135  $queryBuilderProphet->select('foreignTable.uid', 'foreignTable.pid')
136  ->shouldBeCalled()
137  ->willReturn($queryBuilderProphet->reveal());
138  $queryBuilderProphet->from('foreignTable')
139  ->shouldBeCalled()
140  ->willReturn($queryBuilderProphet->reveal());
141  $queryBuilderProphet->from('pages')
142  ->shouldBeCalled()
143  ->willReturn($queryBuilderProphet->reveal());
144  $queryBuilderProphet->where('')
145  ->shouldBeCalled()
146  ->willReturn($queryBuilderProphet->reveal());
147  $queryBuilderProphet->andWhere(' 1=1')
148  ->shouldBeCalled()
149  ->willReturn($queryBuilderProphet->reveal());
150  $queryBuilderProphet->andWhere('`pages.uid` = `foreignTable.pid`')
151  ->shouldBeCalled()
152  ->willReturn($queryBuilderProphet->reveal());
153  $queryBuilderProphet->executeQuery()
154  ->shouldBeCalled()
155  ->willReturn($statementProphet->reveal());
156 
157  // Two instances are needed due to the push/pop behavior of addInstance()
158  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
159  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
160  }
161 
165  public function ‪addDataKeepExistingItems(): void
166  {
167  $input = [
168  'tableName' => 'aTable',
169  'processedTca' => [
170  'columns' => [
171  'aField' => [
172  'config' => [
173  'type' => 'radio',
174  'items' => [
175  0 => [
176  'foo',
177  'bar',
178  ],
179  ],
180  ],
181  ],
182  'anotherField' => [
183  'config' => [
184  'type' => 'group',
185  'items' => [
186  0 => [
187  'foo',
188  'bar',
189  ],
190  ],
191  ],
192  ],
193  ],
194  ],
195  ];
196 
197  $expected = $input;
198  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
199  }
200 
204  public function ‪addDataThrowsExceptionIfAnItemIsNotAnArray(): void
205  {
206  $input = [
207  'tableName' => 'aTable',
208  'processedTca' => [
209  'columns' => [
210  'aField' => [
211  'config' => [
212  'type' => 'select',
213  'renderType' => 'selectSingle',
214  'items' => [
215  0 => 'foo',
216  ],
217  ],
218  ],
219  ],
220  ],
221  ];
222 
223  $this->expectException(\UnexpectedValueException::class);
224  $this->expectExceptionCode(1439288036);
225 
226  (new ‪TcaSelectItems())->addData($input);
227  }
228 
232  public function ‪addDataTranslatesItemLabels(): void
233  {
234  $input = [
235  'tableName' => 'aTable',
236  'databaseRow' => [
237  'aField' => 'aValue',
238  ],
239  'processedTca' => [
240  'columns' => [
241  'aField' => [
242  'config' => [
243  'type' => 'select',
244  'renderType' => 'selectSingle',
245  'items' => [
246  0 => [
247  0 => 'aLabel',
248  1 => 'aValue',
249  ],
250  ],
251  'maxitems' => 99999,
252  ],
253  ],
254  ],
255  ],
256  ];
257 
258  $languageService = $this->prophesize(LanguageService::class);
259  ‪$GLOBALS['LANG'] = $languageService->reveal();
260  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
261 
262  $languageService->sL('aLabel')->shouldBeCalled()->willReturn('translated');
263 
264  $expected = $input;
265  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'translated';
266  $expected['processedTca']['columns']['aField']['config']['items'][0][2] = null;
267  $expected['processedTca']['columns']['aField']['config']['items'][0][3] = null;
268  $expected['processedTca']['columns']['aField']['config']['items'][0][4] = null;
269 
270  $expected['databaseRow']['aField'] = ['aValue'];
271 
272  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
273  }
274 
278  public function ‪addDataAddsDividersIfItemGroupsAreDefined(): void
279  {
280  $input = [
281  'tableName' => 'aTable',
282  'databaseRow' => [
283  'aField' => 'aValue',
284  ],
285  'processedTca' => [
286  'columns' => [
287  'aField' => [
288  'config' => [
289  'type' => 'select',
290  'renderType' => 'selectSingle',
291  'items' => [
292  [
293  'aLabel',
294  'aValue',
295  'an-icon-reference',
296  'non-existing-group',
297  null,
298  ],
299  [
300  'anotherLabel',
301  'anotherValue',
302  'an-icon-reference',
303  'example-group',
304  null,
305  ],
306  ],
307  'itemGroups' => [
308  'example-group' => 'My Example Group',
309  ],
310  'maxitems' => 99999,
311  ],
312  ],
313  ],
314  ],
315  ];
316 
317  $expected = $input;
318  $expected['databaseRow']['aField'] = ['aValue'];
319  $expected['processedTca']['columns']['aField']['config']['items'] = [
320  [
321  'My Example Group',
322  '--div--',
323  null,
324  'example-group',
325  null,
326  ],
327  [
328  'anotherLabel',
329  'anotherValue',
330  'an-icon-reference',
331  'example-group',
332  null,
333  ], [
334  'non-existing-group',
335  '--div--',
336  null,
337  'non-existing-group',
338  null,
339  ],
340  [
341  'aLabel',
342  'aValue',
343  'an-icon-reference',
344  'non-existing-group',
345  null,
346  ],
347  ];
348 
349  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
350  }
351 
355  public function ‪addDataKeepsIconFromItem(): void
356  {
357  $input = [
358  'tableName' => 'aTable',
359  'databaseRow' => [
360  'aField' => 'aValue',
361  ],
362  'processedTca' => [
363  'columns' => [
364  'aField' => [
365  'config' => [
366  'type' => 'select',
367  'renderType' => 'selectSingle',
368  'items' => [
369  0 => [
370  0 => 'aLabel',
371  1 => 'aValue',
372  2 => 'an-icon-reference',
373  3 => null,
374  4 => null,
375  ],
376  ],
377  'maxitems' => 99999,
378  ],
379  ],
380  ],
381  ],
382  ];
383 
384  $expected = $input;
385  $expected['databaseRow']['aField'] = ['aValue'];
386 
387  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
388  }
389 
394  {
395  $directory = ‪Environment::getVarPath() . '/' . ‪StringUtility::getUniqueId('test-') . '/';
396  $input = [
397  'tableName' => 'aTable',
398  'databaseRow' => [],
399  'processedTca' => [
400  'columns' => [
401  'aField' => [
402  'config' => [
403  'type' => 'select',
404  'renderType' => 'selectSingle',
405  'fileFolderConfig' => [
406  'folder' => $directory,
407  'allowedExtensions' => 'gif',
408  'depth' => 1,
409  ],
410  ],
411  ],
412  ],
413  ],
414  ];
415 
416  mkdir($directory);
417  $this->testFilesToDelete[] = $directory;
418  touch($directory . 'anImage.gif');
419  touch($directory . 'aFile.txt');
420  mkdir($directory . '/subdir');
421  touch($directory . '/subdir/anotherImage.gif');
422  mkdir($directory . '/subdir/subsubdir');
423  touch($directory . '/subdir/subsubdir/anotherImage.gif');
424 
425  $expectedItems = [
426  0 => [
427  0 => 'anImage.gif',
428  1 => 'anImage.gif',
429  2 => $directory . 'anImage.gif',
430  3 => null,
431  4 => null,
432  ],
433  1 => [
434  0 => 'subdir/anotherImage.gif',
435  1 => 'subdir/anotherImage.gif',
436  2 => $directory . 'subdir/anotherImage.gif',
437  3 => null,
438  4 => null,
439  ],
440  ];
441 
442  $result = (new ‪TcaSelectItems())->addData($input);
443 
444  self::assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
445  }
446 
451  {
452  $directory = ‪Environment::getVarPath() . '/' . ‪StringUtility::getUniqueId('test-') . '/';
453  $overriddenDirectory = ‪Environment::getVarPath() . '/' . ‪StringUtility::getUniqueId('test-overridden-') . '/';
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' => $directory,
465  'allowedExtensions' => 'gif',
466  'depth' => 1,
467  ],
468  ],
469  ],
470  ],
471  ],
472  'pageTsConfig' => [
473  'TCEFORM.' => [
474  'aTable.' => [
475  'aField.' => [
476  'config.' => [
477  'fileFolderConfig.' => [
478  'folder' => $overriddenDirectory,
479  'allowedExtensions' => 'svg',
480  'depth' => 0,
481  ],
482  ],
483  ],
484  ],
485  ],
486  ],
487  ];
488 
489  mkdir($directory);
490  $this->testFilesToDelete[] = $directory;
491  touch($directory . 'anImage.gif');
492  touch($directory . 'aFile.txt');
493  touch($directory . 'aIcon.svg');
494  mkdir($directory . '/subdir');
495  touch($directory . '/subdir/anotherImage.gif');
496  touch($directory . '/subdir/anotherFile.txt');
497  touch($directory . '/subdir/anotherIcon.txt');
498 
499  mkdir($overriddenDirectory);
500  $this->testFilesToDelete[] = $overriddenDirectory;
501  touch($overriddenDirectory . 'anOverriddenImage.gif');
502  touch($overriddenDirectory . 'anOverriddenFile.txt');
503  touch($overriddenDirectory . 'anOverriddenIcon.svg');
504  mkdir($overriddenDirectory . '/subdir');
505  touch($overriddenDirectory . '/subdir/anotherOverriddenImage.gif');
506  touch($overriddenDirectory . '/subdir/anotherOverriddenFile.txt');
507  touch($overriddenDirectory . '/subdir/anotherOverriddenIcon.svg');
508 
509  $expectedItems = [
510  0 => [
511  0 => 'anOverriddenIcon.svg',
512  1 => 'anOverriddenIcon.svg',
513  2 => $overriddenDirectory . 'anOverriddenIcon.svg',
514  3 => null,
515  4 => null,
516  ],
517  ];
518 
519  $result = (new ‪TcaSelectItems())->addData($input);
520 
521  self::assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
522  }
523 
527  public function ‪addDataThrowsExceptionForInvalidFileFolder(): void
528  {
529  $input = [
530  'tableName' => 'aTable',
531  'databaseRow' => [],
532  'processedTca' => [
533  'columns' => [
534  'aField' => [
535  'config' => [
536  'type' => 'select',
537  'renderType' => 'selectSingle',
538  'fileFolderConfig' => [
539  'folder' => 'EXT:non_existing/Resources/Public/',
540  ],
541  ],
542  ],
543  ],
544  ],
545  ];
546 
547  $this->expectException(\RuntimeException::class);
548  $this->expectExceptionCode(1479399227);
549  (new ‪TcaSelectItems())->addData($input);
550  }
551 
555  public function ‪addDataAddsItemsByAddItemsFromPageTsConfig(): void
556  {
557  $input = [
558  'databaseRow' => [
559  'aField' => '',
560  ],
561  'tableName' => 'aTable',
562  'processedTca' => [
563  'columns' => [
564  'aField' => [
565  'config' => [
566  'type' => 'select',
567  'renderType' => 'selectSingle',
568  'items' => [
569  0 => [
570  0 => 'keepMe',
571  1 => 'keep',
572  null,
573  null,
574  null,
575  ],
576  ],
577  'maxitems' => 99999,
578  ],
579  ],
580  ],
581  ],
582  'pageTsConfig' => [
583  'TCEFORM.' => [
584  'aTable.' => [
585  'aField.' => [
586  'addItems.' => [
587  '1' => 'addMe',
588  ],
589  ],
590  ],
591  ],
592  ],
593  ];
594 
595  $expected = $input;
596  $expected['databaseRow']['aField'] = [];
597  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
598  0 => 'addMe',
599  1 => '1',
600  null,
601  null,
602  null,
603  ];
604 
605  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
606  }
607 
612  {
613  $input = [
614  'databaseRow' => [
615  'aField' => '',
616  ],
617  'tableName' => 'aTable',
618  'processedTca' => [
619  'columns' => [
620  'aField' => [
621  'config' => [
622  'type' => 'select',
623  'renderType' => 'selectSingle',
624  'items' => [
625  0 => [
626  0 => 'keepMe',
627  1 => 'keep',
628  null,
629  null,
630  null,
631  ],
632  ],
633  'maxitems' => 99999,
634  ],
635  ],
636  ],
637  ],
638  'pageTsConfig' => [
639  'TCEFORM.' => [
640  'aTable.' => [
641  'aField.' => [
642  'addItems.' => [
643  'keep' => 'addMe',
644  ],
645  ],
646  ],
647  ],
648  ],
649  ];
650 
651  $expected = $input;
652  $expected['databaseRow']['aField'] = [];
653  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
654  0 => 'addMe',
655  1 => 'keep',
656  null,
657  null,
658  null,
659  ];
660 
661  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
662  }
663 
668  {
669  return [
670  'replace REC_FIELD' => [
671  'AND fTable.title=\'###REC_FIELD_rowField###\'',
672  [
673  ['fTable.title=\'rowFieldValue\''],
674  [' 1=1'],
675  ['`pages.uid` = `fTable.pid`'],
676  ],
677  [],
678  ],
679  'replace REC_FIELD within FlexForm' => [
680  'AND fTable.title=###REC_FIELD_rowFieldFlexForm###',
681  [
682  ['fTable.title=\'rowFieldFlexFormValue\''],
683  [' 1=1'],
684  ['`pages.uid` = `fTable.pid`'],
685  ],
686  [
687  'databaseRow' => [
688  'rowFieldThree' => [
689  0 => 'rowFieldThreeValue',
690  ],
691  ],
692  'flexParentDatabaseRow' => [
693  'rowFieldFlexForm' => [
694  0 => 'rowFieldFlexFormValue',
695  ],
696  ],
697  ],
698  ],
699  'replace REC_FIELD fullQuote' => [
700  'AND fTable.title=###REC_FIELD_rowField###',
701  [
702  ['fTable.title=\'rowFieldValue\''],
703  [' 1=1'],
704  ['`pages.uid` = `fTable.pid`'],
705  ],
706  [],
707  ],
708  'replace REC_FIELD fullQuoteWithArray' => [
709  'AND fTable.title=###REC_FIELD_rowFieldThree###',
710  [
711  ['fTable.title=\'rowFieldThreeValue\''],
712  [' 1=1'],
713  ['`pages.uid` = `fTable.pid`'],
714  ],
715  [
716  'databaseRow' => [
717  'rowFieldThree' => [
718  0 => 'rowFieldThreeValue',
719  ],
720  ],
721  ],
722  ],
723  'replace REC_FIELD multiple markers' => [
724  'AND fTable.title=\'###REC_FIELD_rowField###\' AND fTable.pid=###REC_FIELD_rowFieldTwo###',
725  [
726  ['fTable.title=\'rowFieldValue\' AND fTable.pid=\'rowFieldTwoValue\''],
727  [' 1=1'],
728  ['`pages.uid` = `fTable.pid`'],
729  ],
730  [],
731  ],
732  'replace CURRENT_PID' => [
733  'AND fTable.uid=###CURRENT_PID###',
734  [
735  ['fTable.uid=43'],
736  [' 1=1'],
737  ['`pages.uid` = `fTable.pid`'],
738  ],
739  [],
740  ],
741  'replace CURRENT_PID within FlexForm' => [
742  'AND fTable.uid=###CURRENT_PID###',
743  [
744  ['fTable.uid=77'],
745  [' 1=1'],
746  ['`pages.uid` = `fTable.pid`'],
747  ],
748  [
749  'flexParentDatabaseRow' => [
750  'pid' => '77',
751  ],
752  ],
753  ],
754  'replace CURRENT_PID integer cast' => [
755  'AND fTable.uid=###CURRENT_PID###',
756  [
757  ['fTable.uid=431'],
758  [' 1=1'],
759  ['`pages.uid` = `fTable.pid`'],
760  ],
761  [
762  'effectivePid' => '431string',
763  ],
764  ],
765  'replace THIS_UID' => [
766  'AND fTable.uid=###THIS_UID###',
767  [
768  ['fTable.uid=42'],
769  [' 1=1'],
770  ['`pages.uid` = `fTable.pid`'],
771  ],
772  [],
773  ],
774  'replace THIS_UID integer cast' => [
775  'AND fTable.uid=###THIS_UID###',
776  [
777  ['fTable.uid=421'],
778  [' 1=1'],
779  ['`pages.uid` = `fTable.pid`'],
780  ],
781  [
782  'databaseRow' => [
783  'uid' => '421string',
784  ],
785  ],
786  ],
787  'replace SITEROOT' => [
788  'AND fTable.uid=###SITEROOT###',
789  [
790  ['fTable.uid=44'],
791  [' 1=1'],
792  ['`pages.uid` = `fTable.pid`'],
793  ],
794  [],
795  ],
796  'replace SITEROOT integer cast' => [
797  'AND fTable.uid=###SITEROOT###',
798  [
799  ['fTable.uid=441'],
800  [' 1=1'],
801  ['`pages.uid` = `fTable.pid`'],
802  ],
803  [
804  'rootline' => [
805  1 => [
806  'uid' => '441string',
807  ],
808  ],
809  ],
810  ],
811  'replace PAGE_TSCONFIG_ID' => [
812  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
813  [
814  ['fTable.uid=45'],
815  [' 1=1'],
816  ['`pages.uid` = `fTable.pid`'],
817  ],
818  [
819  'pageTsConfig' => [
820  'TCEFORM.' => [
821  'aTable.' => [
822  'aField.' => [
823  'PAGE_TSCONFIG_ID' => '45',
824  ],
825  ],
826  ],
827  ],
828  ],
829  ],
830  'replace PAGE_TSCONFIG_ID integer cast' => [
831  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
832  [
833  ['fTable.uid=451'],
834  [' 1=1'],
835  ['`pages.uid` = `fTable.pid`'],
836  ],
837  [
838  'pageTsConfig' => [
839  'TCEFORM.' => [
840  'aTable.' => [
841  'aField.' => [
842  'PAGE_TSCONFIG_ID' => '451string',
843  ],
844  ],
845  ],
846  ],
847  ],
848  ],
849  'replace PAGE_TSCONFIG_STR' => [
850  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
851  [
852  ['fTable.uid=\'46\''],
853  [' 1=1'],
854  ['`pages.uid` = `fTable.pid`'],
855  ],
856  [
857  'pageTsConfig' => [
858  'TCEFORM.' => [
859  'aTable.' => [
860  'aField.' => [
861  'PAGE_TSCONFIG_STR' => '46',
862  ],
863  ],
864  ],
865  ],
866  ],
867  ],
868  'replace PAGE_TSCONFIG_IDLIST' => [
869  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
870  [
871  ['fTable.uid IN (47,48)'],
872  [' 1=1'],
873  ['`pages.uid` = `fTable.pid`'],
874  ],
875  [
876  'pageTsConfig' => [
877  'TCEFORM.' => [
878  'aTable.' => [
879  'aField.' => [
880  'PAGE_TSCONFIG_IDLIST' => '47,48',
881  ],
882  ],
883  ],
884  ],
885  ],
886  ],
887  'replace PAGE_TSCONFIG_IDLIST cleans list' => [
888  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
889  [
890  ['fTable.uid IN (471,481)'],
891  [' 1=1'],
892  ['`pages.uid` = `fTable.pid`'],
893  ],
894  [
895  'pageTsConfig' => [
896  'TCEFORM.' => [
897  'aTable.' => [
898  'aField.' => [
899  'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
900  ],
901  ],
902  ],
903  ],
904  ],
905  ],
906  'replace SITE:rootPageId' => [
907  'AND fTable.uid = ###SITE:rootPageId###',
908  [
909  ['fTable.uid = 1'],
910  [' 1=1'],
911  ['`pages.uid` = `fTable.pid`'],
912  ],
913  [],
914  ],
915  'replace SITE:mySetting.foobar' => [
916  'AND fTable.foo = ###SITE:mySetting.foobar###',
917  [
918  ['fTable.foo = 4711'],
919  [' 1=1'],
920  ['`pages.uid` = `fTable.pid`'],
921  ],
922  [],
923  ],
924  'replace SITE:mySetting.doesNotExist' => [
925  'AND fTable.foo = ###SITE:mySetting.doesNotExist###',
926  [
927  ['fTable.foo = \'\''],
928  [' 1=1'],
929  ['`pages.uid` = `fTable.pid`'],
930  ],
931  [],
932  ],
933  'replace replace SITE:rootPageId, SITE:mySetting.foobar and PAGE_TSCONFIG_IDLIST' => [
934  'AND fTable.uid = ###SITE:rootPageId### AND fTable.foo = ###SITE:mySetting.foobar### AND fTable.bar IN (###PAGE_TSCONFIG_IDLIST###)',
935  [
936  ['fTable.uid = 1 AND fTable.foo = 4711 AND fTable.bar IN (471,481)'],
937  [' 1=1'],
938  ['`pages.uid` = `fTable.pid`'],
939  ],
940  [
941  'pageTsConfig' => [
942  'TCEFORM.' => [
943  'aTable.' => [
944  'aField.' => [
945  'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
946  ],
947  ],
948  ],
949  ],
950  ],
951  ],
952  ];
953  }
954 
959  public function ‪addDataReplacesMarkersInForeignTableClause(string $foreignTableWhere, array $expectedWhere, array $inputOverride): void
960  {
961  $input = [
962  'tableName' => 'aTable',
963  'effectivePid' => 43,
964  'databaseRow' => [
965  'uid' => 42,
966  'rowField' => 'rowFieldValue',
967  'rowFieldTwo' => 'rowFieldTwoValue',
968  ],
969  'processedTca' => [
970  'columns' => [
971  'aField' => [
972  'config' => [
973  'type' => 'select',
974  'renderType' => 'selectSingle',
975  'foreign_table' => 'fTable',
976  'foreign_table_where' => $foreignTableWhere,
977  ],
978  ],
979  ],
980  ],
981  'rootline' => [
982  2 => [
983  'uid' => 999,
984  'is_siteroot' => 0,
985  ],
986  1 => [
987  'uid' => 44,
988  'is_siteroot' => 1,
989  ],
990  0 => [
991  'uid' => 0,
992  'is_siteroot' => null,
993  ],
994  ],
995  'pageTsConfig' => [],
996  'site' => new ‪Site('some-site', 1, ['rootPageId' => 1, 'mySetting' => ['foobar' => 4711]]),
997  ];
998  ‪ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
999 
1000  ‪$GLOBALS['TCA']['fTable'] = [];
1001 
1002  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1003  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1004  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1005 
1006  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection();
1007 
1008  $statementProphet = $this->prophesize(Result::class);
1009  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([]);
1010 
1011  $queryBuilderProphet->select('fTable.uid', 'fTable.pid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1012  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1013  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1014  $queryBuilderProphet->where(...array_shift($expectedWhere))->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1015  $queryBuilderProphet->executeQuery()->shouldBeCalled()->willReturn($statementProphet->reveal());
1016 
1017  while ($constraint = array_shift($expectedWhere)) {
1018  $queryBuilderProphet->andWhere(...$constraint)
1019  ->shouldBeCalled()
1020  ->willReturn($queryBuilderProphet->reveal());
1021  }
1022 
1023  // Two instances are needed due to the push/pop behavior of addInstance()
1024  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1025  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1026 
1027  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1028  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1029  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1030 
1031  (new ‪TcaSelectItems())->addData($input);
1032  }
1033 
1038  {
1039  $input = [
1040  'tableName' => 'aTable',
1041  'processedTca' => [
1042  'columns' => [
1043  'aField' => [
1044  'config' => [
1045  'type' => 'select',
1046  'renderType' => 'selectSingle',
1047  'foreign_table' => 'fTable',
1048  ],
1049  ],
1050  ],
1051  ],
1052  ];
1053 
1054  $this->expectException(\UnexpectedValueException::class);
1055  $this->expectExceptionCode(1439569743);
1056 
1057  (new ‪TcaSelectItems())->addData($input);
1058  }
1059 
1063  public function ‪addDataForeignTableSplitsGroupOrderAndLimit(): void
1064  {
1065  $input = [
1066  'tableName' => 'aTable',
1067  'effectivePid' => 42,
1068  'databaseRow' => [
1069  'uid' => 23,
1070  ],
1071  'processedTca' => [
1072  'columns' => [
1073  'aField' => [
1074  'config' => [
1075  'type' => 'select',
1076  'renderType' => 'selectSingle',
1077  'foreign_table' => 'fTable',
1078  'foreign_table_where' => '
1079  AND ftable.uid=1
1080  GROUP BY groupField1, groupField2
1081  ORDER BY orderField
1082  LIMIT 1,2',
1083  ],
1084  ],
1085  ],
1086  ],
1087  'rootline' => [],
1088  'site' => null,
1089  ];
1090 
1091  ‪$GLOBALS['TCA']['fTable'] = [];
1092 
1093  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1094  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1095  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1096 
1097  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1098  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1099  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1100 
1101  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection();
1102 
1103  $statementProphet = $this->prophesize(Result::class);
1104  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([]);
1105 
1106  $queryBuilderProphet->select('fTable.uid', 'fTable.pid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1107  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1108  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1109  $queryBuilderProphet->groupBy('groupField1', 'groupField2')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1110  $queryBuilderProphet->addOrderBy('orderField', null)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1111  $queryBuilderProphet->setFirstResult(1)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1112  $queryBuilderProphet->setMaxResults(2)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1113  $queryBuilderProphet->where('ftable.uid=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1114  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1115  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1116  $queryBuilderProphet->executeQuery()->shouldBeCalled()->willReturn($statementProphet->reveal());
1117 
1118  // Two instances are needed due to the push/pop behavior of addInstance()
1119  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1120  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1121 
1122  (new ‪TcaSelectItems())->addData($input);
1123  }
1124 
1129  {
1130  $input = [
1131  'databaseRow' => [
1132  'uid' => 23,
1133  'aField' => '',
1134  ],
1135  'tableName' => 'aTable',
1136  'effectivePid' => 42,
1137  'processedTca' => [
1138  'columns' => [
1139  'aField' => [
1140  'config' => [
1141  'type' => 'select',
1142  'renderType' => 'selectSingle',
1143  'foreign_table' => 'fTable',
1144  'items' => [
1145  0 => [
1146  0 => 'itemLabel',
1147  1 => 'itemValue',
1148  2 => null,
1149  3 => null,
1150  4 => null,
1151  ],
1152  ],
1153  'maxitems' => 99999,
1154  ],
1155  ],
1156  ],
1157  ],
1158  'rootline' => [],
1159  ];
1160 
1161  ‪$GLOBALS['TCA']['fTable'] = [];
1162 
1163  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1164  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1165  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1166 
1167  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection();
1168 
1169  $queryBuilderProphet->select('fTable.uid', 'fTable.pid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1170  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1171  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1172  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1173  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1174  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1175 
1176  $prevException = new DBALException('Invalid table name', 1476045274);
1177  $exception = new DBALException('Driver error', 1476045971, $prevException);
1178 
1179  $queryBuilderProphet->executeQuery()->shouldBeCalled()->willThrow($exception);
1180 
1181  // Two instances are needed due to the push/pop behavior of addInstance()
1182  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1183  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1184 
1185  $flashMessage = $this->prophesize(FlashMessage::class);
1186  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1187  $flashMessageService = $this->prophesize(FlashMessageService::class);
1188  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1189  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1190  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1191 
1192  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
1193 
1194  $expected = $input;
1195  $expected['databaseRow']['aField'] = [];
1196 
1197  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1198  }
1199 
1203  private function ‪mockForeignTableItemsQuery(): array
1204  {
1205  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection();
1206 
1207  $statementProphet = $this->prophesize(Result::class);
1208 
1209  $queryBuilderProphet->select('fTable.uid', 'fTable.pid', 'fTable.labelField')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1210  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1211  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1212  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1213  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1214  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1215  $queryBuilderProphet->executeQuery()->shouldBeCalled()->willReturn($statementProphet->reveal());
1216 
1217  return [$connectionPoolProphet, $statementProphet];
1218  }
1219 
1223  public function ‪addDataForeignTableHandlesForeignTableRows(): void
1224  {
1225  $input = [
1226  'databaseRow' => [
1227  'uid' => 5,
1228  'aField' => '',
1229  ],
1230  'tableName' => 'aTable',
1231  'effectivePid' => 42,
1232  'processedTca' => [
1233  'columns' => [
1234  'aField' => [
1235  'config' => [
1236  'type' => 'select',
1237  'renderType' => 'selectSingle',
1238  'foreign_table' => 'fTable',
1239  'foreign_table_prefix' => 'aPrefix',
1240  'items' => [],
1241  'maxitems' => 99999,
1242  ],
1243  ],
1244  ],
1245  ],
1246  'rootline' => [],
1247  ];
1248 
1249  ‪$GLOBALS['TCA']['fTable'] = [
1250  'ctrl' => [
1251  'label' => 'labelField',
1252  ],
1253  'columns' => [],
1254  ];
1255 
1256  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1257  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1258  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1259 
1260  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
1261  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
1262 
1263  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1264  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1265  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1266 
1267  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
1268 
1269  // Two instances are needed due to the push/pop behavior of addInstance()
1270  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1271  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1272 
1273  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([
1274  [
1275  'uid' => 1,
1276  'pid' => 23,
1277  'labelField' => 'aLabel',
1278  'aValue' => 'bar,',
1279  ],
1280  [
1281  'uid' => 2,
1282  'pid' => 23,
1283  'labelField' => 'aLabel',
1284  'aValue' => 'bar,',
1285  ],
1286  ]);
1287 
1288  $expected = $input;
1289  $expected['processedTca']['columns']['aField']['config']['items'] = [
1290  0 => [
1291  0 => 'aPrefix[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
1292  1 => 1,
1293  2 => null,
1294  3 => null,
1295  4 => null,
1296  ],
1297  1 => [
1298  0 => 'aPrefix[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
1299  1 => 2,
1300  2 => null,
1301  3 => null,
1302  4 => null,
1303  ],
1304  ];
1305 
1306  $expected['databaseRow']['aField'] = [];
1307 
1308  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1309  }
1310 
1315  {
1316  $input = [
1317  'databaseRow' => [
1318  'uid' => 5,
1319  'aField' => '',
1320  ],
1321  'tableName' => 'aTable',
1322  'effectivePid' => 42,
1323  'processedTca' => [
1324  'columns' => [
1325  'aField' => [
1326  'config' => [
1327  'type' => 'select',
1328  'renderType' => 'selectSingle',
1329  'foreign_table' => 'sys_file_storage',
1330  'foreign_table_prefix' => 'prefix for item labels',
1331  'items' => [],
1332  'maxitems' => 99999,
1333  ],
1334  ],
1335  ],
1336  ],
1337  'rootline' => [],
1338  ];
1339 
1340  ‪$GLOBALS['TCA']['sys_file_storage'] = [
1341  'ctrl' => [
1342  'label' => 'labelField',
1343  ],
1344  'columns' => [],
1345  ];
1346 
1347  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1348  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1349  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1350 
1351  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
1352  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
1353 
1354  $resourceStorageProphecy = $this->prophesize(ResourceStorage::class);
1355  $resourceStorageProphecy->getUid()->willReturn(1);
1356 
1357  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1358  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1359  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1360  $backendUserProphecy->getFileStorages()->shouldBeCalled()->willReturn(
1361  [$resourceStorageProphecy->reveal()]
1362  );
1363 
1364  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection('sys_file_storage');
1365 
1366  $statementProphet = $this->prophesize(Result::class);
1367 
1368  $queryBuilderProphet->select('sys_file_storage.uid', 'sys_file_storage.pid', 'sys_file_storage.labelField')
1369  ->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1370  $queryBuilderProphet->from('sys_file_storage')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1371  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1372  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1373  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1374  $queryBuilderProphet->andWhere('`pages.uid` = `sys_file_storage.pid`')
1375  ->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1376  $queryBuilderProphet->executeQuery()->shouldBeCalled()->willReturn($statementProphet->reveal());
1377 
1378  // Two instances are needed due to the push/pop behavior of addInstance()
1379  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1380  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1381 
1382  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([
1383  [
1384  'uid' => 1,
1385  'pid' => 0,
1386  'labelField' => 'storageFolderLabel',
1387  ],
1388  [
1389  'uid' => 2,
1390  'pid' => 0,
1391  'labelField' => 'storageFolderLabel',
1392  ],
1393  [
1394  'uid' => 3,
1395  'pid' => 0,
1396  'labelField' => 'storageFolderLabel',
1397  ],
1398  ]);
1399 
1400  $expected = $input;
1401  $expected['processedTca']['columns']['aField']['config']['items'] = [
1402  0 => [
1403  0 => 'prefix for item labels[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
1404  1 => 1,
1405  2 => null,
1406  3 => null,
1407  4 => null,
1408  ],
1409  ];
1410 
1411  $expected['databaseRow']['aField'] = [];
1412 
1413  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1414  }
1415 
1419  public function ‪addDataForeignTableResolvesIconFromSelicon(): void
1420  {
1421  $input = [
1422  'databaseRow' => [
1423  'uid' => 5,
1424  'aField' => '',
1425  ],
1426  'tableName' => 'aTable',
1427  'effectivePid' => 42,
1428  'processedTca' => [
1429  'columns' => [
1430  'aField' => [
1431  'config' => [
1432  'type' => 'select',
1433  'renderType' => 'selectSingle',
1434  'foreign_table' => 'fTable',
1435  'maxitems' => 99999,
1436  ],
1437  ],
1438  ],
1439  ],
1440  'rootline' => [],
1441  ];
1442 
1443  // Fake the foreign_table
1444  ‪$GLOBALS['TCA']['fTable'] = [
1445  'ctrl' => [
1446  'label' => 'icon',
1447  'selicon_field' => 'icon',
1448  ],
1449  'columns' => [
1450  'icon' => [],
1451  ],
1452  ];
1453 
1454  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1455  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1456  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1457 
1458  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1459  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1460  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1461 
1462  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection();
1463 
1464  $statementProphet = $this->prophesize(Result::class);
1465 
1466  $queryBuilderProphet->select('fTable.uid', 'fTable.pid', 'fTable.icon')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1467  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1468  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1469  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1470  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1471  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1472  $queryBuilderProphet->executeQuery()->shouldBeCalled()->willReturn($statementProphet->reveal());
1473 
1474  // Two instances are needed due to the push/pop behavior of addInstance()
1475  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1476  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1477 
1478  // Query returns one row, then false on second call
1479  $foreignTableRowResultOne = [
1480  'uid' => 1,
1481  'pid' => 23,
1482  'icon' => 'foo.jpg',
1483  ];
1484  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([$foreignTableRowResultOne]);
1485 
1486  $expected = $input;
1487  $expected['processedTca']['columns']['aField']['config']['items'] = [
1488  0 => [
1489  0 => 'foo.jpg',
1490  1 => 1,
1491  2 => null,
1492  3 => null,
1493  4 => null,
1494  ],
1495  ];
1496  $expected['databaseRow']['aField'] = [];
1497 
1498  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1499  }
1500 
1504  public function ‪addDataRemovesItemsByKeepItemsPageTsConfig(): void
1505  {
1506  $input = [
1507  'databaseRow' => [
1508  'aField' => '',
1509  ],
1510  'tableName' => 'aTable',
1511  'processedTca' => [
1512  'columns' => [
1513  'aField' => [
1514  'config' => [
1515  'type' => 'select',
1516  'renderType' => 'selectSingle',
1517  'items' => [
1518  0 => [
1519  0 => 'keepMe',
1520  1 => 'keep',
1521  null,
1522  null,
1523  null,
1524  ],
1525  1 => [
1526  0 => 'removeMe',
1527  1 => 'remove',
1528  ],
1529  2 => [
1530  0 => 'removeMe',
1531  1 => 0,
1532  ],
1533  ],
1534  'maxitems' => 99999,
1535  ],
1536  ],
1537  ],
1538  ],
1539  'pageTsConfig' => [
1540  'TCEFORM.' => [
1541  'aTable.' => [
1542  'aField.' => [
1543  'keepItems' => 'keep',
1544  ],
1545  ],
1546  ],
1547  ],
1548  ];
1549 
1550  $expected = $input;
1551  $expected['databaseRow']['aField'] = [];
1552  unset(
1553  $expected['processedTca']['columns']['aField']['config']['items'][1],
1554  $expected['processedTca']['columns']['aField']['config']['items'][2]
1555  );
1556 
1557  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1558  }
1559 
1564  {
1565  $input = [
1566  'databaseRow' => [
1567  'aField' => '',
1568  ],
1569  'tableName' => 'aTable',
1570  'processedTca' => [
1571  'columns' => [
1572  'aField' => [
1573  'config' => [
1574  'type' => 'select',
1575  'renderType' => 'selectSingle',
1576  'items' => [
1577  0 => [
1578  0 => 'keepMe',
1579  1 => 'keep',
1580  null,
1581  null,
1582  ],
1583  1 => [
1584  0 => 'removeMe',
1585  1 => 'remove',
1586  ],
1587  ],
1588  'maxitems' => 99999,
1589  ],
1590  ],
1591  ],
1592  ],
1593  'pageTsConfig' => [
1594  'TCEFORM.' => [
1595  'aTable.' => [
1596  'aField.' => [
1597  'keepItems' => '',
1598  ],
1599  ],
1600  ],
1601  ],
1602  ];
1603 
1604  $expected = $input;
1605  $expected['databaseRow']['aField'] = [];
1606  $expected['processedTca']['columns']['aField']['config']['items'] = [];
1607 
1608  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1609  }
1610 
1615  {
1616  $input = [
1617  'databaseRow' => [
1618  'aField' => '',
1619  ],
1620  'tableName' => 'aTable',
1621  'processedTca' => [
1622  'columns' => [
1623  'aField' => [
1624  'config' => [
1625  'type' => 'select',
1626  'renderType' => 'selectSingle',
1627  'items' => [
1628  0 => [
1629  0 => 'keepMe',
1630  1 => '1',
1631  null,
1632  null,
1633  ],
1634  1 => [
1635  0 => 'removeMe',
1636  1 => 'remove',
1637  ],
1638  ],
1639  'maxitems' => 99999,
1640  ],
1641  ],
1642  ],
1643  ],
1644  'pageTsConfig' => [
1645  'TCEFORM.' => [
1646  'aTable.' => [
1647  'aField.' => [
1648  'keepItems' => '1',
1649  'addItems.' => [
1650  '1' => 'addItem #1',
1651  '12' => 'addItem #12',
1652  ],
1653  ],
1654  ],
1655  ],
1656  ],
1657  ];
1658 
1659  $expected = $input;
1660  $expected['databaseRow']['aField'] = [];
1661  $expected['processedTca']['columns']['aField']['config']['items'] = [
1662  0 => [
1663  0 => 'keepMe',
1664  1 => '1',
1665  null,
1666  null,
1667  null,
1668  ],
1669  1 => [
1670  0 => 'addItem #1',
1671  1 => '1',
1672  null,
1673  null,
1674  null,
1675  ],
1676  2 => [
1677  0 => 'addItem #12',
1678  1 => '12',
1679  null,
1680  null,
1681  null,
1682  ],
1683  ];
1684 
1685  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1686  }
1687 
1691  public function ‪addDataRemovesItemsByRemoveItemsPageTsConfig(): void
1692  {
1693  $input = [
1694  'databaseRow' => [
1695  'aField' => '',
1696  ],
1697  'tableName' => 'aTable',
1698  'processedTca' => [
1699  'columns' => [
1700  'aField' => [
1701  'config' => [
1702  'type' => 'select',
1703  'renderType' => 'selectSingle',
1704  'items' => [
1705  0 => [
1706  0 => 'keepMe',
1707  1 => 'keep',
1708  null,
1709  null,
1710  null,
1711  ],
1712  1 => [
1713  0 => 'removeMe',
1714  1 => 'remove',
1715  ],
1716  2 => [
1717  0 => 'keep me',
1718  1 => 0,
1719  null,
1720  null,
1721  null,
1722  ],
1723  ],
1724  'maxitems' => 99999,
1725  ],
1726  ],
1727  ],
1728  ],
1729  'pageTsConfig' => [
1730  'TCEFORM.' => [
1731  'aTable.' => [
1732  'aField.' => [
1733  'removeItems' => 'remove',
1734  ],
1735  ],
1736  ],
1737  ],
1738  ];
1739 
1740  $expected = $input;
1741  $expected['databaseRow']['aField'] = [];
1742  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1743  $expected['processedTca']['columns']['aField']['config']['items'] = array_values($expected['processedTca']['columns']['aField']['config']['items']);
1744  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1745  }
1746 
1751  {
1752  $input = [
1753  'databaseRow' => [
1754  'aField' => '',
1755  ],
1756  'tableName' => 'aTable',
1757  'processedTca' => [
1758  'columns' => [
1759  'aField' => [
1760  'config' => [
1761  'type' => 'select',
1762  'renderType' => 'selectSingle',
1763  'items' => [
1764  0 => [
1765  0 => 'keepMe',
1766  1 => 'keep',
1767  null,
1768  null,
1769  null,
1770  ],
1771  1 => [
1772  0 => 'keepMe',
1773  1 => 'keepMe2',
1774  null,
1775  null,
1776  null,
1777  ],
1778  2 => [
1779  0 => 'remove me',
1780  1 => 0,
1781  ],
1782  ],
1783  'maxitems' => 99999,
1784  ],
1785  ],
1786  ],
1787  ],
1788  'pageTsConfig' => [
1789  'TCEFORM.' => [
1790  'aTable.' => [
1791  'aField.' => [
1792  'removeItems' => '0',
1793  ],
1794  ],
1795  ],
1796  ],
1797  ];
1798 
1799  $expected = $input;
1800  $expected['databaseRow']['aField'] = [];
1801  unset($expected['processedTca']['columns']['aField']['config']['items'][2]);
1802  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1803  }
1804 
1809  {
1810  $input = [
1811  'databaseRow' => [
1812  'aField' => '',
1813  ],
1814  'tableName' => 'aTable',
1815  'processedTca' => [
1816  'columns' => [
1817  'aField' => [
1818  'config' => [
1819  'type' => 'select',
1820  'renderType' => 'selectSingle',
1821  'items' => [
1822  0 => [
1823  0 => 'keepMe',
1824  1 => 'keep',
1825  null,
1826  null,
1827  null,
1828  ],
1829  1 => [
1830  0 => 'removeMe',
1831  1 => 'remove',
1832  ],
1833  ],
1834  'maxitems' => 99999,
1835  ],
1836  ],
1837  ],
1838  ],
1839  'pageTsConfig' => [
1840  'TCEFORM.' => [
1841  'aTable.' => [
1842  'aField.' => [
1843  'removeItems' => 'remove,add',
1844  'addItems.' => [
1845  'add' => 'addMe',
1846  ],
1847  ],
1848  ],
1849  ],
1850  ],
1851  ];
1852 
1853  $expected = $input;
1854  $expected['databaseRow']['aField'] = [];
1855  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1856 
1857  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1858  }
1859 
1864  {
1865  $input = [
1866  'databaseRow' => [
1867  'aField' => 'aValue,remove',
1868  ],
1869  'tableName' => 'aTable',
1870  'processedTca' => [
1871  'ctrl' => [
1872  'languageField' => 'aField',
1873  ],
1874  'columns' => [
1875  'aField' => [
1876  'config' => [
1877  'type' => 'select',
1878  'renderType' => 'selectSingle',
1879  'items' => [
1880  0 => [
1881  0 => 'keepMe',
1882  1 => 'keep',
1883  null,
1884  null,
1885  null,
1886  ],
1887  1 => [
1888  0 => 'removeMe',
1889  1 => 'remove',
1890  ],
1891  ],
1892  'maxitems' => 99999,
1893  ],
1894  ],
1895  ],
1896  ],
1897  ];
1898 
1899  $languageService = $this->prophesize(LanguageService::class);
1900  ‪$GLOBALS['LANG'] = $languageService->reveal();
1901  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
1902  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1903 
1904  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1905  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1906  $backendUserProphecy->checkLanguageAccess('keep')->shouldBeCalled()->willReturn(true);
1907  $backendUserProphecy->checkLanguageAccess('remove')->shouldBeCalled()->willReturn(false);
1908 
1909  $expected = $input;
1910  $expected['databaseRow']['aField'] = [];
1911  $expected['processedTca']['columns']['aField']['config']['items'] = [
1912  [ '[ INVALID VALUE "aValue" ]', 'aValue', null, 'none', null ],
1913  [ 'keepMe', 'keep', null, null, null ],
1914  ];
1915 
1916  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1917  }
1918 
1922  public function ‪addDataRemovesItemsByUserAuthModeRestriction(): void
1923  {
1924  $input = [
1925  'databaseRow' => [
1926  'aField' => 'keep,remove',
1927  ],
1928  'tableName' => 'aTable',
1929  'processedTca' => [
1930  'columns' => [
1931  'aField' => [
1932  'config' => [
1933  'type' => 'select',
1934  'renderType' => 'selectSingle',
1935  'authMode' => 'explicitAllow',
1936  'items' => [
1937  0 => [
1938  0 => 'keepMe',
1939  1 => 'keep',
1940  null,
1941  null,
1942  null,
1943  ],
1944  1 => [
1945  0 => 'removeMe',
1946  1 => 'remove',
1947  ],
1948  ],
1949  'maxitems' => 99999,
1950  ],
1951  ],
1952  ],
1953  ],
1954  ];
1955 
1956  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1957  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1958  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'keep', 'explicitAllow')->shouldBeCalled()->willReturn(true);
1959  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'remove', 'explicitAllow')->shouldBeCalled()->willReturn(false);
1960 
1961  $expected = $input;
1962  $expected['databaseRow']['aField'] = ['keep'];
1963  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1964 
1965  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
1966  }
1967 
1971  public function ‪addDataKeepsAllPagesDoktypesForAdminUser(): void
1972  {
1973  $input = [
1974  'databaseRow' => [
1975  'doktype' => 'keep',
1976  ],
1977  'tableName' => 'pages',
1978  'processedTca' => [
1979  'columns' => [
1980  'doktype' => [
1981  'config' => [
1982  'type' => 'select',
1983  'renderType' => 'selectSingle',
1984  'items' => [
1985  0 => [
1986  0 => 'keepMe',
1987  1 => 'keep',
1988  null,
1989  null,
1990  null,
1991  ],
1992  ],
1993  'maxitems' => 99999,
1994  ],
1995  ],
1996  ],
1997  ],
1998  ];
1999 
2000  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2001  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2002  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(true);
2003 
2004  $expected = $input;
2005  $expected['databaseRow']['doktype'] = ['keep'];
2006 
2007  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2008  }
2009 
2013  public function ‪addDataKeepsAllowedPageTypesForNonAdminUser(): void
2014  {
2015  $input = [
2016  'databaseRow' => [
2017  'doktype' => 'keep',
2018  ],
2019  'tableName' => 'pages',
2020  'processedTca' => [
2021  'columns' => [
2022  'doktype' => [
2023  'config' => [
2024  'type' => 'select',
2025  'renderType' => 'selectSingle',
2026  'items' => [
2027  0 => [
2028  0 => 'keepMe',
2029  1 => 'keep',
2030  null,
2031  null,
2032  null,
2033  ],
2034  1 => [
2035  0 => 'removeMe',
2036  1 => 'remove',
2037  ],
2038  ],
2039  'maxitems' => 99999,
2040  ],
2041  ],
2042  ],
2043  ],
2044  ];
2045 
2046  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2047  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
2048  $backendUser = $backendUserProphecy->reveal();
2049  $backendUser->groupData = [
2050  'pagetypes_select' => 'foo,keep,anotherAllowedDoktype',
2051  ];
2052  ‪$GLOBALS['BE_USER'] = $backendUser;
2053 
2054  $expected = $input;
2055  $expected['databaseRow']['doktype'] = ['keep'];
2056  unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
2057 
2058  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2059  }
2060 
2064  public function ‪addDataCallsItemsProcFunc(): void
2065  {
2066  $input = [
2067  'tableName' => 'aTable',
2068  'inlineParentUid' => 1,
2069  'inlineParentTableName' => 'aTable',
2070  'inlineParentFieldName' => 'aField',
2071  'inlineParentConfig' => [],
2072  'inlineTopMostParentUid' => 1,
2073  'inlineTopMostParentTableName' => 'topMostTable',
2074  'inlineTopMostParentFieldName' => 'topMostField',
2075  'databaseRow' => [
2076  'aField' => 'aValue',
2077  ],
2078  'processedTca' => [
2079  'columns' => [
2080  'aField' => [
2081  'config' => [
2082  'type' => 'select',
2083  'renderType' => 'selectSingle',
2084  'items' => [],
2085  'itemsProcFunc' => static function (array $parameters, $pObj) {
2086  $parameters['items'] = [
2087  0 => [
2088  0 => 'aLabel',
2089  1 => 'aValue',
2090  2 => null,
2091  3 => null,
2092  4 => null,
2093  ],
2094  ];
2095  },
2096  ],
2097  ],
2098  ],
2099  ],
2100  ];
2101 
2102  $expected = $input;
2103  $expected['databaseRow']['aField'] = ['aValue'];
2104  $expected['processedTca']['columns']['aField']['config'] = [
2105  'type' => 'select',
2106  'renderType' => 'selectSingle',
2107  'items' => [
2108  0 => [
2109  0 => 'aLabel',
2110  1 => 'aValue',
2111  2 => null,
2112  3 => null,
2113  4 => null,
2114  ],
2115  ],
2116  'maxitems' => 99999,
2117  ];
2118 
2119  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
2120  }
2121 
2126  {
2127  $input = [
2128  'databaseRow' => [
2129  'uid' => 5,
2130  'aField' => 2,
2131  ],
2132  'tableName' => 'aTable',
2133  'effectivePid' => 42,
2134  'processedTca' => [
2135  'columns' => [
2136  'aField' => [
2137  'config' => [
2138  'type' => 'select',
2139  'renderType' => 'selectSingle',
2140  'foreign_table' => 'fTable',
2141  'maxitems' => 99999,
2142  ],
2143  ],
2144  ],
2145  ],
2146  'rootline' => [],
2147  ];
2148 
2149  ‪$GLOBALS['TCA']['fTable'] = [
2150  'ctrl' => [
2151  'label' => 'labelField',
2152  ],
2153  'columns' => [
2154  'labelField' => [],
2155  ],
2156  ];
2157 
2158  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2159  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2160  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2161 
2162  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
2163  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
2164 
2165  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2166  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2167  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2168 
2169  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
2170 
2171  // Two instances are needed due to the push/pop behavior of addInstance()
2172  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2173  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2174 
2175  $statementProphet->fetchAllAssociative()->willReturn([
2176  [
2177  'uid' => 1,
2178  'pid' => 23,
2179  'labelField' => 'aLabel_1',
2180  'aValue' => 'bar,',
2181  'dbfield' => 'some data',
2182  ],
2183  [
2184  'uid' => 2,
2185  'pid' => 23,
2186  'labelField' => 'aLabel_2',
2187  'aValue' => 'bar,',
2188  'dbfield' => 'some data',
2189  ],
2190  ]);
2191 
2192  $expected = $input;
2193  $expected['processedTca']['columns']['aField']['config']['items'] = [
2194  0 => [
2195  0 => 'aLabel_1',
2196  1 => 1,
2197  2 => null,
2198  3 => null,
2199  4 => null,
2200  ],
2201  1 => [
2202  0 => 'aLabel_2',
2203  1 => 2,
2204  2 => null,
2205  3 => null,
2206  4 => null,
2207  ],
2208  ];
2209 
2210  $expected['databaseRow']['aField'] = [
2211  0 => '2', // the selected value stored in db
2212  ];
2213 
2214  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2215  }
2216 
2226  {
2227  $input = [
2228  'databaseRow' => [
2229  'uid' => 5,
2230  'aField' => '',
2231  ],
2232  'tableName' => 'aTable',
2233  'inlineParentUid' => 1,
2234  'inlineParentTableName' => 'aTable',
2235  'inlineParentFieldName' => 'aField',
2236  'inlineParentConfig' => [],
2237  'inlineTopMostParentUid' => 1,
2238  'inlineTopMostParentTableName' => 'topMostTable',
2239  'inlineTopMostParentFieldName' => 'topMostField',
2240  'effectivePid' => 42,
2241  'processedTca' => [
2242  'columns' => [
2243  'aField' => [
2244  'config' => [
2245  'type' => 'select',
2246  'renderType' => 'selectSingle',
2247  'foreign_table' => 'fTable',
2248  'itemsProcFunc' => static function (array $parameters, $pObj) {
2249  $filteredItems = [];
2250  // Iterate over given items to filter them
2251  foreach ($parameters['items'] as $item) {
2252  if ($item[1] === 2) { // uid === 2
2253  $filteredItems[] = [
2254  $item[0], // label
2255  $item[1], // uid
2256  null, // icon
2257  null, // groupID
2258  null, // helpText
2259  ];
2260  }
2261  }
2262  $parameters['items'] = $filteredItems;
2263  },
2264  'maxitems' => 99999,
2265  ],
2266  ],
2267  ],
2268  ],
2269  'rootline' => [],
2270  ];
2271 
2272  ‪$GLOBALS['TCA']['fTable'] = [
2273  'ctrl' => [
2274  'label' => 'labelField',
2275  ],
2276  'columns' => [],
2277  ];
2278 
2279  // FileRepository to get the icon of the foreign table
2280  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2281  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2282  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2283 
2284  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
2285  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
2286 
2287  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2288  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2289  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2290 
2291  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
2292 
2293  // Two instances are needed due to the push/pop behavior of addInstance()
2294  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2295  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2296 
2297  // simulates foreign_table containing two rows
2298  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([
2299  [
2300  'uid' => 1,
2301  'pid' => 23,
2302  'labelField' => 'aLabel will be replaced since the label column is not configured',
2303  'aValue' => 'bar, irrelevant',
2304  'dbfield' => 'some random data, irrelevant',
2305  ],
2306  [
2307  'uid' => 2,
2308  'pid' => 23,
2309  'labelField' => 'aLabel will be replaced since the label column is not configured',
2310  'aValue' => 'bar, irrelevant',
2311  'dbfield' => 'some random data, irrelevant',
2312  ],
2313  ]);
2314 
2315  $expected = $input;
2316  $expected['processedTca']['columns']['aField']['config'] = [
2317  'type' => 'select',
2318  'renderType' => 'selectSingle',
2319  'foreign_table' => 'fTable',
2320  'items' => [
2321  0 => [
2322  0 => '[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
2323  1 => 2,
2324  2 => null,
2325  3 => null,
2326  4 => null,
2327  ],
2328  ],
2329  'maxitems' => 99999,
2330  ];
2331 
2332  $expected['databaseRow']['aField'] = [];
2333 
2334  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2335  }
2336 
2347  {
2348  $input = [
2349  'databaseRow' => [
2350  'uid' => 5,
2351  'aField' => '',
2352  ],
2353  'tableName' => 'aTable',
2354  'inlineParentUid' => 1,
2355  'inlineParentTableName' => 'aTable',
2356  'inlineParentFieldName' => 'aField',
2357  'inlineParentConfig' => [],
2358  'inlineTopMostParentUid' => 1,
2359  'inlineTopMostParentTableName' => 'topMostTable',
2360  'inlineTopMostParentFieldName' => 'topMostField',
2361  'effectivePid' => 42,
2362  'processedTca' => [
2363  'columns' => [
2364  'aField' => [
2365  'config' => [
2366  'type' => 'select',
2367  'renderType' => 'selectSingle',
2368  'foreign_table' => 'fTable',
2369  'itemsProcFunc' => static function (array $parameters, $pObj) {
2370  $filteredItems = [];
2371  // Iterate over given items to filter them
2372  foreach ($parameters['items'] as $item) {
2373  if ($item[1] < 3) { // uid < 2
2374  $filteredItems[] = [
2375  $item[0], // label
2376  $item[1], // uid
2377  null, // icon
2378  null, // groupId
2379  null, // helpText
2380  ];
2381  }
2382  }
2383  $parameters['items'] = $filteredItems;
2384  },
2385  'maxitems' => 99999,
2386  ],
2387  ],
2388  ],
2389  ],
2390  'pageTsConfig' => [
2391  'TCEFORM.' => [
2392  'aTable.' => [
2393  'aField.' => [
2394  'removeItems' => '2',
2395  ],
2396  ],
2397  ],
2398  ],
2399  'rootline' => [],
2400  ];
2401 
2402  ‪$GLOBALS['TCA']['fTable'] = [
2403  'ctrl' => [
2404  'label' => 'labelField',
2405  ],
2406  'columns' => [],
2407  ];
2408 
2409  // FileRepository to get the icon of the foreign table
2410  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2411  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2412  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2413 
2414  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
2415  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
2416 
2417  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2418  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2419  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2420 
2421  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
2422 
2423  // Two instances are needed due to the push/pop behavior of addInstance()
2424  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2425  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2426 
2427  // simulates foreign_table containing two rows
2428  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([
2429  [
2430  'uid' => 1,
2431  'pid' => 23,
2432  'labelField' => 'aLabel will be replaced since the label column is not configured',
2433  'randomDbField' => 'bar, irrelevant',
2434  ],
2435  [
2436  'uid' => 2,
2437  'pid' => 23,
2438  'labelField' => 'aLabel will be replaced since the label column is not configured',
2439  'randomDbField' => 'bar, irrelevant',
2440  ],
2441  ]);
2442 
2443  $expected = $input;
2444  $expected['processedTca']['columns']['aField']['config'] = [
2445  'type' => 'select',
2446  'renderType' => 'selectSingle',
2447  'foreign_table' => 'fTable',
2448  'items' => [
2449  0 => [
2450  0 => '[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
2451  1 => 1,
2452  2 => null,
2453  3 => null,
2454  4 => null,
2455  ],
2456  ],
2457  'maxitems' => 99999,
2458  ];
2459 
2460  $expected['databaseRow']['aField'] = [];
2461 
2462  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2463  }
2464 
2475  {
2476  $input = [
2477  'databaseRow' => [
2478  'uid' => 5,
2479  'aField' => '',
2480  ],
2481  'tableName' => 'aTable',
2482  'inlineParentUid' => 1,
2483  'inlineParentTableName' => 'aTable',
2484  'inlineParentFieldName' => 'aField',
2485  'inlineParentConfig' => [],
2486  'inlineTopMostParentUid' => 1,
2487  'inlineTopMostParentTableName' => 'topMostTable',
2488  'inlineTopMostParentFieldName' => 'topMostField',
2489  'effectivePid' => 42,
2490  'processedTca' => [
2491  'columns' => [
2492  'aField' => [
2493  'config' => [
2494  'type' => 'select',
2495  'renderType' => 'selectSingle',
2496  'foreign_table' => 'fTable',
2497  'itemsProcFunc' => static function (array $parameters, $pObj) {
2498  $filteredItems = [];
2499  // Iterate over given items to filter them
2500  foreach ($parameters['items'] as $item) {
2501  if ($item[1] === 2) { // uid must be 2
2502  $filteredItems[] = [
2503  $item[0], // label
2504  $item[1], // uid
2505  null, // icon
2506  null, // groupID
2507  null, // helpText
2508  ];
2509  }
2510  }
2511  $parameters['items'] = $filteredItems;
2512  },
2513  'maxitems' => 99999,
2514  ],
2515  ],
2516  ],
2517  ],
2518  'pageTsConfig' => [
2519  'TCEFORM.' => [
2520  'aTable.' => [
2521  'aField.' => [
2522  'addItems.' => [
2523  '12' => 'Label of the added item',
2524  ],
2525  ],
2526  ],
2527  ],
2528  ],
2529  'rootline' => [],
2530  ];
2531 
2532  ‪$GLOBALS['TCA']['fTable'] = [
2533  'ctrl' => [
2534  'label' => 'labelField',
2535  ],
2536  'columns' => [],
2537  ];
2538 
2539  // FileRepository to get the icon of the foreign table
2540  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2541  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2542  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2543 
2544  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
2545  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
2546 
2547  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2548  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2549  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2550 
2551  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
2552 
2553  // Two instances are needed due to the push/pop behavior of addInstance()
2554  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2555  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2556 
2557  // simulates foreign_table containing two rows
2558  $statementProphet->fetchAllAssociative()->shouldBeCalled()->willReturn([
2559  [
2560  'uid' => 1,
2561  'pid' => 23,
2562  'labelField' => 'aLabel will be replaced since the label column is not configured',
2563  'randomDbField' => 'bar, irrelevant',
2564  ],
2565  [
2566  'uid' => 2,
2567  'pid' => 23,
2568  'labelField' => 'aLabel will be replaced since the label column is not configured',
2569  'randomDbField' => 'bar, irrelevant',
2570  ],
2571  ]);
2572 
2573  $expected = $input;
2574  $expected['processedTca']['columns']['aField']['config'] = [
2575  'type' => 'select',
2576  'renderType' => 'selectSingle',
2577  'foreign_table' => 'fTable',
2578  'items' => [
2579  0 => [
2580  0 => '[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
2581  1 => 2,
2582  2 => null,
2583  3 => null,
2584  4 => null,
2585  ],
2586  1 => [
2587  0 => 'Label of the added item',
2588  1 => 12,
2589  2 => null,
2590  3 => null,
2591  4 => null,
2592  ],
2593  ],
2594  'maxitems' => 99999,
2595  ];
2596 
2597  $expected['databaseRow']['aField'] = [];
2598 
2599  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2600  }
2601 
2605  public function ‪addDataItemsProcFuncReceivesParameters(): void
2606  {
2607  $input = [
2608  'tableName' => 'aTable',
2609  'inlineParentUid' => 1,
2610  'inlineParentTableName' => 'aTable',
2611  'inlineParentFieldName' => 'aField',
2612  'inlineParentConfig' => ['config' => 'someValue'],
2613  'inlineTopMostParentUid' => 1,
2614  'inlineTopMostParentTableName' => 'topMostTable',
2615  'inlineTopMostParentFieldName' => 'topMostField',
2616  'databaseRow' => [
2617  'aField' => 'aValue',
2618  ],
2619  'pageTsConfig' => [
2620  'TCEFORM.' => [
2621  'aTable.' => [
2622  'aField.' => [
2623  'itemsProcFunc.' => [
2624  'itemParamKey' => 'itemParamValue',
2625  ],
2626  ],
2627  ],
2628  ],
2629  ],
2630  'processedTca' => [
2631  'columns' => [
2632  'aField' => [
2633  'config' => [
2634  'type' => 'select',
2635  'renderType' => 'selectSingle',
2636  'aKey' => 'aValue',
2637  'items' => [
2638  0 => [
2639  0 => 'aLabel',
2640  1 => 'aValue',
2641  ],
2642  ],
2643  'itemsProcFunc' => static function (array $parameters, $pObj) {
2644  if ($parameters['items'] !== [ 0 => [ 'aLabel', 'aValue'] ]
2645  || $parameters['config']['aKey'] !== 'aValue'
2646  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
2647  || $parameters['table'] !== 'aTable'
2648  || $parameters['row'] !== [ 'aField' => 'aValue' ]
2649  || $parameters['field'] !== 'aField'
2650  || $parameters['inlineParentUid'] !== 1
2651  || $parameters['inlineParentTableName'] !== 'aTable'
2652  || $parameters['inlineParentFieldName'] !== 'aField'
2653  || $parameters['inlineParentConfig'] !== ['config' => 'someValue']
2654  || $parameters['inlineTopMostParentUid'] !== 1
2655  || $parameters['inlineTopMostParentTableName'] !== 'topMostTable'
2656  || $parameters['inlineTopMostParentFieldName'] !== 'topMostField'
2657  ) {
2658  throw new \UnexpectedValueException('broken', 1476109436);
2659  }
2660  },
2661  ],
2662  ],
2663  ],
2664  ],
2665  ];
2666 
2667  $languageService = $this->prophesize(LanguageService::class);
2668  ‪$GLOBALS['LANG'] = $languageService->reveal();
2669  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2670  $flashMessage = $this->prophesize(FlashMessage::class);
2671  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2672  $flashMessageService = $this->prophesize(FlashMessageService::class);
2673  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2674  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2675  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2676 
2677  // itemsProcFunc must NOT have raised an exception
2678  $flashMessageQueue->enqueue($flashMessage)->shouldNotBeCalled();
2679 
2680  (new ‪TcaSelectItems())->addData($input);
2681  }
2682 
2687  {
2688  $input = [
2689  'tableName' => 'aTable',
2690  'inlineParentUid' => 1,
2691  'inlineParentTableName' => 'aTable',
2692  'inlineParentFieldName' => 'aField',
2693  'inlineParentConfig' => [],
2694  'inlineTopMostParentUid' => 1,
2695  'inlineTopMostParentTableName' => 'topMostTable',
2696  'inlineTopMostParentFieldName' => 'topMostField',
2697  'databaseRow' => [
2698  'aField' => 'aValue',
2699  ],
2700  'pageTsConfig' => [
2701  'TCEFORM.' => [
2702  'aTable.' => [
2703  'aField.' => [
2704  'itemsProcFunc.' => [
2705  'itemParamKey' => 'itemParamValue',
2706  ],
2707  ],
2708  ],
2709  ],
2710  ],
2711  'processedTca' => [
2712  'columns' => [
2713  'aField' => [
2714  'config' => [
2715  'type' => 'select',
2716  'renderType' => 'selectSingle',
2717  'aKey' => 'aValue',
2718  'items' => [
2719  0 => [
2720  0 => 'aLabel',
2721  1 => 'aValue',
2722  ],
2723  ],
2724  'itemsProcFunc' => static function (array $parameters, $pObj) {
2725  throw new \UnexpectedValueException('anException', 1476109437);
2726  },
2727  ],
2728  ],
2729  ],
2730  ],
2731  ];
2732 
2733  $languageService = $this->prophesize(LanguageService::class);
2734  $languageService->sL(Argument::cetera())->willReturn('');
2735  ‪$GLOBALS['LANG'] = $languageService->reveal();
2736  $flashMessage = $this->prophesize(FlashMessage::class);
2737  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2738  $flashMessageService = $this->prophesize(FlashMessageService::class);
2739  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2740  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2741  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2742 
2743  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
2744 
2745  (new ‪TcaSelectItems())->addData($input);
2746  }
2747 
2751  public function ‪addDataTranslatesItemLabelsFromPageTsConfig(): void
2752  {
2753  $input = [
2754  'databaseRow' => [
2755  'aField' => 'aValue',
2756  ],
2757  'tableName' => 'aTable',
2758  'processedTca' => [
2759  'columns' => [
2760  'aField' => [
2761  'config' => [
2762  'type' => 'select',
2763  'renderType' => 'selectSingle',
2764  'items' => [
2765  0 => [
2766  0 => 'aLabel',
2767  1 => 'aValue',
2768  null,
2769  null,
2770  null,
2771  ],
2772  ],
2773  'maxitems' => 99999,
2774  ],
2775  ],
2776  ],
2777  ],
2778  'pageTsConfig' => [
2779  'TCEFORM.' => [
2780  'aTable.' => [
2781  'aField.' => [
2782  'altLabels.' => [
2783  'aValue' => 'labelOverride',
2784  ],
2785  ],
2786  ],
2787  ],
2788  ],
2789  ];
2790 
2791  $languageService = $this->prophesize(LanguageService::class);
2792  ‪$GLOBALS['LANG'] = $languageService->reveal();
2793  $languageService->sL('aLabel')->willReturnArgument(0);
2794  $languageService->sL('labelOverride')->shouldBeCalled()->willReturnArgument(0);
2795  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2796 
2797  $expected = $input;
2798  $expected['databaseRow']['aField'] = ['aValue'];
2799  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'labelOverride';
2800 
2801  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
2802  }
2803 
2807  public function ‪addDataAddsIconsFromPageTsConfig(): void
2808  {
2809  $input = [
2810  'databaseRow' => [
2811  'aField' => 'aValue',
2812  ],
2813  'tableName' => 'aTable',
2814  'processedTca' => [
2815  'columns' => [
2816  'aField' => [
2817  'config' => [
2818  'type' => 'select',
2819  'renderType' => 'selectSingle',
2820  'items' => [
2821  0 => [
2822  0 => 'aLabel',
2823  1 => 'aValue',
2824  2 => 'icon-identifier',
2825  null,
2826  null,
2827  ],
2828  ],
2829  'maxitems' => 99999,
2830  ],
2831  ],
2832  ],
2833  ],
2834  'pageTsConfig' => [
2835  'TCEFORM.' => [
2836  'aTable.' => [
2837  'aField.' => [
2838  'altIcons.' => [
2839  'aValue' => 'icon-identifier-override',
2840  ],
2841  ],
2842  ],
2843  ],
2844  ],
2845  ];
2846 
2847  $languageService = $this->prophesize(LanguageService::class);
2848  ‪$GLOBALS['LANG'] = $languageService->reveal();
2849  $languageService->sL('aLabel')->willReturnArgument(0);
2850  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2851 
2852  $expected = $input;
2853  $expected['databaseRow']['aField'] = ['aValue'];
2854  $expected['processedTca']['columns']['aField']['config']['items'][0][2] = 'icon-identifier-override';
2855 
2856  self::assertSame($expected, (new ‪TcaSelectItems())->addData($input));
2857  }
2858 
2863  {
2864  ‪$GLOBALS['TCA']['foreignTable'] = [];
2865 
2866  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2867  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2868  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2869 
2870  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2871  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2872  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2873 
2875 
2876  $input = [
2877  'command' => 'edit',
2878  'tableName' => 'aTable',
2879  'effectivePid' => 23,
2880  'databaseRow' => [
2881  'uid' => 42,
2882  // Two connected rows
2883  'aField' => 2,
2884  ],
2885  'processedTca' => [
2886  'columns' => [
2887  'aField' => [
2888  'config' => [
2889  'type' => 'select',
2890  'renderType' => 'selectSingle',
2891  'maxitems' => 999,
2892  'foreign_table' => 'foreignTable',
2893  'MM' => 'aTable_foreignTable_mm',
2894  'items' => [],
2895  ],
2896  ],
2897  ],
2898  ],
2899  ];
2900  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2901  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2902  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2903 
2904  $relationHandlerUids = [
2905  23,
2906  24,
2907  ];
2908 
2909  $relationHandlerProphecy->start('', 'foreignTable', 'aTable_foreignTable_mm', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2910  $relationHandlerProphecy->processDeletePlaceholder()->shouldBeCalled();
2911  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2912 
2913  $expected = $input;
2914  $expected['databaseRow']['aField'] = $relationHandlerUids;
2915 
2916  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2917  }
2918 
2923  {
2924  ‪$GLOBALS['TCA']['foreignTable'] = [];
2925 
2926  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2927  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2928  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2929 
2930  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2931  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2932  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2933 
2935 
2936  $input = [
2937  'tableName' => 'aTable',
2938  'effectivePid' => 23,
2939  'databaseRow' => [
2940  'uid' => 42,
2941  // Two connected rows
2942  'aField' => '22,23,24,25',
2943  ],
2944  'processedTca' => [
2945  'columns' => [
2946  'aField' => [
2947  'config' => [
2948  'type' => 'select',
2949  'renderType' => 'selectSingle',
2950  'maxitems' => 999,
2951  'foreign_table' => 'foreignTable',
2952  'items' => [],
2953  ],
2954  ],
2955  ],
2956  ],
2957  ];
2958  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2959  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2960  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2961 
2962  $relationHandlerUids = [
2963  23,
2964  24,
2965  ];
2966 
2967  $relationHandlerProphecy->start('22,23,24,25', 'foreignTable', '', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2968  $relationHandlerProphecy->processDeletePlaceholder()->shouldBeCalled();
2969  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2970 
2971  $expected = $input;
2972  $expected['databaseRow']['aField'] = $relationHandlerUids;
2973 
2974  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
2975  }
2976 
2981  {
2982  ‪$GLOBALS['TCA']['foreignTable'] = [];
2983 
2984  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2985  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2986  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2987 
2988  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2989  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2990  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2991 
2993 
2994  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2995  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2996  $relationHandlerProphecy->start(Argument::cetera())->shouldBeCalled();
2997  $relationHandlerProphecy->processDeletePlaceholder()->shouldBeCalled();
2998  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldBeCalled()->willReturn([1]);
2999 
3000  $input = [
3001  'tableName' => 'aTable',
3002  'effectivePid' => 23,
3003  'databaseRow' => [
3004  'uid' => 5,
3005  'aField' => '1,2,bar,foo',
3006  ],
3007  'processedTca' => [
3008  'columns' => [
3009  'aField' => [
3010  'config' => [
3011  'type' => 'select',
3012  'renderType' => 'selectSingleBox',
3013  'foreign_table' => 'foreignTable',
3014  'maxitems' => 999,
3015  'items' => [
3016  ['foo', 'foo', null, null, null],
3017  ],
3018  ],
3019  ],
3020  ],
3021  ],
3022  ];
3023 
3024  $expected = $input;
3025  $expected['databaseRow']['aField'] = [1, 'foo'];
3026 
3027  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3028  }
3029 
3034  {
3035  $input = [
3036  'tableName' => 'aTable',
3037  'databaseRow' => [
3038  'aField' => 'foo,bar',
3039  ],
3040  'processedTca' => [
3041  'columns' => [
3042  'aField' => [
3043  'config' => [
3044  'type' => 'select',
3045  'renderType' => 'selectSingle',
3046  'maxitems' => 999,
3047  'items' => [
3048  ['foo', 'foo', null, null, null],
3049  ['bar', 'bar', null, null, null],
3050  ],
3051  ],
3052  ],
3053  ],
3054  ],
3055  ];
3056 
3057  $expected = $input;
3058  $expected['databaseRow']['aField'] = [
3059  'foo',
3060  'bar',
3061  ];
3062 
3063  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3064  }
3065 
3070  {
3071  $input = [
3072  'tableName' => 'aTable',
3073  'databaseRow' => [
3074  'aField' => '',
3075  ],
3076  'processedTca' => [
3077  'columns' => [
3078  'aField' => [
3079  'config' => [
3080  'type' => 'select',
3081  'renderType' => 'selectSingle',
3082  'maxitems' => 99999,
3083  'items' => [],
3084  ],
3085  ],
3086  ],
3087  ],
3088  ];
3089 
3090  $expected = $input;
3091  $expected['databaseRow']['aField'] = [];
3092 
3093  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3094  }
3095 
3100  {
3101  $input = [
3102  'tableName' => 'aTable',
3103  'databaseRow' => [
3104  'aField' => 'b,,c',
3105  ],
3106  'processedTca' => [
3107  'columns' => [
3108  'aField' => [
3109  'config' => [
3110  'type' => 'select',
3111  'renderType' => 'selectSingle',
3112  'maxitems' => 999,
3113  'items' => [
3114  ['a', '', null, null, null],
3115  ['b', 'b', null, null, null],
3116  ['c', 'c', null, null, null],
3117  ],
3118  ],
3119  ],
3120  ],
3121  ],
3122  ];
3123 
3124  $expected = $input;
3125  $expected['databaseRow']['aField'] = [
3126  'b',
3127  'c',
3128  ];
3129 
3130  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3131  }
3132 
3137  {
3138  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3139  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3140  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3141  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3142 
3143  $input = [
3144  'tableName' => 'aTable',
3145  'databaseRow' => [
3146  'aField' => 'foo',
3147  ],
3148  'processedTca' => [
3149  'columns' => [
3150  'aField' => [
3151  'config' => [
3152  'type' => 'select',
3153  'renderType' => 'selectSingle',
3154  'maxitems' => 999,
3155  'items' => [
3156  ['foo', 'foo', null, null, null],
3157  ],
3158  ],
3159  ],
3160  ],
3161  ],
3162  ];
3163 
3164  $expected = $input;
3165  $expected['databaseRow']['aField'] = ['foo'];
3166 
3167  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3168  }
3169 
3174  {
3175  $languageService = $this->prophesize(LanguageService::class);
3176  ‪$GLOBALS['LANG'] = $languageService->reveal();
3177  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
3178  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3179 
3180  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3181  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3182  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3183  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3184 
3185  $input = [
3186  'tableName' => 'aTable',
3187  'databaseRow' => [
3188  'aField' => '1,2,bar,foo',
3189  ],
3190  'processedTca' => [
3191  'columns' => [
3192  'aField' => [
3193  'config' => [
3194  'type' => 'select',
3195  'renderType' => 'selectSingle',
3196  'maxitems' => 99999,
3197  'items' => [
3198  ['foo', 'foo', null, null, null],
3199  ],
3200  ],
3201  ],
3202  ],
3203  ],
3204  ];
3205 
3206  $expected = $input;
3207  $expected['databaseRow']['aField'] = ['foo'];
3208  $expected['processedTca']['columns']['aField']['config']['items'] = [
3209  ['[ INVALID VALUE "bar" ]', 'bar', null, 'none', null],
3210  ['[ INVALID VALUE "2" ]', '2', null, 'none', null],
3211  ['[ INVALID VALUE "1" ]', '1', null, 'none', null],
3212  ['foo', 'foo', null, null, null],
3213  ];
3214  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3215  }
3216 
3221  {
3222  $input = [
3223  'tableName' => 'aTable',
3224  'databaseRow' => [
3225  'aField' => '1,foo,foo,2,bar',
3226  ],
3227  'processedTca' => [
3228  'columns' => [
3229  'aField' => [
3230  'config' => [
3231  'type' => 'select',
3232  'renderType' => 'selectSingle',
3233  'multiple' => true,
3234  'maxitems' => 999,
3235  'items' => [
3236  ['1', '1', null, null, null],
3237  ['foo', 'foo', null, null, null],
3238  ['bar', 'bar', null, null, null],
3239  ['2', '2', null, null, null],
3240  ],
3241  ],
3242  ],
3243  ],
3244  ],
3245  ];
3246 
3247  $expected = $input;
3248  $expected['databaseRow']['aField'] = [
3249  '1',
3250  'foo',
3251  'foo',
3252  '2',
3253  'bar',
3254  ];
3255 
3256  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3257  }
3258 
3263  {
3264  $input = [
3265  'tableName' => 'aTable',
3266  'databaseRow' => [
3267  'aField' => '1,foo,foo,2,bar',
3268  ],
3269  'processedTca' => [
3270  'columns' => [
3271  'aField' => [
3272  'config' => [
3273  'type' => 'select',
3274  'renderType' => 'selectSingle',
3275  'multiple' => false,
3276  'maxitems' => 999,
3277  'items' => [
3278  ['1', '1', null, null, null],
3279  ['foo', 'foo', null, null, null],
3280  ['bar', 'bar', null, null, null],
3281  ['2', '2', null, null, null],
3282  ],
3283  ],
3284  ],
3285  ],
3286  ],
3287  ];
3288 
3289  $expected = $input;
3290  $expected['databaseRow']['aField'] = [
3291  0 => '1',
3292  1 => 'foo',
3293  3 => '2',
3294  4 => 'bar',
3295  ];
3296 
3297  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3298  }
3299 
3306  {
3307  return [
3308  'Relation with MM table and new status with default values' => [
3309  [
3310  'tableName' => 'aTable',
3311  'command' => 'new',
3312  'effectivePid' => 42,
3313  'databaseRow' => [
3314  'uid' => 'NEW1234',
3315  'aField' => '24,35',
3316  ],
3317  'processedTca' => [
3318  'columns' => [
3319  'aField' => [
3320  'config' => [
3321  'type' => 'select',
3322  'renderType' => 'selectSingle',
3323  'maxitems' => 999,
3324  'MM' => 'mm_aTable_foreignTable',
3325  'foreign_table' => 'foreignTable',
3326  'items' => [],
3327  ],
3328  ],
3329  ],
3330  ],
3331  ],
3332  [
3333  'MM' => '',
3334  ],
3335  [
3336  24, 35,
3337  ],
3338  ],
3339  'Relation with MM table and item array in list but no new status' => [
3340  [
3341  'tableName' => 'aTable',
3342  'command' => 'edit',
3343  'effectivePid' => 42,
3344  'databaseRow' => [
3345  'uid' => 42,
3346  'aField' => '2',
3347  ],
3348  'processedTca' => [
3349  'columns' => [
3350  'aField' => [
3351  'config' => [
3352  'type' => 'select',
3353  'renderType' => 'selectSingle',
3354  'maxitems' => 999,
3355  'MM' => 'mm_aTable_foreignTable',
3356  'foreign_table' => 'foreignTable',
3357  'items' => [],
3358  ],
3359  ],
3360  ],
3361  ],
3362  ],
3363  [
3364  'relationHandlerStartItemList' => '',
3365  ],
3366  [],
3367  ],
3368  'Relation with MM table and maxitems = 1 processes field value (item count)' => [
3369  [
3370  'tableName' => 'aTable',
3371  'command' => 'edit',
3372  'effectivePid' => 42,
3373  'databaseRow' => [
3374  'uid' => 42,
3375  // MM relation with one item has 1 in field value
3376  'aField' => 1,
3377  ],
3378  'processedTca' => [
3379  'columns' => [
3380  'aField' => [
3381  'config' => [
3382  'type' => 'select',
3383  'renderType' => 'selectSingle',
3384  'maxitems' => 1,
3385  'MM' => 'mm_aTable_foreignTable',
3386  'foreign_table' => 'foreignTable',
3387  'items' => [],
3388  ],
3389  ],
3390  ],
3391  ],
3392  ],
3393  [
3394  'relationHandlerStartItemList' => '',
3395  ],
3396  [
3397  24,
3398  ],
3399  ],
3400  'Relation with MM table and maxitems = 1 results in empty array if no items are set' => [
3401  [
3402  'tableName' => 'aTable',
3403  'command' => 'edit',
3404  'effectivePid' => 42,
3405  'databaseRow' => [
3406  'uid' => 58,
3407  // MM relation with no items has 0 in field value
3408  'aField' => 0,
3409  ],
3410  'processedTca' => [
3411  'columns' => [
3412  'aField' => [
3413  'config' => [
3414  'type' => 'select',
3415  'renderType' => 'selectSingle',
3416  'maxitems' => 1,
3417  'MM' => 'mm_aTable_foreignTable',
3418  'foreign_table' => 'foreignTable',
3419  'items' => [],
3420  ],
3421  ],
3422  ],
3423  ],
3424  ],
3425  [
3426  'relationHandlerStartItemList' => '',
3427  ],
3428  [],
3429  ],
3430  ];
3431  }
3432 
3441  public function ‪processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids): void
3442  {
3443  $field = $overrideRelationHandlerSettings['relationHandlerStartItemList'] ?? $input['databaseRow']['aField'];
3444  $foreignTable = $overrideRelationHandlerSettings['foreign_table'] ?? $input['processedTca']['columns']['aField']['config']['foreign_table'];
3445  $mmTable = $overrideRelationHandlerSettings['MM'] ?? $input['processedTca']['columns']['aField']['config']['MM'];
3446  $uid = $input['databaseRow']['uid'];
3447  $tableName = $input['tableName'];
3448  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
3449 
3450  ‪$GLOBALS['TCA'][$foreignTable] = [];
3451 
3452  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
3453  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
3454  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
3455 
3456  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3457  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3458  $backendUserProphecy->getPagePermsClause(Argument::cetera())->willReturn(' 1=1');
3459 
3461 
3462  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3463  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3464 
3465  $relationHandlerProphecy->start($field, $foreignTable, $mmTable, $uid, $tableName, $fieldConfig)->shouldBeCalled();
3466  $relationHandlerProphecy->processDeletePlaceholder()->shouldBeCalled();
3467  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
3468 
3469  $expected = $input;
3470  $expected['databaseRow']['aField'] = $relationHandlerUids;
3471 
3472  self::assertEquals($expected, (new ‪TcaSelectItems())->addData($input));
3473  }
3474 }
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataReplacesMarkersInForeignTableClauseDataProvider
‪addDataReplacesMarkersInForeignTableClauseDataProvider()
Definition: TcaSelectItemsTest.php:666
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsFileItemsWithConfiguredFileFolder
‪addDataAddsFileItemsWithConfiguredFileFolder()
Definition: TcaSelectItemsTest.php:392
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataCallsItemsProcFunc
‪addDataCallsItemsProcFunc()
Definition: TcaSelectItemsTest.php:2063
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:36
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncReceivesParameters
‪addDataItemsProcFuncReceivesParameters()
Definition: TcaSelectItemsTest.php:2604
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\mockDatabaseConnection
‪array mockDatabaseConnection(string $tableName='fTable')
Definition: TcaSelectItemsTest.php:90
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueDoesNotCallRelationManagerForStaticOnlyItems
‪processSelectFieldValueDoesNotCallRelationManagerForStaticOnlyItems()
Definition: TcaSelectItemsTest.php:3135
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsItemsByAddItemsFromPageTsConfig
‪addDataAddsItemsByAddItemsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:554
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsDividersIfItemGroupsAreDefined
‪addDataAddsDividersIfItemGroupsAreDefined()
Definition: TcaSelectItemsTest.php:277
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableSplitsGroupOrderAndLimit
‪addDataForeignTableSplitsGroupOrderAndLimit()
Definition: TcaSelectItemsTest.php:1062
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepsAllowedPageTypesForNonAdminUser
‪addDataKeepsAllowedPageTypesForNonAdminUser()
Definition: TcaSelectItemsTest.php:2012
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueReturnsEmptyValueForSingleSelect
‪processSelectFieldValueReturnsEmptyValueForSingleSelect()
Definition: TcaSelectItemsTest.php:3068
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByLanguageFieldUserRestriction
‪addDataRemovesItemsByLanguageFieldUserRestriction()
Definition: TcaSelectItemsTest.php:1862
‪TYPO3\CMS\Core\Database\RelationHandler
Definition: RelationHandler.php:37
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionForInvalidFileFolder
‪addDataThrowsExceptionForInvalidFileFolder()
Definition: TcaSelectItemsTest.php:526
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueRemovesInvalidDynamicValues
‪processSelectFieldValueRemovesInvalidDynamicValues()
Definition: TcaSelectItemsTest.php:2979
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByUserAuthModeRestriction
‪addDataRemovesItemsByUserAuthModeRestriction()
Definition: TcaSelectItemsTest.php:1921
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\setUp
‪setUp()
Definition: TcaSelectItemsTest.php:56
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig
‪addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:1562
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig
‪addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig()
Definition: TcaSelectItemsTest.php:610
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepsAllPagesDoktypesForAdminUser
‪addDataKeepsAllPagesDoktypesForAdminUser()
Definition: TcaSelectItemsTest.php:1970
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncWillUseItemsFromForeignTable
‪addDataItemsProcFuncWillUseItemsFromForeignTable()
Definition: TcaSelectItemsTest.php:2224
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldSetsCorrectValuesForMmRelations
‪processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids)
Definition: TcaSelectItemsTest.php:3440
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionIfAnItemIsNotAnArray
‪addDataThrowsExceptionIfAnItemIsNotAnArray()
Definition: TcaSelectItemsTest.php:203
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataReplacesMarkersInForeignTableClause
‪addDataReplacesMarkersInForeignTableClause(string $foreignTableWhere, array $expectedWhere, array $inputOverride)
Definition: TcaSelectItemsTest.php:958
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableHandlesForeignTableRows
‪addDataForeignTableHandlesForeignTableRows()
Definition: TcaSelectItemsTest.php:1222
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsThatAreRestrictedByUserStorageAddedByForeignTable
‪addDataRemovesItemsThatAreRestrictedByUserStorageAddedByForeignTable()
Definition: TcaSelectItemsTest.php:1313
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepExistingItems
‪addDataKeepExistingItems()
Definition: TcaSelectItemsTest.php:164
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueAddsInvalidValuesToItemsForSingleSelects
‪processSelectFieldValueAddsInvalidValuesToItemsForSingleSelects()
Definition: TcaSelectItemsTest.php:3172
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldSetsCorrectValuesForMmRelationsDataProvider
‪array processSelectFieldSetsCorrectValuesForMmRelationsDataProvider()
Definition: TcaSelectItemsTest.php:3304
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataTranslatesItemLabels
‪addDataTranslatesItemLabels()
Definition: TcaSelectItemsTest.php:231
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\mockDatabaseConnectionForProcessSelectField
‪mockDatabaseConnectionForProcessSelectField()
Definition: TcaSelectItemsTest.php:127
‪TYPO3\CMS\Core\Resource\FileRepository
Definition: FileRepository.php:33
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueSetsForeignRelationValues
‪processSelectFieldValueSetsForeignRelationValues()
Definition: TcaSelectItemsTest.php:2921
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableItemsWillReceiveTheLabelFromForeignTableLabelField
‪addDataForeignTableItemsWillReceiveTheLabelFromForeignTableLabelField()
Definition: TcaSelectItemsTest.php:2124
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableQueuesFlashMessageOnDatabaseError
‪addDataForeignTableQueuesFlashMessageOnDatabaseError()
Definition: TcaSelectItemsTest.php:1127
‪TYPO3\CMS\Core\Imaging\IconRegistry
Definition: IconRegistry.php:32
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncWillUseItemsFromForeignTableAndRemoveItemsByPageTsConfig
‪addDataItemsProcFuncWillUseItemsFromForeignTableAndRemoveItemsByPageTsConfig()
Definition: TcaSelectItemsTest.php:2345
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsIconsFromPageTsConfig
‪addDataAddsIconsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:2806
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems
Definition: TcaSelectItems.php:26
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueReturnsDuplicateValuesForMultipleSelect
‪processSelectFieldValueReturnsDuplicateValuesForMultipleSelect()
Definition: TcaSelectItemsTest.php:3219
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByZeroValueRemoveItemsPageTsConfig
‪addDataRemovesItemsByZeroValueRemoveItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:1749
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueTrimsEmptyValueForMultiValueSelect
‪processSelectFieldValueTrimsEmptyValueForMultiValueSelect()
Definition: TcaSelectItemsTest.php:3098
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:125
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:128
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:26
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataTranslatesItemLabelsFromPageTsConfig
‪addDataTranslatesItemLabelsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:2750
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig
‪addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:1613
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByKeepItemsPageTsConfig
‪addDataRemovesItemsByKeepItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:1503
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueReturnsUniqueValuesForMultipleSelect
‪processSelectFieldValueReturnsUniqueValuesForMultipleSelect()
Definition: TcaSelectItemsTest.php:3261
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueSetsMmForeignRelationValues
‪processSelectFieldValueSetsMmForeignRelationValues()
Definition: TcaSelectItemsTest.php:2861
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\mockForeignTableItemsQuery
‪array mockForeignTableItemsQuery()
Definition: TcaSelectItemsTest.php:1202
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableResolvesIconFromSelicon
‪addDataForeignTableResolvesIconFromSelicon()
Definition: TcaSelectItemsTest.php:1418
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByRemoveItemsPageTsConfig
‪addDataRemovesItemsByRemoveItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:1690
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsFileItemsWithOverwrittenFileFolder
‪addDataAddsFileItemsWithOverwrittenFileFolder()
Definition: TcaSelectItemsTest.php:449
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncEnqueuesFlashMessageOnException
‪addDataItemsProcFuncEnqueuesFlashMessageOnException()
Definition: TcaSelectItemsTest.php:2685
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest
Definition: TcaSelectItemsTest.php:51
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:29
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig
‪addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:1807
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueKeepsValuesFromStaticItems
‪processSelectFieldValueKeepsValuesFromStaticItems()
Definition: TcaSelectItemsTest.php:3032
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionIfForeignTableIsNotDefinedInTca
‪addDataThrowsExceptionIfForeignTableIsNotDefinedInTca()
Definition: TcaSelectItemsTest.php:1036
‪TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer
Definition: DefaultRestrictionContainer.php:24
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\tearDown
‪tearDown()
Definition: TcaSelectItemsTest.php:77
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:218
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider
Definition: DatabaseDefaultLanguagePageRowTest.php:18
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncWillUseItemsFromForeignTableAndAddItemsByPageTsConfig
‪addDataItemsProcFuncWillUseItemsFromForeignTableAndAddItemsByPageTsConfig()
Definition: TcaSelectItemsTest.php:2473
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepsIconFromItem
‪addDataKeepsIconFromItem()
Definition: TcaSelectItemsTest.php:354