[!!!][TASK] Improve flex and TCA handling in FormEngine
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Form / FormDataProvider / TcaFlexProcessTest.php
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;
19 use TYPO3\CMS\Backend\Form\FormDataGroup\FlexFormSegment;
20 use TYPO3\CMS\Backend\Form\FormDataProvider\TcaFlexProcess;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Lang\LanguageService;
24
25 /**
26 * Test case
27 */
28 class TcaFlexProcessTest extends \TYPO3\CMS\Components\TestingFramework\Core\UnitTestCase
29 {
30 /**
31 * @var BackendUserAuthentication|ObjectProphecy
32 */
33 protected $backendUserProphecy;
34
35 protected function setUp()
36 {
37 /** @var BackendUserAuthentication|ObjectProphecy backendUserProphecy */
38 $this->backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
39 $GLOBALS['BE_USER'] = $this->backendUserProphecy->reveal();
40 $GLOBALS['BE_USER']->groupData['non_exclude_fields'] = '';
41
42 // Some tests call FormDataCompiler for sub elements. Those tests have functional test characteristics.
43 // This is ok for the time being, but this settings takes care only parts of the compiler are called
44 // to have less dependencies.
45 $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['flexFormSegment'] = [];
46 }
47
48 /**
49 * @test
50 */
51 public function addDataThrowsExceptionWithMissingDataStructureIdentifier()
52 {
53 $input = [
54 'tableName' => 'aTable',
55 'databaseRow' => [],
56 'processedTca' => [
57 'columns' => [
58 'aField' => [
59 'config' => [
60 'type' => 'flex',
61 'ds' => [],
62 ],
63 ],
64 ],
65 ],
66 ];
67
68 $this->expectException(\RuntimeException::class);
69 $this->expectExceptionCode(1480765571);
70 (new TcaFlexProcess())->addData($input);
71 }
72
73 /**
74 * @test
75 */
76 public function addDataRemovesSheetIfDisabledByPageTsConfig()
77 {
78 $input = [
79 'tableName' => 'aTable',
80 'databaseRow' => [
81 'aField' => [
82 'data' => [],
83 ],
84 'pointerField' => 'aFlex',
85 ],
86 'processedTca' => [
87 'columns' => [
88 'aField' => [
89 'config' => [
90 'type' => 'flex',
91 'ds_pointerField' => 'pointerField',
92 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
93 'ds' => [
94 'sheets' => [
95 'aSheet' => [
96 'ROOT' => [
97 'type' => 'array',
98 'el' => [
99 'aFlexField' => [
100 'label' => 'aFlexFieldLabel',
101 'config' => [
102 'type' => 'input',
103 ],
104 ]
105 ],
106 ],
107 ],
108 ],
109 ],
110 ],
111 ],
112 ],
113 ],
114 'pageTsConfig' => [
115 'TCEFORM.' => [
116 'aTable.' => [
117 'aField.' => [
118 'aFlex.' => [
119 'aSheet.' => [
120 'disabled' => 1,
121 ],
122 ],
123 ],
124 ],
125 ],
126 ],
127 ];
128
129 $expected = $input;
130 $expected['processedTca']['columns']['aField']['config']['ds'] = [
131 'sheets' => [],
132 ];
133
134 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
135 }
136
137 /**
138 * @test
139 */
140 public function addDataSetsSheetTitleFromPageTsConfig()
141 {
142 $input = [
143 'tableName' => 'aTable',
144 'databaseRow' => [
145 'aField' => [
146 'data' => [],
147 ],
148 'pointerField' => 'aFlex',
149 ],
150 'processedTca' => [
151 'columns' => [
152 'aField' => [
153 'config' => [
154 'type' => 'flex',
155 'ds_pointerField' => 'pointerField',
156 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
157 'ds' => [
158 'sheets' => [
159 'aSheet' => [
160 'ROOT' => [
161 'type' => 'array',
162 'el' => [
163 'aFlexField' => [
164 'label' => 'aFlexFieldLabel',
165 'config' => [
166 'type' => 'input',
167 ],
168 ]
169 ],
170 ],
171 ],
172 ],
173 ],
174 ],
175 ],
176 ],
177 ],
178 'pageTsConfig' => [
179 'TCEFORM.' => [
180 'aTable.' => [
181 'aField.' => [
182 'aFlex.' => [
183 'aSheet.' => [
184 'sheetTitle' => 'aTitle',
185 ],
186 ],
187 ],
188 ],
189 ],
190 ],
191 ];
192
193 $expected = $input;
194 $expected['processedTca']['columns']['aField']['config']['ds'] = [
195 'sheets' => [
196 'aSheet' => [
197 'ROOT' => [
198 'type' => 'array',
199 'el' => [
200 'aFlexField' => [
201 'label' => 'aFlexFieldLabel',
202 'config' => [
203 'type' => 'input',
204 ],
205 ],
206 ],
207 'sheetTitle' => 'aTitle',
208 ],
209 ],
210 ],
211 ];
212
213 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
214 }
215
216 /**
217 * @test
218 */
219 public function addDataSetsSheetDescriptionFromPageTsConfig()
220 {
221 $input = [
222 'tableName' => 'aTable',
223 'databaseRow' => [
224 'aField' => [
225 'data' => [],
226 ],
227 'pointerField' => 'aFlex',
228 ],
229 'processedTca' => [
230 'columns' => [
231 'aField' => [
232 'config' => [
233 'type' => 'flex',
234 'ds_pointerField' => 'pointerField',
235 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
236 'ds' => [
237 'sheets' => [
238 'aSheet' => [
239 'ROOT' => [
240 'type' => 'array',
241 'el' => [
242 'aFlexField' => [
243 'label' => 'aFlexFieldLabel',
244 'config' => [
245 'type' => 'input',
246 ],
247 ]
248 ],
249 ],
250 ],
251 ],
252 ],
253 ],
254 ],
255 ],
256 ],
257 'pageTsConfig' => [
258 'TCEFORM.' => [
259 'aTable.' => [
260 'aField.' => [
261 'aFlex.' => [
262 'aSheet.' => [
263 'sheetDescription' => 'aDescription',
264 ],
265 ],
266 ],
267 ],
268 ],
269 ],
270 ];
271
272 $expected = $input;
273 $expected['processedTca']['columns']['aField']['config']['ds'] = [
274 'sheets' => [
275 'aSheet' => [
276 'ROOT' => [
277 'type' => 'array',
278 'el' => [
279 'aFlexField' => [
280 'label' => 'aFlexFieldLabel',
281 'config' => [
282 'type' => 'input',
283 ],
284 ],
285 ],
286 'sheetDescription' => 'aDescription',
287 ],
288 ],
289 ],
290 ];
291
292 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
293 }
294
295 /**
296 * @test
297 */
298 public function addDataSetsSheetShortDescriptionFromPageTsConfig()
299 {
300 $input = [
301 'tableName' => 'aTable',
302 'databaseRow' => [
303 'aField' => [
304 'data' => [],
305 ],
306 'pointerField' => 'aFlex',
307 ],
308 'processedTca' => [
309 'columns' => [
310 'aField' => [
311 'config' => [
312 'type' => 'flex',
313 'ds_pointerField' => 'pointerField',
314 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
315 'ds' => [
316 'sheets' => [
317 'aSheet' => [
318 'ROOT' => [
319 'type' => 'array',
320 'el' => [
321 'aFlexField' => [
322 'label' => 'aFlexFieldLabel',
323 'config' => [
324 'type' => 'input',
325 ],
326 ]
327 ],
328 ],
329 ],
330 ],
331 ],
332 ],
333 ],
334 ],
335 ],
336 'pageTsConfig' => [
337 'TCEFORM.' => [
338 'aTable.' => [
339 'aField.' => [
340 'aFlex.' => [
341 'aSheet.' => [
342 'sheetDescription' => 'sheetShortDescr',
343 ],
344 ],
345 ],
346 ],
347 ],
348 ],
349 ];
350
351 $expected = $input;
352 $expected['processedTca']['columns']['aField']['config']['ds'] = [
353 'sheets' => [
354 'aSheet' => [
355 'ROOT' => [
356 'type' => 'array',
357 'el' => [
358 'aFlexField' => [
359 'label' => 'aFlexFieldLabel',
360 'config' => [
361 'type' => 'input',
362 ],
363 ],
364 ],
365 'sheetDescription' => 'sheetShortDescr',
366 ],
367 ],
368 ],
369 ];
370
371 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
372 }
373
374 /**
375 * @test
376 */
377 public function addDataSetsSheetShortDescriptionForSingleSheetFromPageTsConfig()
378 {
379 $input = [
380 'tableName' => 'aTable',
381 'databaseRow' => [
382 'aField' => [
383 'data' => [],
384 ],
385 'pointerField' => 'aFlex',
386 ],
387 'processedTca' => [
388 'columns' => [
389 'aField' => [
390 'config' => [
391 'type' => 'flex',
392 'ds_pointerField' => 'pointerField',
393 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
394 'ds' => [
395 'sheets' => [
396 'sDEF' => [
397 'ROOT' => [
398 'type' => 'array',
399 'el' => [
400 'aFlexField' => [
401 'label' => 'aFlexFieldLabel',
402 'config' => [
403 'type' => 'input',
404 ],
405 ]
406 ],
407 ],
408 ],
409 ],
410 ],
411 ],
412 ],
413 ],
414 ],
415 'pageTsConfig' => [
416 'TCEFORM.' => [
417 'aTable.' => [
418 'aField.' => [
419 'aFlex.' => [
420 'sDEF.' => [
421 'sheetDescription' => 'sheetShortDescr',
422 ],
423 ],
424 ],
425 ],
426 ],
427 ],
428 ];
429
430 $expected = $input;
431 $expected['processedTca']['columns']['aField']['config']['ds'] = [
432 'sheets' => [
433 'sDEF' => [
434 'ROOT' => [
435 'type' => 'array',
436 'el' => [
437 'aFlexField' => [
438 'label' => 'aFlexFieldLabel',
439 'config' => [
440 'type' => 'input',
441 ],
442 ],
443 ],
444 'sheetDescription' => 'sheetShortDescr',
445 ],
446 ],
447 ],
448 ];
449
450 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
451 }
452
453 /**
454 * @test
455 */
456 public function addDataRemovesExcludeFieldFromDataStructure()
457 {
458 $input = [
459 'tableName' => 'aTable',
460 'databaseRow' => [
461 'aField' => [
462 'data' => [],
463 ],
464 'pointerField' => 'aFlex',
465 ],
466 'processedTca' => [
467 'columns' => [
468 'aField' => [
469 'config' => [
470 'type' => 'flex',
471 'ds_pointerField' => 'pointerField',
472 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
473 'ds' => [
474 'sheets' => [
475 'sDEF' => [
476 'ROOT' => [
477 'type' => 'array',
478 'el' => [
479 'aFlexField' => [
480 'label' => 'aFlexFieldLabel',
481 'exclude' => '1',
482 'config' => [
483 'type' => 'input',
484 ],
485 ]
486 ],
487 ],
488 ],
489 ],
490 ],
491 ],
492 ],
493 ],
494 ],
495 'pageTsConfig' => [],
496 ];
497
498 $this->backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
499 $GLOBALS['BE_USER']->groupData['non_exclude_fields'] = '';
500
501 $expected = $input;
502 $expected['processedTca']['columns']['aField']['config']['ds'] = [
503 'sheets' => [
504 'sDEF' => [
505 'ROOT' => [
506 'type' => 'array',
507 'el' => [],
508 ],
509 ],
510 ],
511 ];
512
513 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
514 }
515
516 /**
517 * @test
518 */
519 public function addDataKeepsExcludeFieldInDataStructureWithUserAccess()
520 {
521 $input = [
522 'tableName' => 'aTable',
523 'databaseRow' => [
524 'aField' => [
525 'data' => [],
526 ],
527 'pointerField' => 'aFlex',
528 ],
529 'processedTca' => [
530 'columns' => [
531 'aField' => [
532 'config' => [
533 'type' => 'flex',
534 'ds_pointerField' => 'pointerField',
535 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
536 'ds' => [
537 'sheets' => [
538 'sDEF' => [
539 'ROOT' => [
540 'type' => 'array',
541 'el' => [
542 'aFlexField' => [
543 'label' => 'aFlexFieldLabel',
544 'exclude' => '1',
545 'config' => [
546 'type' => 'input',
547 ],
548 ]
549 ],
550 ],
551 ],
552 ],
553 ],
554 ],
555 ],
556 ],
557 ],
558 'pageTsConfig' => [],
559 ];
560
561 $this->backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
562 $GLOBALS['BE_USER']->groupData['non_exclude_fields'] = 'aTable:aField;aFlex;sDEF;aFlexField';
563
564 $expected = $input;
565 $expected['processedTca']['columns']['aField']['config']['ds'] = [
566 'sheets' => [
567 'sDEF' => [
568 'ROOT' => [
569 'type' => 'array',
570 'el' => [
571 'aFlexField' => [
572 'label' => 'aFlexFieldLabel',
573 'config' => [
574 'type' => 'input',
575 ],
576 'exclude' => '1',
577 ],
578 ],
579 ],
580 ],
581 ],
582 ];
583
584 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
585 }
586
587 /**
588 * @test
589 */
590 public function addDataKeepsExcludeFieldInDataStructureForAdminUser()
591 {
592 $input = [
593 'tableName' => 'aTable',
594 'databaseRow' => [
595 'aField' => [
596 'data' => [],
597 ],
598 'pointerField' => 'aFlex',
599 ],
600 'processedTca' => [
601 'columns' => [
602 'aField' => [
603 'config' => [
604 'type' => 'flex',
605 'ds_pointerField' => 'pointerField',
606 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
607 'ds' => [
608 'sheets' => [
609 'sDEF' => [
610 'ROOT' => [
611 'type' => 'array',
612 'el' => [
613 'aFlexField' => [
614 'label' => 'aFlexFieldLabel',
615 'exclude' => '1',
616 'config' => [
617 'type' => 'input',
618 ],
619 ]
620 ],
621 ],
622 ],
623 ],
624 ],
625 ],
626 ],
627 ],
628 ],
629 'pageTsConfig' => [],
630 ];
631
632 $this->backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(true);
633 $GLOBALS['BE_USER']->groupData['non_exclude_fields'] = '';
634
635 $expected = $input;
636 $expected['processedTca']['columns']['aField']['config']['ds'] = [
637 'sheets' => [
638 'sDEF' => [
639 'ROOT' => [
640 'type' => 'array',
641 'el' => [
642 'aFlexField' => [
643 'label' => 'aFlexFieldLabel',
644 'config' => [
645 'type' => 'input',
646 ],
647 'exclude' => '1',
648 ],
649 ],
650 ],
651 ],
652 ],
653 ];
654
655 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
656 }
657
658 /**
659 * @test
660 */
661 public function addDataRemovesPageTsDisabledFieldFromDataStructure()
662 {
663 $input = [
664 'tableName' => 'aTable',
665 'databaseRow' => [
666 'aField' => [
667 'data' => [],
668 ],
669 'pointerField' => 'aFlex',
670 ],
671 'processedTca' => [
672 'columns' => [
673 'aField' => [
674 'config' => [
675 'type' => 'flex',
676 'ds_pointerField' => 'pointerField',
677 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
678 'ds' => [
679 'sheets' => [
680 'sDEF' => [
681 'ROOT' => [
682 'type' => 'array',
683 'el' => [
684 'aFlexField' => [
685 'label' => 'aFlexFieldLabel',
686 'config' => [
687 'type' => 'input',
688 ],
689 ]
690 ],
691 ],
692 ],
693 ],
694 ],
695 ],
696 ],
697 ],
698 ],
699 'pageTsConfig' => [
700 'TCEFORM.' => [
701 'aTable.' => [
702 'aField.' => [
703 'aFlex.' => [
704 'sDEF.' => [
705 'aFlexField.' => [
706 'disabled' => 1,
707 ],
708 ],
709 ],
710 ],
711 ],
712 ],
713 ],
714 ];
715
716 $expected = $input;
717 $expected['processedTca']['columns']['aField']['config']['ds'] = [
718 'sheets' => [
719 'sDEF' => [
720 'ROOT' => [
721 'type' => 'array',
722 'el' => [],
723 ],
724 ],
725 ],
726 ];
727
728 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
729 }
730
731 /**
732 * @test
733 */
734 public function addDataHandlesPageTsConfigSettingsOfSingleFlexField()
735 {
736 $input = [
737 'tableName' => 'aTable',
738 'databaseRow' => [
739 'aField' => [
740 'data' => [],
741 ],
742 'pointerField' => 'aFlex',
743 ],
744 'processedTca' => [
745 'columns' => [
746 'aField' => [
747 'config' => [
748 'type' => 'flex',
749 'ds_pointerField' => 'pointerField',
750 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
751 'ds' => [
752 'sheets' => [
753 'sDEF' => [
754 'ROOT' => [
755 'type' => 'array',
756 'el' => [
757 'aFlexField' => [
758 'label' => 'aFlexFieldLabel',
759 'config' => [
760 'type' => 'radio',
761 'items' => [
762 0 => [
763 0 => 'aLabel',
764 1 => 'aValue',
765 ],
766 ],
767 ],
768 ],
769 ],
770 ],
771 ],
772 ],
773 ],
774 ],
775 ],
776 ],
777 ],
778 'pageTsConfig' => [
779 'TCEFORM.' => [
780 'aTable.' => [
781 'aField.' => [
782 'aFlex.' => [
783 'sDEF.' => [
784 'aFlexField.' => [
785 'altLabels.' => [
786 '0' => 'labelOverride',
787 ],
788 ],
789 ],
790 ],
791 ],
792 ],
793 ],
794 ],
795 ];
796
797 $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['flexFormSegment'] = [
798 \TYPO3\CMS\Backend\Form\FormDataProvider\TcaRadioItems::class => [],
799 ];
800
801 /** @var LanguageService|ObjectProphecy $languageService */
802 $languageService = $this->prophesize(LanguageService::class);
803 $GLOBALS['LANG'] = $languageService->reveal();
804 $languageService->sL(Argument::cetera())->willReturnArgument(0);
805
806 $this->backendUserProphecy->isAdmin()->willReturn(true);
807 $this->backendUserProphecy->checkLanguageAccess(Argument::cetera())->willReturn(true);
808
809 $expected = $input;
810 $expected['processedTca']['columns']['aField']['config']['ds'] = [
811 'sheets' => [
812 'sDEF' => [
813 'ROOT' => [
814 'type' => 'array',
815 'el' => [
816 'aFlexField' => [
817 'label' => 'aFlexFieldLabel',
818 'config' => [
819 'type' => 'radio',
820 'items' => [
821 0 => [
822 0 => 'labelOverride',
823 1 => 'aValue',
824 ],
825 ],
826 ],
827 ],
828 ],
829 ],
830 ],
831 ],
832 ];
833
834 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
835 }
836
837 /**
838 * @test
839 */
840 public function addDataSetsDefaultValueFromFlexTcaForField()
841 {
842 $input = [
843 'tableName' => 'aTable',
844 'databaseRow' => [
845 'aField' => [
846 'data' => [],
847 ],
848 'pointerField' => 'aFlex',
849 ],
850 'processedTca' => [
851 'columns' => [
852 'aField' => [
853 'config' => [
854 'type' => 'flex',
855 'ds_pointerField' => 'pointerField',
856 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
857 'ds' => [
858 'sheets' => [
859 'sDEF' => [
860 'ROOT' => [
861 'type' => 'array',
862 'el' => [
863 'aFlexField' => [
864 'label' => 'aFlexFieldLabel',
865 'config' => [
866 'type' => 'input',
867 'default' => 'defaultValue',
868 ],
869 ],
870 ],
871 ],
872 ],
873 ],
874 ],
875 ],
876 ],
877 ],
878 ],
879 'pageTsConfig' => [],
880 ];
881
882 $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['flexFormSegment'] = [
883 \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class => [],
884 ];
885
886 /** @var LanguageService|ObjectProphecy $languageService */
887 $languageService = $this->prophesize(LanguageService::class);
888 $GLOBALS['LANG'] = $languageService->reveal();
889 $languageService->sL(Argument::cetera())->willReturnArgument(0);
890
891 $this->backendUserProphecy->isAdmin()->willReturn(true);
892 $this->backendUserProphecy->checkLanguageAccess(Argument::cetera())->willReturn(true);
893
894 $expected = $input;
895 $expected['databaseRow']['aField']['data']['sDEF']['lDEF']['aFlexField']['vDEF'] = 'defaultValue';
896
897 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
898 }
899
900 /**
901 * @test
902 */
903 public function addDataThrowsExceptionForDataStructureTypeArrayWithoutSection()
904 {
905 $input = [
906 'tableName' => 'aTable',
907 'databaseRow' => [
908 'aField' => [
909 'data' => [],
910 'meta' => [],
911 ],
912 ],
913 'processedTca' => [
914 'columns' => [
915 'aField' => [
916 'config' => [
917 'type' => 'flex',
918 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
919 'ds' => [
920 'sheets' => [
921 'sDEF' => [
922 'ROOT' => [
923 'type' => 'array',
924 'el' => [
925 'aFlexField' => [
926 'type' => 'array',
927 ],
928 ],
929 ],
930 ],
931 ],
932 ],
933 ],
934 ],
935 ],
936 ],
937 'pageTsConfig' => [],
938 ];
939
940 $this->backendUserProphecy->isAdmin()->willReturn(true);
941 $this->backendUserProphecy->checkLanguageAccess(Argument::cetera())->willReturn(true);
942
943 $this->expectException(\UnexpectedValueException::class);
944 $this->expectExceptionCode(1440685208);
945
946 (new TcaFlexProcess())->addData($input);
947 }
948
949 /**
950 * @test
951 */
952 public function addDataThrowsExceptionForDataStructureSectionWithoutTypeArray()
953 {
954 $input = [
955 'tableName' => 'aTable',
956 'databaseRow' => [
957 'aField' => [
958 'data' => [],
959 'meta' => [],
960 ],
961 ],
962 'processedTca' => [
963 'columns' => [
964 'aField' => [
965 'config' => [
966 'type' => 'flex',
967 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
968 'ds' => [
969 'sheets' => [
970 'sDEF' => [
971 'ROOT' => [
972 'type' => 'array',
973 'el' => [
974 'aFlexField' => [
975 'section' => '1',
976 ],
977 ],
978 ],
979 ],
980 ],
981 ],
982 ],
983 ],
984 ],
985 ],
986 'pageTsConfig' => [],
987 ];
988
989 $this->backendUserProphecy->isAdmin()->willReturn(true);
990 $this->backendUserProphecy->checkLanguageAccess(Argument::cetera())->willReturn(true);
991
992 $this->expectException(\UnexpectedValueException::class);
993 $this->expectExceptionCode(1440685208);
994
995 (new TcaFlexProcess())->addData($input);
996 }
997
998 /**
999 * @test
1000 */
1001 public function addDataSetsValuesAndStructureForSectionContainerElements()
1002 {
1003 $input = [
1004 'tableName' => 'aTable',
1005 'databaseRow' => [
1006 'aField' => [
1007 'data' => [
1008 'sDEF' => [
1009 'lDEF' => [
1010 'section_1' => [
1011 'el' => [
1012 '1' => [
1013 'container_1' => [
1014 // It should set the default value for aFlexField here
1015 'el' => [
1016 ],
1017 ],
1018 ],
1019 '2' => [
1020 'container_1' => [
1021 'el' => [
1022 'aFlexField' => [
1023 // It should keep this value
1024 'vDEF' => 'dbValue',
1025 ],
1026 ],
1027 ],
1028 ],
1029 ],
1030 ],
1031 ],
1032 ],
1033 ],
1034 'meta' => [],
1035 ],
1036 ],
1037 'processedTca' => [
1038 'columns' => [
1039 'aField' => [
1040 'config' => [
1041 'type' => 'flex',
1042 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1043 'ds' => [
1044 'sheets' => [
1045 'sDEF' => [
1046 'ROOT' => [
1047 'type' => 'array',
1048 'el' => [
1049 'section_1' => [
1050 'section' => '1',
1051 'type' => 'array',
1052 'el' => [
1053 'container_1' => [
1054 'type' => 'array',
1055 'el' => [
1056 'aFlexField' => [
1057 'label' => 'aFlexFieldLabel',
1058 'config' => [
1059 'type' => 'input',
1060 'default' => 'defaultValue',
1061 ],
1062 ],
1063 ],
1064 ],
1065 ],
1066 ],
1067 ],
1068 ],
1069 ],
1070 ],
1071 ],
1072 ],
1073 ],
1074 ],
1075 ],
1076 'pageTsConfig' => [],
1077 ];
1078
1079 $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['flexFormSegment'] = [
1080 \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class => [],
1081 ];
1082
1083 /** @var LanguageService|ObjectProphecy $languageService */
1084 $languageService = $this->prophesize(LanguageService::class);
1085 $GLOBALS['LANG'] = $languageService->reveal();
1086 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1087
1088 $this->backendUserProphecy->isAdmin()->willReturn(true);
1089 $this->backendUserProphecy->checkLanguageAccess(Argument::cetera())->willReturn(true);
1090
1091 $expected = $input;
1092
1093 // A default value for existing container field aFlexField should have been set
1094 $expected['databaseRow']['aField']['data']['sDEF']['lDEF']['section_1']['el']['1']['container_1']['el']['aFlexField']['vDEF'] = 'defaultValue';
1095
1096 // Data structure of given containers is copied over to "children" referencing the existing container name
1097 $expected['processedTca']['columns']['aField']['config']['ds']['sheets']['sDEF']['ROOT']['el']['section_1']['children']['1']
1098 = $expected['processedTca']['columns']['aField']['config']['ds']['sheets']['sDEF']['ROOT']['el']['section_1']['el']['container_1'];
1099 $expected['processedTca']['columns']['aField']['config']['ds']['sheets']['sDEF']['ROOT']['el']['section_1']['children']['2']
1100 = $expected['processedTca']['columns']['aField']['config']['ds']['sheets']['sDEF']['ROOT']['el']['section_1']['el']['container_1'];
1101
1102 $this->assertEquals($expected, (new TcaFlexProcess())->addData($input));
1103 }
1104
1105 /**
1106 * @test
1107 */
1108 public function addDataThrowsExceptionForInlineElementsNestedInSectionContainers()
1109 {
1110 $input = [
1111 'tableName' => 'aTable',
1112 'databaseRow' => [
1113 'aField' => [
1114 'data' => [],
1115 ],
1116 'pointerField' => 'aFlex',
1117 ],
1118 'processedTca' => [
1119 'columns' => [
1120 'aField' => [
1121 'config' => [
1122 'type' => 'flex',
1123 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1124 'ds' => [
1125 'sheets' => [
1126 'sDEF' => [
1127 'ROOT' => [
1128 'type' => 'array',
1129 'el' => [
1130 'section_1' => [
1131 'section' => '1',
1132 'type' => 'array',
1133 'el' => [
1134 'container_1' => [
1135 'type' => 'array',
1136 'el' => [
1137 'aFlexField' => [
1138 'label' => 'aFlexFieldLabel',
1139 'config' => [
1140 'type' => 'inline',
1141 ],
1142 ],
1143 ],
1144 ],
1145 ],
1146 ],
1147 ],
1148 ],
1149 ],
1150 ],
1151 ],
1152 ],
1153 ],
1154 ],
1155 ],
1156 'pageTsConfig' => [],
1157 ];
1158
1159 $this->expectException(\UnexpectedValueException::class);
1160 $this->expectExceptionCode(1458745468);
1161
1162 (new TcaFlexProcess())->addData($input);
1163 }
1164
1165 /**
1166 * @test
1167 */
1168 public function addDataThrowsExceptionForNestedSectionContainers()
1169 {
1170 $input = [
1171 'tableName' => 'aTable',
1172 'databaseRow' => [
1173 'aField' => [
1174 'data' => [],
1175 ],
1176 'pointerField' => 'aFlex',
1177 ],
1178 'processedTca' => [
1179 'columns' => [
1180 'aField' => [
1181 'config' => [
1182 'type' => 'flex',
1183 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1184 'ds' => [
1185 'sheets' => [
1186 'sDEF' => [
1187 'ROOT' => [
1188 'type' => 'array',
1189 'el' => [
1190 'section_1' => [
1191 'section' => '1',
1192 'type' => 'array',
1193 'el' => [
1194 'container_1' => [
1195 'type' => 'array',
1196 'el' => [
1197 'section_nested' => [
1198 'section' => '1',
1199 'type' => 'array',
1200 'el' => [
1201 ],
1202 ],
1203 ],
1204 ],
1205 ],
1206 ],
1207 ],
1208 ],
1209 ],
1210 ],
1211 ],
1212 ],
1213 ],
1214 ],
1215 ],
1216 'pageTsConfig' => [],
1217 ];
1218
1219 $this->expectException(\UnexpectedValueException::class);
1220 $this->expectExceptionCode(1458745712);
1221
1222 (new TcaFlexProcess())->addData($input);
1223 }
1224
1225 /**
1226 * @test
1227 */
1228 public function addDataThrowsExceptionForSelectElementsInSectionContainers()
1229 {
1230 $input = [
1231 'tableName' => 'aTable',
1232 'databaseRow' => [
1233 'aField' => [
1234 'data' => [],
1235 ],
1236 'pointerField' => 'aFlex',
1237 ],
1238 'processedTca' => [
1239 'columns' => [
1240 'aField' => [
1241 'config' => [
1242 'type' => 'flex',
1243 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1244 'ds' => [
1245 'sheets' => [
1246 'sDEF' => [
1247 'ROOT' => [
1248 'type' => 'array',
1249 'el' => [
1250 'section_1' => [
1251 'section' => '1',
1252 'type' => 'array',
1253 'el' => [
1254 'container_1' => [
1255 'type' => 'array',
1256 'el' => [
1257 'section_nested' => [
1258 'config' => [
1259 'type' => 'select',
1260 'MM' => '',
1261 ],
1262 ],
1263 ],
1264 ],
1265 ],
1266 ],
1267 ],
1268 ],
1269 ],
1270 ],
1271 ],
1272 ],
1273 ],
1274 ],
1275 ],
1276 'pageTsConfig' => [],
1277 ];
1278
1279 $this->expectException(\UnexpectedValueException::class);
1280 $this->expectExceptionCode(1481647089);
1281
1282 (new TcaFlexProcess())->addData($input);
1283 }
1284
1285 /**
1286 * @test
1287 */
1288 public function addDataThrowsExceptionForGroupElementsInSectionContainers()
1289 {
1290 $input = [
1291 'tableName' => 'aTable',
1292 'databaseRow' => [
1293 'aField' => [
1294 'data' => [],
1295 ],
1296 'pointerField' => 'aFlex',
1297 ],
1298 'processedTca' => [
1299 'columns' => [
1300 'aField' => [
1301 'config' => [
1302 'type' => 'flex',
1303 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1304 'ds' => [
1305 'sheets' => [
1306 'sDEF' => [
1307 'ROOT' => [
1308 'type' => 'array',
1309 'el' => [
1310 'section_1' => [
1311 'section' => '1',
1312 'type' => 'array',
1313 'el' => [
1314 'container_1' => [
1315 'type' => 'array',
1316 'el' => [
1317 'section_nested' => [
1318 'config' => [
1319 'type' => 'group',
1320 'MM' => '',
1321 ],
1322 ],
1323 ],
1324 ],
1325 ],
1326 ],
1327 ],
1328 ],
1329 ],
1330 ],
1331 ],
1332 ],
1333 ],
1334 ],
1335 ],
1336 'pageTsConfig' => [],
1337 ];
1338
1339 $this->expectException(\UnexpectedValueException::class);
1340 $this->expectExceptionCode(1481647089);
1341
1342 (new TcaFlexProcess())->addData($input);
1343 }
1344
1345 /**
1346 * @test
1347 */
1348 public function addDataCallsFlexFormSegmentGroupForFieldAndAddsFlexParentDatabaseRow()
1349 {
1350 $input = [
1351 'tableName' => 'aTable',
1352 'databaseRow' => [
1353 'aField' => [
1354 'data' => [],
1355 ],
1356 'pointerField' => 'aFlex',
1357 ],
1358 'processedTca' => [
1359 'columns' => [
1360 'aField' => [
1361 'config' => [
1362 'type' => 'flex',
1363 'ds_pointerField' => 'pointerField',
1364 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1365 'ds' => [
1366 'sheets' => [
1367 'sDEF' => [
1368 'ROOT' => [
1369 'type' => 'array',
1370 'el' => [
1371 'aFlexField' => [
1372 'label' => 'aFlexFieldLabel',
1373 'config' => [
1374 'type' => 'input',
1375 ],
1376 ],
1377 ],
1378 ],
1379 ],
1380 ],
1381 ],
1382 ],
1383 ],
1384 ],
1385 ],
1386 'pageTsConfig' => [],
1387 ];
1388
1389 /** @var FlexFormSegment|ObjectProphecy $dummyGroup */
1390 $dummyGroup = $this->prophesize(FlexFormSegment::class);
1391 GeneralUtility::addInstance(FlexFormSegment::class, $dummyGroup->reveal());
1392
1393 // Check array given to flex group contains databaseRow as flexParentDatabaseRow and check compile is called
1394 $dummyGroup->compile(Argument::that(function ($result) use ($input) {
1395 if ($result['flexParentDatabaseRow'] === $input['databaseRow']) {
1396 return true;
1397 }
1398 return false;
1399 }))->shouldBeCalled()->willReturnArgument(0);
1400
1401 (new TcaFlexProcess())->addData($input);
1402 }
1403
1404 /**
1405 * @test
1406 */
1407 public function addDataCallsFlexFormSegmentGroupForDummyContainerAndAddsFlexParentDatabaseRow()
1408 {
1409 $input = [
1410 'tableName' => 'aTable',
1411 'databaseRow' => [
1412 'aField' => [
1413 'data' => [],
1414 ],
1415 'pointerField' => 'aFlex',
1416 ],
1417 'processedTca' => [
1418 'columns' => [
1419 'aField' => [
1420 'config' => [
1421 'type' => 'flex',
1422 'ds_pointerField' => 'pointerField',
1423 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1424 'ds' => [
1425 'sheets' => [
1426 'sDEF' => [
1427 'ROOT' => [
1428 'type' => 'array',
1429 'el' => [
1430 'aFlexField' => [
1431 'label' => 'aFlexFieldLabel',
1432 'config' => [
1433 'type' => 'input',
1434 ],
1435 ],
1436 ],
1437 ],
1438 ],
1439 ],
1440 ],
1441 ],
1442 ],
1443 ],
1444 ],
1445 'pageTsConfig' => [],
1446 ];
1447
1448 /** @var FlexFormSegment|ObjectProphecy $dummyGroupExisting */
1449 $dummyGroupExisting = $this->prophesize(FlexFormSegment::class);
1450 GeneralUtility::addInstance(FlexFormSegment::class, $dummyGroupExisting->reveal());
1451 // Check array given to flex group contains databaseRow as flexParentDatabaseRow and check compile is called
1452 $dummyGroupExisting->compile(Argument::that(function ($result) use ($input) {
1453 if ($result['flexParentDatabaseRow'] === $input['databaseRow']) {
1454 return true;
1455 }
1456 return false;
1457 }))->shouldBeCalled()->willReturnArgument(0);
1458
1459 (new TcaFlexProcess())->addData($input);
1460 }
1461
1462 /**
1463 * Test for the deprecated "flexHack" pageTsConfig transition, verifies that
1464 * all three PAGE_TSCONFIG_ID, PAGE_TSCONFIG_IDLIST and PAGE_TSCONFIG_STR
1465 * are hand over to the flex field compiler.
1466 *
1467 * @test
1468 */
1469 public function addDataHandsPageTsConfigIdOverToFlexFormSegmentGroupAsFlexHack()
1470 {
1471 $input = [
1472 'tableName' => 'aTable',
1473 'databaseRow' => [
1474 'aField' => [
1475 'data' => [],
1476 ],
1477 'pointerField' => 'aFlex',
1478 ],
1479 'processedTca' => [
1480 'columns' => [
1481 'aField' => [
1482 'config' => [
1483 'type' => 'flex',
1484 'ds_pointerField' => 'pointerField',
1485 'dataStructureIdentifier' => '{"type":"tca","tableName":"aTable","fieldName":"aField","dataStructureKey":"aFlex"}',
1486 'ds' => [
1487 'sheets' => [
1488 'sDEF' => [
1489 'ROOT' => [
1490 'type' => 'array',
1491 'el' => [
1492 'aFlexField' => [
1493 'label' => 'aFlexFieldLabel',
1494 'config' => [
1495 'type' => 'input',
1496 ],
1497 ],
1498 ],
1499 ],
1500 ],
1501 ],
1502 ],
1503 ],
1504 ],
1505 ],
1506 ],
1507 'pageTsConfig' => [
1508 'TCEFORM.' => [
1509 'aTable.' => [
1510 'aField.' => [
1511 'PAGE_TSCONFIG_ID' => '42',
1512 'PAGE_TSCONFIG_IDLIST' => '2,3,5',
1513 'PAGE_TSCONFIG_STR' => 'configString',
1514 ],
1515 ],
1516 ],
1517 ],
1518 ];
1519
1520 /** @var FlexFormSegment|ObjectProphecy $dummyGroupExisting */
1521 $dummyGroupExisting = $this->prophesize(FlexFormSegment::class);
1522 GeneralUtility::addInstance(FlexFormSegment::class, $dummyGroupExisting->reveal());
1523 // Check array given to flex group contains pageTsConfig with flexHack field
1524 $dummyGroupExisting->compile(Argument::that(function ($result) use ($input) {
1525 if ($result['pageTsConfig']['flexHack.'] === $input['pageTsConfig']['TCEFORM.']['aTable.']['aField.']) {
1526 return true;
1527 }
1528 return false;
1529 }))->shouldBeCalled()->willReturnArgument(0);
1530
1531 (new TcaFlexProcess())->addData($input);
1532 }
1533 }