TYPO3  7.6
TcaSelectItemsTest.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
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 Prophecy\Argument;
18 use Prophecy\Prophecy\ObjectProphecy;
23 use TYPO3\CMS\Core\Tests\UnitTestCase;
31 
35 class TcaSelectItemsTest extends UnitTestCase
36 {
40  protected $subject;
41 
45  protected $singletonInstances = [];
46 
47  protected function setUp()
48  {
49  $this->singletonInstances = GeneralUtility::getSingletonInstances();
50  $this->subject = new TcaSelectItems();
51  }
52 
53  protected function tearDown()
54  {
56  GeneralUtility::resetSingletonInstances($this->singletonInstances);
57  parent::tearDown();
58  }
59 
63  public function addDataKeepExistingItems()
64  {
65  $input = [
66  'processedTca' => [
67  'columns' => [
68  'aField' => [
69  'config' => [
70  'type' => 'radio',
71  'items' => [
72  0 => [
73  'foo',
74  'bar',
75  ],
76  ],
77  ],
78  ],
79  'anotherField' => [
80  'config' => [
81  'type' => 'group',
82  'items' => [
83  0 => [
84  'foo',
85  'bar',
86  ],
87  ],
88  ],
89  ],
90  ],
91  ],
92  ];
93  $languageService = $this->prophesize(LanguageService::class);
94  $GLOBALS['LANG'] = $languageService->reveal();
95  $languageService->sL(Argument::cetera())->willReturnArgument(0);
96 
97  $expected = $input;
98  $this->assertSame($expected, $this->subject->addData($input));
99  }
100 
105  {
106  $input = [
107  'processedTca' => [
108  'columns' => [
109  'aField' => [
110  'config' => [
111  'type' => 'select',
112  'renderType' => 'selectSingle',
113  'items' => [
114  0 => 'foo',
115  ],
116  ],
117  ],
118  ],
119  ],
120  ];
121 
122  $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439288036);
123 
124  $this->subject->addData($input);
125  }
126 
130  public function addDataTranslatesItemLabels()
131  {
132  $input = [
133  'databaseRow' => [
134  'aField' => 'aValue',
135  ],
136  'processedTca' => [
137  'columns' => [
138  'aField' => [
139  'config' => [
140  'type' => 'select',
141  'renderType' => 'selectSingle',
142  'items' => [
143  0 => [
144  0 => 'aLabel',
145  1 => 'aValue',
146  ],
147  ],
148  'maxitems' => 1
149  ],
150  ],
151  ],
152  ],
153  ];
154 
156  $languageService = $this->prophesize(LanguageService::class);
157  $GLOBALS['LANG'] = $languageService->reveal();
158  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
159 
160  $languageService->sL('aLabel')->shouldBeCalled()->willReturn('translated');
161 
162  $expected = $input;
163  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'translated';
164  $expected['processedTca']['columns']['aField']['config']['items'][0][2] = null;
165  $expected['processedTca']['columns']['aField']['config']['items'][0][3] = null;
166 
167  $expected['databaseRow']['aField'] = ['aValue'];
168 
169  $this->assertSame($expected, $this->subject->addData($input));
170  }
171 
175  public function addDataKeepsIconFromItem()
176  {
177  $input = [
178  'databaseRow' => [
179  'aField' => 'aValue',
180  ],
181  'processedTca' => [
182  'columns' => [
183  'aField' => [
184  'config' => [
185  'type' => 'select',
186  'renderType' => 'selectSingle',
187  'items' => [
188  0 => [
189  0 => 'aLabel',
190  1 => 'aValue',
191  2 => 'an-icon-reference',
192  3 => null,
193  ],
194  ],
195  'maxitems' => 1,
196  ],
197  ],
198  ],
199  ],
200  ];
201 
203  $languageService = $this->prophesize(LanguageService::class);
204  $GLOBALS['LANG'] = $languageService->reveal();
205  $languageService->sL(Argument::cetera())->willReturnArgument(0);
206 
207  $expected = $input;
208  $expected['databaseRow']['aField'] = ['aValue'];
209 
210  $this->assertSame($expected, $this->subject->addData($input));
211  }
212 
217  {
218  $input = [
219  'tableName' => 'aTable',
220  'processedTca' => [
221  'columns' => [
222  'aField' => [
223  'config' => [
224  'type' => 'select',
225  'renderType' => 'selectSingle',
226  'special' => 'anUnknownValue',
227  ],
228  ],
229  ],
230  ],
231  ];
232 
233  $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439298496);
234 
235  $this->subject->addData($input);
236  }
237 
241  public function addDataAddsTablesWithSpecialTables()
242  {
243  $input = [
244  'databaseRow' => [
245  'aField' => '',
246  ],
247  'tableName' => 'aTable',
248  'processedTca' => [
249  'columns' => [
250  'aField' => [
251  'config' => [
252  'type' => 'select',
253  'renderType' => 'selectSingle',
254  'special' => 'tables',
255  'maxitems' => 1,
256  ],
257  ],
258  ],
259  ],
260  ];
261  $GLOBALS['TCA'] = [
262  'notInResult' => [
263  'ctrl' => [
264  'adminOnly' => true,
265  ],
266  ],
267  'aTable' => [
268  'ctrl' => [
269  'title' => 'aTitle',
270  ],
271  ],
272  ];
273  $GLOBALS['TCA_DESCR']['aTable']['columns']['']['description'] = 'aDescription';
274 
276  $languageService = $this->prophesize(LanguageService::class);
277  $GLOBALS['LANG'] = $languageService->reveal();
278  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
279  $languageService->sL(Argument::containingString('INVALID VALUE'))->willReturnArgument(0);
280 
281  $languageService->sL('aTitle')->shouldBeCalled()->willReturnArgument(0);
282  $languageService->loadSingleTableDescription('aTable')->shouldBeCalled();
283 
284  $expected = $input;
285  $expected['databaseRow']['aField'] = [];
286  $expected['processedTca']['columns']['aField']['config']['items'] = [
287  0 => [
288  0 => 'aTitle',
289  1 => 'aTable',
290  2 => 'default-not-found',
291  3 => [
292  'description' => 'aDescription',
293  ],
294  ]
295  ];
296 
297  $this->assertSame($expected, $this->subject->addData($input));
298  }
299 
303  public function addDataAddsTablesWithSpecialPageTypes()
304  {
305  $input = [
306  'databaseRow' => [
307  'aField' => 'aValue',
308  ],
309  'tableName' => 'aTable',
310  'processedTca' => [
311  'columns' => [
312  'aField' => [
313  'config' => [
314  'type' => 'select',
315  'renderType' => 'selectSingle',
316  'special' => 'pagetypes',
317  'items' => [],
318  'maxitems' => 1,
319  ],
320  ],
321  ],
322  ],
323  ];
324  $GLOBALS['TCA'] = [
325  'pages' => [
326  'columns' => [
327  'doktype' => [
328  'config' => [
329  'items' => [
330  0 => [
331  0 => 'aLabel',
332  1 => 'aValue',
333  ],
334  ],
335  ],
336  ],
337  ],
338  ],
339  ];
340 
342  $languageService = $this->prophesize(LanguageService::class);
343  $GLOBALS['LANG'] = $languageService->reveal();
344  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
345 
346  $languageService->sL('aLabel')->shouldBeCalled()->willReturnArgument(0);
347 
348  $expected = $input;
349  $expected['databaseRow']['aField'] = ['aValue'];
350  $expected['processedTca']['columns']['aField']['config']['items'] = [
351  0 => [
352  0 => 'aLabel',
353  1 => 'aValue',
354  2 => 'default-not-found',
355  3 => null,
356  ]
357  ];
358 
359  $this->assertSame($expected, $this->subject->addData($input));
360  }
361 
366  {
367  return [
368  'Table with exclude and non exclude field returns exclude item' => [
369  [
370  // input tca
371  'fooTable' => [
372  'ctrl' => [
373  'title' => 'fooTableTitle',
374  ],
375  'columns' => [
376  'bar' => [
377  'label' => 'barColumnTitle',
378  'exclude' => 1
379  ],
380  'baz' => [
381  'label' => 'bazColumnTitle',
382  ],
383  ],
384  ],
385  ],
386  [
387  // expected items
388  0 => [
389  0 => 'fooTableTitle',
390  1 => '--div--',
391  2 => 'default-not-found',
392  3 => null,
393  ],
394  1 => [
395  0 => 'barColumnTitle (bar)',
396  1 => 'fooTable:bar',
397  2 => 'empty-empty',
398  3 => null,
399  ],
400  ],
401  ],
402  'Root level table with ignored root level restriction returns exclude item' => [
403  [
404  // input tca
405  'fooTable' => [
406  'ctrl' => [
407  'title' => 'fooTableTitle',
408  'rootLevel' => true,
409  'security' => [
410  'ignoreRootLevelRestriction' => true,
411  ],
412  ],
413  'columns' => [
414  'bar' => [
415  'label' => 'barColumnTitle',
416  'exclude' => 1,
417  ],
418  ],
419  ],
420  ],
421  [
422  // expected items
423  0 => [
424  0 => 'fooTableTitle',
425  1 => '--div--',
426  2 => 'default-not-found',
427  3 => null,
428  ],
429  1 => [
430  0 => 'barColumnTitle (bar)',
431  1 => 'fooTable:bar',
432  2 => 'empty-empty',
433  3 => null,
434  ],
435  ],
436  ],
437  'Root level table without ignored root level restriction returns no item' => [
438  [
439  // input tca
440  'fooTable' => [
441  'ctrl' => [
442  'title' => 'fooTableTitle',
443  'rootLevel' => true,
444  ],
445  'columns' => [
446  'bar' => [
447  'label' => 'barColumnTitle',
448  'exclude' => 1,
449  ],
450  ],
451  ],
452  ],
453  [
454  // no items
455  ],
456  ],
457  'Admin table returns no item' => [
458  [
459  // input tca
460  'fooTable' => [
461  'ctrl' => [
462  'title' => 'fooTableTitle',
463  'adminOnly' => true,
464  ],
465  'columns' => [
466  'bar' => [
467  'label' => 'barColumnTitle',
468  'exclude' => 1,
469  ],
470  ],
471  ],
472  ],
473  [
474  // no items
475  ],
476  ],
477  ];
478  }
479 
484  public function addDataAddsExcludeFieldsWithSpecialExclude($tca, $expectedItems)
485  {
486  $input = [
487  'tableName' => 'aTable',
488  'databaseRow' => [],
489  'processedTca' => [
490  'columns' => [
491  'aField' => [
492  'config' => [
493  'type' => 'select',
494  'renderType' => 'selectSingle',
495  'special' => 'exclude',
496  ],
497  ],
498  ],
499  ],
500  ];
501  $GLOBALS['TCA'] = $tca;
502 
504  $languageService = $this->prophesize(LanguageService::class);
505  $GLOBALS['LANG'] = $languageService->reveal();
506  $languageService->loadSingleTableDescription(Argument::cetera())->willReturn(null);
507  $languageService->sL(Argument::cetera())->willReturnArgument(0);
508 
509  $result = $this->subject->addData($input);
510 
511  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
512  }
513 
517  public function addDataAddsExcludeFieldsFromFlexWithSpecialExclude()
518  {
519  $input = [
520  'tableName' => 'aTable',
521  'databaseRow' => [],
522  'processedTca' => [
523  'columns' => [
524  'aField' => [
525  'config' => [
526  'type' => 'select',
527  'renderType' => 'selectSingle',
528  'special' => 'exclude',
529  ],
530  ],
531  ],
532  ],
533  ];
534 
535  $GLOBALS['TCA'] = [
536  'fooTable' => [
537  'ctrl' => [
538  'title' => 'fooTableTitle',
539  ],
540  'columns' => [
541  'aFlexField' => [
542  'label' => 'aFlexFieldTitle',
543  'config' => [
544  'type' => 'flex',
545  'title' => 'title',
546  'ds' => [
547  'dummy' => '
548  <T3DataStructure>
549  <ROOT>
550  <type>array</type>
551  <el>
552  <input1>
553  <TCEforms>
554  <label>flexInputLabel</label>
555  <exclude>1</exclude>
556  <config>
557  <type>input</type>
558  <size>23</size>
559  </config>
560  </TCEforms>
561  </input1>
562  </el>
563  </ROOT>
564  </T3DataStructure>
565  ',
566  ],
567  ],
568  ],
569  ],
570  ],
571  ];
572 
574  $languageService = $this->prophesize(LanguageService::class);
575  $GLOBALS['LANG'] = $languageService->reveal();
576  $languageService->loadSingleTableDescription(Argument::cetera())->willReturn(null);
577  $languageService->sL(Argument::cetera())->willReturnArgument(0);
578 
579  // Needed to suppress a cache in xml2array
581  $database = $this->prophesize(DatabaseConnection::class);
582  $GLOBALS['TYPO3_DB'] = $database->reveal();
583 
584  $expectedItems = [
585  0 => [
586  0 => 'fooTableTitle aFlexFieldTitle dummy',
587  1 => '--div--',
588  2 => 'default-not-found',
589  3 => null,
590  ],
591  1 => [
592  0 => 'flexInputLabel (input1)',
593  1 => 'fooTable:aFlexField;dummy;sDEF;input1',
594  2 => 'empty-empty',
595  3 => null,
596  ],
597  ];
598 
599  $result = $this->subject->addData($input);
600 
601  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
602  }
603 
607  public function addDataAddsExplicitAllowFieldsWithSpecialExplicitValues()
608  {
609  $input = [
610  'tableName' => 'aTable',
611  'databaseRow' => [],
612  'processedTca' => [
613  'columns' => [
614  'aField' => [
615  'config' => [
616  'type' => 'select',
617  'renderType' => 'selectSingle',
618  'special' => 'explicitValues',
619  ],
620  ],
621  ],
622  ],
623  ];
624 
625  $GLOBALS['TCA'] = [
626  'fooTable' => [
627  'ctrl' => [
628  'title' => 'fooTableTitle',
629  ],
630  'columns' => [
631  'aField' => [
632  'label' => 'aFieldTitle',
633  'config' => [
634  'type' => 'select',
635  'renderType' => 'selectSingle',
636  'authMode' => 'explicitAllow',
637  'items' => [
638  0 => [
639  'anItemTitle',
640  'anItemValue',
641  ],
642  ]
643  ],
644  ],
645  ],
646  ],
647  ];
648 
650  $languageService = $this->prophesize(LanguageService::class);
651  $GLOBALS['LANG'] = $languageService->reveal();
652  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
653  $languageService->sL(Argument::cetera())->willReturnArgument(0);
654 
655  $expectedItems = [
656  0 => [
657  0 => 'fooTableTitle: aFieldTitle',
658  1 => '--div--',
659  2 => null,
660  3 => null,
661  ],
662  1 => [
663  0 => '[allowMe] anItemTitle',
664  1 => 'fooTable:aField:anItemValue:ALLOW',
665  2 => 'status-status-permission-granted',
666  3 => null,
667  ],
668  ];
669 
670  $result = $this->subject->addData($input);
671 
672  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
673  }
674 
678  public function addDataAddsExplicitDenyFieldsWithSpecialExplicitValues()
679  {
680  $input = [
681  'tableName' => 'aTable',
682  'databaseRow' => [],
683  'processedTca' => [
684  'columns' => [
685  'aField' => [
686  'config' => [
687  'type' => 'select',
688  'renderType' => 'selectSingle',
689  'special' => 'explicitValues',
690  ],
691  ],
692  ],
693  ],
694  ];
695 
696  $GLOBALS['TCA'] = [
697  'fooTable' => [
698  'ctrl' => [
699  'title' => 'fooTableTitle',
700  ],
701  'columns' => [
702  'aField' => [
703  'label' => 'aFieldTitle',
704  'config' => [
705  'type' => 'select',
706  'renderType' => 'selectSingle',
707  'authMode' => 'explicitDeny',
708  'items' => [
709  0 => [
710  'anItemTitle',
711  'anItemValue',
712  ],
713  ]
714  ],
715  ],
716  ],
717  ],
718  ];
719 
721  $languageService = $this->prophesize(LanguageService::class);
722  $GLOBALS['LANG'] = $languageService->reveal();
723  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
724  $languageService->sL(Argument::cetera())->willReturnArgument(0);
725 
726  $expectedItems = [
727  0 => [
728  0 => 'fooTableTitle: aFieldTitle',
729  1 => '--div--',
730  2 => null,
731  3 => null,
732  ],
733  1 => [
734  0 => '[denyMe] anItemTitle',
735  1 => 'fooTable:aField:anItemValue:DENY',
736  2 => 'status-status-permission-denied',
737  3 => null,
738  ],
739  ];
740 
741  $result = $this->subject->addData($input);
742 
743  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
744  }
745 
749  public function addDataAddsExplicitIndividualAllowFieldsWithSpecialExplicitValues()
750  {
751  $input = [
752  'tableName' => 'aTable',
753  'databaseRow' => [],
754  'processedTca' => [
755  'columns' => [
756  'aField' => [
757  'config' => [
758  'type' => 'select',
759  'renderType' => 'selectSingle',
760  'special' => 'explicitValues',
761  ],
762  ],
763  ],
764  ],
765  ];
766 
767  $GLOBALS['TCA'] = [
768  'fooTable' => [
769  'ctrl' => [
770  'title' => 'fooTableTitle',
771  ],
772  'columns' => [
773  'aField' => [
774  'label' => 'aFieldTitle',
775  'config' => [
776  'type' => 'select',
777  'renderType' => 'selectSingle',
778  'authMode' => 'individual',
779  'items' => [
780  0 => [
781  'aItemTitle',
782  'aItemValue',
783  null,
784  null,
785  'EXPL_ALLOW',
786  ],
787  // 1 is not selectable as allow and is always allowed
788  1 => [
789  'bItemTitle',
790  'bItemValue',
791  ],
792  2 => [
793  'cItemTitle',
794  'cItemValue',
795  null,
796  null,
797  'EXPL_ALLOW',
798  ],
799  ]
800  ],
801  ],
802  ],
803  ],
804  ];
805 
807  $languageService = $this->prophesize(LanguageService::class);
808  $GLOBALS['LANG'] = $languageService->reveal();
809  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
810  $languageService->sL(Argument::cetera())->willReturnArgument(0);
811 
812  $expectedItems = [
813  0 => [
814  0 => 'fooTableTitle: aFieldTitle',
815  1 => '--div--',
816  2 => null,
817  3 => null,
818  ],
819  1 => [
820  0 => '[allowMe] aItemTitle',
821  1 => 'fooTable:aField:aItemValue:ALLOW',
822  2 => 'status-status-permission-granted',
823  3 => null,
824  ],
825  2 => [
826  0 => '[allowMe] cItemTitle',
827  1 => 'fooTable:aField:cItemValue:ALLOW',
828  2 => 'status-status-permission-granted',
829  3 => null,
830  ],
831  ];
832 
833  $result = $this->subject->addData($input);
834 
835  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
836  }
837 
841  public function addDataAddsExplicitIndividualDenyFieldsWithSpecialExplicitValues()
842  {
843  $input = [
844  'tableName' => 'aTable',
845  'databaseRow' => [],
846  'processedTca' => [
847  'columns' => [
848  'aField' => [
849  'config' => [
850  'type' => 'select',
851  'renderType' => 'selectSingle',
852  'special' => 'explicitValues',
853  ],
854  ],
855  ],
856  ],
857  ];
858 
859  $GLOBALS['TCA'] = [
860  'fooTable' => [
861  'ctrl' => [
862  'title' => 'fooTableTitle',
863  ],
864  'columns' => [
865  'aField' => [
866  'label' => 'aFieldTitle',
867  'config' => [
868  'type' => 'select',
869  'renderType' => 'selectSingle',
870  'authMode' => 'individual',
871  'items' => [
872  0 => [
873  'aItemTitle',
874  'aItemValue',
875  null,
876  null,
877  'EXPL_DENY',
878  ],
879  // 1 is not selectable as allow and is always allowed
880  1 => [
881  'bItemTitle',
882  'bItemValue',
883  ],
884  2 => [
885  'cItemTitle',
886  'cItemValue',
887  null,
888  null,
889  'EXPL_DENY',
890  ],
891  ]
892  ],
893  ],
894  ],
895  ],
896  ];
897 
899  $languageService = $this->prophesize(LanguageService::class);
900  $GLOBALS['LANG'] = $languageService->reveal();
901  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
902  $languageService->sL(Argument::cetera())->willReturnArgument(0);
903 
904  $expectedItems = [
905  0 => [
906  0 => 'fooTableTitle: aFieldTitle',
907  1 => '--div--',
908  2 => null,
909  3 => null,
910  ],
911  1 => [
912  0 => '[denyMe] aItemTitle',
913  1 => 'fooTable:aField:aItemValue:DENY',
914  2 => 'status-status-permission-denied',
915  3 => null,
916  ],
917  2 => [
918  0 => '[denyMe] cItemTitle',
919  1 => 'fooTable:aField:cItemValue:DENY',
920  2 => 'status-status-permission-denied',
921  3 => null,
922  ],
923  ];
924 
925  $result = $this->subject->addData($input);
926 
927  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
928  }
929 
933  public function addDataAddsLanguagesWithSpecialLanguages()
934  {
935  $input = [
936  'tableName' => 'aTable',
937  'databaseRow' => [],
938  'processedTca' => [
939  'columns' => [
940  'aField' => [
941  'config' => [
942  'type' => 'select',
943  'renderType' => 'selectSingle',
944  'special' => 'languages',
945  ],
946  ],
947  ],
948  ],
949  'systemLanguageRows' => [
950  0 => [
951  'title' => 'aLangTitle',
952  'uid' => 42,
953  'flagIconIdentifier' => 'aFlag.gif',
954  ],
955  ],
956  ];
957 
959  $languageService = $this->prophesize(LanguageService::class);
960  $GLOBALS['LANG'] = $languageService->reveal();
961  $languageService->sL(Argument::cetera())->willReturnArgument(0);
962 
963  $expectedItems = [
964  0 => [
965  0 => 'aLangTitle [42]',
966  1 => 42,
967  2 => 'aFlag.gif',
968  3 => null,
969  ],
970  ];
971 
972  $result = $this->subject->addData($input);
973 
974  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
975  }
976 
980  public function addDataAddsCustomOptionsWithSpecialCustom()
981  {
982  $input = [
983  'tableName' => 'aTable',
984  'databaseRow' => [],
985  'processedTca' => [
986  'columns' => [
987  'aField' => [
988  'config' => [
989  'type' => 'select',
990  'renderType' => 'selectSingle',
991  'special' => 'custom',
992  ],
993  ],
994  ],
995  ],
996  ];
997 
999  $languageService = $this->prophesize(LanguageService::class);
1000  $GLOBALS['LANG'] = $languageService->reveal();
1001  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1002 
1003  $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'] = [
1004  'aKey' => [
1005  'header' => 'aHeader',
1006  'items' => [
1007  'anItemKey' => [
1008  0 => 'anItemTitle',
1009  ],
1010  ],
1011  ]
1012  ];
1013 
1014  $expectedItems = [
1015  0 => [
1016  0 => 'aHeader',
1017  1 => '--div--',
1018  null,
1019  null,
1020  ],
1021  1 => [
1022  0 => 'anItemTitle',
1023  1 => 'aKey:anItemKey',
1024  2 => 'empty-empty',
1025  3 => null,
1026  ],
1027  ];
1028 
1029  $result = $this->subject->addData($input);
1030 
1031  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1032  }
1033 
1037  public function addDataAddsGroupItemsWithSpecialModListGroup()
1038  {
1039  $input = [
1040  'tableName' => 'aTable',
1041  'databaseRow' => [],
1042  'processedTca' => [
1043  'columns' => [
1044  'aField' => [
1045  'config' => [
1046  'type' => 'select',
1047  'renderType' => 'selectSingle',
1048  'special' => 'modListGroup',
1049  ],
1050  ],
1051  ],
1052  ],
1053  ];
1054 
1055  $GLOBALS['TBE_MODULES'] = [];
1056 
1058  $languageService = $this->prophesize(LanguageService::class);
1059  $GLOBALS['LANG'] = $languageService->reveal();
1060  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1061  $languageService->moduleLabels = [
1062  'tabs_images' => [
1063  'aModule_tab' => PATH_site . 'aModuleTabIcon.gif',
1064  ],
1065  'labels' => [
1066  'aModule_tablabel' => 'aModuleTabLabel',
1067  'aModule_tabdescr' => 'aModuleTabDescription',
1068  ],
1069  'tabs' => [
1070  'aModule_tab' => 'aModuleLabel',
1071  ]
1072  ];
1073 
1075  $moduleLoaderProphecy = $this->prophesize(ModuleLoader::class);
1076  GeneralUtility::addInstance(ModuleLoader::class, $moduleLoaderProphecy->reveal());
1077  $moduleLoaderProphecy->load([])->shouldBeCalled();
1078  $moduleLoaderProphecy->modListGroup = [
1079  'aModule',
1080  ];
1081 
1082  $expectedItems = [
1083  0 => [
1084  0 => 'aModuleLabel',
1085  1 => 'aModule',
1086  2 => '../aModuleTabIcon.gif',
1087  3 => [
1088  'title' => 'aModuleTabLabel',
1089  'description' => 'aModuleTabDescription',
1090  ],
1091  ],
1092  ];
1093 
1094  $result = $this->subject->addData($input);
1095 
1096  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1097  }
1098 
1102  public function addDataAddsFileItemsWithConfiguredFileFolder()
1103  {
1104  $directory = $this->getUniqueId('typo3temp/test-') . '/';
1105  $input = [
1106  'tableName' => 'aTable',
1107  'databaseRow' => [],
1108  'processedTca' => [
1109  'columns' => [
1110  'aField' => [
1111  'config' => [
1112  'type' => 'select',
1113  'renderType' => 'selectSingle',
1114  'fileFolder' => $directory,
1115  'fileFolder_extList' => 'gif',
1116  'fileFolder_recursions' => 1,
1117  ],
1118  ],
1119  ],
1120  ],
1121  ];
1122 
1124  $languageService = $this->prophesize(LanguageService::class);
1125  $GLOBALS['LANG'] = $languageService->reveal();
1126  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1127 
1128  mkdir(PATH_site . $directory);
1129  $this->testFilesToDelete[] = PATH_site . $directory;
1130  touch(PATH_site . $directory . 'anImage.gif');
1131  touch(PATH_site . $directory . 'aFile.txt');
1132  mkdir(PATH_site . $directory . '/subdir');
1133  touch(PATH_site . $directory . '/subdir/anotherImage.gif');
1134 
1135  $expectedItems = [
1136  0 => [
1137  0 => 'anImage.gif',
1138  1 => 'anImage.gif',
1139  2 => '../' . $directory . 'anImage.gif',
1140  3 => null,
1141  ],
1142  1 => [
1143  0 => 'subdir/anotherImage.gif',
1144  1 => 'subdir/anotherImage.gif',
1145  2 => '../' . $directory . 'subdir/anotherImage.gif',
1146  3 => null,
1147  ],
1148  ];
1149 
1150  $result = $this->subject->addData($input);
1151 
1152  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1153  }
1154 
1158  public function addDataAddsItemsByAddItemsFromPageTsConfig()
1159  {
1160  $input = [
1161  'databaseRow' => [
1162  'aField' => '',
1163  ],
1164  'tableName' => 'aTable',
1165  'processedTca' => [
1166  'columns' => [
1167  'aField' => [
1168  'config' => [
1169  'type' => 'select',
1170  'renderType' => 'selectSingle',
1171  'items' => [
1172  0 => [
1173  0 => 'keepMe',
1174  1 => 'keep',
1175  null,
1176  null,
1177  ],
1178  ],
1179  'maxitems' => 1,
1180  ],
1181  ],
1182  ]
1183  ],
1184  'pageTsConfig' => [
1185  'TCEFORM.' => [
1186  'aTable.' => [
1187  'aField.' => [
1188  'addItems.' => [
1189  '1' => 'addMe'
1190  ],
1191  ],
1192  ],
1193  ],
1194  ],
1195  ];
1196 
1198  $languageService = $this->prophesize(LanguageService::class);
1199  $GLOBALS['LANG'] = $languageService->reveal();
1200  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1201 
1202  $expected = $input;
1203  $expected['databaseRow']['aField'] = [];
1204  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1205  0 => 'addMe',
1206  1 => '1',
1207  null,
1208  null,
1209  ];
1210 
1211  $this->assertEquals($expected, $this->subject->addData($input));
1212  }
1213 
1217  public function addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig()
1218  {
1219  $input = [
1220  'databaseRow' => [
1221  'aField' => '',
1222  ],
1223  'tableName' => 'aTable',
1224  'processedTca' => [
1225  'columns' => [
1226  'aField' => [
1227  'config' => [
1228  'type' => 'select',
1229  'renderType' => 'selectSingle',
1230  'items' => [
1231  0 => [
1232  0 => 'keepMe',
1233  1 => 'keep',
1234  null,
1235  null,
1236  ],
1237  ],
1238  'maxitems' => 1,
1239  ],
1240  ],
1241  ]
1242  ],
1243  'pageTsConfig' => [
1244  'TCEFORM.' => [
1245  'aTable.' => [
1246  'aField.' => [
1247  'addItems.' => [
1248  'keep' => 'addMe'
1249  ],
1250  ],
1251  ],
1252  ],
1253  ],
1254  ];
1255 
1257  $languageService = $this->prophesize(LanguageService::class);
1258  $GLOBALS['LANG'] = $languageService->reveal();
1259  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1260 
1261  $expected = $input;
1262  $expected['databaseRow']['aField'] = [];
1263  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1264  0 => 'addMe',
1265  1 => 'keep',
1266  null,
1267  null,
1268  ];
1269 
1270  $this->assertEquals($expected, $this->subject->addData($input));
1271  }
1272 
1277  {
1278  return [
1279  'replace REC_FIELD' => [
1280  'AND fTable.title=\'###REC_FIELD_rowField###\'',
1281  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\'',
1282  [],
1283  ],
1284  'replace REC_FIELD fullQuote' => [
1285  'AND fTable.title=###REC_FIELD_rowField###',
1286  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\'',
1287  [],
1288  ],
1289  'replace REC_FIELD fullQuoteWithArray' => [
1290  'AND fTable.title=###REC_FIELD_rowFieldThree###',
1291  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldThreeValue\'',
1292  [
1293  'databaseRow' => [
1294  'rowFieldThree' => [
1295  0 => 'rowFieldThreeValue'
1296  ]
1297  ],
1298  ],
1299  ],
1300  'replace REC_FIELD multiple markers' => [
1301  'AND fTable.title=\'###REC_FIELD_rowField###\' AND fTable.pid=###REC_FIELD_rowFieldTwo###',
1302  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\' AND fTable.pid=\'rowFieldTwoValue\'',
1303  [],
1304  ],
1305  'replace CURRENT_PID' => [
1306  'AND fTable.uid=###CURRENT_PID###',
1307  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=43',
1308  [],
1309  ],
1310  'replace CURRENT_PID integer cast' => [
1311  'AND fTable.uid=###CURRENT_PID###',
1312  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=431',
1313  [
1314  'effectivePid' => '431string',
1315  ],
1316  ],
1317  'replace THIS_UID' => [
1318  'AND fTable.uid=###THIS_UID###',
1319  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=42',
1320  [],
1321  ],
1322  'replace THIS_UID integer cast' => [
1323  'AND fTable.uid=###THIS_UID###',
1324  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=421',
1325  [
1326  'databaseRow' => [
1327  'uid' => '421string',
1328  ],
1329  ],
1330  ],
1331  'replace SITEROOT' => [
1332  'AND fTable.uid=###SITEROOT###',
1333  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=44',
1334  [],
1335  ],
1336  'replace SITEROOT integer cast' => [
1337  'AND fTable.uid=###SITEROOT###',
1338  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=441',
1339  [
1340  'rootline' => [
1341  1 => [
1342  'uid' => '441string',
1343  ],
1344  ],
1345  ],
1346  ],
1347  'replace PAGE_TSCONFIG_ID' => [
1348  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1349  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=45',
1350  [],
1351  ],
1352  'replace PAGE_TSCONFIG_ID integer cast' => [
1353  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1354  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=451',
1355  [
1356  'pageTsConfig' => [
1357  'TCEFORM.' => [
1358  'aTable.' => [
1359  'aField.' => [
1360  'PAGE_TSCONFIG_ID' => '451string'
1361  ],
1362  ],
1363  ],
1364  ],
1365  ],
1366  ],
1367  'replace PAGE_TSCONFIG_STR' => [
1368  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1369  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=\'46\'',
1370  [],
1371  ],
1372  'replace PAGE_TSCONFIG_IDLIST' => [
1373  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1374  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (47,48)',
1375  [],
1376  ],
1377  'replace PAGE_TSCONFIG_IDLIST cleans list' => [
1378  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1379  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (471,481)',
1380  [
1381  'pageTsConfig' => [
1382  'TCEFORM.' => [
1383  'aTable.' => [
1384  'aField.' => [
1385  'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
1386  ],
1387  ],
1388  ],
1389  ],
1390  ],
1391  ],
1392  ];
1393  }
1394 
1399  public function addDataReplacesMarkersInForeignTableClause($foreignTableWhere, $expectedWhere, array $inputOverride)
1400  {
1401  $input = [
1402  'tableName' => 'aTable',
1403  'effectivePid' => 43,
1404  'databaseRow' => [
1405  'uid' => 42,
1406  'rowField' => 'rowFieldValue',
1407  'rowFieldTwo' => 'rowFieldTwoValue',
1408  ],
1409  'processedTca' => [
1410  'columns' => [
1411  'aField' => [
1412  'config' => [
1413  'type' => 'select',
1414  'renderType' => 'selectSingle',
1415  'foreign_table' => 'fTable',
1416  'foreign_table_where' => $foreignTableWhere,
1417  ],
1418  ],
1419  ]
1420  ],
1421  'rootline' => [
1422  2 => [
1423  'uid' => 999,
1424  'is_siteroot' => 0,
1425  ],
1426  1 => [
1427  'uid' => 44,
1428  'is_siteroot' => 1,
1429  ],
1430  0 => [
1431  'uid' => 0,
1432  'is_siteroot' => null,
1433  ],
1434  ],
1435  'pageTsConfig' => [
1436  'TCEFORM.' => [
1437  'aTable.' => [
1438  'aField.' => [
1439  'PAGE_TSCONFIG_ID' => 45,
1440  'PAGE_TSCONFIG_STR' => '46',
1441  'PAGE_TSCONFIG_IDLIST' => '47, 48',
1442  ],
1443  ],
1444  ],
1445  ],
1446  ];
1447  ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
1448 
1449  $GLOBALS['TCA']['fTable'] = [];
1450 
1451  $expectedQueryArray = [
1452  'SELECT' => 'fTable.uid',
1453  'FROM' => 'fTable, pages',
1454  'WHERE' => $expectedWhere,
1455  'GROUPBY' => '',
1456  'ORDERBY' => '',
1457  'LIMIT' => '',
1458  ];
1459 
1461  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1462  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1463  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1464 
1466  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1467  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1468  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1469  $databaseProphecy->quoteStr(Argument::cetera())->willReturnArgument(0);
1470  $databaseProphecy->fullQuoteStr(Argument::cetera())->will(function ($args) {
1471  return '\'' . $args[0] . '\'';
1472  });
1473  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn(false);
1474  $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(null);
1475 
1476  $databaseProphecy->exec_SELECT_queryArray($expectedQueryArray)->shouldBeCalled()->willReturn(false);
1477 
1478  $this->subject->addData($input);
1479  }
1480 
1485  {
1486  $input = [
1487  'tableName' => 'aTable',
1488  'processedTca' => [
1489  'columns' => [
1490  'aField' => [
1491  'config' => [
1492  'type' => 'select',
1493  'renderType' => 'selectSingle',
1494  'foreign_table' => 'fTable',
1495  ],
1496  ],
1497  ]
1498  ],
1499  ];
1500 
1501  $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439569743);
1502 
1503  $this->subject->addData($input);
1504  }
1505 
1509  public function addDataForeignTableSplitsGroupOrderAndLimit()
1510  {
1511  $input = [
1512  'tableName' => 'aTable',
1513  'databaseRow' => [],
1514  'processedTca' => [
1515  'columns' => [
1516  'aField' => [
1517  'config' => [
1518  'type' => 'select',
1519  'renderType' => 'selectSingle',
1520  'foreign_table' => 'fTable',
1521  'foreign_table_where' => 'AND ftable.uid=1 GROUP BY groupField ORDER BY orderField LIMIT 1,2',
1522  ],
1523  ],
1524  ]
1525  ],
1526  'rootline' => [],
1527  ];
1528 
1529  $GLOBALS['TCA']['fTable'] = [];
1530 
1531  $expectedQueryArray = [
1532  'SELECT' => 'fTable.uid',
1533  'FROM' => 'fTable, pages',
1534  'WHERE' => 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND ftable.uid=1',
1535  'GROUPBY' => 'groupField',
1536  'ORDERBY' => 'orderField',
1537  'LIMIT' => '1,2',
1538  ];
1539 
1541  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1542  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1543  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1544 
1546  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1547  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1548  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1549  $databaseProphecy->quoteStr(Argument::cetera())->willReturnArgument(0);
1550  $databaseProphecy->fullQuoteStr(Argument::cetera())->will(function ($args) {
1551  return '\'' . $args[0] . '\'';
1552  });
1553  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn(false);
1554  $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(null);
1555 
1556  $databaseProphecy->exec_SELECT_queryArray($expectedQueryArray)->shouldBeCalled()->willReturn(false);
1557 
1558  $this->subject->addData($input);
1559  }
1560 
1564  public function addDataForeignTableQueuesFlashMessageOnDatabaseError()
1565  {
1566  $input = [
1567  'databaseRow' => [
1568  'aField' => '',
1569  ],
1570  'tableName' => 'aTable',
1571  'processedTca' => [
1572  'columns' => [
1573  'aField' => [
1574  'config' => [
1575  'type' => 'select',
1576  'renderType' => 'selectSingle',
1577  'foreign_table' => 'fTable',
1578  'items' => [
1579  0 => [
1580  0 => 'itemLabel',
1581  1 => 'itemValue',
1582  2 => null,
1583  3 => null,
1584  ],
1585  ],
1586  'maxitems' => 1,
1587  ],
1588  ],
1589  ]
1590  ],
1591  'rootline' => [],
1592  ];
1593 
1594  $GLOBALS['TCA']['fTable'] = [];
1595 
1597  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1598  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1599  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1600 
1602  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1603  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1604  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1605 
1607  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1608  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1609  $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(false);
1610 
1611  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn('anError');
1612  $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(null);
1613 
1615  $flashMessage = $this->prophesize(FlashMessage::class);
1616  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1618  $flashMessageService = $this->prophesize(FlashMessageService::class);
1619  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1621  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1622  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1623 
1624  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
1625 
1626  $expected = $input;
1627  $expected['databaseRow']['aField'] = [];
1628 
1629  $this->assertEquals($expected, $this->subject->addData($input));
1630  }
1631 
1635  public function addDataForeignTableHandlesForeignTableRows()
1636  {
1637  $input = [
1638  'databaseRow' => [
1639  'aField' => '',
1640  ],
1641  'tableName' => 'aTable',
1642  'processedTca' => [
1643  'columns' => [
1644  'aField' => [
1645  'config' => [
1646  'type' => 'select',
1647  'renderType' => 'selectSingle',
1648  'foreign_table' => 'fTable',
1649  'foreign_table_prefix' => 'aPrefix',
1650  'items' => [],
1651  'maxitems' => 1,
1652  ],
1653  ],
1654  ]
1655  ],
1656  'rootline' => [],
1657  ];
1658 
1659  $GLOBALS['TCA']['fTable'] = [];
1660 
1662  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1663  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1664  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1665 
1667  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1668  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1669  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1670 
1672  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1673  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1674  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1675  $databaseProphecy->sql_free_result(Argument::cetera())->willReturn(null);
1676  $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(true);
1677 
1678  $counter = 0;
1679  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->will(function ($args) use (&$counter) {
1680  $counter++;
1681  if ($counter >= 3) {
1682  return false;
1683  }
1684  return [
1685  'uid' => $counter,
1686  'aValue' => 'bar,',
1687  ];
1688  });
1689 
1690  $expected = $input;
1691  $expected['processedTca']['columns']['aField']['config']['items'] = [
1692  0 => [
1693  0 => 'aPrefix[LLL:EXT:lang/locallang_core.xlf:labels.no_title]',
1694  1 => 1,
1695  2 => 'default-not-found',
1696  3 => null,
1697  ],
1698  1 => [
1699  0 => 'aPrefix[LLL:EXT:lang/locallang_core.xlf:labels.no_title]',
1700  1 => 2,
1701  2 => 'default-not-found',
1702  3 => null,
1703  ],
1704  ];
1705 
1706  $expected['databaseRow']['aField'] = [];
1707 
1708  $this->assertEquals($expected, $this->subject->addData($input));
1709  }
1710 
1714  public function addDataRemovesItemsByKeepItemsPageTsConfig()
1715  {
1716  $input = [
1717  'databaseRow' => [
1718  'aField' => '',
1719  ],
1720  'tableName' => 'aTable',
1721  'processedTca' => [
1722  'columns' => [
1723  'aField' => [
1724  'config' => [
1725  'type' => 'select',
1726  'renderType' => 'selectSingle',
1727  'items' => [
1728  0 => [
1729  0 => 'keepMe',
1730  1 => 'keep',
1731  null,
1732  null,
1733  ],
1734  1 => [
1735  0 => 'removeMe',
1736  1 => 'remove',
1737  ],
1738  ],
1739  'maxitems' => 1,
1740  ],
1741  ],
1742  ]
1743  ],
1744  'pageTsConfig' => [
1745  'TCEFORM.' => [
1746  'aTable.' => [
1747  'aField.' => [
1748  'keepItems' => 'keep',
1749  ],
1750  ],
1751  ],
1752  ],
1753  ];
1754 
1756  $languageService = $this->prophesize(LanguageService::class);
1757  $GLOBALS['LANG'] = $languageService->reveal();
1758  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1759 
1760  $expected = $input;
1761  $expected['databaseRow']['aField'] = [];
1762  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1763 
1764  $this->assertEquals($expected, $this->subject->addData($input));
1765  }
1766 
1770  public function addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig()
1771  {
1772  $input = [
1773  'databaseRow' => [
1774  'aField' => '',
1775  ],
1776  'tableName' => 'aTable',
1777  'processedTca' => [
1778  'columns' => [
1779  'aField' => [
1780  'config' => [
1781  'type' => 'select',
1782  'renderType' => 'selectSingle',
1783  'items' => [
1784  0 => [
1785  0 => 'keepMe',
1786  1 => 'keep',
1787  null,
1788  null,
1789  ],
1790  1 => [
1791  0 => 'removeMe',
1792  1 => 'remove',
1793  ],
1794  ],
1795  'maxitems' => 1,
1796  ],
1797  ],
1798  ]
1799  ],
1800  'pageTsConfig' => [
1801  'TCEFORM.' => [
1802  'aTable.' => [
1803  'aField.' => [
1804  'keepItems' => '',
1805  ],
1806  ],
1807  ],
1808  ],
1809  ];
1810 
1812  $languageService = $this->prophesize(LanguageService::class);
1813  $GLOBALS['LANG'] = $languageService->reveal();
1814  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1815 
1816  $expected = $input;
1817  $expected['databaseRow']['aField'] = [];
1818  $expected['processedTca']['columns']['aField']['config']['items'] = [];
1819 
1820  $this->assertEquals($expected, $this->subject->addData($input));
1821  }
1822 
1826  public function addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig()
1827  {
1828  $input = [
1829  'databaseRow' => [
1830  'aField' => '',
1831  ],
1832  'tableName' => 'aTable',
1833  'processedTca' => [
1834  'columns' => [
1835  'aField' => [
1836  'config' => [
1837  'type' => 'select',
1838  'renderType' => 'selectSingle',
1839  'items' => [
1840  0 => [
1841  0 => 'keepMe',
1842  1 => '1',
1843  null,
1844  null,
1845  ],
1846  1 => [
1847  0 => 'removeMe',
1848  1 => 'remove',
1849  ],
1850  ],
1851  'maxitems' => 1,
1852  ],
1853  ],
1854  ]
1855  ],
1856  'pageTsConfig' => [
1857  'TCEFORM.' => [
1858  'aTable.' => [
1859  'aField.' => [
1860  'keepItems' => '1',
1861  'addItems.' => [
1862  '1' => 'addItem #1',
1863  '12' => 'addItem #12',
1864  ],
1865  ],
1866  ],
1867  ],
1868  ],
1869  ];
1870 
1872  $languageService = $this->prophesize(LanguageService::class);
1873  $GLOBALS['LANG'] = $languageService->reveal();
1874  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1875 
1876  $expected = $input;
1877  $expected['databaseRow']['aField'] = [];
1878  $expected['processedTca']['columns']['aField']['config']['items'] = [
1879  0 => [
1880  0 => 'keepMe',
1881  1 => '1',
1882  null,
1883  null,
1884  ],
1885  1 => [
1886  0 => 'addItem #1',
1887  1 => '1',
1888  null,
1889  null,
1890  ],
1891  2 => [
1892  0 => 'addItem #12',
1893  1 => '12',
1894  null,
1895  null,
1896  ],
1897  ];
1898 
1899  $this->assertEquals($expected, $this->subject->addData($input));
1900  }
1901 
1905  public function addDataRemovesItemsByRemoveItemsPageTsConfig()
1906  {
1907  $input = [
1908  'databaseRow' => [
1909  'aField' => ''
1910  ],
1911  'tableName' => 'aTable',
1912  'processedTca' => [
1913  'columns' => [
1914  'aField' => [
1915  'config' => [
1916  'type' => 'select',
1917  'renderType' => 'selectSingle',
1918  'items' => [
1919  0 => [
1920  0 => 'keepMe',
1921  1 => 'keep',
1922  null,
1923  null,
1924  ],
1925  1 => [
1926  0 => 'removeMe',
1927  1 => 'remove',
1928  ],
1929  ],
1930  'maxitems' => 1,
1931  ],
1932  ],
1933  ]
1934  ],
1935  'pageTsConfig' => [
1936  'TCEFORM.' => [
1937  'aTable.' => [
1938  'aField.' => [
1939  'removeItems' => 'remove',
1940  ],
1941  ],
1942  ],
1943  ],
1944  ];
1945 
1947  $languageService = $this->prophesize(LanguageService::class);
1948  $GLOBALS['LANG'] = $languageService->reveal();
1949  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1950 
1951  $expected = $input;
1952  $expected['databaseRow']['aField'] = [];
1953  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1954 
1955  $this->assertEquals($expected, $this->subject->addData($input));
1956  }
1957 
1961  public function addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig()
1962  {
1963  $input = [
1964  'databaseRow' => [
1965  'aField' => ''
1966  ],
1967  'tableName' => 'aTable',
1968  'processedTca' => [
1969  'columns' => [
1970  'aField' => [
1971  'config' => [
1972  'type' => 'select',
1973  'renderType' => 'selectSingle',
1974  'items' => [
1975  0 => [
1976  0 => 'keepMe',
1977  1 => 'keep',
1978  null,
1979  null,
1980  ],
1981  1 => [
1982  0 => 'removeMe',
1983  1 => 'remove',
1984  ],
1985  ],
1986  'maxitems' => 1,
1987  ],
1988  ],
1989  ]
1990  ],
1991  'pageTsConfig' => [
1992  'TCEFORM.' => [
1993  'aTable.' => [
1994  'aField.' => [
1995  'removeItems' => 'remove,add',
1996  'addItems.' => [
1997  'add' => 'addMe'
1998  ]
1999  ],
2000  ],
2001  ],
2002  ],
2003  ];
2004 
2006  $languageService = $this->prophesize(LanguageService::class);
2007  $GLOBALS['LANG'] = $languageService->reveal();
2008  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2009 
2010  $expected = $input;
2011  $expected['databaseRow']['aField'] = [];
2012  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2013 
2014  $this->assertEquals($expected, $this->subject->addData($input));
2015  }
2016 
2020  public function addDataRemovesItemsByLanguageFieldUserRestriction()
2021  {
2022  $input = [
2023  'databaseRow' => [
2024  'aField' => 'aValue,remove'
2025  ],
2026  'tableName' => 'aTable',
2027  'processedTca' => [
2028  'ctrl' => [
2029  'languageField' => 'aField',
2030  ],
2031  'columns' => [
2032  'aField' => [
2033  'config' => [
2034  'type' => 'select',
2035  'renderType' => 'selectSingle',
2036  'items' => [
2037  0 => [
2038  0 => 'keepMe',
2039  1 => 'keep',
2040  null,
2041  null,
2042  ],
2043  1 => [
2044  0 => 'removeMe',
2045  1 => 'remove',
2046  ],
2047  ],
2048  'maxitems' => 1,
2049  ],
2050  ],
2051  ]
2052  ],
2053  ];
2054 
2056  $languageService = $this->prophesize(LanguageService::class);
2057  $GLOBALS['LANG'] = $languageService->reveal();
2058  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2059  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2060 
2062  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2063  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2064  $backendUserProphecy->checkLanguageAccess('keep')->shouldBeCalled()->willReturn(true);
2065  $backendUserProphecy->checkLanguageAccess('remove')->shouldBeCalled()->willReturn(false);
2066 
2067  $expected = $input;
2068  $expected['databaseRow']['aField'] = [];
2069  $expected['processedTca']['columns']['aField']['config']['items'] = [
2070  [ '[ INVALID VALUE "aValue" ]', 'aValue', null, null ],
2071  [ 'keepMe', 'keep', null, null ],
2072  ];
2073 
2074  $this->assertEquals($expected, $this->subject->addData($input));
2075  }
2076 
2080  public function addDataRemovesItemsByUserAuthModeRestriction()
2081  {
2082  $input = [
2083  'databaseRow' => [
2084  'aField' => 'keep,remove'
2085  ],
2086  'tableName' => 'aTable',
2087  'processedTca' => [
2088  'columns' => [
2089  'aField' => [
2090  'config' => [
2091  'type' => 'select',
2092  'renderType' => 'selectSingle',
2093  'authMode' => 'explicitAllow',
2094  'items' => [
2095  0 => [
2096  0 => 'keepMe',
2097  1 => 'keep',
2098  null,
2099  null,
2100  ],
2101  1 => [
2102  0 => 'removeMe',
2103  1 => 'remove',
2104  ],
2105  ],
2106  'maxitems' => 1,
2107  ],
2108  ],
2109  ]
2110  ],
2111  ];
2112 
2114  $languageService = $this->prophesize(LanguageService::class);
2115  $GLOBALS['LANG'] = $languageService->reveal();
2116  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2117 
2119  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2120  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2121  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'keep', 'explicitAllow')->shouldBeCalled()->willReturn(true);
2122  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'remove', 'explicitAllow')->shouldBeCalled()->willReturn(false);
2123 
2124  $expected = $input;
2125  $expected['databaseRow']['aField'] = ['keep'];
2126  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2127 
2128  $this->assertEquals($expected, $this->subject->addData($input));
2129  }
2130 
2134  public function addDataKeepsAllPagesDoktypesForAdminUser()
2135  {
2136  $input = [
2137  'databaseRow' => [
2138  'doktype' => 'keep'
2139  ],
2140  'tableName' => 'pages',
2141  'processedTca' => [
2142  'columns' => [
2143  'doktype' => [
2144  'config' => [
2145  'type' => 'select',
2146  'renderType' => 'selectSingle',
2147  'items' => [
2148  0 => [
2149  0 => 'keepMe',
2150  1 => 'keep',
2151  null,
2152  null,
2153  ],
2154  ],
2155  'maxitems' => 1,
2156  ],
2157  ],
2158  ],
2159  ],
2160  ];
2161 
2163  $languageService = $this->prophesize(LanguageService::class);
2164  $GLOBALS['LANG'] = $languageService->reveal();
2165  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2166 
2168  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2169  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2170  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(true);
2171 
2172  $expected = $input;
2173  $expected['databaseRow']['doktype'] = ['keep'];
2174 
2175  $this->assertEquals($expected, $this->subject->addData($input));
2176  }
2177 
2181  public function addDataKeepsAllowedPageTypesForNonAdminUser()
2182  {
2183  $input = [
2184  'databaseRow' => [
2185  'doktype' => 'keep',
2186  ],
2187  'tableName' => 'pages',
2188  'processedTca' => [
2189  'columns' => [
2190  'doktype' => [
2191  'config' => [
2192  'type' => 'select',
2193  'renderType' => 'selectSingle',
2194  'items' => [
2195  0 => [
2196  0 => 'keepMe',
2197  1 => 'keep',
2198  null,
2199  null,
2200  ],
2201  1 => [
2202  0 => 'removeMe',
2203  1 => 'remove',
2204  ],
2205  ],
2206  'maxitems' => 1,
2207  ],
2208  ],
2209  ],
2210  ],
2211  ];
2212 
2214  $languageService = $this->prophesize(LanguageService::class);
2215  $GLOBALS['LANG'] = $languageService->reveal();
2216  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2217 
2219  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2220  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2221  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
2222  $backendUserProphecy->groupData = [
2223  'pagetypes_select' => 'foo,keep,anotherAllowedDoktype',
2224  ];
2225 
2226  $expected = $input;
2227  $expected['databaseRow']['doktype'] = ['keep'];
2228  unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
2229 
2230  $this->assertEquals($expected, $this->subject->addData($input));
2231  }
2232 
2236  public function addDataCallsItemsProcFunc()
2237  {
2238  $input = [
2239  'tableName' => 'aTable',
2240  'databaseRow' => [
2241  'aField' => 'aValue'
2242  ],
2243  'processedTca' => [
2244  'columns' => [
2245  'aField' => [
2246  'config' => [
2247  'type' => 'select',
2248  'renderType' => 'selectSingle',
2249  'items' => [],
2250  'itemsProcFunc' => function (array $parameters, $pObj) {
2251  $parameters['items'] = [
2252  0 => [
2253  0 => 'aLabel',
2254  1 => 'aValue',
2255  2 => null,
2256  3 => null,
2257  ],
2258  ];
2259  },
2260  ],
2261  ],
2262  ],
2263  ],
2264  ];
2265 
2267  $languageService = $this->prophesize(LanguageService::class);
2268  $GLOBALS['LANG'] = $languageService->reveal();
2269  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2270 
2271  $expected = $input;
2272  $expected['databaseRow']['aField'] = ['aValue'];
2273  $expected['processedTca']['columns']['aField']['config'] = [
2274  'type' => 'select',
2275  'renderType' => 'selectSingle',
2276  'items' => [
2277  0 => [
2278  0 => 'aLabel',
2279  1 => 'aValue',
2280  2 => null,
2281  3 => null,
2282  ],
2283  ],
2284  'maxitems' => 1,
2285  ];
2286 
2287  $this->assertSame($expected, $this->subject->addData($input));
2288  }
2289 
2293  public function addDataItemsProcFuncReceivesParameters()
2294  {
2295  $input = [
2296  'tableName' => 'aTable',
2297  'databaseRow' => [
2298  'aField' => 'aValue',
2299  ],
2300  'pageTsConfig' => [
2301  'TCEFORM.' => [
2302  'aTable.' => [
2303  'aField.' => [
2304  'itemsProcFunc.' => [
2305  'itemParamKey' => 'itemParamValue',
2306  ],
2307  ]
2308  ],
2309  ],
2310  ],
2311  'processedTca' => [
2312  'columns' => [
2313  'aField' => [
2314  'config' => [
2315  'type' => 'select',
2316  'renderType' => 'selectSingle',
2317  'aKey' => 'aValue',
2318  'items' => [
2319  0 => [
2320  0 => 'aLabel',
2321  1 => 'aValue',
2322  ],
2323  ],
2324  'itemsProcFunc' => function (array $parameters, $pObj) {
2325  if ($parameters['items'] !== [ 0 => [ 'aLabel', 'aValue'] ]
2326  || $parameters['config']['aKey'] !== 'aValue'
2327  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
2328  || $parameters['table'] !== 'aTable'
2329  || $parameters['row'] !== [ 'aField' => 'aValue' ]
2330  || $parameters['field'] !== 'aField'
2331  ) {
2332  throw new \UnexpectedValueException('broken', 1438604329);
2333  }
2334  },
2335  ],
2336  ],
2337  ],
2338  ],
2339  ];
2340 
2341  $languageService = $this->prophesize(LanguageService::class);
2342  $GLOBALS['LANG'] = $languageService->reveal();
2343  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2345  $flashMessage = $this->prophesize(FlashMessage::class);
2346  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2348  $flashMessageService = $this->prophesize(FlashMessageService::class);
2349  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2351  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2352  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2353 
2354  // itemsProcFunc must NOT have raised an exception
2355  $flashMessageQueue->enqueue($flashMessage)->shouldNotBeCalled();
2356 
2357  $this->subject->addData($input);
2358  }
2359 
2363  public function addDataItemsProcFuncEnqueuesFlashMessageOnException()
2364  {
2365  $input = [
2366  'tableName' => 'aTable',
2367  'databaseRow' => [
2368  'aField' => 'aValue',
2369  ],
2370  'pageTsConfig' => [
2371  'TCEFORM.' => [
2372  'aTable.' => [
2373  'aField.' => [
2374  'itemsProcFunc.' => [
2375  'itemParamKey' => 'itemParamValue',
2376  ],
2377  ]
2378  ],
2379  ],
2380  ],
2381  'processedTca' => [
2382  'columns' => [
2383  'aField' => [
2384  'config' => [
2385  'type' => 'select',
2386  'renderType' => 'selectSingle',
2387  'aKey' => 'aValue',
2388  'items' => [
2389  0 => [
2390  0 => 'aLabel',
2391  1 => 'aValue',
2392  ],
2393  ],
2394  'itemsProcFunc' => function (array $parameters, $pObj) {
2395  throw new \UnexpectedValueException('anException', 1438604329);
2396  },
2397  ],
2398  ],
2399  ],
2400  ],
2401  ];
2402 
2403  $languageService = $this->prophesize(LanguageService::class);
2404  $GLOBALS['LANG'] = $languageService->reveal();
2406  $flashMessage = $this->prophesize(FlashMessage::class);
2407  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2409  $flashMessageService = $this->prophesize(FlashMessageService::class);
2410  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2412  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2413  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2414 
2415  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
2416 
2417  $this->subject->addData($input);
2418  }
2419 
2423  public function addDataTranslatesItemLabelsFromPageTsConfig()
2424  {
2425  $input = [
2426  'databaseRow' => [
2427  'aField' => 'aValue',
2428  ],
2429  'tableName' => 'aTable',
2430  'processedTca' => [
2431  'columns' => [
2432  'aField' => [
2433  'config' => [
2434  'type' => 'select',
2435  'renderType' => 'selectSingle',
2436  'items' => [
2437  0 => [
2438  0 => 'aLabel',
2439  1 => 'aValue',
2440  null,
2441  null,
2442  ],
2443  ],
2444  'maxitems' => 1,
2445  ],
2446  ],
2447  ],
2448  ],
2449  'pageTsConfig' => [
2450  'TCEFORM.' => [
2451  'aTable.' => [
2452  'aField.' => [
2453  'altLabels.' => [
2454  'aValue' => 'labelOverride',
2455  ],
2456  ]
2457  ],
2458  ],
2459  ],
2460  ];
2461 
2463  $languageService = $this->prophesize(LanguageService::class);
2464  $GLOBALS['LANG'] = $languageService->reveal();
2465  $languageService->sL('aLabel')->willReturnArgument(0);
2466  $languageService->sL('labelOverride')->shouldBeCalled()->willReturnArgument(0);
2467  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2468 
2469  $expected = $input;
2470  $expected['databaseRow']['aField'] = ['aValue'];
2471  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'labelOverride';
2472 
2473  $this->assertSame($expected, $this->subject->addData($input));
2474  $this->subject->addData($input);
2475  }
2476 
2480  public function processSelectFieldValueSetsMmForeignRelationValues()
2481  {
2482  $GLOBALS['TCA']['foreignTable'] = [];
2483 
2485  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2486  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2487 
2489  $database = $this->prophesize(DatabaseConnection::class);
2490  $GLOBALS['TYPO3_DB'] = $database->reveal();
2491 
2492  $input = [
2493  'tableName' => 'aTable',
2494  'databaseRow' => [
2495  'uid' => 42,
2496  // Two connected rows
2497  'aField' => 2,
2498  ],
2499  'processedTca' => [
2500  'columns' => [
2501  'aField' => [
2502  'config' => [
2503  'type' => 'select',
2504  'renderType' => 'selectSingle',
2505  'maxitems' => 999,
2506  'foreign_table' => 'foreignTable',
2507  'MM' => 'aTable_foreignTable_mm',
2508  'items' => [],
2509  ],
2510  ],
2511  ],
2512  ],
2513  ];
2514  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2516  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2517  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2518 
2519  $relationHandlerUids = [
2520  23,
2521  24
2522  ];
2523 
2524  $relationHandlerProphecy->start(2, 'foreignTable', 'aTable_foreignTable_mm', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2525  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2526 
2527  $expected = $input;
2528  $expected['databaseRow']['aField'] = $relationHandlerUids;
2529 
2530  $this->assertEquals($expected, $this->subject->addData($input));
2531  }
2532 
2536  public function processSelectFieldValueSetsForeignRelationValues()
2537  {
2538  $GLOBALS['TCA']['foreignTable'] = [];
2539 
2541  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2542  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2543 
2545  $database = $this->prophesize(DatabaseConnection::class);
2546  $GLOBALS['TYPO3_DB'] = $database->reveal();
2547 
2548  $input = [
2549  'tableName' => 'aTable',
2550  'databaseRow' => [
2551  'uid' => 42,
2552  // Two connected rows
2553  'aField' => '22,23,24,25',
2554  ],
2555  'processedTca' => [
2556  'columns' => [
2557  'aField' => [
2558  'config' => [
2559  'type' => 'select',
2560  'renderType' => 'selectSingle',
2561  'maxitems' => 999,
2562  'foreign_table' => 'foreignTable',
2563  'items' => [],
2564  ],
2565  ],
2566  ],
2567  ],
2568  ];
2569  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2571  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2572  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2573 
2574  $relationHandlerUids = [
2575  23,
2576  24
2577  ];
2578 
2579  $relationHandlerProphecy->start('22,23,24,25', 'foreignTable', '', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2580  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2581 
2582  $expected = $input;
2583  $expected['databaseRow']['aField'] = $relationHandlerUids;
2584 
2585  $this->assertEquals($expected, $this->subject->addData($input));
2586  }
2587 
2591  public function processSelectFieldValueRemovesInvalidDynamicValues()
2592  {
2593  $languageService = $this->prophesize(LanguageService::class);
2594  $GLOBALS['LANG'] = $languageService->reveal();
2595  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2596 
2597  $GLOBALS['TCA']['foreignTable'] = [];
2598 
2600  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2601  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2602 
2604  $database = $this->prophesize(DatabaseConnection::class);
2605  $GLOBALS['TYPO3_DB'] = $database->reveal();
2606 
2607  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2608  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2609  $relationHandlerProphecy->start(Argument::cetera())->shouldBeCalled();
2610  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldBeCalled()->willReturn([1]);
2611 
2612  $input = [
2613  'tableName' => 'aTable',
2614  'databaseRow' => [
2615  'aField' => '1,2,bar,foo',
2616  ],
2617  'processedTca' => [
2618  'columns' => [
2619  'aField' => [
2620  'config' => [
2621  'type' => 'select',
2622  'renderType' => 'selectSingleBox',
2623  'foreign_table' => 'foreignTable',
2624  'maxitems' => 999,
2625  'items' => [
2626  ['foo', 'foo', null, null],
2627  ],
2628  ],
2629  ],
2630  ],
2631  ],
2632  ];
2633 
2634  $expected = $input;
2635  $expected['databaseRow']['aField'] = ['foo', 1];
2636 
2637  $this->assertEquals($expected, $this->subject->addData($input));
2638  }
2639 
2644  {
2645  $languageService = $this->prophesize(LanguageService::class);
2646  $GLOBALS['LANG'] = $languageService->reveal();
2647  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2648 
2649  $input = [
2650  'tableName' => 'aTable',
2651  'databaseRow' => [
2652  'aField' => 'foo,bar',
2653  ],
2654  'processedTca' => [
2655  'columns' => [
2656  'aField' => [
2657  'config' => [
2658  'type' => 'select',
2659  'renderType' => 'selectSingle',
2660  'maxitems' => 999,
2661  'items' => [
2662  ['foo', 'foo', null, null],
2663  ['bar', 'bar', null, null],
2664  ],
2665  ],
2666  ],
2667  ],
2668  ],
2669  ];
2670 
2671  $expected = $input;
2672  $expected['databaseRow']['aField'] = [
2673  'foo',
2674  'bar'
2675  ];
2676 
2677  $this->assertEquals($expected, $this->subject->addData($input));
2678  }
2679 
2684  {
2685  $languageService = $this->prophesize(LanguageService::class);
2686  $GLOBALS['LANG'] = $languageService->reveal();
2687  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2688 
2689  $input = [
2690  'tableName' => 'aTable',
2691  'databaseRow' => [
2692  'aField' => '',
2693  ],
2694  'processedTca' => [
2695  'columns' => [
2696  'aField' => [
2697  'config' => [
2698  'type' => 'select',
2699  'renderType' => 'selectSingle',
2700  'maxitems' => 1,
2701  'items' => [],
2702  ],
2703  ],
2704  ],
2705  ],
2706  ];
2707 
2708  $expected = $input;
2709  $expected['databaseRow']['aField'] = [];
2710 
2711  $this->assertEquals($expected, $this->subject->addData($input));
2712  }
2713 
2718  {
2719  $languageService = $this->prophesize(LanguageService::class);
2720  $GLOBALS['LANG'] = $languageService->reveal();
2721  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2722 
2723  $input = [
2724  'tableName' => 'aTable',
2725  'databaseRow' => [
2726  'aField' => 'b,,c',
2727  ],
2728  'processedTca' => [
2729  'columns' => [
2730  'aField' => [
2731  'config' => [
2732  'type' => 'select',
2733  'renderType' => 'selectSingle',
2734  'maxitems' => 999,
2735  'items' => [
2736  ['a', '', null, null],
2737  ['b', 'b', null, null],
2738  ['c', 'c', null, null],
2739  ],
2740  ],
2741  ],
2742  ],
2743  ],
2744  ];
2745 
2746  $expected = $input;
2747  $expected['databaseRow']['aField'] = [
2748  'b',
2749  'c',
2750  ];
2751 
2752  $this->assertEquals($expected, $this->subject->addData($input));
2753  }
2754 
2759  {
2760  $languageService = $this->prophesize(LanguageService::class);
2761  $GLOBALS['LANG'] = $languageService->reveal();
2762  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2763 
2764  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2765  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2766  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
2767  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
2768 
2769  $input = [
2770  'tableName' => 'aTable',
2771  'databaseRow' => [
2772  'aField' => 'foo',
2773  ],
2774  'processedTca' => [
2775  'columns' => [
2776  'aField' => [
2777  'config' => [
2778  'type' => 'select',
2779  'renderType' => 'selectSingle',
2780  'maxitems' => 999,
2781  'items' => [
2782  ['foo', 'foo', null, null],
2783  ],
2784  ],
2785  ],
2786  ],
2787  ],
2788  ];
2789 
2790  $expected = $input;
2791  $expected['databaseRow']['aField'] = ['foo'];
2792 
2793  $this->assertEquals($expected, $this->subject->addData($input));
2794  }
2795 
2800  {
2801  $languageService = $this->prophesize(LanguageService::class);
2802  $GLOBALS['LANG'] = $languageService->reveal();
2803  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2804  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2805 
2806  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2807  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2808  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
2809  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
2810 
2811  $input = [
2812  'tableName' => 'aTable',
2813  'databaseRow' => [
2814  'aField' => '1,2,bar,foo',
2815  ],
2816  'processedTca' => [
2817  'columns' => [
2818  'aField' => [
2819  'config' => [
2820  'type' => 'select',
2821  'renderType' => 'selectSingle',
2822  'maxitems' => 1,
2823  'items' => [
2824  ['foo', 'foo', null, null],
2825  ],
2826  ],
2827  ],
2828  ],
2829  ],
2830  ];
2831 
2832  $expected = $input;
2833  $expected['databaseRow']['aField'] = ['foo'];
2834  $expected['processedTca']['columns']['aField']['config']['items'] = [
2835  ['[ INVALID VALUE "bar" ]', 'bar', null, null],
2836  ['[ INVALID VALUE "2" ]', '2', null, null],
2837  ['[ INVALID VALUE "1" ]', '1', null, null],
2838  ['foo', 'foo', null, null],
2839  ];
2840  $this->assertEquals($expected, $this->subject->addData($input));
2841  }
2842 
2843 
2850  {
2851  return array(
2852  'Relation with MM table and new status with default values' => [
2853  [
2854  'tableName' => 'aTable',
2855  'command' => 'new',
2856  'databaseRow' => [
2857  'uid' => 'NEW1234',
2858  'aField' => '24,35',
2859  ],
2860  'processedTca' => [
2861  'columns' => [
2862  'aField' => [
2863  'config' => [
2864  'type' => 'select',
2865  'renderType' => 'selectSingle',
2866  'maxitems' => 999,
2867  'MM' => 'mm_aTable_foreignTable',
2868  'foreign_table' => 'foreignTable',
2869  'items' => [],
2870  ],
2871  ],
2872  ],
2873  ],
2874  ],
2875  [
2876  'MM' => ''
2877  ],
2878  [
2879  24, 35
2880  ]
2881  ],
2882  'Relation with MM table and item array in list but no new status' => [
2883  [
2884  'tableName' => 'aTable',
2885  'databaseRow' => [
2886  'uid' => 'NEW1234',
2887  'aField' => '24,35',
2888  ],
2889  'processedTca' => [
2890  'columns' => [
2891  'aField' => [
2892  'config' => [
2893  'type' => 'select',
2894  'renderType' => 'selectSingle',
2895  'maxitems' => 999,
2896  'MM' => 'mm_aTable_foreignTable',
2897  'foreign_table' => 'foreignTable',
2898  'items' => [],
2899  ],
2900  ],
2901  ],
2902  ],
2903  ],
2904  [],
2905  []
2906  ],
2907  'Relation with MM table and maxitems = 1 processes field value (item count)' => [
2908  [
2909  'tableName' => 'aTable',
2910  'databaseRow' => [
2911  'uid' => 42,
2912  // MM relation with one item has 1 in field value
2913  'aField' => 1,
2914  ],
2915  'processedTca' => [
2916  'columns' => [
2917  'aField' => [
2918  'config' => [
2919  'type' => 'select',
2920  'renderType' => 'selectSingle',
2921  'maxitems' => 1,
2922  'MM' => 'mm_aTable_foreignTable',
2923  'foreign_table' => 'foreignTable',
2924  'items' => [],
2925  ],
2926  ],
2927  ],
2928  ],
2929  ],
2930  [],
2931  [
2932  24
2933  ]
2934  ],
2935  'Relation with MM table and maxitems = 1 results in empty array if no items are set' => [
2936  [
2937  'tableName' => 'aTable',
2938  'databaseRow' => [
2939  'uid' => 58,
2940  // MM relation with no items has 0 in field value
2941  'aField' => 0,
2942  ],
2943  'processedTca' => [
2944  'columns' => [
2945  'aField' => [
2946  'config' => [
2947  'type' => 'select',
2948  'renderType' => 'selectSingle',
2949  'maxitems' => 1,
2950  'MM' => 'mm_aTable_foreignTable',
2951  'foreign_table' => 'foreignTable',
2952  'items' => [],
2953  ],
2954  ],
2955  ],
2956  ],
2957  ],
2958  [],
2959  []
2960  ]
2961  );
2962  }
2963 
2972  public function processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids)
2973  {
2974  $field = $input['databaseRow']['aField'];
2975  $foreignTable = isset($overrideRelationHandlerSettings['foreign_table']) ? $overrideRelationHandlerSettings['foreign_table'] : $input['processedTca']['columns']['aField']['config']['foreign_table'];
2976  $mmTable = isset($overrideRelationHandlerSettings['MM']) ? $overrideRelationHandlerSettings['MM'] : $input['processedTca']['columns']['aField']['config']['MM'];
2977  $uid = $input['databaseRow']['uid'];
2978  $tableName = $input['tableName'];
2979  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2980 
2981  $GLOBALS['TCA'][$foreignTable] = [];
2982 
2984  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2985  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2986 
2988  $database = $this->prophesize(DatabaseConnection::class);
2989  $GLOBALS['TYPO3_DB'] = $database->reveal();
2990 
2992  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2993  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2994 
2995  $relationHandlerProphecy->start($field, $foreignTable, $mmTable, $uid, $tableName, $fieldConfig)->shouldBeCalled();
2996  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2997 
2998  $expected = $input;
2999  $expected['databaseRow']['aField'] = $relationHandlerUids;
3000 
3001  $this->assertEquals($expected, $this->subject->addData($input));
3002  }
3003 }