TYPO3 CMS  TYPO3_7-6
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 
31 
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  'anotherKey' => [
1011  0 => 'anotherTitle',
1012  1 => 'status-status-permission-denied',
1013  2 => 'aDescription',
1014  ],
1015  ],
1016  ]
1017  ];
1018 
1019  $expectedItems = [
1020  0 => [
1021  0 => 'aHeader',
1022  1 => '--div--',
1023  null,
1024  null,
1025  ],
1026  1 => [
1027  0 => 'anItemTitle',
1028  1 => 'aKey:anItemKey',
1029  2 => 'empty-empty',
1030  3 => null,
1031  ],
1032  2 => [
1033  0 => 'anotherTitle',
1034  1 => 'aKey:anotherKey',
1035  2 => 'status-status-permission-denied',
1036  3 => [ 'description' => 'aDescription' ],
1037  ],
1038  ];
1039 
1040  $result = $this->subject->addData($input);
1041 
1042  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1043  }
1044 
1048  public function addDataAddsGroupItemsWithSpecialModListGroup()
1049  {
1050  $input = [
1051  'tableName' => 'aTable',
1052  'databaseRow' => [],
1053  'processedTca' => [
1054  'columns' => [
1055  'aField' => [
1056  'config' => [
1057  'type' => 'select',
1058  'renderType' => 'selectSingle',
1059  'special' => 'modListGroup',
1060  ],
1061  ],
1062  ],
1063  ],
1064  ];
1065 
1066  $GLOBALS['TBE_MODULES'] = [];
1067 
1069  $languageService = $this->prophesize(LanguageService::class);
1070  $GLOBALS['LANG'] = $languageService->reveal();
1071  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1072  $languageService->moduleLabels = [
1073  'tabs_images' => [
1074  'aModule_tab' => PATH_site . 'aModuleTabIcon.gif',
1075  ],
1076  'labels' => [
1077  'aModule_tablabel' => 'aModuleTabLabel',
1078  'aModule_tabdescr' => 'aModuleTabDescription',
1079  ],
1080  'tabs' => [
1081  'aModule_tab' => 'aModuleLabel',
1082  ]
1083  ];
1084 
1086  $moduleLoaderProphecy = $this->prophesize(ModuleLoader::class);
1087  GeneralUtility::addInstance(ModuleLoader::class, $moduleLoaderProphecy->reveal());
1088  $moduleLoaderProphecy->load([])->shouldBeCalled();
1089  $moduleLoaderProphecy->modListGroup = [
1090  'aModule',
1091  ];
1092 
1093  $expectedItems = [
1094  0 => [
1095  0 => 'aModuleLabel',
1096  1 => 'aModule',
1097  2 => '../aModuleTabIcon.gif',
1098  3 => [
1099  'title' => 'aModuleTabLabel',
1100  'description' => 'aModuleTabDescription',
1101  ],
1102  ],
1103  ];
1104 
1105  $result = $this->subject->addData($input);
1106 
1107  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1108  }
1109 
1113  public function addDataAddsFileItemsWithConfiguredFileFolder()
1114  {
1115  $directory = $this->getUniqueId('typo3temp/test-') . '/';
1116  $input = [
1117  'tableName' => 'aTable',
1118  'databaseRow' => [],
1119  'processedTca' => [
1120  'columns' => [
1121  'aField' => [
1122  'config' => [
1123  'type' => 'select',
1124  'renderType' => 'selectSingle',
1125  'fileFolder' => $directory,
1126  'fileFolder_extList' => 'gif',
1127  'fileFolder_recursions' => 1,
1128  ],
1129  ],
1130  ],
1131  ],
1132  ];
1133 
1135  $languageService = $this->prophesize(LanguageService::class);
1136  $GLOBALS['LANG'] = $languageService->reveal();
1137  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1138 
1139  mkdir(PATH_site . $directory);
1140  $this->testFilesToDelete[] = PATH_site . $directory;
1141  touch(PATH_site . $directory . 'anImage.gif');
1142  touch(PATH_site . $directory . 'aFile.txt');
1143  mkdir(PATH_site . $directory . '/subdir');
1144  touch(PATH_site . $directory . '/subdir/anotherImage.gif');
1145 
1146  $expectedItems = [
1147  0 => [
1148  0 => 'anImage.gif',
1149  1 => 'anImage.gif',
1150  2 => '../' . $directory . 'anImage.gif',
1151  3 => null,
1152  ],
1153  1 => [
1154  0 => 'subdir/anotherImage.gif',
1155  1 => 'subdir/anotherImage.gif',
1156  2 => '../' . $directory . 'subdir/anotherImage.gif',
1157  3 => null,
1158  ],
1159  ];
1160 
1161  $result = $this->subject->addData($input);
1162 
1163  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1164  }
1165 
1170  {
1171  $input = [
1172  'tableName' => 'aTable',
1173  'databaseRow' => [],
1174  'processedTca' => [
1175  'columns' => [
1176  'aField' => [
1177  'config' => [
1178  'type' => 'select',
1179  'renderType' => 'selectSingle',
1180  'fileFolder' => 'EXT:non_existing/Resources/Public/',
1181  ],
1182  ],
1183  ],
1184  ],
1185  ];
1186 
1187  $this->setExpectedException(\RuntimeException::class, $this->anything(), 1479399227);
1188  $this->subject->addData($input);
1189  }
1190 
1194  public function addDataAddsItemsByAddItemsFromPageTsConfig()
1195  {
1196  $input = [
1197  'databaseRow' => [
1198  'aField' => '',
1199  ],
1200  'tableName' => 'aTable',
1201  'processedTca' => [
1202  'columns' => [
1203  'aField' => [
1204  'config' => [
1205  'type' => 'select',
1206  'renderType' => 'selectSingle',
1207  'items' => [
1208  0 => [
1209  0 => 'keepMe',
1210  1 => 'keep',
1211  null,
1212  null,
1213  ],
1214  ],
1215  'maxitems' => 1,
1216  ],
1217  ],
1218  ]
1219  ],
1220  'pageTsConfig' => [
1221  'TCEFORM.' => [
1222  'aTable.' => [
1223  'aField.' => [
1224  'addItems.' => [
1225  '1' => 'addMe'
1226  ],
1227  ],
1228  ],
1229  ],
1230  ],
1231  ];
1232 
1234  $languageService = $this->prophesize(LanguageService::class);
1235  $GLOBALS['LANG'] = $languageService->reveal();
1236  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1237 
1238  $expected = $input;
1239  $expected['databaseRow']['aField'] = [];
1240  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1241  0 => 'addMe',
1242  1 => '1',
1243  null,
1244  null,
1245  ];
1246 
1247  $this->assertEquals($expected, $this->subject->addData($input));
1248  }
1249 
1253  public function addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig()
1254  {
1255  $input = [
1256  'databaseRow' => [
1257  'aField' => '',
1258  ],
1259  'tableName' => 'aTable',
1260  'processedTca' => [
1261  'columns' => [
1262  'aField' => [
1263  'config' => [
1264  'type' => 'select',
1265  'renderType' => 'selectSingle',
1266  'items' => [
1267  0 => [
1268  0 => 'keepMe',
1269  1 => 'keep',
1270  null,
1271  null,
1272  ],
1273  ],
1274  'maxitems' => 1,
1275  ],
1276  ],
1277  ]
1278  ],
1279  'pageTsConfig' => [
1280  'TCEFORM.' => [
1281  'aTable.' => [
1282  'aField.' => [
1283  'addItems.' => [
1284  'keep' => 'addMe'
1285  ],
1286  ],
1287  ],
1288  ],
1289  ],
1290  ];
1291 
1293  $languageService = $this->prophesize(LanguageService::class);
1294  $GLOBALS['LANG'] = $languageService->reveal();
1295  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1296 
1297  $expected = $input;
1298  $expected['databaseRow']['aField'] = [];
1299  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1300  0 => 'addMe',
1301  1 => 'keep',
1302  null,
1303  null,
1304  ];
1305 
1306  $this->assertEquals($expected, $this->subject->addData($input));
1307  }
1308 
1313  {
1314  return [
1315  'replace REC_FIELD' => [
1316  'AND fTable.title=\'###REC_FIELD_rowField###\'',
1317  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\'',
1318  [],
1319  ],
1320  'replace REC_FIELD within FlexForm' => [
1321  'AND fTable.title=###REC_FIELD_rowFieldFlexForm###',
1322  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldFlexFormValue\'',
1323  [
1324  'databaseRow' => [
1325  'rowFieldThree' => [
1326  0 => 'rowFieldThreeValue'
1327  ]
1328  ],
1329  'flexParentDatabaseRow' => [
1330  'rowFieldFlexForm' => [
1331  0 => 'rowFieldFlexFormValue'
1332  ]
1333  ],
1334  ],
1335  ],
1336  'replace REC_FIELD fullQuote' => [
1337  'AND fTable.title=###REC_FIELD_rowField###',
1338  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\'',
1339  [],
1340  ],
1341  'replace REC_FIELD fullQuoteWithArray' => [
1342  'AND fTable.title=###REC_FIELD_rowFieldThree###',
1343  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldThreeValue\'',
1344  [
1345  'databaseRow' => [
1346  'rowFieldThree' => [
1347  0 => 'rowFieldThreeValue'
1348  ]
1349  ],
1350  ],
1351  ],
1352  'replace REC_FIELD multiple markers' => [
1353  'AND fTable.title=\'###REC_FIELD_rowField###\' AND fTable.pid=###REC_FIELD_rowFieldTwo###',
1354  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\' AND fTable.pid=\'rowFieldTwoValue\'',
1355  [],
1356  ],
1357  'replace CURRENT_PID' => [
1358  'AND fTable.uid=###CURRENT_PID###',
1359  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=43',
1360  [],
1361  ],
1362  'replace CURRENT_PID within FlexForm' => [
1363  'AND fTable.uid=###CURRENT_PID###',
1364  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=77',
1365  [
1366  'flexParentDatabaseRow' => [
1367  'pid' => '77',
1368  ],
1369  ],
1370  ],
1371  'replace CURRENT_PID integer cast' => [
1372  'AND fTable.uid=###CURRENT_PID###',
1373  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=431',
1374  [
1375  'effectivePid' => '431string',
1376  ],
1377  ],
1378  'replace THIS_UID' => [
1379  'AND fTable.uid=###THIS_UID###',
1380  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=42',
1381  [],
1382  ],
1383  'replace THIS_UID integer cast' => [
1384  'AND fTable.uid=###THIS_UID###',
1385  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=421',
1386  [
1387  'databaseRow' => [
1388  'uid' => '421string',
1389  ],
1390  ],
1391  ],
1392  'replace SITEROOT' => [
1393  'AND fTable.uid=###SITEROOT###',
1394  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=44',
1395  [],
1396  ],
1397  'replace SITEROOT integer cast' => [
1398  'AND fTable.uid=###SITEROOT###',
1399  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=441',
1400  [
1401  'rootline' => [
1402  1 => [
1403  'uid' => '441string',
1404  ],
1405  ],
1406  ],
1407  ],
1408  'replace PAGE_TSCONFIG_ID' => [
1409  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1410  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=45',
1411  [
1412  'pageTsConfig' => [
1413  'TCEFORM.' => [
1414  'aTable.' => [
1415  'aField.' => [
1416  'PAGE_TSCONFIG_ID' => '45',
1417  ],
1418  ],
1419  ],
1420  ],
1421  ],
1422  ],
1423  'replace PAGE_TSCONFIG_ID integer cast' => [
1424  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1425  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=451',
1426  [
1427  'pageTsConfig' => [
1428  'TCEFORM.' => [
1429  'aTable.' => [
1430  'aField.' => [
1431  'PAGE_TSCONFIG_ID' => '451string'
1432  ],
1433  ],
1434  ],
1435  ],
1436  ],
1437  ],
1438  'replace PAGE_TSCONFIG_STR' => [
1439  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1440  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=\'46\'',
1441  [
1442  'pageTsConfig' => [
1443  'TCEFORM.' => [
1444  'aTable.' => [
1445  'aField.' => [
1446  'PAGE_TSCONFIG_STR' => '46',
1447  ],
1448  ],
1449  ],
1450  ],
1451  ],
1452  ],
1453  'replace PAGE_TSCONFIG_IDLIST' => [
1454  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1455  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (47,48)',
1456  [
1457  'pageTsConfig' => [
1458  'TCEFORM.' => [
1459  'aTable.' => [
1460  'aField.' => [
1461  'PAGE_TSCONFIG_IDLIST' => '47,48',
1462  ],
1463  ],
1464  ],
1465  ],
1466  ],
1467  ],
1468  'replace PAGE_TSCONFIG_IDLIST cleans list' => [
1469  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1470  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (471,481)',
1471  [
1472  'pageTsConfig' => [
1473  'TCEFORM.' => [
1474  'aTable.' => [
1475  'aField.' => [
1476  'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
1477  ],
1478  ],
1479  ],
1480  ],
1481  ],
1482  ],
1483  'deprecated flexHack PAGE_TSCONFIG_ID is substituted' => [
1484  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1485  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=123',
1486  [
1487  'pageTsConfig' => [
1488  'flexHack.' => [
1489  'PAGE_TSCONFIG_ID' => '123',
1490  ],
1491  ],
1492  ],
1493  ],
1494  'deprecated flexHack PAGE_TSCONFIG_IDLIST is substituted' => [
1495  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1496  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (123,124)',
1497  [
1498  'pageTsConfig' => [
1499  'flexHack.' => [
1500  'PAGE_TSCONFIG_IDLIST' => '123,124',
1501  ],
1502  ],
1503  ],
1504  ],
1505  'deprecated flexHack PAGE_TSCONFIG_STR is substituted' => [
1506  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1507  'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=\'aString\'',
1508  [
1509  'pageTsConfig' => [
1510  'flexHack.' => [
1511  'PAGE_TSCONFIG_STR' => 'aString',
1512  ],
1513  ],
1514  ],
1515  ],
1516  ];
1517  }
1518 
1523  public function addDataReplacesMarkersInForeignTableClause($foreignTableWhere, $expectedWhere, array $inputOverride)
1524  {
1525  $input = [
1526  'tableName' => 'aTable',
1527  'effectivePid' => 43,
1528  'databaseRow' => [
1529  'uid' => 42,
1530  'rowField' => 'rowFieldValue',
1531  'rowFieldTwo' => 'rowFieldTwoValue',
1532  ],
1533  'processedTca' => [
1534  'columns' => [
1535  'aField' => [
1536  'config' => [
1537  'type' => 'select',
1538  'renderType' => 'selectSingle',
1539  'foreign_table' => 'fTable',
1540  'foreign_table_where' => $foreignTableWhere,
1541  ],
1542  ],
1543  ]
1544  ],
1545  'rootline' => [
1546  2 => [
1547  'uid' => 999,
1548  'is_siteroot' => 0,
1549  ],
1550  1 => [
1551  'uid' => 44,
1552  'is_siteroot' => 1,
1553  ],
1554  0 => [
1555  'uid' => 0,
1556  'is_siteroot' => null,
1557  ],
1558  ],
1559  'pageTsConfig' => [],
1560  ];
1561  ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
1562 
1563  $GLOBALS['TCA']['fTable'] = [];
1564 
1565  $expectedQueryArray = [
1566  'SELECT' => 'fTable.uid',
1567  'FROM' => 'fTable, pages',
1568  'WHERE' => $expectedWhere,
1569  'GROUPBY' => '',
1570  'ORDERBY' => '',
1571  'LIMIT' => '',
1572  ];
1573 
1575  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1576  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1577  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1578 
1580  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1581  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1582  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1583  $databaseProphecy->quoteStr(Argument::cetera())->willReturnArgument(0);
1584  $databaseProphecy->fullQuoteStr(Argument::cetera())->will(function ($args) {
1585  return '\'' . $args[0] . '\'';
1586  });
1587  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn(false);
1588  $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(null);
1589 
1590  $databaseProphecy->exec_SELECT_queryArray($expectedQueryArray)->shouldBeCalled()->willReturn(false);
1591 
1592  $this->subject->addData($input);
1593  }
1594 
1599  {
1600  $input = [
1601  'tableName' => 'aTable',
1602  'processedTca' => [
1603  'columns' => [
1604  'aField' => [
1605  'config' => [
1606  'type' => 'select',
1607  'renderType' => 'selectSingle',
1608  'foreign_table' => 'fTable',
1609  ],
1610  ],
1611  ]
1612  ],
1613  ];
1614 
1615  $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439569743);
1616 
1617  $this->subject->addData($input);
1618  }
1619 
1623  public function addDataForeignTableSplitsGroupOrderAndLimit()
1624  {
1625  $input = [
1626  'tableName' => 'aTable',
1627  'databaseRow' => [],
1628  'processedTca' => [
1629  'columns' => [
1630  'aField' => [
1631  'config' => [
1632  'type' => 'select',
1633  'renderType' => 'selectSingle',
1634  'foreign_table' => 'fTable',
1635  'foreign_table_where' => 'AND ftable.uid=1 GROUP BY groupField ORDER BY orderField LIMIT 1,2',
1636  ],
1637  ],
1638  ]
1639  ],
1640  'rootline' => [],
1641  ];
1642 
1643  $GLOBALS['TCA']['fTable'] = [];
1644 
1645  $expectedQueryArray = [
1646  'SELECT' => 'fTable.uid',
1647  'FROM' => 'fTable, pages',
1648  'WHERE' => 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND ftable.uid=1',
1649  'GROUPBY' => 'groupField',
1650  'ORDERBY' => 'orderField',
1651  'LIMIT' => '1,2',
1652  ];
1653 
1655  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1656  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1657  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1658 
1660  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1661  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1662  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1663  $databaseProphecy->quoteStr(Argument::cetera())->willReturnArgument(0);
1664  $databaseProphecy->fullQuoteStr(Argument::cetera())->will(function ($args) {
1665  return '\'' . $args[0] . '\'';
1666  });
1667  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn(false);
1668  $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(null);
1669 
1670  $databaseProphecy->exec_SELECT_queryArray($expectedQueryArray)->shouldBeCalled()->willReturn(false);
1671 
1672  $this->subject->addData($input);
1673  }
1674 
1678  public function addDataForeignTableQueuesFlashMessageOnDatabaseError()
1679  {
1680  $input = [
1681  'databaseRow' => [
1682  'aField' => '',
1683  ],
1684  'tableName' => 'aTable',
1685  'processedTca' => [
1686  'columns' => [
1687  'aField' => [
1688  'config' => [
1689  'type' => 'select',
1690  'renderType' => 'selectSingle',
1691  'foreign_table' => 'fTable',
1692  'items' => [
1693  0 => [
1694  0 => 'itemLabel',
1695  1 => 'itemValue',
1696  2 => null,
1697  3 => null,
1698  ],
1699  ],
1700  'maxitems' => 1,
1701  ],
1702  ],
1703  ]
1704  ],
1705  'rootline' => [],
1706  ];
1707 
1708  $GLOBALS['TCA']['fTable'] = [];
1709 
1711  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1712  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1713  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1714 
1716  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1717  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1718  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1719 
1721  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1722  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1723  $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(false);
1724 
1725  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn('anError');
1726  $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(null);
1727 
1729  $flashMessage = $this->prophesize(FlashMessage::class);
1730  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1732  $flashMessageService = $this->prophesize(FlashMessageService::class);
1733  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1735  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1736  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1737 
1738  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
1739 
1740  $expected = $input;
1741  $expected['databaseRow']['aField'] = [];
1742 
1743  $this->assertEquals($expected, $this->subject->addData($input));
1744  }
1745 
1749  public function addDataForeignTableHandlesForeignTableRows()
1750  {
1751  $input = [
1752  'databaseRow' => [
1753  'aField' => '',
1754  ],
1755  'tableName' => 'aTable',
1756  'processedTca' => [
1757  'columns' => [
1758  'aField' => [
1759  'config' => [
1760  'type' => 'select',
1761  'renderType' => 'selectSingle',
1762  'foreign_table' => 'fTable',
1763  'foreign_table_prefix' => 'aPrefix',
1764  'items' => [],
1765  'maxitems' => 1,
1766  ],
1767  ],
1768  ]
1769  ],
1770  'rootline' => [],
1771  ];
1772 
1773  $GLOBALS['TCA']['fTable'] = [];
1774 
1776  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1777  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1778  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1779 
1781  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1782  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1783  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1784 
1786  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1787  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1788  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1789  $databaseProphecy->sql_free_result(Argument::cetera())->willReturn(null);
1790  $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(true);
1791 
1792  $counter = 0;
1793  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->will(function ($args) use (&$counter) {
1794  $counter++;
1795  if ($counter >= 3) {
1796  return false;
1797  }
1798  return [
1799  'uid' => $counter,
1800  'aValue' => 'bar,',
1801  ];
1802  });
1803 
1804  $expected = $input;
1805  $expected['processedTca']['columns']['aField']['config']['items'] = [
1806  0 => [
1807  0 => 'aPrefix[LLL:EXT:lang/locallang_core.xlf:labels.no_title]',
1808  1 => 1,
1809  2 => 'default-not-found',
1810  3 => null,
1811  ],
1812  1 => [
1813  0 => 'aPrefix[LLL:EXT:lang/locallang_core.xlf:labels.no_title]',
1814  1 => 2,
1815  2 => 'default-not-found',
1816  3 => null,
1817  ],
1818  ];
1819 
1820  $expected['databaseRow']['aField'] = [];
1821 
1822  $this->assertEquals($expected, $this->subject->addData($input));
1823  }
1824 
1828  public function addDataForeignTableResolvesIconFromSelicon()
1829  {
1830  $input = [
1831  'databaseRow' => [
1832  'aField' => '',
1833  ],
1834  'tableName' => 'aTable',
1835  'processedTca' => [
1836  'columns' => [
1837  'aField' => [
1838  'config' => [
1839  'type' => 'select',
1840  'renderType' => 'selectSingle',
1841  'foreign_table' => 'fTable',
1842  'maxitems' => 1,
1843  ],
1844  ],
1845  ]
1846  ],
1847  'rootline' => [],
1848  ];
1849 
1850  // Fake the foreign_table
1851  $GLOBALS['TCA']['fTable'] = [
1852  'ctrl' => [
1853  'label' => 'icon',
1854  'selicon_field' => 'icon',
1855  'selicon_field_path' => 'uploads/media',
1856  ],
1857  'columns' =>[
1858  'icon' => [
1859  'config' => [
1860  'type' => 'group',
1861  ],
1862  ],
1863  ],
1864  ];
1865 
1867  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1868  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1869  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1870 
1872  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1873  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1874  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1875 
1877  $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1878  $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1879  $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
1880  $databaseProphecy->sql_free_result(Argument::cetera())->willReturn(null);
1881  // Query on foreign table is successful
1882  $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(true);
1883  // Query returns one row, then false on second call
1884  $foreignTableRowResultOne = [
1885  'uid' => 1,
1886  'icon' => 'foo.jpg',
1887  ];
1888  $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn($foreignTableRowResultOne, false);
1889 
1890  $expected = $input;
1891  $expected['processedTca']['columns']['aField']['config']['items'] = [
1892  0 => [
1893  0 => 'foo.jpg',
1894  1 => 1,
1895  2 => '../uploads/media/foo.jpg', // combination of selicon_field_path and the row value of field 'icon'
1896  3 => null,
1897  ],
1898  ];
1899  $expected['databaseRow']['aField'] = [];
1900 
1901  $this->assertEquals($expected, $this->subject->addData($input));
1902  }
1903 
1907  public function addDataRemovesItemsByKeepItemsPageTsConfig()
1908  {
1909  $input = [
1910  'databaseRow' => [
1911  'aField' => '',
1912  ],
1913  'tableName' => 'aTable',
1914  'processedTca' => [
1915  'columns' => [
1916  'aField' => [
1917  'config' => [
1918  'type' => 'select',
1919  'renderType' => 'selectSingle',
1920  'items' => [
1921  0 => [
1922  0 => 'keepMe',
1923  1 => 'keep',
1924  null,
1925  null,
1926  ],
1927  1 => [
1928  0 => 'removeMe',
1929  1 => 'remove',
1930  ],
1931  ],
1932  'maxitems' => 1,
1933  ],
1934  ],
1935  ]
1936  ],
1937  'pageTsConfig' => [
1938  'TCEFORM.' => [
1939  'aTable.' => [
1940  'aField.' => [
1941  'keepItems' => 'keep',
1942  ],
1943  ],
1944  ],
1945  ],
1946  ];
1947 
1949  $languageService = $this->prophesize(LanguageService::class);
1950  $GLOBALS['LANG'] = $languageService->reveal();
1951  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1952 
1953  $expected = $input;
1954  $expected['databaseRow']['aField'] = [];
1955  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1956 
1957  $this->assertEquals($expected, $this->subject->addData($input));
1958  }
1959 
1963  public function addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig()
1964  {
1965  $input = [
1966  'databaseRow' => [
1967  'aField' => '',
1968  ],
1969  'tableName' => 'aTable',
1970  'processedTca' => [
1971  'columns' => [
1972  'aField' => [
1973  'config' => [
1974  'type' => 'select',
1975  'renderType' => 'selectSingle',
1976  'items' => [
1977  0 => [
1978  0 => 'keepMe',
1979  1 => 'keep',
1980  null,
1981  null,
1982  ],
1983  1 => [
1984  0 => 'removeMe',
1985  1 => 'remove',
1986  ],
1987  ],
1988  'maxitems' => 1,
1989  ],
1990  ],
1991  ]
1992  ],
1993  'pageTsConfig' => [
1994  'TCEFORM.' => [
1995  'aTable.' => [
1996  'aField.' => [
1997  'keepItems' => '',
1998  ],
1999  ],
2000  ],
2001  ],
2002  ];
2003 
2005  $languageService = $this->prophesize(LanguageService::class);
2006  $GLOBALS['LANG'] = $languageService->reveal();
2007  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2008 
2009  $expected = $input;
2010  $expected['databaseRow']['aField'] = [];
2011  $expected['processedTca']['columns']['aField']['config']['items'] = [];
2012 
2013  $this->assertEquals($expected, $this->subject->addData($input));
2014  }
2015 
2019  public function addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig()
2020  {
2021  $input = [
2022  'databaseRow' => [
2023  'aField' => '',
2024  ],
2025  'tableName' => 'aTable',
2026  'processedTca' => [
2027  'columns' => [
2028  'aField' => [
2029  'config' => [
2030  'type' => 'select',
2031  'renderType' => 'selectSingle',
2032  'items' => [
2033  0 => [
2034  0 => 'keepMe',
2035  1 => '1',
2036  null,
2037  null,
2038  ],
2039  1 => [
2040  0 => 'removeMe',
2041  1 => 'remove',
2042  ],
2043  ],
2044  'maxitems' => 1,
2045  ],
2046  ],
2047  ]
2048  ],
2049  'pageTsConfig' => [
2050  'TCEFORM.' => [
2051  'aTable.' => [
2052  'aField.' => [
2053  'keepItems' => '1',
2054  'addItems.' => [
2055  '1' => 'addItem #1',
2056  '12' => 'addItem #12',
2057  ],
2058  ],
2059  ],
2060  ],
2061  ],
2062  ];
2063 
2065  $languageService = $this->prophesize(LanguageService::class);
2066  $GLOBALS['LANG'] = $languageService->reveal();
2067  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2068 
2069  $expected = $input;
2070  $expected['databaseRow']['aField'] = [];
2071  $expected['processedTca']['columns']['aField']['config']['items'] = [
2072  0 => [
2073  0 => 'keepMe',
2074  1 => '1',
2075  null,
2076  null,
2077  ],
2078  1 => [
2079  0 => 'addItem #1',
2080  1 => '1',
2081  null,
2082  null,
2083  ],
2084  2 => [
2085  0 => 'addItem #12',
2086  1 => '12',
2087  null,
2088  null,
2089  ],
2090  ];
2091 
2092  $this->assertEquals($expected, $this->subject->addData($input));
2093  }
2094 
2098  public function addDataRemovesItemsByRemoveItemsPageTsConfig()
2099  {
2100  $input = [
2101  'databaseRow' => [
2102  'aField' => ''
2103  ],
2104  'tableName' => 'aTable',
2105  'processedTca' => [
2106  'columns' => [
2107  'aField' => [
2108  'config' => [
2109  'type' => 'select',
2110  'renderType' => 'selectSingle',
2111  'items' => [
2112  0 => [
2113  0 => 'keepMe',
2114  1 => 'keep',
2115  null,
2116  null,
2117  ],
2118  1 => [
2119  0 => 'removeMe',
2120  1 => 'remove',
2121  ],
2122  ],
2123  'maxitems' => 1,
2124  ],
2125  ],
2126  ]
2127  ],
2128  'pageTsConfig' => [
2129  'TCEFORM.' => [
2130  'aTable.' => [
2131  'aField.' => [
2132  'removeItems' => 'remove',
2133  ],
2134  ],
2135  ],
2136  ],
2137  ];
2138 
2140  $languageService = $this->prophesize(LanguageService::class);
2141  $GLOBALS['LANG'] = $languageService->reveal();
2142  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2143 
2144  $expected = $input;
2145  $expected['databaseRow']['aField'] = [];
2146  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2147 
2148  $this->assertEquals($expected, $this->subject->addData($input));
2149  }
2150 
2154  public function addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig()
2155  {
2156  $input = [
2157  'databaseRow' => [
2158  'aField' => ''
2159  ],
2160  'tableName' => 'aTable',
2161  'processedTca' => [
2162  'columns' => [
2163  'aField' => [
2164  'config' => [
2165  'type' => 'select',
2166  'renderType' => 'selectSingle',
2167  'items' => [
2168  0 => [
2169  0 => 'keepMe',
2170  1 => 'keep',
2171  null,
2172  null,
2173  ],
2174  1 => [
2175  0 => 'removeMe',
2176  1 => 'remove',
2177  ],
2178  ],
2179  'maxitems' => 1,
2180  ],
2181  ],
2182  ]
2183  ],
2184  'pageTsConfig' => [
2185  'TCEFORM.' => [
2186  'aTable.' => [
2187  'aField.' => [
2188  'removeItems' => 'remove,add',
2189  'addItems.' => [
2190  'add' => 'addMe'
2191  ]
2192  ],
2193  ],
2194  ],
2195  ],
2196  ];
2197 
2199  $languageService = $this->prophesize(LanguageService::class);
2200  $GLOBALS['LANG'] = $languageService->reveal();
2201  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2202 
2203  $expected = $input;
2204  $expected['databaseRow']['aField'] = [];
2205  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2206 
2207  $this->assertEquals($expected, $this->subject->addData($input));
2208  }
2209 
2213  public function addDataRemovesItemsByLanguageFieldUserRestriction()
2214  {
2215  $input = [
2216  'databaseRow' => [
2217  'aField' => 'aValue,remove'
2218  ],
2219  'tableName' => 'aTable',
2220  'processedTca' => [
2221  'ctrl' => [
2222  'languageField' => 'aField',
2223  ],
2224  'columns' => [
2225  'aField' => [
2226  'config' => [
2227  'type' => 'select',
2228  'renderType' => 'selectSingle',
2229  'items' => [
2230  0 => [
2231  0 => 'keepMe',
2232  1 => 'keep',
2233  null,
2234  null,
2235  ],
2236  1 => [
2237  0 => 'removeMe',
2238  1 => 'remove',
2239  ],
2240  ],
2241  'maxitems' => 1,
2242  ],
2243  ],
2244  ]
2245  ],
2246  ];
2247 
2249  $languageService = $this->prophesize(LanguageService::class);
2250  $GLOBALS['LANG'] = $languageService->reveal();
2251  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2252  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2253 
2255  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2256  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2257  $backendUserProphecy->checkLanguageAccess('keep')->shouldBeCalled()->willReturn(true);
2258  $backendUserProphecy->checkLanguageAccess('remove')->shouldBeCalled()->willReturn(false);
2259 
2260  $expected = $input;
2261  $expected['databaseRow']['aField'] = [];
2262  $expected['processedTca']['columns']['aField']['config']['items'] = [
2263  [ '[ INVALID VALUE "aValue" ]', 'aValue', null, null ],
2264  [ 'keepMe', 'keep', null, null ],
2265  ];
2266 
2267  $this->assertEquals($expected, $this->subject->addData($input));
2268  }
2269 
2273  public function addDataRemovesItemsByUserAuthModeRestriction()
2274  {
2275  $input = [
2276  'databaseRow' => [
2277  'aField' => 'keep,remove'
2278  ],
2279  'tableName' => 'aTable',
2280  'processedTca' => [
2281  'columns' => [
2282  'aField' => [
2283  'config' => [
2284  'type' => 'select',
2285  'renderType' => 'selectSingle',
2286  'authMode' => 'explicitAllow',
2287  'items' => [
2288  0 => [
2289  0 => 'keepMe',
2290  1 => 'keep',
2291  null,
2292  null,
2293  ],
2294  1 => [
2295  0 => 'removeMe',
2296  1 => 'remove',
2297  ],
2298  ],
2299  'maxitems' => 1,
2300  ],
2301  ],
2302  ]
2303  ],
2304  ];
2305 
2307  $languageService = $this->prophesize(LanguageService::class);
2308  $GLOBALS['LANG'] = $languageService->reveal();
2309  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2310 
2312  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2313  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2314  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'keep', 'explicitAllow')->shouldBeCalled()->willReturn(true);
2315  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'remove', 'explicitAllow')->shouldBeCalled()->willReturn(false);
2316 
2317  $expected = $input;
2318  $expected['databaseRow']['aField'] = ['keep'];
2319  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2320 
2321  $this->assertEquals($expected, $this->subject->addData($input));
2322  }
2323 
2327  public function addDataKeepsAllPagesDoktypesForAdminUser()
2328  {
2329  $input = [
2330  'databaseRow' => [
2331  'doktype' => 'keep'
2332  ],
2333  'tableName' => 'pages',
2334  'processedTca' => [
2335  'columns' => [
2336  'doktype' => [
2337  'config' => [
2338  'type' => 'select',
2339  'renderType' => 'selectSingle',
2340  'items' => [
2341  0 => [
2342  0 => 'keepMe',
2343  1 => 'keep',
2344  null,
2345  null,
2346  ],
2347  ],
2348  'maxitems' => 1,
2349  ],
2350  ],
2351  ],
2352  ],
2353  ];
2354 
2356  $languageService = $this->prophesize(LanguageService::class);
2357  $GLOBALS['LANG'] = $languageService->reveal();
2358  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2359 
2361  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2362  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2363  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(true);
2364 
2365  $expected = $input;
2366  $expected['databaseRow']['doktype'] = ['keep'];
2367 
2368  $this->assertEquals($expected, $this->subject->addData($input));
2369  }
2370 
2374  public function addDataKeepsAllowedPageTypesForNonAdminUser()
2375  {
2376  $input = [
2377  'databaseRow' => [
2378  'doktype' => 'keep',
2379  ],
2380  'tableName' => 'pages',
2381  'processedTca' => [
2382  'columns' => [
2383  'doktype' => [
2384  'config' => [
2385  'type' => 'select',
2386  'renderType' => 'selectSingle',
2387  'items' => [
2388  0 => [
2389  0 => 'keepMe',
2390  1 => 'keep',
2391  null,
2392  null,
2393  ],
2394  1 => [
2395  0 => 'removeMe',
2396  1 => 'remove',
2397  ],
2398  ],
2399  'maxitems' => 1,
2400  ],
2401  ],
2402  ],
2403  ],
2404  ];
2405 
2407  $languageService = $this->prophesize(LanguageService::class);
2408  $GLOBALS['LANG'] = $languageService->reveal();
2409  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2410 
2412  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2413  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2414  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
2415  $backendUserProphecy->groupData = [
2416  'pagetypes_select' => 'foo,keep,anotherAllowedDoktype',
2417  ];
2418 
2419  $expected = $input;
2420  $expected['databaseRow']['doktype'] = ['keep'];
2421  unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
2422 
2423  $this->assertEquals($expected, $this->subject->addData($input));
2424  }
2425 
2429  public function addDataCallsItemsProcFunc()
2430  {
2431  $input = [
2432  'tableName' => 'aTable',
2433  'databaseRow' => [
2434  'aField' => 'aValue'
2435  ],
2436  'processedTca' => [
2437  'columns' => [
2438  'aField' => [
2439  'config' => [
2440  'type' => 'select',
2441  'renderType' => 'selectSingle',
2442  'items' => [],
2443  'itemsProcFunc' => function (array $parameters, $pObj) {
2444  $parameters['items'] = [
2445  0 => [
2446  0 => 'aLabel',
2447  1 => 'aValue',
2448  2 => null,
2449  3 => null,
2450  ],
2451  ];
2452  },
2453  ],
2454  ],
2455  ],
2456  ],
2457  ];
2458 
2460  $languageService = $this->prophesize(LanguageService::class);
2461  $GLOBALS['LANG'] = $languageService->reveal();
2462  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2463 
2464  $expected = $input;
2465  $expected['databaseRow']['aField'] = ['aValue'];
2466  $expected['processedTca']['columns']['aField']['config'] = [
2467  'type' => 'select',
2468  'renderType' => 'selectSingle',
2469  'items' => [
2470  0 => [
2471  0 => 'aLabel',
2472  1 => 'aValue',
2473  2 => null,
2474  3 => null,
2475  ],
2476  ],
2477  'maxitems' => 1,
2478  ];
2479 
2480  $this->assertSame($expected, $this->subject->addData($input));
2481  }
2482 
2486  public function addDataItemsProcFuncReceivesParameters()
2487  {
2488  $input = [
2489  'tableName' => 'aTable',
2490  'databaseRow' => [
2491  'aField' => 'aValue',
2492  ],
2493  'pageTsConfig' => [
2494  'TCEFORM.' => [
2495  'aTable.' => [
2496  'aField.' => [
2497  'itemsProcFunc.' => [
2498  'itemParamKey' => 'itemParamValue',
2499  ],
2500  ]
2501  ],
2502  ],
2503  ],
2504  'processedTca' => [
2505  'columns' => [
2506  'aField' => [
2507  'config' => [
2508  'type' => 'select',
2509  'renderType' => 'selectSingle',
2510  'aKey' => 'aValue',
2511  'items' => [
2512  0 => [
2513  0 => 'aLabel',
2514  1 => 'aValue',
2515  ],
2516  ],
2517  'itemsProcFunc' => function (array $parameters, $pObj) {
2518  if ($parameters['items'] !== [ 0 => [ 'aLabel', 'aValue'] ]
2519  || $parameters['config']['aKey'] !== 'aValue'
2520  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
2521  || $parameters['table'] !== 'aTable'
2522  || $parameters['row'] !== [ 'aField' => 'aValue' ]
2523  || $parameters['field'] !== 'aField'
2524  ) {
2525  throw new \UnexpectedValueException('broken', 1438604329);
2526  }
2527  },
2528  ],
2529  ],
2530  ],
2531  ],
2532  ];
2533 
2534  $languageService = $this->prophesize(LanguageService::class);
2535  $GLOBALS['LANG'] = $languageService->reveal();
2536  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2538  $flashMessage = $this->prophesize(FlashMessage::class);
2539  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2541  $flashMessageService = $this->prophesize(FlashMessageService::class);
2542  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2544  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2545  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2546 
2547  // itemsProcFunc must NOT have raised an exception
2548  $flashMessageQueue->enqueue($flashMessage)->shouldNotBeCalled();
2549 
2550  $this->subject->addData($input);
2551  }
2552 
2556  public function addDataItemsProcFuncEnqueuesFlashMessageOnException()
2557  {
2558  $input = [
2559  'tableName' => 'aTable',
2560  'databaseRow' => [
2561  'aField' => 'aValue',
2562  ],
2563  'pageTsConfig' => [
2564  'TCEFORM.' => [
2565  'aTable.' => [
2566  'aField.' => [
2567  'itemsProcFunc.' => [
2568  'itemParamKey' => 'itemParamValue',
2569  ],
2570  ]
2571  ],
2572  ],
2573  ],
2574  'processedTca' => [
2575  'columns' => [
2576  'aField' => [
2577  'config' => [
2578  'type' => 'select',
2579  'renderType' => 'selectSingle',
2580  'aKey' => 'aValue',
2581  'items' => [
2582  0 => [
2583  0 => 'aLabel',
2584  1 => 'aValue',
2585  ],
2586  ],
2587  'itemsProcFunc' => function (array $parameters, $pObj) {
2588  throw new \UnexpectedValueException('anException', 1438604329);
2589  },
2590  ],
2591  ],
2592  ],
2593  ],
2594  ];
2595 
2596  $languageService = $this->prophesize(LanguageService::class);
2597  $GLOBALS['LANG'] = $languageService->reveal();
2599  $flashMessage = $this->prophesize(FlashMessage::class);
2600  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2602  $flashMessageService = $this->prophesize(FlashMessageService::class);
2603  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2605  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2606  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2607 
2608  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
2609 
2610  $this->subject->addData($input);
2611  }
2612 
2616  public function addDataTranslatesItemLabelsFromPageTsConfig()
2617  {
2618  $input = [
2619  'databaseRow' => [
2620  'aField' => 'aValue',
2621  ],
2622  'tableName' => 'aTable',
2623  'processedTca' => [
2624  'columns' => [
2625  'aField' => [
2626  'config' => [
2627  'type' => 'select',
2628  'renderType' => 'selectSingle',
2629  'items' => [
2630  0 => [
2631  0 => 'aLabel',
2632  1 => 'aValue',
2633  null,
2634  null,
2635  ],
2636  ],
2637  'maxitems' => 1,
2638  ],
2639  ],
2640  ],
2641  ],
2642  'pageTsConfig' => [
2643  'TCEFORM.' => [
2644  'aTable.' => [
2645  'aField.' => [
2646  'altLabels.' => [
2647  'aValue' => 'labelOverride',
2648  ],
2649  ]
2650  ],
2651  ],
2652  ],
2653  ];
2654 
2656  $languageService = $this->prophesize(LanguageService::class);
2657  $GLOBALS['LANG'] = $languageService->reveal();
2658  $languageService->sL('aLabel')->willReturnArgument(0);
2659  $languageService->sL('labelOverride')->shouldBeCalled()->willReturnArgument(0);
2660  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2661 
2662  $expected = $input;
2663  $expected['databaseRow']['aField'] = ['aValue'];
2664  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'labelOverride';
2665 
2666  $this->assertSame($expected, $this->subject->addData($input));
2667  $this->subject->addData($input);
2668  }
2669 
2673  public function processSelectFieldValueSetsMmForeignRelationValues()
2674  {
2675  $GLOBALS['TCA']['foreignTable'] = [];
2676 
2678  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2679  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2680 
2682  $database = $this->prophesize(DatabaseConnection::class);
2683  $GLOBALS['TYPO3_DB'] = $database->reveal();
2684 
2685  $input = [
2686  'tableName' => 'aTable',
2687  'databaseRow' => [
2688  'uid' => 42,
2689  // Two connected rows
2690  'aField' => 2,
2691  ],
2692  'processedTca' => [
2693  'columns' => [
2694  'aField' => [
2695  'config' => [
2696  'type' => 'select',
2697  'renderType' => 'selectSingle',
2698  'maxitems' => 999,
2699  'foreign_table' => 'foreignTable',
2700  'MM' => 'aTable_foreignTable_mm',
2701  'items' => [],
2702  ],
2703  ],
2704  ],
2705  ],
2706  ];
2707  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2709  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2710  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2711 
2712  $relationHandlerUids = [
2713  23,
2714  24
2715  ];
2716 
2717  $relationHandlerProphecy->start(2, 'foreignTable', 'aTable_foreignTable_mm', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2718  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2719 
2720  $expected = $input;
2721  $expected['databaseRow']['aField'] = $relationHandlerUids;
2722 
2723  $this->assertEquals($expected, $this->subject->addData($input));
2724  }
2725 
2729  public function processSelectFieldValueSetsForeignRelationValues()
2730  {
2731  $GLOBALS['TCA']['foreignTable'] = [];
2732 
2734  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2735  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2736 
2738  $database = $this->prophesize(DatabaseConnection::class);
2739  $GLOBALS['TYPO3_DB'] = $database->reveal();
2740 
2741  $input = [
2742  'tableName' => 'aTable',
2743  'databaseRow' => [
2744  'uid' => 42,
2745  // Two connected rows
2746  'aField' => '22,23,24,25',
2747  ],
2748  'processedTca' => [
2749  'columns' => [
2750  'aField' => [
2751  'config' => [
2752  'type' => 'select',
2753  'renderType' => 'selectSingle',
2754  'maxitems' => 999,
2755  'foreign_table' => 'foreignTable',
2756  'items' => [],
2757  ],
2758  ],
2759  ],
2760  ],
2761  ];
2762  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2764  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2765  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2766 
2767  $relationHandlerUids = [
2768  23,
2769  24
2770  ];
2771 
2772  $relationHandlerProphecy->start('22,23,24,25', 'foreignTable', '', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2773  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2774 
2775  $expected = $input;
2776  $expected['databaseRow']['aField'] = $relationHandlerUids;
2777 
2778  $this->assertEquals($expected, $this->subject->addData($input));
2779  }
2780 
2784  public function processSelectFieldValueRemovesInvalidDynamicValues()
2785  {
2786  $languageService = $this->prophesize(LanguageService::class);
2787  $GLOBALS['LANG'] = $languageService->reveal();
2788  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2789 
2790  $GLOBALS['TCA']['foreignTable'] = [];
2791 
2793  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2794  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2795 
2797  $database = $this->prophesize(DatabaseConnection::class);
2798  $GLOBALS['TYPO3_DB'] = $database->reveal();
2799 
2800  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2801  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2802  $relationHandlerProphecy->start(Argument::cetera())->shouldBeCalled();
2803  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldBeCalled()->willReturn([1]);
2804 
2805  $input = [
2806  'tableName' => 'aTable',
2807  'databaseRow' => [
2808  'aField' => '1,2,bar,foo',
2809  ],
2810  'processedTca' => [
2811  'columns' => [
2812  'aField' => [
2813  'config' => [
2814  'type' => 'select',
2815  'renderType' => 'selectSingleBox',
2816  'foreign_table' => 'foreignTable',
2817  'maxitems' => 999,
2818  'items' => [
2819  ['foo', 'foo', null, null],
2820  ],
2821  ],
2822  ],
2823  ],
2824  ],
2825  ];
2826 
2827  $expected = $input;
2828  $expected['databaseRow']['aField'] = ['foo', 1];
2829 
2830  $this->assertEquals($expected, $this->subject->addData($input));
2831  }
2832 
2837  {
2838  $languageService = $this->prophesize(LanguageService::class);
2839  $GLOBALS['LANG'] = $languageService->reveal();
2840  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2841 
2842  $input = [
2843  'tableName' => 'aTable',
2844  'databaseRow' => [
2845  'aField' => 'foo,bar',
2846  ],
2847  'processedTca' => [
2848  'columns' => [
2849  'aField' => [
2850  'config' => [
2851  'type' => 'select',
2852  'renderType' => 'selectSingle',
2853  'maxitems' => 999,
2854  'items' => [
2855  ['foo', 'foo', null, null],
2856  ['bar', 'bar', null, null],
2857  ],
2858  ],
2859  ],
2860  ],
2861  ],
2862  ];
2863 
2864  $expected = $input;
2865  $expected['databaseRow']['aField'] = [
2866  'foo',
2867  'bar'
2868  ];
2869 
2870  $this->assertEquals($expected, $this->subject->addData($input));
2871  }
2872 
2877  {
2878  $languageService = $this->prophesize(LanguageService::class);
2879  $GLOBALS['LANG'] = $languageService->reveal();
2880  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2881 
2882  $input = [
2883  'tableName' => 'aTable',
2884  'databaseRow' => [
2885  'aField' => '',
2886  ],
2887  'processedTca' => [
2888  'columns' => [
2889  'aField' => [
2890  'config' => [
2891  'type' => 'select',
2892  'renderType' => 'selectSingle',
2893  'maxitems' => 1,
2894  'items' => [],
2895  ],
2896  ],
2897  ],
2898  ],
2899  ];
2900 
2901  $expected = $input;
2902  $expected['databaseRow']['aField'] = [];
2903 
2904  $this->assertEquals($expected, $this->subject->addData($input));
2905  }
2906 
2911  {
2912  $languageService = $this->prophesize(LanguageService::class);
2913  $GLOBALS['LANG'] = $languageService->reveal();
2914  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2915 
2916  $input = [
2917  'tableName' => 'aTable',
2918  'databaseRow' => [
2919  'aField' => 'b,,c',
2920  ],
2921  'processedTca' => [
2922  'columns' => [
2923  'aField' => [
2924  'config' => [
2925  'type' => 'select',
2926  'renderType' => 'selectSingle',
2927  'maxitems' => 999,
2928  'items' => [
2929  ['a', '', null, null],
2930  ['b', 'b', null, null],
2931  ['c', 'c', null, null],
2932  ],
2933  ],
2934  ],
2935  ],
2936  ],
2937  ];
2938 
2939  $expected = $input;
2940  $expected['databaseRow']['aField'] = [
2941  'b',
2942  'c',
2943  ];
2944 
2945  $this->assertEquals($expected, $this->subject->addData($input));
2946  }
2947 
2952  {
2953  $languageService = $this->prophesize(LanguageService::class);
2954  $GLOBALS['LANG'] = $languageService->reveal();
2955  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2956 
2957  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2958  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2959  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
2960  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
2961 
2962  $input = [
2963  'tableName' => 'aTable',
2964  'databaseRow' => [
2965  'aField' => 'foo',
2966  ],
2967  'processedTca' => [
2968  'columns' => [
2969  'aField' => [
2970  'config' => [
2971  'type' => 'select',
2972  'renderType' => 'selectSingle',
2973  'maxitems' => 999,
2974  'items' => [
2975  ['foo', 'foo', null, null],
2976  ],
2977  ],
2978  ],
2979  ],
2980  ],
2981  ];
2982 
2983  $expected = $input;
2984  $expected['databaseRow']['aField'] = ['foo'];
2985 
2986  $this->assertEquals($expected, $this->subject->addData($input));
2987  }
2988 
2993  {
2994  $languageService = $this->prophesize(LanguageService::class);
2995  $GLOBALS['LANG'] = $languageService->reveal();
2996  $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2997  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2998 
2999  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3000  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3001  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3002  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3003 
3004  $input = [
3005  'tableName' => 'aTable',
3006  'databaseRow' => [
3007  'aField' => '1,2,bar,foo',
3008  ],
3009  'processedTca' => [
3010  'columns' => [
3011  'aField' => [
3012  'config' => [
3013  'type' => 'select',
3014  'renderType' => 'selectSingle',
3015  'maxitems' => 1,
3016  'items' => [
3017  ['foo', 'foo', null, null],
3018  ],
3019  ],
3020  ],
3021  ],
3022  ],
3023  ];
3024 
3025  $expected = $input;
3026  $expected['databaseRow']['aField'] = ['foo'];
3027  $expected['processedTca']['columns']['aField']['config']['items'] = [
3028  ['[ INVALID VALUE "bar" ]', 'bar', null, null],
3029  ['[ INVALID VALUE "2" ]', '2', null, null],
3030  ['[ INVALID VALUE "1" ]', '1', null, null],
3031  ['foo', 'foo', null, null],
3032  ];
3033  $this->assertEquals($expected, $this->subject->addData($input));
3034  }
3035 
3040  {
3041  $languageService = $this->prophesize(LanguageService::class);
3042  $GLOBALS['LANG'] = $languageService->reveal();
3043  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3044 
3045  $input = [
3046  'tableName' => 'aTable',
3047  'databaseRow' => [
3048  'aField' => '1,foo,foo,2,bar',
3049  ],
3050  'processedTca' => [
3051  'columns' => [
3052  'aField' => [
3053  'config' => [
3054  'type' => 'select',
3055  'renderType' => 'selectSingle',
3056  'multiple' => true,
3057  'maxitems' => 999,
3058  'items' => [
3059  ['1', '1', null, null],
3060  ['foo', 'foo', null, null],
3061  ['bar', 'bar', null, null],
3062  ['2', '2', null, null],
3063  ],
3064  ],
3065  ],
3066  ],
3067  ],
3068  ];
3069 
3070  $expected = $input;
3071  $expected['databaseRow']['aField'] = [
3072  '1',
3073  'foo',
3074  'foo',
3075  '2',
3076  'bar'
3077  ];
3078 
3079  $this->assertEquals($expected, $this->subject->addData($input));
3080  }
3081 
3086  {
3087  $languageService = $this->prophesize(LanguageService::class);
3088  $GLOBALS['LANG'] = $languageService->reveal();
3089  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3090 
3091  $input = [
3092  'tableName' => 'aTable',
3093  'databaseRow' => [
3094  'aField' => '1,foo,foo,2,bar',
3095  ],
3096  'processedTca' => [
3097  'columns' => [
3098  'aField' => [
3099  'config' => [
3100  'type' => 'select',
3101  'renderType' => 'selectSingle',
3102  'multiple' => false,
3103  'maxitems' => 999,
3104  'items' => [
3105  ['1', '1', null, null],
3106  ['foo', 'foo', null, null],
3107  ['bar', 'bar', null, null],
3108  ['2', '2', null, null],
3109  ],
3110  ],
3111  ],
3112  ],
3113  ],
3114  ];
3115 
3116  $expected = $input;
3117  $expected['databaseRow']['aField'] = [
3118  0 => '1',
3119  1 => 'foo',
3120  3 => '2',
3121  4 => 'bar',
3122  ];
3123 
3124  $this->assertEquals($expected, $this->subject->addData($input));
3125  }
3126 
3133  {
3134  return [
3135  'Relation with MM table and new status with default values' => [
3136  [
3137  'tableName' => 'aTable',
3138  'command' => 'new',
3139  'databaseRow' => [
3140  'uid' => 'NEW1234',
3141  'aField' => '24,35',
3142  ],
3143  'processedTca' => [
3144  'columns' => [
3145  'aField' => [
3146  'config' => [
3147  'type' => 'select',
3148  'renderType' => 'selectSingle',
3149  'maxitems' => 999,
3150  'MM' => 'mm_aTable_foreignTable',
3151  'foreign_table' => 'foreignTable',
3152  'items' => [],
3153  ],
3154  ],
3155  ],
3156  ],
3157  ],
3158  [
3159  'MM' => ''
3160  ],
3161  [
3162  24, 35
3163  ]
3164  ],
3165  'Relation with MM table and item array in list but no new status' => [
3166  [
3167  'tableName' => 'aTable',
3168  'databaseRow' => [
3169  'uid' => 'NEW1234',
3170  'aField' => '24,35',
3171  ],
3172  'processedTca' => [
3173  'columns' => [
3174  'aField' => [
3175  'config' => [
3176  'type' => 'select',
3177  'renderType' => 'selectSingle',
3178  'maxitems' => 999,
3179  'MM' => 'mm_aTable_foreignTable',
3180  'foreign_table' => 'foreignTable',
3181  'items' => [],
3182  ],
3183  ],
3184  ],
3185  ],
3186  ],
3187  [],
3188  []
3189  ],
3190  'Relation with MM table and maxitems = 1 processes field value (item count)' => [
3191  [
3192  'tableName' => 'aTable',
3193  'databaseRow' => [
3194  'uid' => 42,
3195  // MM relation with one item has 1 in field value
3196  'aField' => 1,
3197  ],
3198  'processedTca' => [
3199  'columns' => [
3200  'aField' => [
3201  'config' => [
3202  'type' => 'select',
3203  'renderType' => 'selectSingle',
3204  'maxitems' => 1,
3205  'MM' => 'mm_aTable_foreignTable',
3206  'foreign_table' => 'foreignTable',
3207  'items' => [],
3208  ],
3209  ],
3210  ],
3211  ],
3212  ],
3213  [],
3214  [
3215  24
3216  ]
3217  ],
3218  'Relation with MM table and maxitems = 1 results in empty array if no items are set' => [
3219  [
3220  'tableName' => 'aTable',
3221  'databaseRow' => [
3222  'uid' => 58,
3223  // MM relation with no items has 0 in field value
3224  'aField' => 0,
3225  ],
3226  'processedTca' => [
3227  'columns' => [
3228  'aField' => [
3229  'config' => [
3230  'type' => 'select',
3231  'renderType' => 'selectSingle',
3232  'maxitems' => 1,
3233  'MM' => 'mm_aTable_foreignTable',
3234  'foreign_table' => 'foreignTable',
3235  'items' => [],
3236  ],
3237  ],
3238  ],
3239  ],
3240  ],
3241  [],
3242  []
3243  ]
3244  ];
3245  }
3246 
3255  public function processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids)
3256  {
3257  $field = $input['databaseRow']['aField'];
3258  $foreignTable = isset($overrideRelationHandlerSettings['foreign_table']) ? $overrideRelationHandlerSettings['foreign_table'] : $input['processedTca']['columns']['aField']['config']['foreign_table'];
3259  $mmTable = isset($overrideRelationHandlerSettings['MM']) ? $overrideRelationHandlerSettings['MM'] : $input['processedTca']['columns']['aField']['config']['MM'];
3260  $uid = $input['databaseRow']['uid'];
3261  $tableName = $input['tableName'];
3262  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
3263 
3264  $GLOBALS['TCA'][$foreignTable] = [];
3265 
3267  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3268  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3269 
3271  $database = $this->prophesize(DatabaseConnection::class);
3272  $GLOBALS['TYPO3_DB'] = $database->reveal();
3273 
3275  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3276  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3277 
3278  $relationHandlerProphecy->start($field, $foreignTable, $mmTable, $uid, $tableName, $fieldConfig)->shouldBeCalled();
3279  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
3280 
3281  $expected = $input;
3282  $expected['databaseRow']['aField'] = $relationHandlerUids;
3283 
3284  $this->assertEquals($expected, $this->subject->addData($input));
3285  }
3286 }
static addInstance($className, $instance)
$database
Definition: server.php:40
static setSingletonInstance($className, SingletonInterface $instance)
static resetSingletonInstances(array $newSingletonInstances)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
$uid
Definition: server.php:38
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']