[TASK] Disallow empty values for multi select fields
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Form / FormDataProvider / TcaSelectItemsTest.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\Configuration\TranslationConfigurationProvider;
20 use TYPO3\CMS\Backend\Module\ModuleLoader;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\Database\DatabaseConnection;
23 use TYPO3\CMS\Core\Database\RelationHandler;
24 use TYPO3\CMS\Core\Tests\UnitTestCase;
25 use TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems;
26 use TYPO3\CMS\Core\Utility\ArrayUtility;
27 use TYPO3\CMS\Lang\LanguageService;
28 use TYPO3\CMS\Core\Messaging\FlashMessage;
29 use TYPO3\CMS\Core\Messaging\FlashMessageService;
30 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32
33 /**
34 * Test case
35 */
36 class TcaSelectItemsTest extends UnitTestCase {
37
38 /**
39 * @var TcaSelectItems
40 */
41 protected $subject;
42
43 /**
44 * @var array A backup of registered singleton instances
45 */
46 protected $singletonInstances = [];
47
48 public function setUp() {
49 $this->singletonInstances = GeneralUtility::getSingletonInstances();
50 $this->subject = new TcaSelectItems();
51 }
52
53 protected function tearDown() {
54 GeneralUtility::purgeInstances();
55 GeneralUtility::resetSingletonInstances($this->singletonInstances);
56 parent::tearDown();
57 }
58
59 /**
60 * @test
61 */
62 public function addDataKeepExistingItems() {
63 $input = [
64 'processedTca' => [
65 'columns' => [
66 'aField' => [
67 'config' => [
68 'type' => 'radio',
69 'items' => [
70 0 => [
71 'foo',
72 'bar',
73 ],
74 ],
75 ],
76 ],
77 'anotherField' => [
78 'config' => [
79 'type' => 'group',
80 'items' => [
81 0 => [
82 'foo',
83 'bar',
84 ],
85 ],
86 ],
87 ],
88 ],
89 ],
90 ];
91 $languageService = $this->prophesize(LanguageService::class);
92 $GLOBALS['LANG'] = $languageService->reveal();
93 $languageService->sL(Argument::cetera())->willReturnArgument(0);
94
95 $expected = $input;
96 $this->assertSame($expected, $this->subject->addData($input));
97 }
98
99 /**
100 * @test
101 */
102 public function addDataThrowsExceptionIfAnItemIsNotAnArray() {
103 $input = [
104 'processedTca' => [
105 'columns' => [
106 'aField' => [
107 'config' => [
108 'type' => 'select',
109 'items' => [
110 0 => 'foo',
111 ],
112 ],
113 ],
114 ],
115 ],
116 ];
117
118 $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439288036);
119
120 $this->subject->addData($input);
121 }
122
123 /**
124 * @test
125 */
126 public function addDataTranslatesItemLabels() {
127 $input = [
128 'databaseRow' => [
129 'aField' => 'aValue',
130 ],
131 'processedTca' => [
132 'columns' => [
133 'aField' => [
134 'config' => [
135 'type' => 'select',
136 'items' => [
137 0 => [
138 0 => 'aLabel',
139 1 => 'aValue',
140 ],
141 ],
142 'maxitems' => 1
143 ],
144 ],
145 ],
146 ],
147 ];
148
149 /** @var LanguageService|ObjectProphecy $languageService */
150 $languageService = $this->prophesize(LanguageService::class);
151 $GLOBALS['LANG'] = $languageService->reveal();
152
153 $languageService->sL('aLabel')->shouldBeCalled()->willReturn('translated');
154
155 $expected = $input;
156 $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'translated';
157 $expected['processedTca']['columns']['aField']['config']['items'][0][2] = NULL;
158 $expected['processedTca']['columns']['aField']['config']['items'][0][3] = NULL;
159
160 $expected['databaseRow']['aField'] = ['aValue'];
161
162 $this->assertSame($expected, $this->subject->addData($input));
163 }
164
165 /**
166 * @test
167 */
168 public function addDataKeepsIconFromItem() {
169 $input = [
170 'databaseRow' => [
171 'aField' => 'aValue',
172 ],
173 'processedTca' => [
174 'columns' => [
175 'aField' => [
176 'config' => [
177 'type' => 'select',
178 'items' => [
179 0 => [
180 0 => 'aLabel',
181 1 => 'aValue',
182 2 => 'an-icon-reference',
183 3 => NULL,
184 ],
185 ],
186 'maxitems' => 1,
187 ],
188 ],
189 ],
190 ],
191 ];
192
193 /** @var LanguageService|ObjectProphecy $languageService */
194 $languageService = $this->prophesize(LanguageService::class);
195 $GLOBALS['LANG'] = $languageService->reveal();
196 $languageService->sL(Argument::cetera())->willReturnArgument(0);
197
198 $expected = $input;
199 $expected['databaseRow']['aField'] = ['aValue'];
200
201 $this->assertSame($expected, $this->subject->addData($input));
202 }
203
204 /**
205 * @test
206 */
207 public function addDataThrowsExceptionWithUnknownSpecialValue() {
208 $input = [
209 'tableName' => 'aTable',
210 'processedTca' => [
211 'columns' => [
212 'aField' => [
213 'config' => [
214 'type' => 'select',
215 'special' => 'anUnknownValue',
216 ],
217 ],
218 ],
219 ],
220 ];
221
222 $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439298496);
223
224 $this->subject->addData($input);
225 }
226
227 /**
228 * @test
229 */
230 public function addDataAddsTablesWithSpecialTables() {
231 $input = [
232 'databaseRow' => [
233 'aField' => 'aValue',
234 ],
235 'tableName' => 'aTable',
236 'processedTca' => [
237 'columns' => [
238 'aField' => [
239 'config' => [
240 'type' => 'select',
241 'special' => 'tables',
242 'maxitems' => 1,
243 ],
244 ],
245 ],
246 ],
247 ];
248 $GLOBALS['TCA'] = [
249 'notInResult' => [
250 'ctrl' => [
251 'adminOnly' => TRUE,
252 ],
253 ],
254 'aTable' => [
255 'ctrl' => [
256 'title' => 'aTitle',
257 ],
258 ],
259 ];
260 $GLOBALS['TCA_DESCR']['aTable']['columns']['']['description'] = 'aDescription';
261
262 /** @var LanguageService|ObjectProphecy $languageService */
263 $languageService = $this->prophesize(LanguageService::class);
264 $GLOBALS['LANG'] = $languageService->reveal();
265
266 $languageService->sL('aTitle')->shouldBeCalled()->willReturnArgument(0);
267 $languageService->loadSingleTableDescription('aTable')->shouldBeCalled();
268
269 $expected = $input;
270 $expected['databaseRow']['aField'] = ['aValue'];
271 $expected['processedTca']['columns']['aField']['config']['items'] = [
272 0 => [
273 0 => 'aTitle',
274 1 => 'aTable',
275 2 => 'status-status-icon-missing',
276 3 => [
277 'description' => 'aDescription',
278 ],
279 ]
280 ];
281
282 $this->assertSame($expected, $this->subject->addData($input));
283 }
284
285 /**
286 * @test
287 */
288 public function addDataAddsTablesWithSpecialPageTypes() {
289 $input = [
290 'databaseRow' => [
291 'aField' => 'aValue',
292 ],
293 'tableName' => 'aTable',
294 'processedTca' => [
295 'columns' => [
296 'aField' => [
297 'config' => [
298 'type' => 'select',
299 'special' => 'pagetypes',
300 'items' => [],
301 'maxitems' => 1,
302 ],
303 ],
304 ],
305 ],
306 ];
307 $GLOBALS['TCA'] = [
308 'pages' => [
309 'columns' => [
310 'doktype' => [
311 'config' => [
312 'items' => [
313 0 => [
314 0 => 'aLabel',
315 1 => 'aValue',
316 ],
317 ],
318 ],
319 ],
320 ],
321 ],
322 ];
323
324 /** @var LanguageService|ObjectProphecy $languageService */
325 $languageService = $this->prophesize(LanguageService::class);
326 $GLOBALS['LANG'] = $languageService->reveal();
327
328 $languageService->sL('aLabel')->shouldBeCalled()->willReturnArgument(0);
329
330 $expected = $input;
331 $expected['databaseRow']['aField'] = ['aValue'];
332 $expected['processedTca']['columns']['aField']['config']['items'] = [
333 0 => [
334 0 => 'aLabel',
335 1 => 'aValue',
336 2 => 'status-status-icon-missing',
337 3 => NULL,
338 ]
339 ];
340
341 $this->assertSame($expected, $this->subject->addData($input));
342 }
343
344 /**
345 * Data provider
346 */
347 public function addDataAddsExcludeFieldsWithSpecialExcludeDataProvider() {
348 return [
349 'Table with exclude and non exclude field returns exclude item' => [
350 [
351 // input tca
352 'fooTable' => [
353 'ctrl' => [
354 'title' => 'fooTableTitle',
355 ],
356 'columns' => [
357 'bar' => [
358 'label' => 'barColumnTitle',
359 'exclude' => 1
360 ],
361 'baz' => [
362 'label' => 'bazColumnTitle',
363 ],
364 ],
365 ],
366 ],
367 [
368 // expected items
369 0 => [
370 0 => 'fooTableTitle',
371 1 => '--div--',
372 2 => 'status-status-icon-missing',
373 3 => NULL,
374 ],
375 1 => [
376 0 => 'barColumnTitle (bar)',
377 1 => 'fooTable:bar',
378 2 => 'empty-empty',
379 3 => NULL,
380 ],
381 ],
382 ],
383 'Root level table with ignored root level restriction returns exclude item' => [
384 [
385 // input tca
386 'fooTable' => [
387 'ctrl' => [
388 'title' => 'fooTableTitle',
389 'rootLevel' => TRUE,
390 'security' => [
391 'ignoreRootLevelRestriction' => TRUE,
392 ],
393 ],
394 'columns' => [
395 'bar' => [
396 'label' => 'barColumnTitle',
397 'exclude' => 1,
398 ],
399 ],
400 ],
401 ],
402 [
403 // expected items
404 0 => [
405 0 => 'fooTableTitle',
406 1 => '--div--',
407 2 => 'status-status-icon-missing',
408 3 => NULL,
409 ],
410 1 => [
411 0 => 'barColumnTitle (bar)',
412 1 => 'fooTable:bar',
413 2 => 'empty-empty',
414 3 => NULL,
415 ],
416 ],
417 ],
418 'Root level table without ignored root level restriction returns no item' => [
419 [
420 // input tca
421 'fooTable' => [
422 'ctrl' => [
423 'title' => 'fooTableTitle',
424 'rootLevel' => TRUE,
425 ],
426 'columns' => [
427 'bar' => [
428 'label' => 'barColumnTitle',
429 'exclude' => 1,
430 ],
431 ],
432 ],
433 ],
434 [
435 // no items
436 ],
437 ],
438 'Admin table returns no item' => [
439 [
440 // input tca
441 'fooTable' => [
442 'ctrl' => [
443 'title' => 'fooTableTitle',
444 'adminOnly' => TRUE,
445 ],
446 'columns' => [
447 'bar' => [
448 'label' => 'barColumnTitle',
449 'exclude' => 1,
450 ],
451 ],
452 ],
453 ],
454 [
455 // no items
456 ],
457 ],
458 ];
459 }
460
461 /**
462 * @test
463 * @dataProvider addDataAddsExcludeFieldsWithSpecialExcludeDataProvider
464 */
465 public function addDataAddsExcludeFieldsWithSpecialExclude($tca, $expectedItems) {
466 $input = [
467 'tableName' => 'aTable',
468 'processedTca' => [
469 'columns' => [
470 'aField' => [
471 'config' => [
472 'type' => 'select',
473 'special' => 'exclude',
474 ],
475 ],
476 ],
477 ],
478 ];
479 $GLOBALS['TCA'] = $tca;
480
481 /** @var LanguageService|ObjectProphecy $languageService */
482 $languageService = $this->prophesize(LanguageService::class);
483 $GLOBALS['LANG'] = $languageService->reveal();
484 $languageService->loadSingleTableDescription(Argument::cetera())->willReturn(NULL);
485 $languageService->sL(Argument::cetera())->willReturnArgument(0);
486
487 $result = $this->subject->addData($input);
488
489 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
490 }
491
492 /**
493 * @test
494 */
495 public function addDataAddsExcludeFieldsFromFlexWithSpecialExclude() {
496 $input = [
497 'tableName' => 'aTable',
498 'processedTca' => [
499 'columns' => [
500 'aField' => [
501 'config' => [
502 'type' => 'select',
503 'special' => 'exclude',
504 ],
505 ],
506 ],
507 ],
508 ];
509
510 $GLOBALS['TCA'] = [
511 'fooTable' => [
512 'ctrl' => [
513 'title' => 'fooTableTitle',
514 ],
515 'columns' => [
516 'aFlexField' => [
517 'label' => 'aFlexFieldTitle',
518 'config' => [
519 'type' => 'flex',
520 'title' => 'title',
521 'ds' => [
522 'dummy' => '
523 <T3DataStructure>
524 <ROOT>
525 <type>array</type>
526 <el>
527 <input1>
528 <TCEforms>
529 <label>flexInputLabel</label>
530 <exclude>1</exclude>
531 <config>
532 <type>input</type>
533 <size>23</size>
534 </config>
535 </TCEforms>
536 </input1>
537 </el>
538 </ROOT>
539 </T3DataStructure>
540 ',
541 ],
542 ],
543 ],
544 ],
545 ],
546 ];
547
548 /** @var LanguageService|ObjectProphecy $languageService */
549 $languageService = $this->prophesize(LanguageService::class);
550 $GLOBALS['LANG'] = $languageService->reveal();
551 $languageService->loadSingleTableDescription(Argument::cetera())->willReturn(NULL);
552 $languageService->sL(Argument::cetera())->willReturnArgument(0);
553
554 // Needed to suppress a cache in xml2array
555 /** @var DatabaseConnection|ObjectProphecy $database */
556 $database = $this->prophesize(DatabaseConnection::class);
557 $GLOBALS['TYPO3_DB'] = $database->reveal();
558
559 $expectedItems = [
560 0 => [
561 0 => 'fooTableTitle',
562 1 => '--div--',
563 2 => 'status-status-icon-missing',
564 3 => NULL,
565 ],
566 1 => [
567 0 => ' (input1)',
568 1 => 'fooTable:aFlexField;dummy;sDEF;input1',
569 2 => 'empty-empty',
570 3 => NULL,
571 ],
572 ];
573
574 $result = $this->subject->addData($input);
575
576 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
577 }
578
579 /**
580 * @test
581 */
582 public function addDataAddsExplicitAllowFieldsWithSpecialExplicitValues() {
583 $input = [
584 'tableName' => 'aTable',
585 'processedTca' => [
586 'columns' => [
587 'aField' => [
588 'config' => [
589 'type' => 'select',
590 'special' => 'explicitValues',
591 ],
592 ],
593 ],
594 ],
595 ];
596
597 $GLOBALS['TCA'] = [
598 'fooTable' => [
599 'ctrl' => [
600 'title' => 'fooTableTitle',
601 ],
602 'columns' => [
603 'aField' => [
604 'label' => 'aFieldTitle',
605 'config' => [
606 'type' => 'select',
607 'authMode' => 'explicitAllow',
608 'items' => [
609 0 => [
610 'anItemTitle',
611 'anItemValue',
612 ],
613 ]
614 ],
615 ],
616 ],
617 ],
618 ];
619
620 /** @var LanguageService|ObjectProphecy $languageService */
621 $languageService = $this->prophesize(LanguageService::class);
622 $GLOBALS['LANG'] = $languageService->reveal();
623 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
624 $languageService->sL(Argument::cetera())->willReturnArgument(0);
625
626 $expectedItems = [
627 0 => [
628 0 => 'fooTableTitle: aFieldTitle',
629 1 => '--div--',
630 2 => NULL,
631 3 => NULL,
632 ],
633 1 => [
634 0 => '[allowMe] anItemTitle',
635 1 => 'fooTable:aField:anItemValue:ALLOW',
636 2 => 'status-status-permission-granted',
637 3 => NULL,
638 ],
639 ];
640
641 $result = $this->subject->addData($input);
642
643 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
644 }
645
646 /**
647 * @test
648 */
649 public function addDataAddsExplicitDenyFieldsWithSpecialExplicitValues() {
650 $input = [
651 'tableName' => 'aTable',
652 'processedTca' => [
653 'columns' => [
654 'aField' => [
655 'config' => [
656 'type' => 'select',
657 'special' => 'explicitValues',
658 ],
659 ],
660 ],
661 ],
662 ];
663
664 $GLOBALS['TCA'] = [
665 'fooTable' => [
666 'ctrl' => [
667 'title' => 'fooTableTitle',
668 ],
669 'columns' => [
670 'aField' => [
671 'label' => 'aFieldTitle',
672 'config' => [
673 'type' => 'select',
674 'authMode' => 'explicitDeny',
675 'items' => [
676 0 => [
677 'anItemTitle',
678 'anItemValue',
679 ],
680 ]
681 ],
682 ],
683 ],
684 ],
685 ];
686
687 /** @var LanguageService|ObjectProphecy $languageService */
688 $languageService = $this->prophesize(LanguageService::class);
689 $GLOBALS['LANG'] = $languageService->reveal();
690 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
691 $languageService->sL(Argument::cetera())->willReturnArgument(0);
692
693 $expectedItems = [
694 0 => [
695 0 => 'fooTableTitle: aFieldTitle',
696 1 => '--div--',
697 2 => NULL,
698 3 => NULL,
699 ],
700 1 => [
701 0 => '[denyMe] anItemTitle',
702 1 => 'fooTable:aField:anItemValue:DENY',
703 2 => 'status-status-permission-denied',
704 3 => NULL,
705 ],
706 ];
707
708 $result = $this->subject->addData($input);
709
710 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
711 }
712
713 /**
714 * @test
715 */
716 public function addDataAddsExplicitIndividualAllowFieldsWithSpecialExplicitValues() {
717 $input = [
718 'tableName' => 'aTable',
719 'processedTca' => [
720 'columns' => [
721 'aField' => [
722 'config' => [
723 'type' => 'select',
724 'special' => 'explicitValues',
725 ],
726 ],
727 ],
728 ],
729 ];
730
731 $GLOBALS['TCA'] = [
732 'fooTable' => [
733 'ctrl' => [
734 'title' => 'fooTableTitle',
735 ],
736 'columns' => [
737 'aField' => [
738 'label' => 'aFieldTitle',
739 'config' => [
740 'type' => 'select',
741 'authMode' => 'individual',
742 'items' => [
743 0 => [
744 'aItemTitle',
745 'aItemValue',
746 NULL,
747 NULL,
748 'EXPL_ALLOW',
749 ],
750 // 1 is not selectable as allow and is always allowed
751 1 => [
752 'bItemTitle',
753 'bItemValue',
754 ],
755 2 => [
756 'cItemTitle',
757 'cItemValue',
758 NULL,
759 NULL,
760 'EXPL_ALLOW',
761 ],
762 ]
763 ],
764 ],
765 ],
766 ],
767 ];
768
769 /** @var LanguageService|ObjectProphecy $languageService */
770 $languageService = $this->prophesize(LanguageService::class);
771 $GLOBALS['LANG'] = $languageService->reveal();
772 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
773 $languageService->sL(Argument::cetera())->willReturnArgument(0);
774
775 $expectedItems = [
776 0 => [
777 0 => 'fooTableTitle: aFieldTitle',
778 1 => '--div--',
779 2 => NULL,
780 3 => NULL,
781 ],
782 1 => [
783 0 => '[allowMe] aItemTitle',
784 1 => 'fooTable:aField:aItemValue:ALLOW',
785 2 => 'status-status-permission-granted',
786 3 => NULL,
787 ],
788 2 => [
789 0 => '[allowMe] cItemTitle',
790 1 => 'fooTable:aField:cItemValue:ALLOW',
791 2 => 'status-status-permission-granted',
792 3 => NULL,
793 ],
794 ];
795
796 $result = $this->subject->addData($input);
797
798 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
799 }
800
801 /**
802 * @test
803 */
804 public function addDataAddsExplicitIndividualDenyFieldsWithSpecialExplicitValues() {
805 $input = [
806 'tableName' => 'aTable',
807 'processedTca' => [
808 'columns' => [
809 'aField' => [
810 'config' => [
811 'type' => 'select',
812 'special' => 'explicitValues',
813 ],
814 ],
815 ],
816 ],
817 ];
818
819 $GLOBALS['TCA'] = [
820 'fooTable' => [
821 'ctrl' => [
822 'title' => 'fooTableTitle',
823 ],
824 'columns' => [
825 'aField' => [
826 'label' => 'aFieldTitle',
827 'config' => [
828 'type' => 'select',
829 'authMode' => 'individual',
830 'items' => [
831 0 => [
832 'aItemTitle',
833 'aItemValue',
834 NULL,
835 NULL,
836 'EXPL_DENY',
837 ],
838 // 1 is not selectable as allow and is always allowed
839 1 => [
840 'bItemTitle',
841 'bItemValue',
842 ],
843 2 => [
844 'cItemTitle',
845 'cItemValue',
846 NULL,
847 NULL,
848 'EXPL_DENY',
849 ],
850 ]
851 ],
852 ],
853 ],
854 ],
855 ];
856
857 /** @var LanguageService|ObjectProphecy $languageService */
858 $languageService = $this->prophesize(LanguageService::class);
859 $GLOBALS['LANG'] = $languageService->reveal();
860 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
861 $languageService->sL(Argument::cetera())->willReturnArgument(0);
862
863 $expectedItems = [
864 0 => [
865 0 => 'fooTableTitle: aFieldTitle',
866 1 => '--div--',
867 2 => NULL,
868 3 => NULL,
869 ],
870 1 => [
871 0 => '[denyMe] aItemTitle',
872 1 => 'fooTable:aField:aItemValue:DENY',
873 2 => 'status-status-permission-denied',
874 3 => NULL,
875 ],
876 2 => [
877 0 => '[denyMe] cItemTitle',
878 1 => 'fooTable:aField:cItemValue:DENY',
879 2 => 'status-status-permission-denied',
880 3 => NULL,
881 ],
882 ];
883
884 $result = $this->subject->addData($input);
885
886 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
887 }
888
889 /**
890 * @test
891 */
892 public function addDataAddsLanguagesWithSpecialLanguages() {
893 $input = [
894 'tableName' => 'aTable',
895 'processedTca' => [
896 'columns' => [
897 'aField' => [
898 'config' => [
899 'type' => 'select',
900 'special' => 'languages',
901 ],
902 ],
903 ],
904 ],
905 ];
906
907 /** @var LanguageService|ObjectProphecy $languageService */
908 $languageService = $this->prophesize(LanguageService::class);
909 $GLOBALS['LANG'] = $languageService->reveal();
910 $languageService->sL(Argument::cetera())->willReturnArgument(0);
911
912 $languages = [
913 0 => [
914 'title' => 'aLangTitle',
915 'uid' => 42,
916 'flagIcon' => 'aFlag.gif',
917 ],
918 ];
919
920 $translationProphecy = $this->prophesize(TranslationConfigurationProvider::class);
921 GeneralUtility::addInstance(TranslationConfigurationProvider::class, $translationProphecy->reveal());
922 $translationProphecy->getSystemLanguages()->shouldBeCalled()->willReturn($languages);
923
924 $expectedItems = [
925 0 => [
926 0 => 'aLangTitle [42]',
927 1 => 42,
928 2 => 'aFlag.gif',
929 3 => NULL,
930 ],
931 ];
932
933 $result = $this->subject->addData($input);
934
935 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
936 }
937
938 /**
939 * @test
940 */
941 public function addDataAddsCustomOptionsWithSpecialCustom() {
942 $input = [
943 'tableName' => 'aTable',
944 'processedTca' => [
945 'columns' => [
946 'aField' => [
947 'config' => [
948 'type' => 'select',
949 'special' => 'custom',
950 ],
951 ],
952 ],
953 ],
954 ];
955
956 /** @var LanguageService|ObjectProphecy $languageService */
957 $languageService = $this->prophesize(LanguageService::class);
958 $GLOBALS['LANG'] = $languageService->reveal();
959 $languageService->sL(Argument::cetera())->willReturnArgument(0);
960
961 $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'] = [
962 'aKey' => [
963 'header' => 'aHeader',
964 'items' => [
965 'anItemKey' => [
966 0 => 'anItemTitle',
967 ],
968 ],
969 ]
970 ];
971
972 $expectedItems = [
973 0 => [
974 0 => 'aHeader',
975 1 => '--div--',
976 NULL,
977 NULL,
978 ],
979 1 => [
980 0 => 'anItemTitle',
981 1 => 'aKey:anItemKey',
982 2 => 'empty-empty',
983 3 => NULL,
984 ],
985 ];
986
987 $result = $this->subject->addData($input);
988
989 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
990 }
991
992 /**
993 * @test
994 */
995 public function addDataAddsGroupItemsWithSpecialModListGroup() {
996 $input = [
997 'tableName' => 'aTable',
998 'processedTca' => [
999 'columns' => [
1000 'aField' => [
1001 'config' => [
1002 'type' => 'select',
1003 'special' => 'modListGroup',
1004 ],
1005 ],
1006 ],
1007 ],
1008 ];
1009
1010 $GLOBALS['TBE_MODULES'] = [];
1011
1012 /** @var LanguageService|ObjectProphecy $languageService */
1013 $languageService = $this->prophesize(LanguageService::class);
1014 $GLOBALS['LANG'] = $languageService->reveal();
1015 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1016 $languageService->moduleLabels = [
1017 'tabs_images' => [
1018 'aModule_tab' => PATH_site . 'aModuleTabIcon.gif',
1019 ],
1020 'labels' => [
1021 'aModule_tablabel' => 'aModuleTabLabel',
1022 'aModule_tabdescr' => 'aModuleTabDescription',
1023 ],
1024 'tabs' => [
1025 'aModule_tab' => 'aModuleLabel',
1026 ]
1027 ];
1028
1029 /** @var ModuleLoader|ObjectProphecy $moduleLoaderProphecy */
1030 $moduleLoaderProphecy = $this->prophesize(ModuleLoader::class);
1031 GeneralUtility::addInstance(ModuleLoader::class, $moduleLoaderProphecy->reveal());
1032 $moduleLoaderProphecy->load([])->shouldBeCalled();
1033 $moduleLoaderProphecy->modListGroup = [
1034 'aModule',
1035 ];
1036
1037 $expectedItems = [
1038 0 => [
1039 0 => 'aModuleLabel',
1040 1 => 'aModule',
1041 2 => '../aModuleTabIcon.gif',
1042 3 => [
1043 'title' => 'aModuleTabLabel',
1044 'description' => 'aModuleTabDescription',
1045 ],
1046 ],
1047 ];
1048
1049 $result = $this->subject->addData($input);
1050
1051 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1052 }
1053
1054 /**
1055 * @test
1056 */
1057 public function addDataAddsFileItemsWithConfiguredFileFolder() {
1058 $directory = $this->getUniqueId('typo3temp/test-') . '/';
1059 $input = [
1060 'tableName' => 'aTable',
1061 'processedTca' => [
1062 'columns' => [
1063 'aField' => [
1064 'config' => [
1065 'type' => 'select',
1066 'fileFolder' => $directory,
1067 'fileFolder_extList' => 'gif',
1068 'fileFolder_recursions' => 1,
1069 ],
1070 ],
1071 ],
1072 ],
1073 ];
1074
1075 /** @var LanguageService|ObjectProphecy $languageService */
1076 $languageService = $this->prophesize(LanguageService::class);
1077 $GLOBALS['LANG'] = $languageService->reveal();
1078 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1079
1080 mkdir(PATH_site . $directory);
1081 $this->testFilesToDelete[] = PATH_site . $directory;
1082 touch(PATH_site . $directory . 'anImage.gif');
1083 touch(PATH_site . $directory . 'aFile.txt');
1084 mkdir(PATH_site . $directory . '/subdir');
1085 touch(PATH_site . $directory . '/subdir/anotherImage.gif');
1086
1087 $expectedItems = [
1088 0 => [
1089 0 => 'anImage.gif',
1090 1 => 'anImage.gif',
1091 2 => '../' . $directory . 'anImage.gif',
1092 3 => NULL,
1093 ],
1094 1 => [
1095 0 => 'subdir/anotherImage.gif',
1096 1 => 'subdir/anotherImage.gif',
1097 2 => '../' . $directory . 'subdir/anotherImage.gif',
1098 3 => NULL,
1099 ],
1100 ];
1101
1102 $result = $this->subject->addData($input);
1103
1104 $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1105 }
1106
1107 /**
1108 * Data provider
1109 */
1110 public function addDataReplacesMarkersInForeignTableClauseDataProvider() {
1111 return [
1112 'replace REC_FIELD' => [
1113 'AND fTable.title=\'###REC_FIELD_rowField###\'',
1114 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\'',
1115 [],
1116 ],
1117 'replace REC_FIELD fullQuote' => [
1118 'AND fTable.title=###REC_FIELD_rowField###',
1119 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\'',
1120 [],
1121 ],
1122 'replace REC_FIELD multiple markers' => [
1123 'AND fTable.title=\'###REC_FIELD_rowField###\' AND fTable.pid=###REC_FIELD_rowFieldTwo###',
1124 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.title=\'rowFieldValue\' AND fTable.pid=\'rowFieldTwoValue\'',
1125 [],
1126 ],
1127 'replace CURRENT_PID' => [
1128 'AND fTable.uid=###CURRENT_PID###',
1129 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=43',
1130 [],
1131 ],
1132 'replace CURRENT_PID integer cast' => [
1133 'AND fTable.uid=###CURRENT_PID###',
1134 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=431',
1135 [
1136 'effectivePid' => '431string',
1137 ],
1138 ],
1139 'replace THIS_UID' => [
1140 'AND fTable.uid=###THIS_UID###',
1141 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=42',
1142 [],
1143 ],
1144 'replace THIS_UID integer cast' => [
1145 'AND fTable.uid=###THIS_UID###',
1146 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=421',
1147 [
1148 'databaseRow' => [
1149 'uid' => '421string',
1150 ],
1151 ],
1152 ],
1153 'replace SITEROOT' => [
1154 'AND fTable.uid=###SITEROOT###',
1155 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=44',
1156 [],
1157 ],
1158 'replace SITEROOT integer cast' => [
1159 'AND fTable.uid=###SITEROOT###',
1160 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=441',
1161 [
1162 'rootline' => [
1163 1 => [
1164 'uid' => '441string',
1165 ],
1166 ],
1167 ],
1168 ],
1169 'replace PAGE_TSCONFIG_ID' => [
1170 'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1171 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=45',
1172 [],
1173 ],
1174 'replace PAGE_TSCONFIG_ID integer cast' => [
1175 'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1176 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=451',
1177 [
1178 'pageTsConfigMerged' => [
1179 'TCEFORM.' => [
1180 'aTable.' => [
1181 'aField.' => [
1182 'PAGE_TSCONFIG_ID' => '451string'
1183 ],
1184 ],
1185 ],
1186 ],
1187 ],
1188 ],
1189 'replace PAGE_TSCONFIG_STR' => [
1190 'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1191 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid=\'46\'',
1192 [],
1193 ],
1194 'replace PAGE_TSCONFIG_IDLIST' => [
1195 'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1196 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (47,48)',
1197 [],
1198 ],
1199 'replace PAGE_TSCONFIG_IDLIST cleans list' => [
1200 'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1201 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND fTable.uid IN (471,481)',
1202 [
1203 'pageTsConfigMerged' => [
1204 'TCEFORM.' => [
1205 'aTable.' => [
1206 'aField.' => [
1207 'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
1208 ],
1209 ],
1210 ],
1211 ],
1212 ],
1213 ],
1214 ];
1215 }
1216
1217 /**
1218 * @test
1219 * @dataProvider addDataReplacesMarkersInForeignTableClauseDataProvider
1220 */
1221 public function addDataReplacesMarkersInForeignTableClause($foreignTableWhere, $expectedWhere, array $inputOverride) {
1222 $input = [
1223 'tableName' => 'aTable',
1224 'effectivePid' => 43,
1225 'databaseRow' => [
1226 'uid' => 42,
1227 'rowField' => 'rowFieldValue',
1228 'rowFieldTwo' => 'rowFieldTwoValue',
1229 ],
1230 'processedTca' => [
1231 'columns' => [
1232 'aField' => [
1233 'config' => [
1234 'type' => 'select',
1235 'foreign_table' => 'fTable',
1236 'foreign_table_where' => $foreignTableWhere,
1237 ],
1238 ],
1239 ]
1240 ],
1241 'rootline' => [
1242 2 => [
1243 'uid' => 999,
1244 'is_siteroot' => 0,
1245 ],
1246 1 => [
1247 'uid' => 44,
1248 'is_siteroot' => 1,
1249 ],
1250 0 => [
1251 'uid' => 0,
1252 'is_siteroot' => NULL,
1253 ],
1254 ],
1255 'pageTsConfigMerged' => [
1256 'TCEFORM.' => [
1257 'aTable.' => [
1258 'aField.' => [
1259 'PAGE_TSCONFIG_ID' => 45,
1260 'PAGE_TSCONFIG_STR' => '46',
1261 'PAGE_TSCONFIG_IDLIST' => '47, 48',
1262 ],
1263 ],
1264 ],
1265 ],
1266 ];
1267 ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
1268
1269 $GLOBALS['TCA']['fTable'] = [];
1270
1271 $expectedQueryArray = [
1272 'SELECT' => 'fTable.uid',
1273 'FROM' => 'fTable, pages',
1274 'WHERE' => $expectedWhere,
1275 'GROUPBY' => '',
1276 'ORDERBY' => '',
1277 'LIMIT' => '',
1278 ];
1279
1280 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1281 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1282 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1283 $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1284
1285 /** @var DatabaseConnection|ObjectProphecy $databaseProphecy */
1286 $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1287 $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1288 $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(FALSE);
1289 $databaseProphecy->quoteStr(Argument::cetera())->willReturnArgument(0);
1290 $databaseProphecy->fullQuoteStr(Argument::cetera())->will(function ($args) {
1291 return '\'' . $args[0] . '\'';
1292 });
1293 $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn(FALSE);
1294 $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(NULL);
1295
1296 $databaseProphecy->exec_SELECT_queryArray($expectedQueryArray)->shouldBeCalled()->willReturn(FALSE);
1297
1298 $this->subject->addData($input);
1299 }
1300
1301 /**
1302 * @test
1303 */
1304 public function addDataThrowsExceptionIfForeignTableIsNotDefinedInTca() {
1305 $input = [
1306 'tableName' => 'aTable',
1307 'processedTca' => [
1308 'columns' => [
1309 'aField' => [
1310 'config' => [
1311 'type' => 'select',
1312 'foreign_table' => 'fTable',
1313 ],
1314 ],
1315 ]
1316 ],
1317 ];
1318
1319 $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1439569743);
1320
1321 $this->subject->addData($input);
1322 }
1323
1324 /**
1325 * @test
1326 */
1327 public function addDataForeignTableSplitsGroupOrderAndLimit() {
1328 $input = [
1329 'tableName' => 'aTable',
1330 'processedTca' => [
1331 'columns' => [
1332 'aField' => [
1333 'config' => [
1334 'type' => 'select',
1335 'foreign_table' => 'fTable',
1336 'foreign_table_where' => 'AND ftable.uid=1 GROUP BY groupField ORDER BY orderField LIMIT 1,2',
1337 ],
1338 ],
1339 ]
1340 ],
1341 'rootline' => [],
1342 ];
1343
1344 $GLOBALS['TCA']['fTable'] = [];
1345
1346 $expectedQueryArray = [
1347 'SELECT' => 'fTable.uid',
1348 'FROM' => 'fTable, pages',
1349 'WHERE' => 'pages.uid=fTable.pid AND pages.deleted=0 AND 1=1 AND ftable.uid=1',
1350 'GROUPBY' => 'groupField',
1351 'ORDERBY' => 'orderField',
1352 'LIMIT' => '1,2',
1353 ];
1354
1355 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1356 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1357 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1358 $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1359
1360 /** @var DatabaseConnection|ObjectProphecy $databaseProphecy */
1361 $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1362 $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1363 $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(FALSE);
1364 $databaseProphecy->quoteStr(Argument::cetera())->willReturnArgument(0);
1365 $databaseProphecy->fullQuoteStr(Argument::cetera())->will(function ($args) {
1366 return '\'' . $args[0] . '\'';
1367 });
1368 $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn(FALSE);
1369 $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(NULL);
1370
1371 $databaseProphecy->exec_SELECT_queryArray($expectedQueryArray)->shouldBeCalled()->willReturn(FALSE);
1372
1373 $this->subject->addData($input);
1374 }
1375
1376 /**
1377 * @test
1378 */
1379 public function addDataForeignTableQueuesFlashMessageOnDatabaseError() {
1380 $input = [
1381 'databaseRow' => [
1382 'aField' => 'aValue',
1383 ],
1384 'tableName' => 'aTable',
1385 'processedTca' => [
1386 'columns' => [
1387 'aField' => [
1388 'config' => [
1389 'type' => 'select',
1390 'foreign_table' => 'fTable',
1391 'items' => [
1392 0 => [
1393 0 => 'itemLabel',
1394 1 => 'itemValue',
1395 2 => NULL,
1396 3 => NULL,
1397 ],
1398 ],
1399 'maxitems' => 1,
1400 ],
1401 ],
1402 ]
1403 ],
1404 'rootline' => [],
1405 ];
1406
1407 $GLOBALS['TCA']['fTable'] = [];
1408
1409 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1410 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1411 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1412 $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1413
1414 /** @var LanguageService|ObjectProphecy $languageServiceProphecy */
1415 $languageServiceProphecy = $this->prophesize(LanguageService::class);
1416 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1417 $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1418
1419 /** @var DatabaseConnection|ObjectProphecy $databaseProphecy */
1420 $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1421 $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1422 $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(FALSE);
1423
1424 $databaseProphecy->sql_error()->shouldBeCalled()->willReturn('anError');
1425 $databaseProphecy->sql_free_result(Argument::cetera())->shouldBeCalled()->willReturn(NULL);
1426
1427 /** @var FlashMessage|ObjectProphecy $flashMessage */
1428 $flashMessage = $this->prophesize(FlashMessage::class);
1429 GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1430 /** @var FlashMessageService|ObjectProphecy $flashMessageService */
1431 $flashMessageService = $this->prophesize(FlashMessageService::class);
1432 GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1433 /** @var FlashMessageQueue|ObjectProphecy $flashMessageQueue */
1434 $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1435 $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1436
1437 $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
1438
1439 $expected = $input;
1440 $expected['databaseRow']['aField'] = ['aValue'];
1441
1442 $this->assertEquals($expected, $this->subject->addData($input));
1443 }
1444
1445 /**
1446 * @test
1447 */
1448 public function addDataForeignTableHandlesForegnTableRows() {
1449 $input = [
1450 'databaseRow' => [
1451 'aField' => 'aValue',
1452 ],
1453 'tableName' => 'aTable',
1454 'processedTca' => [
1455 'columns' => [
1456 'aField' => [
1457 'config' => [
1458 'type' => 'select',
1459 'foreign_table' => 'fTable',
1460 'foreign_table_prefix' => 'aPrefix',
1461 'items' => [],
1462 'maxitems' => 1,
1463 ],
1464 ],
1465 ]
1466 ],
1467 'rootline' => [],
1468 ];
1469
1470 $GLOBALS['TCA']['fTable'] = [];
1471
1472 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1473 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1474 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1475 $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1476
1477 /** @var LanguageService|ObjectProphecy $languageServiceProphecy */
1478 $languageServiceProphecy = $this->prophesize(LanguageService::class);
1479 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1480 $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1481
1482 /** @var DatabaseConnection|ObjectProphecy $databaseProphecy */
1483 $databaseProphecy = $this->prophesize(DatabaseConnection::class);
1484 $GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
1485 $databaseProphecy->sql_error()->shouldBeCalled()->willReturn(FALSE);
1486 $databaseProphecy->sql_free_result(Argument::cetera())->willReturn(NULL);
1487 $databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(TRUE);
1488
1489 $counter = 0;
1490 $databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->will(function ($args) use (&$counter) {
1491 $counter++;
1492 if ($counter >= 3) {
1493 return FALSE;
1494 }
1495 return [
1496 'uid' => $counter,
1497 'aValue' => 'bar,',
1498 ];
1499 });
1500
1501 $expected = $input;
1502 $expected['processedTca']['columns']['aField']['config']['items'] = [
1503 0 => [
1504 0 => 'aPrefix[LLL:EXT:lang/locallang_core.xlf:labels.no_title]',
1505 1 => 1,
1506 2 => 'status-status-icon-missing',
1507 3 => NULL,
1508 ],
1509 1 => [
1510 0 => 'aPrefix[LLL:EXT:lang/locallang_core.xlf:labels.no_title]',
1511 1 => 2,
1512 2 => 'status-status-icon-missing',
1513 3 => NULL,
1514 ],
1515 ];
1516
1517 $expected['databaseRow']['aField'] = ['aValue'];
1518
1519 $this->assertEquals($expected, $this->subject->addData($input));
1520 }
1521
1522 /**
1523 * @test
1524 */
1525 public function addDataRemovesItemsByKeepItemsPageTsConfig() {
1526 $input = [
1527 'databaseRow' => [
1528 'aField' => 'aValue',
1529 ],
1530 'tableName' => 'aTable',
1531 'processedTca' => [
1532 'columns' => [
1533 'aField' => [
1534 'config' => [
1535 'type' => 'select',
1536 'items' => [
1537 0 => [
1538 0 => 'keepMe',
1539 1 => 'keep',
1540 NULL,
1541 NULL,
1542 ],
1543 1 => [
1544 0 => 'removeMe',
1545 1 => 'remove',
1546 ],
1547 ],
1548 'maxitems' => 1,
1549 ],
1550 ],
1551 ]
1552 ],
1553 'pageTsConfigMerged' => [
1554 'TCEFORM.' => [
1555 'aTable.' => [
1556 'aField.' => [
1557 'keepItems' => 'keep',
1558 ],
1559 ],
1560 ],
1561 ],
1562 ];
1563
1564 /** @var LanguageService|ObjectProphecy $languageService */
1565 $languageService = $this->prophesize(LanguageService::class);
1566 $GLOBALS['LANG'] = $languageService->reveal();
1567 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1568
1569 $expected = $input;
1570 $expected['databaseRow']['aField'] = ['aValue'];
1571 unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1572
1573 $this->assertEquals($expected, $this->subject->addData($input));
1574 }
1575
1576 /**
1577 * @test
1578 */
1579 public function addDataRemovesItemsByRemoveItemsPageTsConfig() {
1580 $input = [
1581 'databaseRow' => [
1582 'aField' => 'aValue'
1583 ],
1584 'tableName' => 'aTable',
1585 'processedTca' => [
1586 'columns' => [
1587 'aField' => [
1588 'config' => [
1589 'type' => 'select',
1590 'items' => [
1591 0 => [
1592 0 => 'keepMe',
1593 1 => 'keep',
1594 NULL,
1595 NULL,
1596 ],
1597 1 => [
1598 0 => 'removeMe',
1599 1 => 'remove',
1600 ],
1601 ],
1602 'maxitems' => 1,
1603 ],
1604 ],
1605 ]
1606 ],
1607 'pageTsConfigMerged' => [
1608 'TCEFORM.' => [
1609 'aTable.' => [
1610 'aField.' => [
1611 'removeItems' => 'remove',
1612 ],
1613 ],
1614 ],
1615 ],
1616 ];
1617
1618 /** @var LanguageService|ObjectProphecy $languageService */
1619 $languageService = $this->prophesize(LanguageService::class);
1620 $GLOBALS['LANG'] = $languageService->reveal();
1621 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1622
1623 $expected = $input;
1624 $expected['databaseRow']['aField'] = ['aValue'];
1625 unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1626
1627 $this->assertEquals($expected, $this->subject->addData($input));
1628 }
1629
1630 /**
1631 * @test
1632 */
1633 public function addDataRemovesItemsByLanguageFieldUserRestriction() {
1634 $input = [
1635 'databaseRow' => [
1636 'aField' => 'aValue'
1637 ],
1638 'tableName' => 'aTable',
1639 'processedTca' => [
1640 'ctrl' => [
1641 'languageField' => 'aField',
1642 ],
1643 'columns' => [
1644 'aField' => [
1645 'config' => [
1646 'type' => 'select',
1647 'items' => [
1648 0 => [
1649 0 => 'keepMe',
1650 1 => 'keep',
1651 NULL,
1652 NULL,
1653 ],
1654 1 => [
1655 0 => 'removeMe',
1656 1 => 'remove',
1657 ],
1658 ],
1659 'maxitems' => 1,
1660 ],
1661 ],
1662 ]
1663 ],
1664 ];
1665
1666 /** @var LanguageService|ObjectProphecy $languageService */
1667 $languageService = $this->prophesize(LanguageService::class);
1668 $GLOBALS['LANG'] = $languageService->reveal();
1669 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1670
1671 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1672 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1673 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1674 $backendUserProphecy->checkLanguageAccess('keep')->shouldBeCalled()->willReturn(TRUE);
1675 $backendUserProphecy->checkLanguageAccess('remove')->shouldBeCalled()->willReturn(FALSE);
1676
1677 $expected = $input;
1678 $expected['databaseRow']['aField'] = ['aValue'];
1679 unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1680
1681 $this->assertEquals($expected, $this->subject->addData($input));
1682 }
1683
1684 /**
1685 * @test
1686 */
1687 public function addDataRemovesItemsByUserAuthModeRestriction() {
1688 $input = [
1689 'databaseRow' => [
1690 'aField' => 'aValue'
1691 ],
1692 'tableName' => 'aTable',
1693 'processedTca' => [
1694 'columns' => [
1695 'aField' => [
1696 'config' => [
1697 'type' => 'select',
1698 'authMode' => 'explicitAllow',
1699 'items' => [
1700 0 => [
1701 0 => 'keepMe',
1702 1 => 'keep',
1703 NULL,
1704 NULL,
1705 ],
1706 1 => [
1707 0 => 'removeMe',
1708 1 => 'remove',
1709 ],
1710 ],
1711 'maxitems' => 1,
1712 ],
1713 ],
1714 ]
1715 ],
1716 ];
1717
1718 /** @var LanguageService|ObjectProphecy $languageService */
1719 $languageService = $this->prophesize(LanguageService::class);
1720 $GLOBALS['LANG'] = $languageService->reveal();
1721 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1722
1723 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1724 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1725 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1726 $backendUserProphecy->checkAuthMode('aTable', 'aField', 'keep', 'explicitAllow')->shouldBeCalled()->willReturn(TRUE);
1727 $backendUserProphecy->checkAuthMode('aTable', 'aField', 'remove', 'explicitAllow')->shouldBeCalled()->willReturn(FALSE);
1728
1729 $expected = $input;
1730 $expected['databaseRow']['aField'] = ['aValue'];
1731 unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
1732
1733 $this->assertEquals($expected, $this->subject->addData($input));
1734 }
1735
1736 /**
1737 * @test
1738 */
1739 public function addDataKeepsAllPagesDoktypesForAdminUser() {
1740 $input = [
1741 'databaseRow' => [
1742 'doktype' => 'keep'
1743 ],
1744 'tableName' => 'pages',
1745 'processedTca' => [
1746 'columns' => [
1747 'doktype' => [
1748 'config' => [
1749 'type' => 'select',
1750 'items' => [
1751 0 => [
1752 0 => 'keepMe',
1753 1 => 'keep',
1754 NULL,
1755 NULL,
1756 ],
1757 ],
1758 'maxitems' => 1,
1759 ],
1760 ],
1761 ],
1762 ],
1763 ];
1764
1765 /** @var LanguageService|ObjectProphecy $languageService */
1766 $languageService = $this->prophesize(LanguageService::class);
1767 $GLOBALS['LANG'] = $languageService->reveal();
1768 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1769
1770 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1771 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1772 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1773 $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(TRUE);
1774
1775 $expected = $input;
1776 $expected['databaseRow']['doktype'] = ['keep'];
1777
1778 $this->assertEquals($expected, $this->subject->addData($input));
1779 }
1780
1781 /**
1782 * @test
1783 */
1784 public function addDataKeepsAllowedPageTypesForNonAdminUser() {
1785 $input = [
1786 'databaseRow' => [
1787 'doktype' => 'keep',
1788 ],
1789 'tableName' => 'pages',
1790 'processedTca' => [
1791 'columns' => [
1792 'doktype' => [
1793 'config' => [
1794 'type' => 'select',
1795 'items' => [
1796 0 => [
1797 0 => 'keepMe',
1798 1 => 'keep',
1799 NULL,
1800 NULL,
1801 ],
1802 1 => [
1803 0 => 'removeMe',
1804 1 => 'remove',
1805 ],
1806 ],
1807 'maxitems' => 1,
1808 ],
1809 ],
1810 ],
1811 ],
1812 ];
1813
1814 /** @var LanguageService|ObjectProphecy $languageService */
1815 $languageService = $this->prophesize(LanguageService::class);
1816 $GLOBALS['LANG'] = $languageService->reveal();
1817 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1818
1819 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
1820 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1821 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1822 $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(FALSE);
1823 $backendUserProphecy->groupData = [
1824 'pagetypes_select' => 'foo,keep,anotherAllowedDoktype',
1825 ];
1826
1827 $expected = $input;
1828 $expected['databaseRow']['doktype'] = ['keep'];
1829 unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
1830
1831 $this->assertEquals($expected, $this->subject->addData($input));
1832 }
1833
1834 /**
1835 * @test
1836 */
1837 public function addDataCallsItemsProcFunc() {
1838 $input = [
1839 'tableName' => 'aTable',
1840 'databaseRow' => [
1841 'aField' => 'aValue'
1842 ],
1843 'processedTca' => [
1844 'columns' => [
1845 'aField' => [
1846 'config' => [
1847 'type' => 'select',
1848 'items' => [],
1849 'itemsProcFunc' => function (array $parameters, $pObj) {
1850 $parameters['items'] = [
1851 0 => [
1852 0 => 'aLabel',
1853 1 => 'aValue',
1854 2 => NULL,
1855 3 => NULL,
1856 ],
1857 ];
1858 },
1859 ],
1860 ],
1861 ],
1862 ],
1863 ];
1864
1865 /** @var LanguageService|ObjectProphecy $languageService */
1866 $languageService = $this->prophesize(LanguageService::class);
1867 $GLOBALS['LANG'] = $languageService->reveal();
1868 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1869
1870 $expected = $input;
1871 $expected['databaseRow']['aField'] = ['aValue'];
1872 $expected['processedTca']['columns']['aField']['config'] = [
1873 'type' => 'select',
1874 'items' => [
1875 0 => [
1876 0 => 'aLabel',
1877 1 => 'aValue',
1878 2 => NULL,
1879 3 => NULL,
1880 ],
1881 ],
1882 'maxitems' => 1,
1883 ];
1884
1885 $this->assertSame($expected, $this->subject->addData($input));
1886 }
1887
1888 /**
1889 * @test
1890 */
1891 public function addDataItemsProcFuncReceivesParameters() {
1892 $input = [
1893 'tableName' => 'aTable',
1894 'databaseRow' => [
1895 'aField' => 'aValue',
1896 ],
1897 'pageTsConfigMerged' => [
1898 'TCEFORM.' => [
1899 'aTable.' => [
1900 'aField.' => [
1901 'itemsProcFunc.' => [
1902 'itemParamKey' => 'itemParamValue',
1903 ],
1904 ]
1905 ],
1906 ],
1907 ],
1908 'processedTca' => [
1909 'columns' => [
1910 'aField' => [
1911 'config' => [
1912 'type' => 'select',
1913 'aKey' => 'aValue',
1914 'items' => [
1915 0 => [
1916 0 => 'aLabel',
1917 1 => 'aValue',
1918 ],
1919 ],
1920 'itemsProcFunc' => function (array $parameters, $pObj) {
1921 if ($parameters['items'] !== [ 0 => [ 'aLabel', 'aValue'] ]
1922 || $parameters['config']['aKey'] !== 'aValue'
1923 || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
1924 || $parameters['table'] !== 'aTable'
1925 || $parameters['row'] !== [ 'aField' => 'aValue' ]
1926 || $parameters['field'] !== 'aField'
1927 ) {
1928 throw new \UnexpectedValueException('broken', 1438604329);
1929 }
1930 },
1931 ],
1932 ],
1933 ],
1934 ],
1935 ];
1936
1937 $languageService = $this->prophesize(LanguageService::class);
1938 $GLOBALS['LANG'] = $languageService->reveal();
1939 $languageService->sL(Argument::cetera())->willReturnArgument(0);
1940 /** @var FlashMessage|ObjectProphecy $flashMessage */
1941 $flashMessage = $this->prophesize(FlashMessage::class);
1942 GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1943 /** @var FlashMessageService|ObjectProphecy $flashMessageService */
1944 $flashMessageService = $this->prophesize(FlashMessageService::class);
1945 GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1946 /** @var FlashMessageQueue|ObjectProphecy $flashMessageQueue */
1947 $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1948 $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1949
1950 // itemsProcFunc must NOT have raised an exception
1951 $flashMessageQueue->enqueue($flashMessage)->shouldNotBeCalled();
1952
1953 $this->subject->addData($input);
1954 }
1955
1956 /**
1957 * @test
1958 */
1959 public function addDataItemsProcFuncEnqueuesFlashMessageOnException() {
1960 $input = [
1961 'tableName' => 'aTable',
1962 'databaseRow' => [
1963 'aField' => 'aValue',
1964 ],
1965 'pageTsConfigMerged' => [
1966 'TCEFORM.' => [
1967 'aTable.' => [
1968 'aField.' => [
1969 'itemsProcFunc.' => [
1970 'itemParamKey' => 'itemParamValue',
1971 ],
1972 ]
1973 ],
1974 ],
1975 ],
1976 'processedTca' => [
1977 'columns' => [
1978 'aField' => [
1979 'config' => [
1980 'type' => 'select',
1981 'aKey' => 'aValue',
1982 'items' => [
1983 0 => [
1984 0 => 'aLabel',
1985 1 => 'aValue',
1986 ],
1987 ],
1988 'itemsProcFunc' => function (array $parameters, $pObj) {
1989 throw new \UnexpectedValueException('anException', 1438604329);
1990 },
1991 ],
1992 ],
1993 ],
1994 ],
1995 ];
1996
1997 $languageService = $this->prophesize(LanguageService::class);
1998 $GLOBALS['LANG'] = $languageService->reveal();
1999 /** @var FlashMessage|ObjectProphecy $flashMessage */
2000 $flashMessage = $this->prophesize(FlashMessage::class);
2001 GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2002 /** @var FlashMessageService|ObjectProphecy $flashMessageService */
2003 $flashMessageService = $this->prophesize(FlashMessageService::class);
2004 GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2005 /** @var FlashMessageQueue|ObjectProphecy $flashMessageQueue */
2006 $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2007 $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2008
2009 $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
2010
2011 $this->subject->addData($input);
2012 }
2013
2014 /**
2015 * @test
2016 */
2017 public function addDataTranslatesItemLabelsFromPageTsConfig() {
2018 $input = [
2019 'databaseRow' => [
2020 'aField' => 'aValue',
2021 ],
2022 'tableName' => 'aTable',
2023 'processedTca' => [
2024 'columns' => [
2025 'aField' => [
2026 'config' => [
2027 'type' => 'select',
2028 'items' => [
2029 0 => [
2030 0 => 'aLabel',
2031 1 => 'aValue',
2032 NULL,
2033 NULL,
2034 ],
2035 ],
2036 'maxitems' => 1,
2037 ],
2038 ],
2039 ],
2040 ],
2041 'pageTsConfigMerged' => [
2042 'TCEFORM.' => [
2043 'aTable.' => [
2044 'aField.' => [
2045 'altLabels.' => [
2046 'aValue' => 'labelOverride',
2047 ],
2048 ]
2049 ],
2050 ],
2051 ],
2052 ];
2053
2054 /** @var LanguageService|ObjectProphecy $languageService */
2055 $languageService = $this->prophesize(LanguageService::class);
2056 $GLOBALS['LANG'] = $languageService->reveal();
2057 $languageService->sL('aLabel')->willReturnArgument(0);
2058
2059 $languageService->sL('labelOverride')->shouldBeCalled()->willReturnArgument(0);
2060
2061 $expected = $input;
2062 $expected['databaseRow']['aField'] = ['aValue'];
2063 $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'labelOverride';
2064
2065 $this->assertSame($expected, $this->subject->addData($input));
2066 $this->subject->addData($input);
2067 }
2068
2069 /**
2070 * @test
2071 */
2072 public function processSelectFieldValueSetsMmForeignRelationValues() {
2073 $GLOBALS['TCA']['foreignTable'] = [];
2074
2075 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
2076 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2077 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2078
2079 /** @var DatabaseConnection|ObjectProphecy $database */
2080 $database = $this->prophesize(DatabaseConnection::class);
2081 $GLOBALS['TYPO3_DB'] = $database->reveal();
2082
2083 $input = [
2084 'tableName' => 'aTable',
2085 'databaseRow' => [
2086 'uid' => 42,
2087 // Two connected rows
2088 'aField' => 2,
2089 ],
2090 'processedTca' => [
2091 'columns' => [
2092 'aField' => [
2093 'config' => [
2094 'type' => 'select',
2095 'maxitems' => 999,
2096 'foreign_table' => 'foreignTable',
2097 'MM' => 'aTable_foreignTable_mm',
2098 'items' => [],
2099 ],
2100 ],
2101 ],
2102 ],
2103 ];
2104 $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2105 /** @var RelationHandler|ObjectProphecy $relationHandlerProphecy */
2106 $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2107 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2108
2109 $relationHandlerUids = [
2110 23,
2111 24
2112 ];
2113
2114 $relationHandlerProphecy->start(2, 'foreignTable', 'aTable_foreignTable_mm', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2115 $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2116
2117 $expected = $input;
2118 $expected['databaseRow']['aField'] = $relationHandlerUids;
2119
2120 $this->assertEquals($expected, $this->subject->addData($input));
2121 }
2122
2123 /**
2124 * @test
2125 */
2126 public function processSelectFieldValueSetsForeignRelationValues() {
2127 $GLOBALS['TCA']['foreignTable'] = [];
2128
2129 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
2130 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2131 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2132
2133 /** @var DatabaseConnection|ObjectProphecy $database */
2134 $database = $this->prophesize(DatabaseConnection::class);
2135 $GLOBALS['TYPO3_DB'] = $database->reveal();
2136
2137 $input = [
2138 'tableName' => 'aTable',
2139 'databaseRow' => [
2140 'uid' => 42,
2141 // Two connected rows
2142 'aField' => '22,23,24,25',
2143 ],
2144 'processedTca' => [
2145 'columns' => [
2146 'aField' => [
2147 'config' => [
2148 'type' => 'select',
2149 'maxitems' => 999,
2150 'foreign_table' => 'foreignTable',
2151 'items' => [],
2152 ],
2153 ],
2154 ],
2155 ],
2156 ];
2157 $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2158 /** @var RelationHandler|ObjectProphecy $relationHandlerProphecy */
2159 $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2160 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2161
2162 $relationHandlerUids = [
2163 23,
2164 24
2165 ];
2166
2167 $relationHandlerProphecy->start('22,23,24,25', 'foreignTable', '', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2168 $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2169
2170 $expected = $input;
2171 $expected['databaseRow']['aField'] = $relationHandlerUids;
2172
2173 $this->assertEquals($expected, $this->subject->addData($input));
2174 }
2175
2176 /**
2177 * @test
2178 */
2179 public function processSelectFieldValueRemovesInvalidDynamicValues() {
2180 $languageService = $this->prophesize(LanguageService::class);
2181 $GLOBALS['LANG'] = $languageService->reveal();
2182 $languageService->sL(Argument::cetera())->willReturnArgument(0);
2183
2184 $GLOBALS['TCA']['foreignTable'] = [];
2185
2186 /** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
2187 $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2188 $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2189
2190 /** @var DatabaseConnection|ObjectProphecy $database */
2191 $database = $this->prophesize(DatabaseConnection::class);
2192 $GLOBALS['TYPO3_DB'] = $database->reveal();
2193
2194 $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2195 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2196 $relationHandlerProphecy->start(Argument::cetera())->shouldBeCalled();
2197 $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldBeCalled()->willReturn([1]);
2198
2199 $input = [
2200 'tableName' => 'aTable',
2201 'databaseRow' => [
2202 'aField' => '1,2,bar,foo',
2203 ],
2204 'processedTca' => [
2205 'columns' => [
2206 'aField' => [
2207 'config' => [
2208 'type' => 'select',
2209 'foreign_table' => 'foreignTable',
2210 'maxitems' => 999,
2211 'items' => [
2212 ['foo', 'foo', NULL, NULL],
2213 ],
2214 ],
2215 ],
2216 ],
2217 ],
2218 ];
2219
2220 $expected = $input;
2221 $expected['databaseRow']['aField'] = ['foo', 1];
2222
2223 $this->assertEquals($expected, $this->subject->addData($input));
2224 }
2225
2226 /**
2227 * @test
2228 */
2229 public function processSelectFieldValueKeepsValuesFromStaticItems() {
2230 $languageService = $this->prophesize(LanguageService::class);
2231 $GLOBALS['LANG'] = $languageService->reveal();
2232 $languageService->sL(Argument::cetera())->willReturnArgument(0);
2233
2234 $input = [
2235 'tableName' => 'aTable',
2236 'databaseRow' => [
2237 'aField' => 'foo,bar',
2238 ],
2239 'processedTca' => [
2240 'columns' => [
2241 'aField' => [
2242 'config' => [
2243 'type' => 'select',
2244 'maxitems' => 999,
2245 'items' => [
2246 ['foo', 'foo', NULL, NULL],
2247 ['bar', 'bar', NULL, NULL],
2248 ],
2249 ],
2250 ],
2251 ],
2252 ],
2253 ];
2254
2255 $expected = $input;
2256 $expected['databaseRow']['aField'] = [
2257 'foo',
2258 'bar'
2259 ];
2260
2261 $this->assertEquals($expected, $this->subject->addData($input));
2262 }
2263
2264 /**
2265 * @test
2266 */
2267 public function processSelectFieldValueReturnsEmptyValueForSingleSelect() {
2268 $languageService = $this->prophesize(LanguageService::class);
2269 $GLOBALS['LANG'] = $languageService->reveal();
2270 $languageService->sL(Argument::cetera())->willReturnArgument(0);
2271
2272 $input = [
2273 'tableName' => 'aTable',
2274 'databaseRow' => [
2275 'aField' => '',
2276 ],
2277 'processedTca' => [
2278 'columns' => [
2279 'aField' => [
2280 'config' => [
2281 'type' => 'select',
2282 'maxitems' => 1,
2283 'items' => [],
2284 ],
2285 ],
2286 ],
2287 ],
2288 ];
2289
2290 $expected = $input;
2291 $expected['databaseRow']['aField'] = [
2292 '',
2293 ];
2294
2295 $this->assertEquals($expected, $this->subject->addData($input));
2296 }
2297
2298 /**
2299 * @test
2300 */
2301 public function processSelectFieldValueTrimsEmptyValueForMultiValueSelect() {
2302 $languageService = $this->prophesize(LanguageService::class);
2303 $GLOBALS['LANG'] = $languageService->reveal();
2304 $languageService->sL(Argument::cetera())->willReturnArgument(0);
2305
2306 $input = [
2307 'tableName' => 'aTable',
2308 'databaseRow' => [
2309 'aField' => 'b,,c',
2310 ],
2311 'processedTca' => [
2312 'columns' => [
2313 'aField' => [
2314 'config' => [
2315 'type' => 'select',
2316 'maxitems' => 999,
2317 'items' => [
2318 ['a', '', NULL, NULL],
2319 ['b', 'b', NULL, NULL],
2320 ['c', 'c', NULL, NULL],
2321 ],
2322 ],
2323 ],
2324 ],
2325 ],
2326 ];
2327
2328 $expected = $input;
2329 $expected['databaseRow']['aField'] = [
2330 'b',
2331 'c',
2332 ];
2333
2334 $this->assertEquals($expected, $this->subject->addData($input));
2335 }
2336
2337 /**
2338 * @test
2339 */
2340 public function processSelectFieldValueDoesNotCallRelationManagerForStaticOnlyItems() {
2341 $languageService = $this->prophesize(LanguageService::class);
2342 $GLOBALS['LANG'] = $languageService->reveal();
2343 $languageService->sL(Argument::cetera())->willReturnArgument(0);
2344
2345 $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2346 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2347 $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
2348 $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
2349
2350 $input = [
2351 'tableName' => 'aTable',
2352 'databaseRow' => [
2353 'aField' => '1,2,bar,foo',
2354 ],
2355 'processedTca' => [
2356 'columns' => [
2357 'aField' => [
2358 'config' => [
2359 'type' => 'select',
2360 'maxitems' => 999,
2361 'items' => [
2362 ['foo', 'foo', NULL, NULL],
2363 ],
2364 ],
2365 ],
2366 ],
2367 ],
2368 ];
2369
2370 $expected = $input;
2371 $expected['databaseRow']['aField'] = ['foo'];
2372
2373 $this->assertEquals($expected, $this->subject->addData($input));
2374
2375 }
2376
2377 /**
2378 * @test
2379 */
2380 public function processSelectFieldValueDoesNotTouchValueForSingleSelects() {
2381 $languageService = $this->prophesize(LanguageService::class);
2382 $GLOBALS['LANG'] = $languageService->reveal();
2383 $languageService->sL(Argument::cetera())->willReturnArgument(0);
2384
2385 $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2386 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2387 $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
2388 $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
2389
2390 $input = [
2391 'tableName' => 'aTable',
2392 'databaseRow' => [
2393 'aField' => '1,2,bar,foo',
2394 ],
2395 'processedTca' => [
2396 'columns' => [
2397 'aField' => [
2398 'config' => [
2399 'type' => 'select',
2400 'maxitems' => 1,
2401 'items' => [
2402 ['foo', 'foo', NULL, NULL],
2403 ],
2404 ],
2405 ],
2406 ],
2407 ],
2408 ];
2409
2410 $expected = $input;
2411 $expected['databaseRow']['aField'] = ['1,2,bar,foo'];
2412
2413 $this->assertEquals($expected, $this->subject->addData($input));
2414
2415 }
2416 }