‪TYPO3CMS  9.5
TcaSelectItemsTest.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Doctrine\DBAL\DBALException;
18 use Doctrine\DBAL\Driver\Statement;
19 use Prophecy\Argument;
20 use Prophecy\Prophecy\ObjectProphecy;
43 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
44 
48 class ‪TcaSelectItemsTest extends UnitTestCase
49 {
53  protected function ‪setUp()
54  {
55  // Default LANG prophecy just returns incoming value as label if calling ->sL()
56  $languageServiceProphecy = $this->prophesize(LanguageService::class);
57  $languageServiceProphecy->loadSingleTableDescription(Argument::cetera())->willReturn(null);
58  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
59  ‪$GLOBALS['LANG'] = $languageServiceProphecy->reveal();
60 
61  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
62  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
63 
64  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
65  $cacheProphecy = $this->prophesize(FrontendInterface::class);
66  $cacheManagerProphecy->getCache('cache_runtime')->willReturn($cacheProphecy->reveal());
67  $cacheManagerProphecy->getCache('assets')->willReturn($cacheProphecy->reveal());
68  $cacheProphecy->get(Argument::cetera())->willReturn(false);
69  $cacheProphecy->set(Argument::cetera())->willReturn(false);
70  GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
71  }
72 
76  protected function ‪tearDown()
77  {
78  GeneralUtility::purgeInstances();
79  parent::tearDown();
80  }
81 
89  protected function ‪mockDatabaseConnection($tableName = 'fTable')
90  {
91  $connectionProphet = $this->prophesize(Connection::class);
92  $connectionProphet->quote(Argument::cetera())->will(function ($arguments) {
93  return "'" . $arguments[0] . "'";
94  });
95  $connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
96  return '`' . $arguments[0] . '`';
97  });
98 
99  $restrictionProphet = $this->prophesize(DefaultRestrictionContainer::class);
100  $restrictionProphet->removeAll()->willReturn($restrictionProphet->reveal());
101  $restrictionProphet->add(Argument::cetera())->willReturn($restrictionProphet->reveal());
102 
103  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
104  $queryBuilderProphet->expr()->willReturn(
105  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
106  );
107  $queryBuilderProphet->getRestrictions()->willReturn($restrictionProphet->reveal());
108  $queryBuilderProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
109  return '`' . $arguments[0] . '`';
110  });
111 
112  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
113  $connectionPoolProphet->getConnectionForTable($tableName)
114  ->willReturn($connectionProphet->reveal());
115  $connectionPoolProphet->getQueryBuilderForTable($tableName)
116  ->shouldBeCalled()
117  ->willReturn($queryBuilderProphet->reveal());
118 
119  return [$queryBuilderProphet, $connectionPoolProphet, $connectionProphet, $restrictionProphet];
120  }
121 
127  {
128  list($queryBuilderProphet, $connectionPoolProphet) = $this->‪mockDatabaseConnection('foreignTable');
129 
131  $statementProphet = $this->prophesize(Statement::class);
132  $statementProphet->fetch()->shouldBeCalled();
133 
134  $queryBuilderProphet->select('foreignTable.uid')
135  ->shouldBeCalled()
136  ->willReturn($queryBuilderProphet->reveal());
137  $queryBuilderProphet->from('foreignTable')
138  ->shouldBeCalled()
139  ->willReturn($queryBuilderProphet->reveal());
140  $queryBuilderProphet->from('pages')
141  ->shouldBeCalled()
142  ->willReturn($queryBuilderProphet->reveal());
143  $queryBuilderProphet->where('')
144  ->shouldBeCalled()
145  ->willReturn($queryBuilderProphet->reveal());
146  $queryBuilderProphet->andWhere(' 1=1')
147  ->shouldBeCalled()
148  ->willReturn($queryBuilderProphet->reveal());
149  $queryBuilderProphet->andWhere('`pages.uid` = `foreignTable.pid`')
150  ->shouldBeCalled()
151  ->willReturn($queryBuilderProphet->reveal());
152  $queryBuilderProphet->execute()
153  ->shouldBeCalled()
154  ->willReturn($statementProphet->reveal());
155 
156  // Two instances are needed due to the push/pop behavior of addInstance()
157  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
158  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
159  }
160 
164  public function ‪addDataKeepExistingItems()
165  {
166  $input = [
167  'tableName' => 'aTable',
168  'processedTca' => [
169  'columns' => [
170  'aField' => [
171  'config' => [
172  'type' => 'radio',
173  'items' => [
174  0 => [
175  'foo',
176  'bar',
177  ],
178  ],
179  ],
180  ],
181  'anotherField' => [
182  'config' => [
183  'type' => 'group',
184  'items' => [
185  0 => [
186  'foo',
187  'bar',
188  ],
189  ],
190  ],
191  ],
192  ],
193  ],
194  ];
195 
196  $expected = $input;
197  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
198  }
199 
204  {
205  $input = [
206  'tableName' => 'aTable',
207  'processedTca' => [
208  'columns' => [
209  'aField' => [
210  'config' => [
211  'type' => 'select',
212  'renderType' => 'selectSingle',
213  'items' => [
214  0 => 'foo',
215  ],
216  ],
217  ],
218  ],
219  ],
220  ];
221 
222  $this->expectException(\UnexpectedValueException::class);
223  $this->expectExceptionCode(1439288036);
224 
225  (new ‪TcaSelectItems)->addData($input);
226  }
227 
232  {
233  $input = [
234  'tableName' => 'aTable',
235  'databaseRow' => [
236  'aField' => 'aValue',
237  ],
238  'processedTca' => [
239  'columns' => [
240  'aField' => [
241  'config' => [
242  'type' => 'select',
243  'renderType' => 'selectSingle',
244  'items' => [
245  0 => [
246  0 => 'aLabel',
247  1 => 'aValue',
248  ],
249  ],
250  'maxitems' => 99999,
251  ],
252  ],
253  ],
254  ],
255  ];
256 
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 
269  $expected['databaseRow']['aField'] = ['aValue'];
270 
271  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
272  }
273 
277  public function ‪addDataKeepsIconFromItem()
278  {
279  $input = [
280  'tableName' => 'aTable',
281  'databaseRow' => [
282  'aField' => 'aValue',
283  ],
284  'processedTca' => [
285  'columns' => [
286  'aField' => [
287  'config' => [
288  'type' => 'select',
289  'renderType' => 'selectSingle',
290  'items' => [
291  0 => [
292  0 => 'aLabel',
293  1 => 'aValue',
294  2 => 'an-icon-reference',
295  3 => null,
296  ],
297  ],
298  'maxitems' => 99999,
299  ],
300  ],
301  ],
302  ],
303  ];
304 
305  $expected = $input;
306  $expected['databaseRow']['aField'] = ['aValue'];
307 
308  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
309  }
310 
315  {
316  $input = [
317  'tableName' => 'aTable',
318  'processedTca' => [
319  'columns' => [
320  'aField' => [
321  'config' => [
322  'type' => 'select',
323  'renderType' => 'selectSingle',
324  'special' => 'anUnknownValue',
325  ],
326  ],
327  ],
328  ],
329  ];
330 
331  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
332  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
333 
334  $this->expectException(\UnexpectedValueException::class);
335  $this->expectExceptionCode(1439298496);
336 
337  (new ‪TcaSelectItems)->addData($input);
338  }
339 
344  {
345  $input = [
346  'databaseRow' => [
347  'aField' => '',
348  ],
349  'tableName' => 'aTable',
350  'processedTca' => [
351  'columns' => [
352  'aField' => [
353  'config' => [
354  'type' => 'select',
355  'renderType' => 'selectSingle',
356  'special' => 'tables',
357  'maxitems' => 99999,
358  ],
359  ],
360  ],
361  ],
362  ];
363  ‪$GLOBALS['TCA'] = [
364  'notInResult' => [
365  'ctrl' => [
366  'adminOnly' => true,
367  ],
368  ],
369  'aTable' => [
370  'ctrl' => [
371  'title' => 'aTitle',
372  ],
373  ],
374  ];
375  ‪$GLOBALS['TCA_DESCR']['aTable']['columns']['']['description'] = 'aDescription';
376 
377  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
378  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
379 
381  $languageService = $this->prophesize(LanguageService::class);
382  ‪$GLOBALS['LANG'] = $languageService->reveal();
383  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
384  $languageService->sL(Argument::containingString('INVALID VALUE'))->willReturnArgument(0);
385 
386  $languageService->sL('aTitle')->shouldBeCalled()->willReturnArgument(0);
387  $languageService->loadSingleTableDescription('aTable')->shouldBeCalled();
388 
389  $expected = $input;
390  $expected['databaseRow']['aField'] = [];
391  $expected['processedTca']['columns']['aField']['config']['items'] = [
392  0 => [
393  0 => 'aTitle',
394  1 => 'aTable',
395  2 => null,
396  3 => [
397  'description' => 'aDescription',
398  ],
399  ]
400  ];
401 
402  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
403  }
404 
409  {
410  $input = [
411  'databaseRow' => [
412  'aField' => 'aValue',
413  ],
414  'tableName' => 'aTable',
415  'processedTca' => [
416  'columns' => [
417  'aField' => [
418  'config' => [
419  'type' => 'select',
420  'renderType' => 'selectSingle',
421  'special' => 'pagetypes',
422  'items' => [],
423  'maxitems' => 99999,
424  ],
425  ],
426  ],
427  ],
428  ];
429  ‪$GLOBALS['TCA'] = [
430  'pages' => [
431  'columns' => [
432  'doktype' => [
433  'config' => [
434  'items' => [
435  0 => [
436  0 => 'aLabel',
437  1 => 'aValue',
438  ],
439  ],
440  ],
441  ],
442  ],
443  ],
444  ];
445 
446  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
447  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
448 
450  $languageService = $this->prophesize(LanguageService::class);
451  ‪$GLOBALS['LANG'] = $languageService->reveal();
452  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
453 
454  $languageService->sL('aLabel')->shouldBeCalled()->willReturnArgument(0);
455 
456  $expected = $input;
457  $expected['databaseRow']['aField'] = ['aValue'];
458  $expected['processedTca']['columns']['aField']['config']['items'] = [
459  0 => [
460  0 => 'aLabel',
461  1 => 'aValue',
462  2 => null,
463  3 => null,
464  ]
465  ];
466 
467  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
468  }
469 
474  {
475  return [
476  'Table with exclude and non exclude field returns exclude item' => [
477  [
478  // input tca
479  'fooTable' => [
480  'ctrl' => [
481  'title' => 'fooTableTitle',
482  ],
483  'columns' => [
484  'bar' => [
485  'label' => 'barColumnTitle',
486  'exclude' => 1
487  ],
488  'baz' => [
489  'label' => 'bazColumnTitle',
490  ],
491  ],
492  ],
493  ],
494  [
495  // expected items
496  0 => [
497  0 => 'fooTableTitle',
498  1 => '--div--',
499  2 => null,
500  3 => null,
501  ],
502  1 => [
503  0 => 'barColumnTitle (bar)',
504  1 => 'fooTable:bar',
505  2 => 'empty-empty',
506  3 => null,
507  ],
508  ],
509  ],
510  'Root level table with ignored root level restriction returns exclude item' => [
511  [
512  // input tca
513  'fooTable' => [
514  'ctrl' => [
515  'title' => 'fooTableTitle',
516  'rootLevel' => 1,
517  'security' => [
518  'ignoreRootLevelRestriction' => true,
519  ],
520  ],
521  'columns' => [
522  'bar' => [
523  'label' => 'barColumnTitle',
524  'exclude' => true,
525  ],
526  ],
527  ],
528  ],
529  [
530  // expected items
531  0 => [
532  0 => 'fooTableTitle',
533  1 => '--div--',
534  2 => null,
535  3 => null,
536  ],
537  1 => [
538  0 => 'barColumnTitle (bar)',
539  1 => 'fooTable:bar',
540  2 => 'empty-empty',
541  3 => null,
542  ],
543  ],
544  ],
545  'Root level table without ignored root level restriction returns no item' => [
546  [
547  // input tca
548  'fooTable' => [
549  'ctrl' => [
550  'title' => 'fooTableTitle',
551  'rootLevel' => 1,
552  ],
553  'columns' => [
554  'bar' => [
555  'label' => 'barColumnTitle',
556  'exclude' => true,
557  ],
558  ],
559  ],
560  ],
561  [
562  // no items
563  ],
564  ],
565  'Admin table returns no item' => [
566  [
567  // input tca
568  'fooTable' => [
569  'ctrl' => [
570  'title' => 'fooTableTitle',
571  'adminOnly' => true,
572  ],
573  'columns' => [
574  'bar' => [
575  'label' => 'barColumnTitle',
576  'exclude' => true,
577  ],
578  ],
579  ],
580  ],
581  [
582  // no items
583  ],
584  ],
585  ];
586  }
587 
593  {
594  $input = [
595  'tableName' => 'aTable',
596  'databaseRow' => [],
597  'processedTca' => [
598  'columns' => [
599  'aField' => [
600  'config' => [
601  'type' => 'select',
602  'renderType' => 'selectSingle',
603  'special' => 'exclude',
604  ],
605  ],
606  ],
607  ],
608  ];
609  ‪$GLOBALS['TCA'] = ‪$tca;
610 
611  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
612  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
613 
614  $result = (new ‪TcaSelectItems)->addData($input);
615 
616  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
617  }
618 
623  {
624  $input = [
625  'tableName' => 'aTable',
626  'databaseRow' => [],
627  'processedTca' => [
628  'columns' => [
629  'aField' => [
630  'config' => [
631  'type' => 'select',
632  'renderType' => 'selectSingle',
633  'special' => 'exclude',
634  ],
635  ],
636  ],
637  ],
638  ];
639 
640  ‪$GLOBALS['TCA'] = [
641  'fooTable' => [
642  'ctrl' => [
643  'title' => 'fooTableTitle',
644  ],
645  'columns' => [
646  'aFlexField' => [
647  'label' => 'aFlexFieldTitle',
648  'config' => [
649  'type' => 'flex',
650  'title' => 'title',
651  'ds' => [
652  'dummy' => '
653  <T3DataStructure>
654  <ROOT>
655  <type>array</type>
656  <el>
657  <input1>
658  <TCEforms>
659  <label>flexInputLabel</label>
660  <exclude>1</exclude>
661  <config>
662  <type>input</type>
663  <size>23</size>
664  </config>
665  </TCEforms>
666  </input1>
667  </el>
668  </ROOT>
669  </T3DataStructure>
670  ',
671  ],
672  ],
673  ],
674  ],
675  ],
676  ];
677 
678  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
679  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
680 
681  $expectedItems = [
682  0 => [
683  0 => 'fooTableTitle aFlexFieldTitle dummy',
684  1 => '--div--',
685  2 => null,
686  3 => null,
687  ],
688  1 => [
689  0 => 'flexInputLabel (input1)',
690  1 => 'fooTable:aFlexField;dummy;sDEF;input1',
691  2 => 'empty-empty',
692  3 => null,
693  ],
694  ];
695 
696  $result = (new ‪TcaSelectItems)->addData($input);
697 
698  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
699  }
700 
705  {
706  $input = [
707  'tableName' => 'aTable',
708  'databaseRow' => [],
709  'processedTca' => [
710  'columns' => [
711  'aField' => [
712  'config' => [
713  'type' => 'select',
714  'renderType' => 'selectSingle',
715  'special' => 'explicitValues',
716  ],
717  ],
718  ],
719  ],
720  ];
721 
722  ‪$GLOBALS['TCA'] = [
723  'fooTable' => [
724  'ctrl' => [
725  'title' => 'fooTableTitle',
726  ],
727  'columns' => [
728  'aField' => [
729  'label' => 'aFieldTitle',
730  'config' => [
731  'type' => 'select',
732  'renderType' => 'selectSingle',
733  'authMode' => 'explicitAllow',
734  'items' => [
735  0 => [
736  'anItemTitle',
737  'anItemValue',
738  ],
739  ]
740  ],
741  ],
742  ],
743  ],
744  ];
745 
746  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
747  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
748 
750  $languageService = $this->prophesize(LanguageService::class);
751  ‪$GLOBALS['LANG'] = $languageService->reveal();
752  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
753  $languageService->sL(Argument::cetera())->willReturnArgument(0);
754 
755  $expectedItems = [
756  0 => [
757  0 => 'fooTableTitle: aFieldTitle',
758  1 => '--div--',
759  2 => null,
760  3 => null,
761  ],
762  1 => [
763  0 => '[allowMe] anItemTitle',
764  1 => 'fooTable:aField:anItemValue:ALLOW',
765  2 => 'status-status-permission-granted',
766  3 => null,
767  ],
768  ];
769 
770  $result = (new ‪TcaSelectItems)->addData($input);
771 
772  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
773  }
774 
779  {
780  $input = [
781  'tableName' => 'aTable',
782  'databaseRow' => [],
783  'processedTca' => [
784  'columns' => [
785  'aField' => [
786  'config' => [
787  'type' => 'select',
788  'renderType' => 'selectSingle',
789  'special' => 'explicitValues',
790  ],
791  ],
792  ],
793  ],
794  ];
795 
796  ‪$GLOBALS['TCA'] = [
797  'fooTable' => [
798  'ctrl' => [
799  'title' => 'fooTableTitle',
800  ],
801  'columns' => [
802  'aField' => [
803  'label' => 'aFieldTitle',
804  'config' => [
805  'type' => 'select',
806  'renderType' => 'selectSingle',
807  'authMode' => 'explicitDeny',
808  'items' => [
809  0 => [
810  'anItemTitle',
811  'anItemValue',
812  ],
813  ]
814  ],
815  ],
816  ],
817  ],
818  ];
819 
820  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
821  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
822 
824  $languageService = $this->prophesize(LanguageService::class);
825  ‪$GLOBALS['LANG'] = $languageService->reveal();
826  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
827  $languageService->sL(Argument::cetera())->willReturnArgument(0);
828 
829  $expectedItems = [
830  0 => [
831  0 => 'fooTableTitle: aFieldTitle',
832  1 => '--div--',
833  2 => null,
834  3 => null,
835  ],
836  1 => [
837  0 => '[denyMe] anItemTitle',
838  1 => 'fooTable:aField:anItemValue:DENY',
839  2 => 'status-status-permission-denied',
840  3 => null,
841  ],
842  ];
843 
844  $result = (new ‪TcaSelectItems)->addData($input);
845 
846  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
847  }
848 
853  {
854  $input = [
855  'tableName' => 'aTable',
856  'databaseRow' => [],
857  'processedTca' => [
858  'columns' => [
859  'aField' => [
860  'config' => [
861  'type' => 'select',
862  'renderType' => 'selectSingle',
863  'special' => 'explicitValues',
864  ],
865  ],
866  ],
867  ],
868  ];
869 
870  ‪$GLOBALS['TCA'] = [
871  'fooTable' => [
872  'ctrl' => [
873  'title' => 'fooTableTitle',
874  ],
875  'columns' => [
876  'aField' => [
877  'label' => 'aFieldTitle',
878  'config' => [
879  'type' => 'select',
880  'renderType' => 'selectSingle',
881  'authMode' => 'individual',
882  'items' => [
883  0 => [
884  'aItemTitle',
885  'aItemValue',
886  null,
887  null,
888  'EXPL_ALLOW',
889  ],
890  // 1 is not selectable as allow and is always allowed
891  1 => [
892  'bItemTitle',
893  'bItemValue',
894  ],
895  2 => [
896  'cItemTitle',
897  'cItemValue',
898  null,
899  null,
900  'EXPL_ALLOW',
901  ],
902  ]
903  ],
904  ],
905  ],
906  ],
907  ];
908 
909  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
910  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
911 
913  $languageService = $this->prophesize(LanguageService::class);
914  ‪$GLOBALS['LANG'] = $languageService->reveal();
915  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
916  $languageService->sL(Argument::cetera())->willReturnArgument(0);
917 
918  $expectedItems = [
919  0 => [
920  0 => 'fooTableTitle: aFieldTitle',
921  1 => '--div--',
922  2 => null,
923  3 => null,
924  ],
925  1 => [
926  0 => '[allowMe] aItemTitle',
927  1 => 'fooTable:aField:aItemValue:ALLOW',
928  2 => 'status-status-permission-granted',
929  3 => null,
930  ],
931  2 => [
932  0 => '[allowMe] cItemTitle',
933  1 => 'fooTable:aField:cItemValue:ALLOW',
934  2 => 'status-status-permission-granted',
935  3 => null,
936  ],
937  ];
938 
939  $result = (new ‪TcaSelectItems)->addData($input);
940 
941  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
942  }
943 
948  {
949  $input = [
950  'tableName' => 'aTable',
951  'databaseRow' => [],
952  'processedTca' => [
953  'columns' => [
954  'aField' => [
955  'config' => [
956  'type' => 'select',
957  'renderType' => 'selectSingle',
958  'special' => 'explicitValues',
959  ],
960  ],
961  ],
962  ],
963  ];
964 
965  ‪$GLOBALS['TCA'] = [
966  'fooTable' => [
967  'ctrl' => [
968  'title' => 'fooTableTitle',
969  ],
970  'columns' => [
971  'aField' => [
972  'label' => 'aFieldTitle',
973  'config' => [
974  'type' => 'select',
975  'renderType' => 'selectSingle',
976  'authMode' => 'individual',
977  'items' => [
978  0 => [
979  'aItemTitle',
980  'aItemValue',
981  null,
982  null,
983  'EXPL_DENY',
984  ],
985  // 1 is not selectable as allow and is always allowed
986  1 => [
987  'bItemTitle',
988  'bItemValue',
989  ],
990  2 => [
991  'cItemTitle',
992  'cItemValue',
993  null,
994  null,
995  'EXPL_DENY',
996  ],
997  ]
998  ],
999  ],
1000  ],
1001  ],
1002  ];
1003 
1004  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
1005  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
1006 
1008  $languageService = $this->prophesize(LanguageService::class);
1009  ‪$GLOBALS['LANG'] = $languageService->reveal();
1010  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
1011  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1012 
1013  $expectedItems = [
1014  0 => [
1015  0 => 'fooTableTitle: aFieldTitle',
1016  1 => '--div--',
1017  2 => null,
1018  3 => null,
1019  ],
1020  1 => [
1021  0 => '[denyMe] aItemTitle',
1022  1 => 'fooTable:aField:aItemValue:DENY',
1023  2 => 'status-status-permission-denied',
1024  3 => null,
1025  ],
1026  2 => [
1027  0 => '[denyMe] cItemTitle',
1028  1 => 'fooTable:aField:cItemValue:DENY',
1029  2 => 'status-status-permission-denied',
1030  3 => null,
1031  ],
1032  ];
1033 
1034  $result = (new ‪TcaSelectItems)->addData($input);
1035 
1036  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1037  }
1038 
1043  {
1044  $input = [
1045  'tableName' => 'aTable',
1046  'databaseRow' => [],
1047  'processedTca' => [
1048  'columns' => [
1049  'aField' => [
1050  'config' => [
1051  'type' => 'select',
1052  'renderType' => 'selectSingle',
1053  'special' => 'languages',
1054  ],
1055  ],
1056  ],
1057  ],
1058  'systemLanguageRows' => [
1059  0 => [
1060  'title' => 'aLangTitle',
1061  'uid' => 42,
1062  'flagIconIdentifier' => 'aFlag.gif',
1063  ],
1064  ],
1065  ];
1066 
1067  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
1068  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
1069 
1070  $expectedItems = [
1071  0 => [
1072  0 => 'aLangTitle',
1073  1 => 42,
1074  2 => 'aFlag.gif',
1075  3 => null,
1076  ],
1077  ];
1078 
1079  $result = (new ‪TcaSelectItems)->addData($input);
1080 
1081  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1082  }
1083 
1088  {
1089  $input = [
1090  'tableName' => 'aTable',
1091  'databaseRow' => [],
1092  'processedTca' => [
1093  'columns' => [
1094  'aField' => [
1095  'config' => [
1096  'type' => 'select',
1097  'renderType' => 'selectSingle',
1098  'special' => 'custom',
1099  ],
1100  ],
1101  ],
1102  ],
1103  ];
1104 
1105  ‪$GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'] = [
1106  'aKey' => [
1107  'header' => 'aHeader',
1108  'items' => [
1109  'anItemKey' => [
1110  0 => 'anItemTitle',
1111  ],
1112  'anotherKey' => [
1113  0 => 'anotherTitle',
1114  1 => 'status-status-permission-denied',
1115  2 => 'aDescription',
1116  ],
1117  ],
1118  ]
1119  ];
1120 
1121  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
1122  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
1123 
1124  $expectedItems = [
1125  0 => [
1126  0 => 'aHeader',
1127  1 => '--div--',
1128  null,
1129  null,
1130  ],
1131  1 => [
1132  0 => 'anItemTitle',
1133  1 => 'aKey:anItemKey',
1134  2 => 'empty-empty',
1135  3 => null,
1136  ],
1137  2 => [
1138  0 => 'anotherTitle',
1139  1 => 'aKey:anotherKey',
1140  2 => 'empty-empty',
1141  3 => [ 'description' => 'aDescription' ],
1142  ],
1143  ];
1144 
1145  $result = (new ‪TcaSelectItems)->addData($input);
1146 
1147  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1148  }
1149 
1154  {
1155  $input = [
1156  'tableName' => 'aTable',
1157  'databaseRow' => [],
1158  'processedTca' => [
1159  'columns' => [
1160  'aField' => [
1161  'config' => [
1162  'type' => 'select',
1163  'renderType' => 'selectSingle',
1164  'special' => 'modListGroup',
1165  ],
1166  ],
1167  ],
1168  ],
1169  ];
1170 
1171  ‪$GLOBALS['TBE_MODULES'] = [];
1172 
1173  $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
1174  GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
1175 
1177  $moduleLoaderProphecy = $this->prophesize(ModuleLoader::class);
1178  GeneralUtility::addInstance(ModuleLoader::class, $moduleLoaderProphecy->reveal());
1179  $moduleLoaderProphecy->load([])->shouldBeCalled();
1180  $moduleLoaderProphecy->modListGroup = [
1181  'aModule',
1182  ];
1183  $moduleLoaderProphecy->modules = [
1184  'aModule' => [
1185  'iconIdentifier' => 'empty-empty'
1186  ]
1187  ];
1188  $moduleLoaderProphecy->getLabelsForModule('aModule')->shouldBeCalled()->willReturn([
1189  'shortdescription' => 'aModuleTabLabel',
1190  'description' => 'aModuleTabDescription',
1191  'title' => 'aModuleLabel'
1192  ]);
1193 
1194  $expectedItems = [
1195  0 => [
1196  0 => 'aModuleLabel',
1197  1 => 'aModule',
1198  2 => 'empty-empty',
1199  3 => [
1200  'title' => 'aModuleTabLabel',
1201  'description' => 'aModuleTabDescription',
1202  ],
1203  ],
1204  ];
1205 
1206  $result = (new ‪TcaSelectItems)->addData($input);
1207 
1208  $result['processedTca']['columns']['aField']['config']['items'][0][2] = str_replace([CR, LF, "\t"], '', $result['processedTca']['columns']['aField']['config']['items'][0][2]);
1209  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1210  }
1211 
1216  {
1217  $directory = $this->getUniqueId('typo3temp/var/tests/test-') . '/';
1218  $input = [
1219  'tableName' => 'aTable',
1220  'databaseRow' => [],
1221  'processedTca' => [
1222  'columns' => [
1223  'aField' => [
1224  'config' => [
1225  'type' => 'select',
1226  'renderType' => 'selectSingle',
1227  'fileFolder' => $directory,
1228  'fileFolder_extList' => 'gif',
1229  'fileFolder_recursions' => 1,
1230  ],
1231  ],
1232  ],
1233  ],
1234  ];
1235 
1236  mkdir(‪Environment::getPublicPath() . '/' . $directory);
1237  $this->testFilesToDelete[] = ‪Environment::getPublicPath() . '/' . $directory;
1238  touch(‪Environment::getPublicPath() . '/' . $directory . 'anImage.gif');
1239  touch(‪Environment::getPublicPath() . '/' . $directory . 'aFile.txt');
1240  mkdir(‪Environment::getPublicPath() . '/' . $directory . '/subdir');
1241  touch(‪Environment::getPublicPath() . '/' . $directory . '/subdir/anotherImage.gif');
1242 
1243  $expectedItems = [
1244  0 => [
1245  0 => 'anImage.gif',
1246  1 => 'anImage.gif',
1247  2 => ‪Environment::getPublicPath() . '/' . $directory . 'anImage.gif',
1248  3 => null,
1249  ],
1250  1 => [
1251  0 => 'subdir/anotherImage.gif',
1252  1 => 'subdir/anotherImage.gif',
1253  2 => ‪Environment::getPublicPath() . '/' . $directory . 'subdir/anotherImage.gif',
1254  3 => null,
1255  ],
1256  ];
1257 
1258  $result = (new ‪TcaSelectItems)->addData($input);
1259 
1260  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1261  }
1262 
1267  {
1268  $input = [
1269  'tableName' => 'aTable',
1270  'databaseRow' => [],
1271  'processedTca' => [
1272  'columns' => [
1273  'aField' => [
1274  'config' => [
1275  'type' => 'select',
1276  'renderType' => 'selectSingle',
1277  'fileFolder' => 'EXT:non_existing/Resources/Public/',
1278  ],
1279  ],
1280  ],
1281  ],
1282  ];
1283 
1284  $this->expectException(\RuntimeException::class);
1285  $this->expectExceptionCode(1479399227);
1286  (new ‪TcaSelectItems)->addData($input);
1287  }
1288 
1293  {
1294  $input = [
1295  'databaseRow' => [
1296  'aField' => '',
1297  ],
1298  'tableName' => 'aTable',
1299  'processedTca' => [
1300  'columns' => [
1301  'aField' => [
1302  'config' => [
1303  'type' => 'select',
1304  'renderType' => 'selectSingle',
1305  'items' => [
1306  0 => [
1307  0 => 'keepMe',
1308  1 => 'keep',
1309  null,
1310  null,
1311  ],
1312  ],
1313  'maxitems' => 99999,
1314  ],
1315  ],
1316  ]
1317  ],
1318  'pageTsConfig' => [
1319  'TCEFORM.' => [
1320  'aTable.' => [
1321  'aField.' => [
1322  'addItems.' => [
1323  '1' => 'addMe'
1324  ],
1325  ],
1326  ],
1327  ],
1328  ],
1329  ];
1330 
1331  $expected = $input;
1332  $expected['databaseRow']['aField'] = [];
1333  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1334  0 => 'addMe',
1335  1 => '1',
1336  null,
1337  null,
1338  ];
1339 
1340  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
1341  }
1342 
1347  {
1348  $input = [
1349  'databaseRow' => [
1350  'aField' => '',
1351  ],
1352  'tableName' => 'aTable',
1353  'processedTca' => [
1354  'columns' => [
1355  'aField' => [
1356  'config' => [
1357  'type' => 'select',
1358  'renderType' => 'selectSingle',
1359  'items' => [
1360  0 => [
1361  0 => 'keepMe',
1362  1 => 'keep',
1363  null,
1364  null,
1365  ],
1366  ],
1367  'maxitems' => 99999,
1368  ],
1369  ],
1370  ]
1371  ],
1372  'pageTsConfig' => [
1373  'TCEFORM.' => [
1374  'aTable.' => [
1375  'aField.' => [
1376  'addItems.' => [
1377  'keep' => 'addMe'
1378  ],
1379  ],
1380  ],
1381  ],
1382  ],
1383  ];
1384 
1385  $expected = $input;
1386  $expected['databaseRow']['aField'] = [];
1387  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1388  0 => 'addMe',
1389  1 => 'keep',
1390  null,
1391  null,
1392  ];
1393 
1394  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
1395  }
1396 
1401  {
1402  return [
1403  'replace REC_FIELD' => [
1404  'AND fTable.title=\'###REC_FIELD_rowField###\'',
1405  [
1406  ['fTable.title=\'rowFieldValue\''],
1407  [' 1=1'],
1408  ['`pages.uid` = `fTable.pid`']
1409  ],
1410  [],
1411  ],
1412  'replace REC_FIELD within FlexForm' => [
1413  'AND fTable.title=###REC_FIELD_rowFieldFlexForm###',
1414  [
1415  ['fTable.title=\'rowFieldFlexFormValue\''],
1416  [' 1=1'],
1417  ['`pages.uid` = `fTable.pid`']
1418  ],
1419  [
1420  'databaseRow' => [
1421  'rowFieldThree' => [
1422  0 => 'rowFieldThreeValue'
1423  ]
1424  ],
1425  'flexParentDatabaseRow' => [
1426  'rowFieldFlexForm' => [
1427  0 => 'rowFieldFlexFormValue'
1428  ]
1429  ],
1430  ],
1431  ],
1432  'replace REC_FIELD fullQuote' => [
1433  'AND fTable.title=###REC_FIELD_rowField###',
1434  [
1435  ['fTable.title=\'rowFieldValue\''],
1436  [' 1=1'],
1437  ['`pages.uid` = `fTable.pid`']
1438  ],
1439  [],
1440  ],
1441  'replace REC_FIELD fullQuoteWithArray' => [
1442  'AND fTable.title=###REC_FIELD_rowFieldThree###',
1443  [
1444  ['fTable.title=\'rowFieldThreeValue\''],
1445  [' 1=1'],
1446  ['`pages.uid` = `fTable.pid`']
1447  ],
1448  [
1449  'databaseRow' => [
1450  'rowFieldThree' => [
1451  0 => 'rowFieldThreeValue'
1452  ]
1453  ],
1454  ],
1455  ],
1456  'replace REC_FIELD multiple markers' => [
1457  'AND fTable.title=\'###REC_FIELD_rowField###\' AND fTable.pid=###REC_FIELD_rowFieldTwo###',
1458  [
1459  ['fTable.title=\'rowFieldValue\' AND fTable.pid=\'rowFieldTwoValue\''],
1460  [' 1=1'],
1461  ['`pages.uid` = `fTable.pid`']
1462  ],
1463  [],
1464  ],
1465  'replace CURRENT_PID' => [
1466  'AND fTable.uid=###CURRENT_PID###',
1467  [
1468  ['fTable.uid=43'],
1469  [' 1=1'],
1470  ['`pages.uid` = `fTable.pid`']
1471  ],
1472  [],
1473  ],
1474  'replace CURRENT_PID within FlexForm' => [
1475  'AND fTable.uid=###CURRENT_PID###',
1476  [
1477  ['fTable.uid=77'],
1478  [' 1=1'],
1479  ['`pages.uid` = `fTable.pid`']
1480  ],
1481  [
1482  'flexParentDatabaseRow' => [
1483  'pid' => '77',
1484  ],
1485  ],
1486  ],
1487  'replace CURRENT_PID integer cast' => [
1488  'AND fTable.uid=###CURRENT_PID###',
1489  [
1490  ['fTable.uid=431'],
1491  [' 1=1'],
1492  ['`pages.uid` = `fTable.pid`']
1493  ],
1494  [
1495  'effectivePid' => '431string',
1496  ],
1497  ],
1498  'replace THIS_UID' => [
1499  'AND fTable.uid=###THIS_UID###',
1500  [
1501  ['fTable.uid=42'],
1502  [' 1=1'],
1503  ['`pages.uid` = `fTable.pid`']
1504  ],
1505  [],
1506  ],
1507  'replace THIS_UID integer cast' => [
1508  'AND fTable.uid=###THIS_UID###',
1509  [
1510  ['fTable.uid=421'],
1511  [' 1=1'],
1512  ['`pages.uid` = `fTable.pid`']
1513  ],
1514  [
1515  'databaseRow' => [
1516  'uid' => '421string',
1517  ],
1518  ],
1519  ],
1520  'replace SITEROOT' => [
1521  'AND fTable.uid=###SITEROOT###',
1522  [
1523  ['fTable.uid=44'],
1524  [' 1=1'],
1525  ['`pages.uid` = `fTable.pid`']
1526  ],
1527  [],
1528  ],
1529  'replace SITEROOT integer cast' => [
1530  'AND fTable.uid=###SITEROOT###',
1531  [
1532  ['fTable.uid=441'],
1533  [' 1=1'],
1534  ['`pages.uid` = `fTable.pid`']
1535  ],
1536  [
1537  'rootline' => [
1538  1 => [
1539  'uid' => '441string',
1540  ],
1541  ],
1542  ],
1543  ],
1544  'replace PAGE_TSCONFIG_ID' => [
1545  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1546  [
1547  ['fTable.uid=45'],
1548  [' 1=1'],
1549  ['`pages.uid` = `fTable.pid`']
1550  ],
1551  [
1552  'pageTsConfig' => [
1553  'TCEFORM.' => [
1554  'aTable.' => [
1555  'aField.' => [
1556  'PAGE_TSCONFIG_ID' => '45',
1557  ],
1558  ],
1559  ],
1560  ],
1561  ],
1562  ],
1563  'replace PAGE_TSCONFIG_ID integer cast' => [
1564  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1565  [
1566  ['fTable.uid=451'],
1567  [' 1=1'],
1568  ['`pages.uid` = `fTable.pid`']
1569  ],
1570  [
1571  'pageTsConfig' => [
1572  'TCEFORM.' => [
1573  'aTable.' => [
1574  'aField.' => [
1575  'PAGE_TSCONFIG_ID' => '451string'
1576  ],
1577  ],
1578  ],
1579  ],
1580  ],
1581  ],
1582  'replace PAGE_TSCONFIG_STR' => [
1583  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1584  [
1585  ['fTable.uid=\'46\''],
1586  [' 1=1'],
1587  ['`pages.uid` = `fTable.pid`']
1588  ],
1589  [
1590  'pageTsConfig' => [
1591  'TCEFORM.' => [
1592  'aTable.' => [
1593  'aField.' => [
1594  'PAGE_TSCONFIG_STR' => '46',
1595  ],
1596  ],
1597  ],
1598  ],
1599  ],
1600  ],
1601  'replace PAGE_TSCONFIG_IDLIST' => [
1602  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1603  [
1604  ['fTable.uid IN (47,48)'],
1605  [' 1=1'],
1606  ['`pages.uid` = `fTable.pid`']
1607  ],
1608  [
1609  'pageTsConfig' => [
1610  'TCEFORM.' => [
1611  'aTable.' => [
1612  'aField.' => [
1613  'PAGE_TSCONFIG_IDLIST' => '47,48',
1614  ],
1615  ],
1616  ],
1617  ],
1618  ],
1619  ],
1620  'replace PAGE_TSCONFIG_IDLIST cleans list' => [
1621  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1622  [
1623  ['fTable.uid IN (471,481)'],
1624  [' 1=1'],
1625  ['`pages.uid` = `fTable.pid`']
1626  ],
1627  [
1628  'pageTsConfig' => [
1629  'TCEFORM.' => [
1630  'aTable.' => [
1631  'aField.' => [
1632  'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
1633  ],
1634  ],
1635  ],
1636  ],
1637  ],
1638  ],
1639  ];
1640  }
1641 
1646  public function ‪addDataReplacesMarkersInForeignTableClause($foreignTableWhere, $expectedWhere, array $inputOverride)
1647  {
1648  $input = [
1649  'tableName' => 'aTable',
1650  'effectivePid' => 43,
1651  'databaseRow' => [
1652  'uid' => 42,
1653  'rowField' => 'rowFieldValue',
1654  'rowFieldTwo' => 'rowFieldTwoValue',
1655  ],
1656  'processedTca' => [
1657  'columns' => [
1658  'aField' => [
1659  'config' => [
1660  'type' => 'select',
1661  'renderType' => 'selectSingle',
1662  'foreign_table' => 'fTable',
1663  'foreign_table_where' => $foreignTableWhere,
1664  ],
1665  ],
1666  ]
1667  ],
1668  'rootline' => [
1669  2 => [
1670  'uid' => 999,
1671  'is_siteroot' => 0,
1672  ],
1673  1 => [
1674  'uid' => 44,
1675  'is_siteroot' => 1,
1676  ],
1677  0 => [
1678  'uid' => 0,
1679  'is_siteroot' => null,
1680  ],
1681  ],
1682  'pageTsConfig' => [],
1683  ];
1684  ‪ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
1685 
1686  ‪$GLOBALS['TCA']['fTable'] = [];
1687 
1688  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
1689  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
1690 
1691  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1692  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1693  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1694 
1695  list($queryBuilderProphet, $connectionPoolProphet) = $this->‪mockDatabaseConnection();
1696 
1698  $statementProphet = $this->prophesize(Statement::class);
1699 
1700  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1701  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1702  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1703  $queryBuilderProphet->where(...array_shift($expectedWhere))->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1704  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
1705 
1706  while ($constraint = array_shift($expectedWhere)) {
1707  $queryBuilderProphet->andWhere(...$constraint)
1708  ->shouldBeCalled()
1709  ->willReturn($queryBuilderProphet->reveal());
1710  }
1711 
1712  // Two instances are needed due to the push/pop behavior of addInstance()
1713  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1714  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1715 
1717  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1718  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1719  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1720 
1721  (new ‪TcaSelectItems)->addData($input);
1722  }
1723 
1728  {
1729  $input = [
1730  'tableName' => 'aTable',
1731  'processedTca' => [
1732  'columns' => [
1733  'aField' => [
1734  'config' => [
1735  'type' => 'select',
1736  'renderType' => 'selectSingle',
1737  'foreign_table' => 'fTable',
1738  ],
1739  ],
1740  ]
1741  ],
1742  ];
1743 
1744  $this->expectException(\UnexpectedValueException::class);
1745  $this->expectExceptionCode(1439569743);
1746 
1747  (new ‪TcaSelectItems)->addData($input);
1748  }
1749 
1754  {
1755  $input = [
1756  'tableName' => 'aTable',
1757  'effectivePid' => 42,
1758  'databaseRow' => [
1759  'uid' => 23,
1760  ],
1761  'processedTca' => [
1762  'columns' => [
1763  'aField' => [
1764  'config' => [
1765  'type' => 'select',
1766  'renderType' => 'selectSingle',
1767  'foreign_table' => 'fTable',
1768  'foreign_table_where' => '
1769  AND ftable.uid=1
1770  GROUP BY groupField1, groupField2
1771  ORDER BY orderField
1772  LIMIT 1,2',
1773  ],
1774  ],
1775  ]
1776  ],
1777  'rootline' => [],
1778  ];
1779 
1780  ‪$GLOBALS['TCA']['fTable'] = [];
1781 
1782  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
1783  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
1784 
1785  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1786  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1787  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1788 
1790  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1791  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1792  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1793 
1794  list($queryBuilderProphet, $connectionPoolProphet) = $this->‪mockDatabaseConnection();
1795 
1797  $statementProphet = $this->prophesize(Statement::class);
1798 
1799  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1800  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1801  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1802  $queryBuilderProphet->groupBy('groupField1', 'groupField2')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1803  $queryBuilderProphet->addOrderBy('orderField', null)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1804  $queryBuilderProphet->setFirstResult(1)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1805  $queryBuilderProphet->setMaxResults(2)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1806  $queryBuilderProphet->where('ftable.uid=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1807  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1808  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1809  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
1810 
1811  // Two instances are needed due to the push/pop behavior of addInstance()
1812  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1813  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1814 
1815  (new ‪TcaSelectItems)->addData($input);
1816  }
1817 
1822  {
1823  $input = [
1824  'databaseRow' => [
1825  'uid' => 23,
1826  'aField' => '',
1827  ],
1828  'tableName' => 'aTable',
1829  'effectivePid' => 42,
1830  'processedTca' => [
1831  'columns' => [
1832  'aField' => [
1833  'config' => [
1834  'type' => 'select',
1835  'renderType' => 'selectSingle',
1836  'foreign_table' => 'fTable',
1837  'items' => [
1838  0 => [
1839  0 => 'itemLabel',
1840  1 => 'itemValue',
1841  2 => null,
1842  3 => null,
1843  ],
1844  ],
1845  'maxitems' => 99999,
1846  ],
1847  ],
1848  ]
1849  ],
1850  'rootline' => [],
1851  ];
1852 
1853  ‪$GLOBALS['TCA']['fTable'] = [];
1854 
1856  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1857  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1858  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1859 
1860  list($queryBuilderProphet, $connectionPoolProphet) = $this->‪mockDatabaseConnection();
1861 
1863  $statementProphet = $this->prophesize(Statement::class);
1864 
1865  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1866  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1867  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1868  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1869  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1870  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1871 
1872  $prevException = new DBALException('Invalid table name', 1476045274);
1873  $exception = new DBALException('Driver error', 1476045971, $prevException);
1874 
1875  $queryBuilderProphet->execute()->shouldBeCalled()->willThrow($exception);
1876 
1877  // Two instances are needed due to the push/pop behavior of addInstance()
1878  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1879  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1880 
1882  $flashMessage = $this->prophesize(FlashMessage::class);
1883  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1885  $flashMessageService = $this->prophesize(FlashMessageService::class);
1886  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1888  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1889  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1890 
1891  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
1892 
1893  $expected = $input;
1894  $expected['databaseRow']['aField'] = [];
1895 
1896  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
1897  }
1898 
1902  private function ‪mockForeignTableItemsQuery(): array
1903  {
1904  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection();
1905 
1907  $statementProphet = $this->prophesize(Statement::class);
1908 
1909  $queryBuilderProphet->select('fTable.uid', 'fTable.labelField')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1910  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1911  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1912  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1913  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1914  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1915  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
1916 
1917  return [$connectionPoolProphet, $statementProphet];
1918  }
1919 
1924  {
1925  $input = [
1926  'databaseRow' => [
1927  'uid' => 5,
1928  'aField' => '',
1929  ],
1930  'tableName' => 'aTable',
1931  'effectivePid' => 42,
1932  'processedTca' => [
1933  'columns' => [
1934  'aField' => [
1935  'config' => [
1936  'type' => 'select',
1937  'renderType' => 'selectSingle',
1938  'foreign_table' => 'fTable',
1939  'foreign_table_prefix' => 'aPrefix',
1940  'items' => [],
1941  'maxitems' => 99999,
1942  ],
1943  ],
1944  ]
1945  ],
1946  'rootline' => [],
1947  ];
1948 
1949  ‪$GLOBALS['TCA']['fTable'] = [
1950  'ctrl' => [
1951  'label' => 'labelField',
1952  ],
1953  'columns' => [],
1954  ];
1955 
1956  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
1957  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
1958 
1959  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
1960  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
1961  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
1962 
1964  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1965  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1966  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1967 
1968  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
1969 
1970  // Two instances are needed due to the push/pop behavior of addInstance()
1971  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1972  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1973 
1974  $counter = 0;
1975  $statementProphet->fetch()->shouldBeCalled()->will(function (‪$args) use (&$counter) {
1976  $counter++;
1977  if ($counter >= 3) {
1978  return false;
1979  }
1980  return [
1981  'uid' => $counter,
1982  'pid' => 23,
1983  'labelField' => 'aLabel',
1984  'aValue' => 'bar,',
1985  ];
1986  });
1987 
1988  $expected = $input;
1989  $expected['processedTca']['columns']['aField']['config']['items'] = [
1990  0 => [
1991  0 => 'aPrefix[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
1992  1 => 1,
1993  2 => null,
1994  3 => null,
1995  ],
1996  1 => [
1997  0 => 'aPrefix[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
1998  1 => 2,
1999  2 => null,
2000  3 => null,
2001  ],
2002  ];
2003 
2004  $expected['databaseRow']['aField'] = [];
2005 
2006  self::assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2007  }
2008 
2013  {
2014  $input = [
2015  'databaseRow' => [
2016  'uid' => 5,
2017  'aField' => '',
2018  ],
2019  'tableName' => 'aTable',
2020  'effectivePid' => 42,
2021  'processedTca' => [
2022  'columns' => [
2023  'aField' => [
2024  'config' => [
2025  'type' => 'select',
2026  'renderType' => 'selectSingle',
2027  'foreign_table' => 'sys_file_storage',
2028  'foreign_table_prefix' => 'prefix for item labels',
2029  'items' => [],
2030  'maxitems' => 99999,
2031  ],
2032  ],
2033  ]
2034  ],
2035  'rootline' => [],
2036  ];
2037 
2038  ‪$GLOBALS['TCA']['sys_file_storage'] = [
2039  'ctrl' => [
2040  'label' => 'labelField',
2041  ],
2042  'columns' => [],
2043  ];
2044 
2045  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2046  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2047  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2048 
2049  $resourceStorageProphecy = $this->prophesize(ResourceStorage::class);
2050  $resourceStorageProphecy->getUid()->willReturn(1);
2051 
2053  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2054  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2055  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2056  $backendUserProphecy->getFileStorages()->shouldBeCalled()->willReturn(
2057  [$resourceStorageProphecy->reveal()]
2058  );
2059 
2060  [$queryBuilderProphet, $connectionPoolProphet] = $this->‪mockDatabaseConnection('sys_file_storage');
2061 
2063  $statementProphet = $this->prophesize(Statement::class);
2064 
2065  $queryBuilderProphet->select('sys_file_storage.uid', 'sys_file_storage.labelField')
2066  ->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2067  $queryBuilderProphet->from('sys_file_storage')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2068  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2069  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2070  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2071  $queryBuilderProphet->andWhere('`pages.uid` = `sys_file_storage.pid`')
2072  ->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2073  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
2074 
2075  // Two instances are needed due to the push/pop behavior of addInstance()
2076  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2077  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2078 
2079  $counter = 0;
2080  $statementProphet->fetch()->shouldBeCalled()->will(function (‪$args) use (&$counter) {
2081  $counter++;
2082  if ($counter >= 3) {
2083  return false;
2084  }
2085  return [
2086  'uid' => $counter,
2087  'pid' => 0,
2088  'labelField' => 'storageFolderLabel'
2089  ];
2090  });
2091 
2092  $expected = $input;
2093  $expected['processedTca']['columns']['aField']['config']['items'] = [
2094  0 => [
2095  0 => 'prefix for item labels[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
2096  1 => 1,
2097  2 => 'default-not-found',
2098  3 => null,
2099  ]
2100  ];
2101 
2102  $expected['databaseRow']['aField'] = [];
2103 
2104  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2105  }
2106 
2111  {
2112  $input = [
2113  'databaseRow' => [
2114  'uid' => 5,
2115  'aField' => '',
2116  ],
2117  'tableName' => 'aTable',
2118  'effectivePid' => 42,
2119  'processedTca' => [
2120  'columns' => [
2121  'aField' => [
2122  'config' => [
2123  'type' => 'select',
2124  'renderType' => 'selectSingle',
2125  'foreign_table' => 'fTable',
2126  'maxitems' => 99999,
2127  ],
2128  ],
2129  ]
2130  ],
2131  'rootline' => [],
2132  ];
2133 
2134  // Fake the foreign_table
2135  ‪$GLOBALS['TCA']['fTable'] = [
2136  'ctrl' => [
2137  'label' => 'icon',
2138  'selicon_field' => 'icon',
2139  'selicon_field_path' => 'uploads/media',
2140  ],
2141  'columns' =>[
2142  'icon' => [],
2143  ],
2144  ];
2145 
2146  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
2147  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
2148 
2149  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2150  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2151  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2152 
2154  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2155  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2156  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2157 
2158  list($queryBuilderProphet, $connectionPoolProphet) = $this->‪mockDatabaseConnection();
2159 
2161  $statementProphet = $this->prophesize(Statement::class);
2162 
2163  $queryBuilderProphet->select('fTable.uid', 'fTable.icon')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2164  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2165  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2166  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2167  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2168  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2169  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
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  // Query returns one row, then false on second call
2176  $foreignTableRowResultOne = [
2177  'uid' => 1,
2178  'pid' => 23,
2179  'icon' => 'foo.jpg',
2180  ];
2181  $statementProphet->fetch()->shouldBeCalled()->willReturn($foreignTableRowResultOne, false);
2182 
2183  $expected = $input;
2184  $expected['processedTca']['columns']['aField']['config']['items'] = [
2185  0 => [
2186  0 => 'foo.jpg',
2187  1 => 1,
2188  2 => 'uploads/media/foo.jpg', // combination of selicon_field_path and the row value of field 'icon'
2189  3 => null,
2190  ],
2191  ];
2192  $expected['databaseRow']['aField'] = [];
2193 
2194  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2195  }
2196 
2201  {
2202  $input = [
2203  'databaseRow' => [
2204  'aField' => '',
2205  ],
2206  'tableName' => 'aTable',
2207  'processedTca' => [
2208  'columns' => [
2209  'aField' => [
2210  'config' => [
2211  'type' => 'select',
2212  'renderType' => 'selectSingle',
2213  'items' => [
2214  0 => [
2215  0 => 'keepMe',
2216  1 => 'keep',
2217  null,
2218  null,
2219  ],
2220  1 => [
2221  0 => 'removeMe',
2222  1 => 'remove',
2223  ],
2224  2 => [
2225  0 => 'removeMe',
2226  1 => 0,
2227  ],
2228  ],
2229  'maxitems' => 99999,
2230  ],
2231  ],
2232  ]
2233  ],
2234  'pageTsConfig' => [
2235  'TCEFORM.' => [
2236  'aTable.' => [
2237  'aField.' => [
2238  'keepItems' => 'keep',
2239  ],
2240  ],
2241  ],
2242  ],
2243  ];
2244 
2245  $expected = $input;
2246  $expected['databaseRow']['aField'] = [];
2247  unset(
2248  $expected['processedTca']['columns']['aField']['config']['items'][1],
2249  $expected['processedTca']['columns']['aField']['config']['items'][2]
2250  );
2251 
2252  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2253  }
2254 
2259  {
2260  $input = [
2261  'databaseRow' => [
2262  'aField' => '',
2263  ],
2264  'tableName' => 'aTable',
2265  'processedTca' => [
2266  'columns' => [
2267  'aField' => [
2268  'config' => [
2269  'type' => 'select',
2270  'renderType' => 'selectSingle',
2271  'items' => [
2272  0 => [
2273  0 => 'keepMe',
2274  1 => 'keep',
2275  null,
2276  null,
2277  ],
2278  1 => [
2279  0 => 'removeMe',
2280  1 => 'remove',
2281  ],
2282  ],
2283  'maxitems' => 99999,
2284  ],
2285  ],
2286  ]
2287  ],
2288  'pageTsConfig' => [
2289  'TCEFORM.' => [
2290  'aTable.' => [
2291  'aField.' => [
2292  'keepItems' => '',
2293  ],
2294  ],
2295  ],
2296  ],
2297  ];
2298 
2299  $expected = $input;
2300  $expected['databaseRow']['aField'] = [];
2301  $expected['processedTca']['columns']['aField']['config']['items'] = [];
2302 
2303  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2304  }
2305 
2310  {
2311  $input = [
2312  'databaseRow' => [
2313  'aField' => '',
2314  ],
2315  'tableName' => 'aTable',
2316  'processedTca' => [
2317  'columns' => [
2318  'aField' => [
2319  'config' => [
2320  'type' => 'select',
2321  'renderType' => 'selectSingle',
2322  'items' => [
2323  0 => [
2324  0 => 'keepMe',
2325  1 => '1',
2326  null,
2327  null,
2328  ],
2329  1 => [
2330  0 => 'removeMe',
2331  1 => 'remove',
2332  ],
2333  ],
2334  'maxitems' => 99999,
2335  ],
2336  ],
2337  ]
2338  ],
2339  'pageTsConfig' => [
2340  'TCEFORM.' => [
2341  'aTable.' => [
2342  'aField.' => [
2343  'keepItems' => '1',
2344  'addItems.' => [
2345  '1' => 'addItem #1',
2346  '12' => 'addItem #12',
2347  ],
2348  ],
2349  ],
2350  ],
2351  ],
2352  ];
2353 
2354  $expected = $input;
2355  $expected['databaseRow']['aField'] = [];
2356  $expected['processedTca']['columns']['aField']['config']['items'] = [
2357  0 => [
2358  0 => 'keepMe',
2359  1 => '1',
2360  null,
2361  null,
2362  ],
2363  1 => [
2364  0 => 'addItem #1',
2365  1 => '1',
2366  null,
2367  null,
2368  ],
2369  2 => [
2370  0 => 'addItem #12',
2371  1 => '12',
2372  null,
2373  null,
2374  ],
2375  ];
2376 
2377  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2378  }
2379 
2384  {
2385  $input = [
2386  'databaseRow' => [
2387  'aField' => ''
2388  ],
2389  'tableName' => 'aTable',
2390  'processedTca' => [
2391  'columns' => [
2392  'aField' => [
2393  'config' => [
2394  'type' => 'select',
2395  'renderType' => 'selectSingle',
2396  'items' => [
2397  0 => [
2398  0 => 'keepMe',
2399  1 => 'keep',
2400  null,
2401  null,
2402  ],
2403  1 => [
2404  0 => 'removeMe',
2405  1 => 'remove',
2406  ],
2407  2 => [
2408  0 => 'keep me',
2409  1 => 0,
2410  null,
2411  null,
2412  ],
2413  ],
2414  'maxitems' => 99999,
2415  ],
2416  ],
2417  ]
2418  ],
2419  'pageTsConfig' => [
2420  'TCEFORM.' => [
2421  'aTable.' => [
2422  'aField.' => [
2423  'removeItems' => 'remove',
2424  ],
2425  ],
2426  ],
2427  ],
2428  ];
2429 
2430  $expected = $input;
2431  $expected['databaseRow']['aField'] = [];
2432  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2433  $expected['processedTca']['columns']['aField']['config']['items'] = array_values($expected['processedTca']['columns']['aField']['config']['items']);
2434  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2435  }
2436 
2441  {
2442  $input = [
2443  'databaseRow' => [
2444  'aField' => ''
2445  ],
2446  'tableName' => 'aTable',
2447  'processedTca' => [
2448  'columns' => [
2449  'aField' => [
2450  'config' => [
2451  'type' => 'select',
2452  'renderType' => 'selectSingle',
2453  'items' => [
2454  0 => [
2455  0 => 'keepMe',
2456  1 => 'keep',
2457  null,
2458  null,
2459  ],
2460  1 => [
2461  0 => 'keepMe',
2462  1 => 'keepMe2',
2463  null,
2464  null,
2465  ],
2466  2 => [
2467  0 => 'remove me',
2468  1 => 0,
2469  ],
2470  ],
2471  'maxitems' => 99999,
2472  ],
2473  ],
2474  ]
2475  ],
2476  'pageTsConfig' => [
2477  'TCEFORM.' => [
2478  'aTable.' => [
2479  'aField.' => [
2480  'removeItems' => '0',
2481  ],
2482  ],
2483  ],
2484  ],
2485  ];
2486 
2487  $expected = $input;
2488  $expected['databaseRow']['aField'] = [];
2489  unset($expected['processedTca']['columns']['aField']['config']['items'][2]);
2490  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2491  }
2492 
2497  {
2498  $input = [
2499  'databaseRow' => [
2500  'aField' => ''
2501  ],
2502  'tableName' => 'aTable',
2503  'processedTca' => [
2504  'columns' => [
2505  'aField' => [
2506  'config' => [
2507  'type' => 'select',
2508  'renderType' => 'selectSingle',
2509  'items' => [
2510  0 => [
2511  0 => 'keepMe',
2512  1 => 'keep',
2513  null,
2514  null,
2515  ],
2516  1 => [
2517  0 => 'removeMe',
2518  1 => 'remove',
2519  ],
2520  ],
2521  'maxitems' => 99999,
2522  ],
2523  ],
2524  ]
2525  ],
2526  'pageTsConfig' => [
2527  'TCEFORM.' => [
2528  'aTable.' => [
2529  'aField.' => [
2530  'removeItems' => 'remove,add',
2531  'addItems.' => [
2532  'add' => 'addMe'
2533  ]
2534  ],
2535  ],
2536  ],
2537  ],
2538  ];
2539 
2540  $expected = $input;
2541  $expected['databaseRow']['aField'] = [];
2542  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2543 
2544  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2545  }
2546 
2551  {
2552  $input = [
2553  'databaseRow' => [
2554  'aField' => 'aValue,remove'
2555  ],
2556  'tableName' => 'aTable',
2557  'processedTca' => [
2558  'ctrl' => [
2559  'languageField' => 'aField',
2560  ],
2561  'columns' => [
2562  'aField' => [
2563  'config' => [
2564  'type' => 'select',
2565  'renderType' => 'selectSingle',
2566  'items' => [
2567  0 => [
2568  0 => 'keepMe',
2569  1 => 'keep',
2570  null,
2571  null,
2572  ],
2573  1 => [
2574  0 => 'removeMe',
2575  1 => 'remove',
2576  ],
2577  ],
2578  'maxitems' => 99999,
2579  ],
2580  ],
2581  ]
2582  ],
2583  ];
2584 
2586  $languageService = $this->prophesize(LanguageService::class);
2587  ‪$GLOBALS['LANG'] = $languageService->reveal();
2588  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2589  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2590 
2592  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2593  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2594  $backendUserProphecy->checkLanguageAccess('keep')->shouldBeCalled()->willReturn(true);
2595  $backendUserProphecy->checkLanguageAccess('remove')->shouldBeCalled()->willReturn(false);
2596 
2597  $expected = $input;
2598  $expected['databaseRow']['aField'] = [];
2599  $expected['processedTca']['columns']['aField']['config']['items'] = [
2600  [ '[ INVALID VALUE "aValue" ]', 'aValue', null, null ],
2601  [ 'keepMe', 'keep', null, null ],
2602  ];
2603 
2604  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2605  }
2606 
2611  {
2612  $input = [
2613  'databaseRow' => [
2614  'aField' => 'keep,remove'
2615  ],
2616  'tableName' => 'aTable',
2617  'processedTca' => [
2618  'columns' => [
2619  'aField' => [
2620  'config' => [
2621  'type' => 'select',
2622  'renderType' => 'selectSingle',
2623  'authMode' => 'explicitAllow',
2624  'items' => [
2625  0 => [
2626  0 => 'keepMe',
2627  1 => 'keep',
2628  null,
2629  null,
2630  ],
2631  1 => [
2632  0 => 'removeMe',
2633  1 => 'remove',
2634  ],
2635  ],
2636  'maxitems' => 99999,
2637  ],
2638  ],
2639  ]
2640  ],
2641  ];
2642 
2644  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2645  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2646  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'keep', 'explicitAllow')->shouldBeCalled()->willReturn(true);
2647  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'remove', 'explicitAllow')->shouldBeCalled()->willReturn(false);
2648 
2649  $expected = $input;
2650  $expected['databaseRow']['aField'] = ['keep'];
2651  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2652 
2653  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2654  }
2655 
2660  {
2661  $input = [
2662  'databaseRow' => [
2663  'doktype' => 'keep'
2664  ],
2665  'tableName' => 'pages',
2666  'processedTca' => [
2667  'columns' => [
2668  'doktype' => [
2669  'config' => [
2670  'type' => 'select',
2671  'renderType' => 'selectSingle',
2672  'items' => [
2673  0 => [
2674  0 => 'keepMe',
2675  1 => 'keep',
2676  null,
2677  null,
2678  ],
2679  ],
2680  'maxitems' => 99999,
2681  ],
2682  ],
2683  ],
2684  ],
2685  ];
2686 
2688  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2689  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2690  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(true);
2691 
2692  $expected = $input;
2693  $expected['databaseRow']['doktype'] = ['keep'];
2694 
2695  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2696  }
2697 
2702  {
2703  $input = [
2704  'databaseRow' => [
2705  'doktype' => 'keep',
2706  ],
2707  'tableName' => 'pages',
2708  'processedTca' => [
2709  'columns' => [
2710  'doktype' => [
2711  'config' => [
2712  'type' => 'select',
2713  'renderType' => 'selectSingle',
2714  'items' => [
2715  0 => [
2716  0 => 'keepMe',
2717  1 => 'keep',
2718  null,
2719  null,
2720  ],
2721  1 => [
2722  0 => 'removeMe',
2723  1 => 'remove',
2724  ],
2725  ],
2726  'maxitems' => 99999,
2727  ],
2728  ],
2729  ],
2730  ],
2731  ];
2732 
2734  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2735  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2736  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
2737  $backendUserProphecy->groupData = [
2738  'pagetypes_select' => 'foo,keep,anotherAllowedDoktype',
2739  ];
2740 
2741  $expected = $input;
2742  $expected['databaseRow']['doktype'] = ['keep'];
2743  unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
2744 
2745  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2746  }
2747 
2752  {
2753  $input = [
2754  'tableName' => 'aTable',
2755  'databaseRow' => [
2756  'aField' => 'aValue'
2757  ],
2758  'processedTca' => [
2759  'columns' => [
2760  'aField' => [
2761  'config' => [
2762  'type' => 'select',
2763  'renderType' => 'selectSingle',
2764  'items' => [],
2765  'itemsProcFunc' => function (array $parameters, $pObj) {
2766  $parameters['items'] = [
2767  0 => [
2768  0 => 'aLabel',
2769  1 => 'aValue',
2770  2 => null,
2771  3 => null,
2772  ],
2773  ];
2774  },
2775  ],
2776  ],
2777  ],
2778  ],
2779  ];
2780 
2781  $expected = $input;
2782  $expected['databaseRow']['aField'] = ['aValue'];
2783  $expected['processedTca']['columns']['aField']['config'] = [
2784  'type' => 'select',
2785  'renderType' => 'selectSingle',
2786  'items' => [
2787  0 => [
2788  0 => 'aLabel',
2789  1 => 'aValue',
2790  2 => null,
2791  3 => null,
2792  ],
2793  ],
2794  'maxitems' => 99999,
2795  ];
2796 
2797  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
2798  }
2799 
2804  {
2805  $input = [
2806  'databaseRow' => [
2807  'uid' => 5,
2808  'aField' => 2
2809  ],
2810  'tableName' => 'aTable',
2811  'effectivePid' => 42,
2812  'processedTca' => [
2813  'columns' => [
2814  'aField' => [
2815  'config' => [
2816  'type' => 'select',
2817  'renderType' => 'selectSingle',
2818  'foreign_table' => 'fTable',
2819  'maxitems' => 99999,
2820  ],
2821  ],
2822  ]
2823  ],
2824  'rootline' => [],
2825  ];
2826 
2827  ‪$GLOBALS['TCA']['fTable'] = [
2828  'ctrl' => [
2829  'label' => 'labelField',
2830  ],
2831  'columns' => [
2832  'labelField' => []
2833  ],
2834  ];
2835 
2836  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2837  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2838  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2839 
2841  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2842  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2843  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2844 
2845  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
2846 
2847  // Two instances are needed due to the push/pop behavior of addInstance()
2848  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2849  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2850 
2851  $counter = 0;
2852  $statementProphet->fetch()->shouldBeCalled()->will(function (‪$args) use (&$counter) {
2853  $counter++;
2854  if ($counter >= 3) {
2855  return false;
2856  }
2857  return [
2858  'uid' => $counter,
2859  'pid' => 23,
2860  'labelField' => 'aLabel_' . $counter,
2861  'aValue' => 'bar,',
2862  'dbfield' => 'some data'
2863  ];
2864  });
2865 
2866  $expected = $input;
2867  $expected['processedTca']['columns']['aField']['config']['items'] = [
2868  0 => [
2869  0 => 'aLabel_1',
2870  1 => 1,
2871  2 => 'default-not-found',
2872  3 => null,
2873  ],
2874  1 => [
2875  0 => 'aLabel_2',
2876  1 => 2,
2877  2 => 'default-not-found',
2878  3 => null,
2879  ],
2880  ];
2881 
2882  $expected['databaseRow']['aField'] = [
2883  0 => '2' // the selected value stored in db
2884  ];
2885 
2886  self::assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2887  }
2888 
2898  {
2899  $input = [
2900  'databaseRow' => [
2901  'uid' => 5,
2902  'aField' => ''
2903  ],
2904  'tableName' => 'aTable',
2905  'effectivePid' => 42,
2906  'processedTca' => [
2907  'columns' => [
2908  'aField' => [
2909  'config' => [
2910  'type' => 'select',
2911  'renderType' => 'selectSingle',
2912  'foreign_table' => 'fTable',
2913  'itemsProcFunc' => function (array $parameters, $pObj) {
2914  $filteredItems = [];
2915  // Iterate over given items to filter them
2916  foreach ($parameters['items'] as $item) {
2917  if ($item[1] === 2) { // uid === 2
2918  $filteredItems[] = [
2919  $item[0], // label
2920  $item[1], // uid
2921  null, // icon
2922  null // helpText
2923  ];
2924  }
2925  }
2926  $parameters['items'] = $filteredItems;
2927  },
2928  'maxitems' => 99999,
2929  ],
2930  ],
2931  ]
2932  ],
2933  'rootline' => [],
2934  ];
2935 
2936  ‪$GLOBALS['TCA']['fTable'] = [
2937  'ctrl' => [
2938  'label' => 'labelField',
2939  ],
2940  'columns' => [],
2941  ];
2942 
2943  // FileRepository to get the icon of the foreign table
2944  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
2945  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
2946  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
2947 
2949  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2950  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2951  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2952 
2953  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
2954 
2955  // Two instances are needed due to the push/pop behavior of addInstance()
2956  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2957  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2958 
2959  $counter = 0;
2960 
2961  // simulates foreign_table containing two rows
2962  $statementProphet->fetch()->shouldBeCalled()->will(function (‪$args) use (&$counter) {
2963  $counter++;
2964  if ($counter >= 3) {
2965  return false;
2966  }
2967  return [
2968  'uid' => $counter,
2969  'pid' => 23,
2970  'labelField' => 'aLabel will be replaced since the label column is not configured',
2971  'aValue' => 'bar, irrelevant',
2972  'dbfield' => 'some random data, irrelevant'
2973  ];
2974  });
2975 
2976  $expected = $input;
2977  $expected['processedTca']['columns']['aField']['config'] = [
2978  'type' => 'select',
2979  'renderType' => 'selectSingle',
2980  'foreign_table' => 'fTable',
2981  'items' => [
2982  0 => [
2983  0 => '[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
2984  1 => 2,
2985  2 => null,
2986  3 => null,
2987  ],
2988  ],
2989  'maxitems' => 99999
2990  ];
2991 
2992  $expected['databaseRow']['aField'] = [];
2993 
2994  self::assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
2995  }
2996 
3007  {
3008  $input = [
3009  'databaseRow' => [
3010  'uid' => 5,
3011  'aField' => ''
3012  ],
3013  'tableName' => 'aTable',
3014  'effectivePid' => 42,
3015  'processedTca' => [
3016  'columns' => [
3017  'aField' => [
3018  'config' => [
3019  'type' => 'select',
3020  'renderType' => 'selectSingle',
3021  'foreign_table' => 'fTable',
3022  'itemsProcFunc' => function (array $parameters, $pObj) {
3023  $filteredItems = [];
3024  // Iterate over given items to filter them
3025  foreach ($parameters['items'] as $item) {
3026  if ($item[1] < 3) { // uid < 2
3027  $filteredItems[] = [
3028  $item[0], // label
3029  $item[1], // uid
3030  null, // icon
3031  null // helpText
3032  ];
3033  }
3034  }
3035  $parameters['items'] = $filteredItems;
3036  },
3037  'maxitems' => 99999,
3038  ],
3039  ],
3040  ]
3041  ],
3042  'pageTsConfig' => [
3043  'TCEFORM.' => [
3044  'aTable.' => [
3045  'aField.' => [
3046  'removeItems' => '2'
3047  ],
3048  ],
3049  ],
3050  ],
3051  'rootline' => [],
3052  ];
3053 
3054  ‪$GLOBALS['TCA']['fTable'] = [
3055  'ctrl' => [
3056  'label' => 'labelField',
3057  ],
3058  'columns' => [],
3059  ];
3060 
3061  // FileRepository to get the icon of the foreign table
3062  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
3063  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
3064  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
3065 
3067  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3068  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3069  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3070 
3071  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
3072 
3073  // Two instances are needed due to the push/pop behavior of addInstance()
3074  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
3075  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
3076 
3077  $counter = 0;
3078 
3079  // simulates foreign_table containing two rows
3080  $statementProphet->fetch()->shouldBeCalled()->will(function (‪$args) use (&$counter) {
3081  $counter++;
3082  if ($counter >= 3) {
3083  return false;
3084  }
3085  return [
3086  'uid' => $counter,
3087  'pid' => 23,
3088  'labelField' => 'aLabel will be replaced since the label column is not configured',
3089  'randomDbField' => 'bar, irrelevant'
3090  ];
3091  });
3092 
3093  $expected = $input;
3094  $expected['processedTca']['columns']['aField']['config'] = [
3095  'type' => 'select',
3096  'renderType' => 'selectSingle',
3097  'foreign_table' => 'fTable',
3098  'items' => [
3099  0 => [
3100  0 => '[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
3101  1 => 1,
3102  2 => null,
3103  3 => null,
3104  ]
3105  ],
3106  'maxitems' => 99999
3107  ];
3108 
3109  $expected['databaseRow']['aField'] = [];
3110 
3111  self::assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3112  }
3113 
3124  {
3125  $input = [
3126  'databaseRow' => [
3127  'uid' => 5,
3128  'aField' => ''
3129  ],
3130  'tableName' => 'aTable',
3131  'effectivePid' => 42,
3132  'processedTca' => [
3133  'columns' => [
3134  'aField' => [
3135  'config' => [
3136  'type' => 'select',
3137  'renderType' => 'selectSingle',
3138  'foreign_table' => 'fTable',
3139  'itemsProcFunc' => function (array $parameters, $pObj) {
3140  $filteredItems = [];
3141  // Iterate over given items to filter them
3142  foreach ($parameters['items'] as $item) {
3143  if ($item[1] === 2) { // uid must be 2
3144  $filteredItems[] = [
3145  $item[0], // label
3146  $item[1], // uid
3147  null, // icon
3148  null // helpText
3149  ];
3150  }
3151  }
3152  $parameters['items'] = $filteredItems;
3153  },
3154  'maxitems' => 99999,
3155  ],
3156  ],
3157  ]
3158  ],
3159  'pageTsConfig' => [
3160  'TCEFORM.' => [
3161  'aTable.' => [
3162  'aField.' => [
3163  'addItems.' => [
3164  '12' => 'Label of the added item'
3165  ]
3166  ],
3167  ],
3168  ],
3169  ],
3170  'rootline' => [],
3171  ];
3172 
3173  ‪$GLOBALS['TCA']['fTable'] = [
3174  'ctrl' => [
3175  'label' => 'labelField',
3176  ],
3177  'columns' => [],
3178  ];
3179 
3180  // FileRepository to get the icon of the foreign table
3181  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
3182  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
3183  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
3184 
3186  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3187  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3188  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3189 
3190  [$connectionPoolProphet, $statementProphet] = $this->‪mockForeignTableItemsQuery();
3191 
3192  // Two instances are needed due to the push/pop behavior of addInstance()
3193  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
3194  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
3195 
3196  $counter = 0;
3197 
3198  // simulates foreign_table containing two rows
3199  $statementProphet->fetch()->shouldBeCalled()->will(function (‪$args) use (&$counter) {
3200  $counter++;
3201  if ($counter >= 3) {
3202  return false;
3203  }
3204  return [
3205  'uid' => $counter,
3206  'pid' => 23,
3207  'labelField' => 'aLabel will be replaced since the label column is not configured',
3208  'randomDbField' => 'bar, irrelevant'
3209  ];
3210  });
3211 
3212  $expected = $input;
3213  $expected['processedTca']['columns']['aField']['config'] = [
3214  'type' => 'select',
3215  'renderType' => 'selectSingle',
3216  'foreign_table' => 'fTable',
3217  'items' => [
3218  0 => [
3219  0 => '[LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
3220  1 => 2,
3221  2 => null,
3222  3 => null,
3223  ],
3224  1 => [
3225  0 => 'Label of the added item',
3226  1 => 12,
3227  2 => null,
3228  3 => null,
3229  ],
3230  ],
3231  'maxitems' => 99999
3232  ];
3233 
3234  $expected['databaseRow']['aField'] = [];
3235 
3236  self::assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3237  }
3238 
3243  {
3244  $input = [
3245  'tableName' => 'aTable',
3246  'databaseRow' => [
3247  'aField' => 'aValue',
3248  ],
3249  'pageTsConfig' => [
3250  'TCEFORM.' => [
3251  'aTable.' => [
3252  'aField.' => [
3253  'itemsProcFunc.' => [
3254  'itemParamKey' => 'itemParamValue',
3255  ],
3256  ]
3257  ],
3258  ],
3259  ],
3260  'processedTca' => [
3261  'columns' => [
3262  'aField' => [
3263  'config' => [
3264  'type' => 'select',
3265  'renderType' => 'selectSingle',
3266  'aKey' => 'aValue',
3267  'items' => [
3268  0 => [
3269  0 => 'aLabel',
3270  1 => 'aValue',
3271  ],
3272  ],
3273  'itemsProcFunc' => function (array $parameters, $pObj) {
3274  if ($parameters['items'] !== [ 0 => [ 'aLabel', 'aValue'] ]
3275  || $parameters['config']['aKey'] !== 'aValue'
3276  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
3277  || $parameters['table'] !== 'aTable'
3278  || $parameters['row'] !== [ 'aField' => 'aValue' ]
3279  || $parameters['field'] !== 'aField'
3280  ) {
3281  throw new \UnexpectedValueException('broken', 1476109436);
3282  }
3283  },
3284  ],
3285  ],
3286  ],
3287  ],
3288  ];
3289 
3290  $languageService = $this->prophesize(LanguageService::class);
3291  ‪$GLOBALS['LANG'] = $languageService->reveal();
3292  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3294  $flashMessage = $this->prophesize(FlashMessage::class);
3295  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
3297  $flashMessageService = $this->prophesize(FlashMessageService::class);
3298  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
3300  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
3301  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
3302 
3303  // itemsProcFunc must NOT have raised an exception
3304  $flashMessageQueue->enqueue($flashMessage)->shouldNotBeCalled();
3305 
3306  (new ‪TcaSelectItems)->addData($input);
3307  }
3308 
3313  {
3314  $input = [
3315  'tableName' => 'aTable',
3316  'databaseRow' => [
3317  'aField' => 'aValue',
3318  ],
3319  'pageTsConfig' => [
3320  'TCEFORM.' => [
3321  'aTable.' => [
3322  'aField.' => [
3323  'itemsProcFunc.' => [
3324  'itemParamKey' => 'itemParamValue',
3325  ],
3326  ]
3327  ],
3328  ],
3329  ],
3330  'processedTca' => [
3331  'columns' => [
3332  'aField' => [
3333  'config' => [
3334  'type' => 'select',
3335  'renderType' => 'selectSingle',
3336  'aKey' => 'aValue',
3337  'items' => [
3338  0 => [
3339  0 => 'aLabel',
3340  1 => 'aValue',
3341  ],
3342  ],
3343  'itemsProcFunc' => function (array $parameters, $pObj) {
3344  throw new \UnexpectedValueException('anException', 1476109437);
3345  },
3346  ],
3347  ],
3348  ],
3349  ],
3350  ];
3351 
3352  $languageService = $this->prophesize(LanguageService::class);
3353  ‪$GLOBALS['LANG'] = $languageService->reveal();
3355  $flashMessage = $this->prophesize(FlashMessage::class);
3356  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
3358  $flashMessageService = $this->prophesize(FlashMessageService::class);
3359  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
3361  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
3362  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
3363 
3364  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
3365 
3366  (new ‪TcaSelectItems)->addData($input);
3367  }
3368 
3373  {
3374  $input = [
3375  'databaseRow' => [
3376  'aField' => 'aValue',
3377  ],
3378  'tableName' => 'aTable',
3379  'processedTca' => [
3380  'columns' => [
3381  'aField' => [
3382  'config' => [
3383  'type' => 'select',
3384  'renderType' => 'selectSingle',
3385  'items' => [
3386  0 => [
3387  0 => 'aLabel',
3388  1 => 'aValue',
3389  null,
3390  null,
3391  ],
3392  ],
3393  'maxitems' => 99999,
3394  ],
3395  ],
3396  ],
3397  ],
3398  'pageTsConfig' => [
3399  'TCEFORM.' => [
3400  'aTable.' => [
3401  'aField.' => [
3402  'altLabels.' => [
3403  'aValue' => 'labelOverride',
3404  ],
3405  ]
3406  ],
3407  ],
3408  ],
3409  ];
3410 
3412  $languageService = $this->prophesize(LanguageService::class);
3413  ‪$GLOBALS['LANG'] = $languageService->reveal();
3414  $languageService->sL('aLabel')->willReturnArgument(0);
3415  $languageService->sL('labelOverride')->shouldBeCalled()->willReturnArgument(0);
3416  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
3417 
3418  $expected = $input;
3419  $expected['databaseRow']['aField'] = ['aValue'];
3420  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'labelOverride';
3421 
3422  $this->assertSame($expected, (new ‪TcaSelectItems)->addData($input));
3423  }
3424 
3429  {
3430  ‪$GLOBALS['TCA']['foreignTable'] = [];
3431 
3432  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
3433  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
3434 
3435  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
3436  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
3437  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
3438 
3440  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3441  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3442  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3443 
3445 
3446  $input = [
3447  'command' => 'edit',
3448  'tableName' => 'aTable',
3449  'effectivePid' => 23,
3450  'databaseRow' => [
3451  'uid' => 42,
3452  // Two connected rows
3453  'aField' => 2,
3454  ],
3455  'processedTca' => [
3456  'columns' => [
3457  'aField' => [
3458  'config' => [
3459  'type' => 'select',
3460  'renderType' => 'selectSingle',
3461  'maxitems' => 999,
3462  'foreign_table' => 'foreignTable',
3463  'MM' => 'aTable_foreignTable_mm',
3464  'items' => [],
3465  ],
3466  ],
3467  ],
3468  ],
3469  ];
3470  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
3472  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3473  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3474 
3475  $relationHandlerUids = [
3476  23,
3477  24
3478  ];
3479 
3480  $relationHandlerProphecy->start('', 'foreignTable', 'aTable_foreignTable_mm', 42, 'aTable', $fieldConfig)->shouldBeCalled();
3481  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
3482 
3483  $expected = $input;
3484  $expected['databaseRow']['aField'] = $relationHandlerUids;
3485 
3486  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3487  }
3488 
3493  {
3494  ‪$GLOBALS['TCA']['foreignTable'] = [];
3495 
3496  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
3497  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
3498 
3499  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
3500  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
3501  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
3502 
3504  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3505  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3506  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3507 
3509 
3510  $input = [
3511  'tableName' => 'aTable',
3512  'effectivePid' => 23,
3513  'databaseRow' => [
3514  'uid' => 42,
3515  // Two connected rows
3516  'aField' => '22,23,24,25',
3517  ],
3518  'processedTca' => [
3519  'columns' => [
3520  'aField' => [
3521  'config' => [
3522  'type' => 'select',
3523  'renderType' => 'selectSingle',
3524  'maxitems' => 999,
3525  'foreign_table' => 'foreignTable',
3526  'items' => [],
3527  ],
3528  ],
3529  ],
3530  ],
3531  ];
3532  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
3534  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3535  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3536 
3537  $relationHandlerUids = [
3538  23,
3539  24
3540  ];
3541 
3542  $relationHandlerProphecy->start('22,23,24,25', 'foreignTable', '', 42, 'aTable', $fieldConfig)->shouldBeCalled();
3543  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
3544 
3545  $expected = $input;
3546  $expected['databaseRow']['aField'] = $relationHandlerUids;
3547 
3548  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3549  }
3550 
3555  {
3556  ‪$GLOBALS['TCA']['foreignTable'] = [];
3557 
3558  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
3559  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
3560 
3561  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
3562  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
3563  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
3564 
3566  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3567  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3568  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3569 
3571 
3572  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3573  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3574  $relationHandlerProphecy->start(Argument::cetera())->shouldBeCalled();
3575  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldBeCalled()->willReturn([1]);
3576 
3577  $input = [
3578  'tableName' => 'aTable',
3579  'effectivePid' => 23,
3580  'databaseRow' => [
3581  'uid' => 5,
3582  'aField' => '1,2,bar,foo',
3583  ],
3584  'processedTca' => [
3585  'columns' => [
3586  'aField' => [
3587  'config' => [
3588  'type' => 'select',
3589  'renderType' => 'selectSingleBox',
3590  'foreign_table' => 'foreignTable',
3591  'maxitems' => 999,
3592  'items' => [
3593  ['foo', 'foo', null, null],
3594  ],
3595  ],
3596  ],
3597  ],
3598  ],
3599  ];
3600 
3601  $expected = $input;
3602  $expected['databaseRow']['aField'] = [1, 'foo'];
3603 
3604  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3605  }
3606 
3611  {
3612  $input = [
3613  'tableName' => 'aTable',
3614  'databaseRow' => [
3615  'aField' => 'foo,bar',
3616  ],
3617  'processedTca' => [
3618  'columns' => [
3619  'aField' => [
3620  'config' => [
3621  'type' => 'select',
3622  'renderType' => 'selectSingle',
3623  'maxitems' => 999,
3624  'items' => [
3625  ['foo', 'foo', null, null],
3626  ['bar', 'bar', null, null],
3627  ],
3628  ],
3629  ],
3630  ],
3631  ],
3632  ];
3633 
3634  $expected = $input;
3635  $expected['databaseRow']['aField'] = [
3636  'foo',
3637  'bar'
3638  ];
3639 
3640  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3641  }
3642 
3647  {
3648  $input = [
3649  'tableName' => 'aTable',
3650  'databaseRow' => [
3651  'aField' => '',
3652  ],
3653  'processedTca' => [
3654  'columns' => [
3655  'aField' => [
3656  'config' => [
3657  'type' => 'select',
3658  'renderType' => 'selectSingle',
3659  'maxitems' => 99999,
3660  'items' => [],
3661  ],
3662  ],
3663  ],
3664  ],
3665  ];
3666 
3667  $expected = $input;
3668  $expected['databaseRow']['aField'] = [];
3669 
3670  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3671  }
3672 
3677  {
3678  $input = [
3679  'tableName' => 'aTable',
3680  'databaseRow' => [
3681  'aField' => 'b,,c',
3682  ],
3683  'processedTca' => [
3684  'columns' => [
3685  'aField' => [
3686  'config' => [
3687  'type' => 'select',
3688  'renderType' => 'selectSingle',
3689  'maxitems' => 999,
3690  'items' => [
3691  ['a', '', null, null],
3692  ['b', 'b', null, null],
3693  ['c', 'c', null, null],
3694  ],
3695  ],
3696  ],
3697  ],
3698  ],
3699  ];
3700 
3701  $expected = $input;
3702  $expected['databaseRow']['aField'] = [
3703  'b',
3704  'c',
3705  ];
3706 
3707  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3708  }
3709 
3714  {
3715  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3716  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3717  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3718  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3719 
3720  $input = [
3721  'tableName' => 'aTable',
3722  'databaseRow' => [
3723  'aField' => 'foo',
3724  ],
3725  'processedTca' => [
3726  'columns' => [
3727  'aField' => [
3728  'config' => [
3729  'type' => 'select',
3730  'renderType' => 'selectSingle',
3731  'maxitems' => 999,
3732  'items' => [
3733  ['foo', 'foo', null, null],
3734  ],
3735  ],
3736  ],
3737  ],
3738  ],
3739  ];
3740 
3741  $expected = $input;
3742  $expected['databaseRow']['aField'] = ['foo'];
3743 
3744  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3745  }
3746 
3751  {
3752  $languageService = $this->prophesize(LanguageService::class);
3753  ‪$GLOBALS['LANG'] = $languageService->reveal();
3754  $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
3755  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3756 
3757  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3758  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3759  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3760  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3761 
3762  $input = [
3763  'tableName' => 'aTable',
3764  'databaseRow' => [
3765  'aField' => '1,2,bar,foo',
3766  ],
3767  'processedTca' => [
3768  'columns' => [
3769  'aField' => [
3770  'config' => [
3771  'type' => 'select',
3772  'renderType' => 'selectSingle',
3773  'maxitems' => 99999,
3774  'items' => [
3775  ['foo', 'foo', null, null],
3776  ],
3777  ],
3778  ],
3779  ],
3780  ],
3781  ];
3782 
3783  $expected = $input;
3784  $expected['databaseRow']['aField'] = ['foo'];
3785  $expected['processedTca']['columns']['aField']['config']['items'] = [
3786  ['[ INVALID VALUE "bar" ]', 'bar', null, null],
3787  ['[ INVALID VALUE "2" ]', '2', null, null],
3788  ['[ INVALID VALUE "1" ]', '1', null, null],
3789  ['foo', 'foo', null, null],
3790  ];
3791  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3792  }
3793 
3798  {
3799  $input = [
3800  'tableName' => 'aTable',
3801  'databaseRow' => [
3802  'aField' => '1,foo,foo,2,bar',
3803  ],
3804  'processedTca' => [
3805  'columns' => [
3806  'aField' => [
3807  'config' => [
3808  'type' => 'select',
3809  'renderType' => 'selectSingle',
3810  'multiple' => true,
3811  'maxitems' => 999,
3812  'items' => [
3813  ['1', '1', null, null],
3814  ['foo', 'foo', null, null],
3815  ['bar', 'bar', null, null],
3816  ['2', '2', null, null],
3817  ],
3818  ],
3819  ],
3820  ],
3821  ],
3822  ];
3823 
3824  $expected = $input;
3825  $expected['databaseRow']['aField'] = [
3826  '1',
3827  'foo',
3828  'foo',
3829  '2',
3830  'bar'
3831  ];
3832 
3833  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3834  }
3835 
3840  {
3841  $input = [
3842  'tableName' => 'aTable',
3843  'databaseRow' => [
3844  'aField' => '1,foo,foo,2,bar',
3845  ],
3846  'processedTca' => [
3847  'columns' => [
3848  'aField' => [
3849  'config' => [
3850  'type' => 'select',
3851  'renderType' => 'selectSingle',
3852  'multiple' => false,
3853  'maxitems' => 999,
3854  'items' => [
3855  ['1', '1', null, null],
3856  ['foo', 'foo', null, null],
3857  ['bar', 'bar', null, null],
3858  ['2', '2', null, null],
3859  ],
3860  ],
3861  ],
3862  ],
3863  ],
3864  ];
3865 
3866  $expected = $input;
3867  $expected['databaseRow']['aField'] = [
3868  0 => '1',
3869  1 => 'foo',
3870  3 => '2',
3871  4 => 'bar',
3872  ];
3873 
3874  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
3875  }
3876 
3883  {
3884  return [
3885  'Relation with MM table and new status with default values' => [
3886  [
3887  'tableName' => 'aTable',
3888  'command' => 'new',
3889  'effectivePid' => 42,
3890  'databaseRow' => [
3891  'uid' => 'NEW1234',
3892  'aField' => '24,35',
3893  ],
3894  'processedTca' => [
3895  'columns' => [
3896  'aField' => [
3897  'config' => [
3898  'type' => 'select',
3899  'renderType' => 'selectSingle',
3900  'maxitems' => 999,
3901  'MM' => 'mm_aTable_foreignTable',
3902  'foreign_table' => 'foreignTable',
3903  'items' => [],
3904  ],
3905  ],
3906  ],
3907  ],
3908  ],
3909  [
3910  'MM' => ''
3911  ],
3912  [
3913  24, 35
3914  ]
3915  ],
3916  'Relation with MM table and item array in list but no new status' => [
3917  [
3918  'tableName' => 'aTable',
3919  'command' => 'edit',
3920  'effectivePid' => 42,
3921  'databaseRow' => [
3922  'uid' => 42,
3923  'aField' => '2',
3924  ],
3925  'processedTca' => [
3926  'columns' => [
3927  'aField' => [
3928  'config' => [
3929  'type' => 'select',
3930  'renderType' => 'selectSingle',
3931  'maxitems' => 999,
3932  'MM' => 'mm_aTable_foreignTable',
3933  'foreign_table' => 'foreignTable',
3934  'items' => [],
3935  ],
3936  ],
3937  ],
3938  ],
3939  ],
3940  [
3941  'relationHandlerStartItemList' => '',
3942  ],
3943  []
3944  ],
3945  'Relation with MM table and maxitems = 1 processes field value (item count)' => [
3946  [
3947  'tableName' => 'aTable',
3948  'command' => 'edit',
3949  'effectivePid' => 42,
3950  'databaseRow' => [
3951  'uid' => 42,
3952  // MM relation with one item has 1 in field value
3953  'aField' => 1,
3954  ],
3955  'processedTca' => [
3956  'columns' => [
3957  'aField' => [
3958  'config' => [
3959  'type' => 'select',
3960  'renderType' => 'selectSingle',
3961  'maxitems' => 1,
3962  'MM' => 'mm_aTable_foreignTable',
3963  'foreign_table' => 'foreignTable',
3964  'items' => [],
3965  ],
3966  ],
3967  ],
3968  ],
3969  ],
3970  [
3971  'relationHandlerStartItemList' => '',
3972  ],
3973  [
3974  24
3975  ]
3976  ],
3977  'Relation with MM table and maxitems = 1 results in empty array if no items are set' => [
3978  [
3979  'tableName' => 'aTable',
3980  'command' => 'edit',
3981  'effectivePid' => 42,
3982  'databaseRow' => [
3983  'uid' => 58,
3984  // MM relation with no items has 0 in field value
3985  'aField' => 0,
3986  ],
3987  'processedTca' => [
3988  'columns' => [
3989  'aField' => [
3990  'config' => [
3991  'type' => 'select',
3992  'renderType' => 'selectSingle',
3993  'maxitems' => 1,
3994  'MM' => 'mm_aTable_foreignTable',
3995  'foreign_table' => 'foreignTable',
3996  'items' => [],
3997  ],
3998  ],
3999  ],
4000  ],
4001  ],
4002  [
4003  'relationHandlerStartItemList' => '',
4004  ],
4005  []
4006  ]
4007  ];
4008  }
4009 
4018  public function ‪processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids)
4019  {
4020  $field = $overrideRelationHandlerSettings['relationHandlerStartItemList'] ?? $input['databaseRow']['aField'];
4021  $foreignTable = $overrideRelationHandlerSettings['foreign_table'] ?? $input['processedTca']['columns']['aField']['config']['foreign_table'];
4022  $mmTable = $overrideRelationHandlerSettings['MM'] ?? $input['processedTca']['columns']['aField']['config']['MM'];
4023  $uid = $input['databaseRow']['uid'];
4024  $tableName = $input['tableName'];
4025  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
4026 
4027  ‪$GLOBALS['TCA'][$foreignTable] = [];
4028 
4029  $iconFactoryProphecy = $this->prophesize(IconFactory::class);
4030  GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
4031 
4032  $fileRepositoryProphecy = $this->prophesize(FileRepository::class);
4033  $fileRepositoryProphecy->findByRelation(Argument::cetera())->shouldNotBeCalled();
4034  GeneralUtility::setSingletonInstance(FileRepository::class, $fileRepositoryProphecy->reveal());
4035 
4037  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
4038  ‪$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
4039  $backendUserProphecy->getPagePermsClause(Argument::cetera())->willReturn(' 1=1');
4040 
4042 
4044  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
4045  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
4046 
4047  $relationHandlerProphecy->start($field, $foreignTable, $mmTable, $uid, $tableName, $fieldConfig)->shouldBeCalled();
4048  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
4049 
4050  $expected = $input;
4051  $expected['databaseRow']['aField'] = $relationHandlerUids;
4052 
4053  $this->assertEquals($expected, (new ‪TcaSelectItems)->addData($input));
4054  }
4055 }
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataReplacesMarkersInForeignTableClause
‪addDataReplacesMarkersInForeignTableClause($foreignTableWhere, $expectedWhere, array $inputOverride)
Definition: TcaSelectItemsTest.php:1646
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataReplacesMarkersInForeignTableClauseDataProvider
‪addDataReplacesMarkersInForeignTableClauseDataProvider()
Definition: TcaSelectItemsTest.php:1400
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsFileItemsWithConfiguredFileFolder
‪addDataAddsFileItemsWithConfiguredFileFolder()
Definition: TcaSelectItemsTest.php:1215
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataCallsItemsProcFunc
‪addDataCallsItemsProcFunc()
Definition: TcaSelectItemsTest.php:2751
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExplicitAllowFieldsWithSpecialExplicitValues
‪addDataAddsExplicitAllowFieldsWithSpecialExplicitValues()
Definition: TcaSelectItemsTest.php:704
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:33
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:153
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExplicitIndividualAllowFieldsWithSpecialExplicitValues
‪addDataAddsExplicitIndividualAllowFieldsWithSpecialExplicitValues()
Definition: TcaSelectItemsTest.php:852
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncReceivesParameters
‪addDataItemsProcFuncReceivesParameters()
Definition: TcaSelectItemsTest.php:3242
‪$args
‪$args
Definition: checkIntegrityCsvFixtures.php:230
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueDoesNotCallRelationManagerForStaticOnlyItems
‪processSelectFieldValueDoesNotCallRelationManagerForStaticOnlyItems()
Definition: TcaSelectItemsTest.php:3713
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsItemsByAddItemsFromPageTsConfig
‪addDataAddsItemsByAddItemsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:1292
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableSplitsGroupOrderAndLimit
‪addDataForeignTableSplitsGroupOrderAndLimit()
Definition: TcaSelectItemsTest.php:1753
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepsAllowedPageTypesForNonAdminUser
‪addDataKeepsAllowedPageTypesForNonAdminUser()
Definition: TcaSelectItemsTest.php:2701
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueReturnsEmptyValueForSingleSelect
‪processSelectFieldValueReturnsEmptyValueForSingleSelect()
Definition: TcaSelectItemsTest.php:3646
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByLanguageFieldUserRestriction
‪addDataRemovesItemsByLanguageFieldUserRestriction()
Definition: TcaSelectItemsTest.php:2550
‪TYPO3\CMS\Core\Database\RelationHandler
Definition: RelationHandler.php:32
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsThatAreRestictedByUserStorageAddedByForeignTable
‪addDataRemovesItemsThatAreRestictedByUserStorageAddedByForeignTable()
Definition: TcaSelectItemsTest.php:2012
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\mockDatabaseConnection
‪array mockDatabaseConnection($tableName='fTable')
Definition: TcaSelectItemsTest.php:89
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionForInvalidFileFolder
‪addDataThrowsExceptionForInvalidFileFolder()
Definition: TcaSelectItemsTest.php:1266
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueRemovesInvalidDynamicValues
‪processSelectFieldValueRemovesInvalidDynamicValues()
Definition: TcaSelectItemsTest.php:3554
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByUserAuthModeRestriction
‪addDataRemovesItemsByUserAuthModeRestriction()
Definition: TcaSelectItemsTest.php:2610
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\setUp
‪setUp()
Definition: TcaSelectItemsTest.php:53
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig
‪addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:2258
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig
‪addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig()
Definition: TcaSelectItemsTest.php:1346
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:31
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:614
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepsAllPagesDoktypesForAdminUser
‪addDataKeepsAllPagesDoktypesForAdminUser()
Definition: TcaSelectItemsTest.php:2659
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncWillUseItemsFromForeignTable
‪addDataItemsProcFuncWillUseItemsFromForeignTable()
Definition: TcaSelectItemsTest.php:2897
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldSetsCorrectValuesForMmRelations
‪processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids)
Definition: TcaSelectItemsTest.php:4018
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExcludeFieldsWithSpecialExcludeDataProvider
‪addDataAddsExcludeFieldsWithSpecialExcludeDataProvider()
Definition: TcaSelectItemsTest.php:473
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionIfAnItemIsNotAnArray
‪addDataThrowsExceptionIfAnItemIsNotAnArray()
Definition: TcaSelectItemsTest.php:203
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:47
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableHandlesForeignTableRows
‪addDataForeignTableHandlesForeignTableRows()
Definition: TcaSelectItemsTest.php:1923
‪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:3750
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExcludeFieldsFromFlexWithSpecialExclude
‪addDataAddsExcludeFieldsFromFlexWithSpecialExclude()
Definition: TcaSelectItemsTest.php:622
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldSetsCorrectValuesForMmRelationsDataProvider
‪array processSelectFieldSetsCorrectValuesForMmRelationsDataProvider()
Definition: TcaSelectItemsTest.php:3882
‪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:126
‪TYPO3\CMS\Core\Resource\FileRepository
Definition: FileRepository.php:32
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExplicitIndividualDenyFieldsWithSpecialExplicitValues
‪addDataAddsExplicitIndividualDenyFieldsWithSpecialExplicitValues()
Definition: TcaSelectItemsTest.php:947
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueSetsForeignRelationValues
‪processSelectFieldValueSetsForeignRelationValues()
Definition: TcaSelectItemsTest.php:3492
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableItemsWillReceiveTheLabelFromForeignTableLabelField
‪addDataForeignTableItemsWillReceiveTheLabelFromForeignTableLabelField()
Definition: TcaSelectItemsTest.php:2803
‪TYPO3\CMS\Backend\Module\ModuleLoader
Definition: ModuleLoader.php:32
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableQueuesFlashMessageOnDatabaseError
‪addDataForeignTableQueuesFlashMessageOnDatabaseError()
Definition: TcaSelectItemsTest.php:1821
‪TYPO3\CMS\Core\Imaging\IconRegistry
Definition: IconRegistry.php:34
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsGroupItemsWithSpecialModListGroup
‪addDataAddsGroupItemsWithSpecialModListGroup()
Definition: TcaSelectItemsTest.php:1153
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:45
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncWillUseItemsFromForeignTableAndRemoveItemsByPageTsConfig
‪addDataItemsProcFuncWillUseItemsFromForeignTableAndRemoveItemsByPageTsConfig()
Definition: TcaSelectItemsTest.php:3006
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems
Definition: TcaSelectItems.php:24
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueReturnsDuplicateValuesForMultipleSelect
‪processSelectFieldValueReturnsDuplicateValuesForMultipleSelect()
Definition: TcaSelectItemsTest.php:3797
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByZeroValueRemoveItemsPageTsConfig
‪addDataRemovesItemsByZeroValueRemoveItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:2440
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:21
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExcludeFieldsWithSpecialExclude
‪addDataAddsExcludeFieldsWithSpecialExclude($tca, $expectedItems)
Definition: TcaSelectItemsTest.php:592
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueTrimsEmptyValueForMultiValueSelect
‪processSelectFieldValueTrimsEmptyValueForMultiValueSelect()
Definition: TcaSelectItemsTest.php:3676
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:74
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:22
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataTranslatesItemLabelsFromPageTsConfig
‪addDataTranslatesItemLabelsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:3372
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsTablesWithSpecialTables
‪addDataAddsTablesWithSpecialTables()
Definition: TcaSelectItemsTest.php:343
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsLanguagesWithSpecialLanguages
‪addDataAddsLanguagesWithSpecialLanguages()
Definition: TcaSelectItemsTest.php:1042
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig
‪addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig()
Definition: TcaSelectItemsTest.php:2309
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByKeepItemsPageTsConfig
‪addDataRemovesItemsByKeepItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:2200
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsCustomOptionsWithSpecialCustom
‪addDataAddsCustomOptionsWithSpecialCustom()
Definition: TcaSelectItemsTest.php:1087
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueReturnsUniqueValuesForMultipleSelect
‪processSelectFieldValueReturnsUniqueValuesForMultipleSelect()
Definition: TcaSelectItemsTest.php:3839
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueSetsMmForeignRelationValues
‪processSelectFieldValueSetsMmForeignRelationValues()
Definition: TcaSelectItemsTest.php:3428
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\mockForeignTableItemsQuery
‪array mockForeignTableItemsQuery()
Definition: TcaSelectItemsTest.php:1902
‪$tca
‪$tca
Definition: sys_file_metadata.php:4
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataForeignTableResolvesIconFromSelicon
‪addDataForeignTableResolvesIconFromSelicon()
Definition: TcaSelectItemsTest.php:2110
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsByRemoveItemsPageTsConfig
‪addDataRemovesItemsByRemoveItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:2383
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsTablesWithSpecialPageTypes
‪addDataAddsTablesWithSpecialPageTypes()
Definition: TcaSelectItemsTest.php:408
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:29
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncEnqueuesFlashMessageOnException
‪addDataItemsProcFuncEnqueuesFlashMessageOnException()
Definition: TcaSelectItemsTest.php:3312
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest
Definition: TcaSelectItemsTest.php:49
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:25
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig
‪addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig()
Definition: TcaSelectItemsTest.php:2496
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\processSelectFieldValueKeepsValuesFromStaticItems
‪processSelectFieldValueKeepsValuesFromStaticItems()
Definition: TcaSelectItemsTest.php:3610
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:25
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionIfForeignTableIsNotDefinedInTca
‪addDataThrowsExceptionIfForeignTableIsNotDefinedInTca()
Definition: TcaSelectItemsTest.php:1727
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataAddsExplicitDenyFieldsWithSpecialExplicitValues
‪addDataAddsExplicitDenyFieldsWithSpecialExplicitValues()
Definition: TcaSelectItemsTest.php:778
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataThrowsExceptionWithUnknownSpecialValue
‪addDataThrowsExceptionWithUnknownSpecialValue()
Definition: TcaSelectItemsTest.php:314
‪TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer
Definition: DefaultRestrictionContainer.php:22
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\tearDown
‪tearDown()
Definition: TcaSelectItemsTest.php:76
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider
Definition: DatabaseDefaultLanguagePageRowTest.php:3
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataItemsProcFuncWillUseItemsFromForeignTableAndAddItemsByPageTsConfig
‪addDataItemsProcFuncWillUseItemsFromForeignTableAndAddItemsByPageTsConfig()
Definition: TcaSelectItemsTest.php:3123
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaSelectItemsTest\addDataKeepsIconFromItem
‪addDataKeepsIconFromItem()
Definition: TcaSelectItemsTest.php:277