[BUGFIX] Show correct label for IRRE records
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Form / FormDataProvider / TcaRecordTitleTest.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\FormDataProvider\TcaRecordTitle;
20 use TYPO3\CMS\Core\Tests\UnitTestCase;
21 use TYPO3\CMS\Lang\LanguageService;
22
23 /**
24 * Test case
25 */
26 class TcaRecordTitleTest extends UnitTestCase
27 {
28 /**
29 * @var TcaRecordTitle
30 */
31 protected $subject;
32
33 /**
34 * @var string
35 */
36 protected $timeZone;
37
38 public function setUp()
39 {
40 $this->subject = new TcaRecordTitle();
41 $this->timeZone = date_default_timezone_get();
42 date_default_timezone_set('UTC');
43 }
44
45 protected function tearDown()
46 {
47 date_default_timezone_set($this->timeZone);
48 }
49
50 /**
51 * @test
52 */
53 public function addDataThrowsExceptionWithMissingLabel()
54 {
55 $input = [
56 'tableName' => 'aTable',
57 'databaseRew' => [],
58 'processedTca' => [
59 'ctrl' => [],
60 ],
61 ];
62 $this->setExpectedException(\UnexpectedValueException::class, $this->any(), 1443706103);
63 $this->subject->addData($input);
64 }
65
66 /**
67 * @test
68 */
69 public function addDataReturnsRecordTitleForLabelUserFunction()
70 {
71 $input = [
72 'tableName' => 'aTable',
73 'databaseRow' => [],
74 'processedTca' => [
75 'ctrl' => [
76 'label' => 'uid',
77 'label_userFunc' => function (&$parameters) {
78 $parameters['title'] = 'Test';
79 }
80 ],
81 'columns' => [],
82 ],
83 ];
84
85 $expected = $input;
86 $expected['recordTitle'] = 'Test';
87
88 $this->assertSame($expected, $this->subject->addData($input));
89 }
90
91 /**
92 * @test
93 */
94 public function addDataReturnsRecordTitleForFormattedLabelUserFunction()
95 {
96 $input = [
97 'tableName' => 'aTable',
98 'databaseRow' => [],
99 'isInlineChild' => true,
100 'processedTca' => [
101 'ctrl' => [
102 'label' => 'uid',
103 'formattedLabel_userFunc' => function (&$parameters) {
104 $parameters['title'] = 'Test';
105 }
106 ],
107 'columns' => [],
108 ],
109 ];
110
111 $expected = $input;
112 $expected['recordTitle'] = 'Test';
113
114 $this->assertSame($expected, $this->subject->addData($input));
115 }
116
117 /**
118 * @test
119 */
120 public function addDataReturnsRecordTitleForInlineChildWithForeignLabel()
121 {
122 $input = [
123 'tableName' => 'aTable',
124 'databaseRow' => [
125 'aField' => 'aValue',
126 ],
127 'processedTca' => [
128 'ctrl' => [
129 'label' => 'foo',
130 'label_userFunc' => function (&$parameters) {
131 $parameters['title'] = 'Value that MUST NOT be used, otherwise the code is broken.';
132 }
133 ],
134 'columns' => [
135 'aField' => [
136 'config' => [
137 'type' => 'input',
138 ],
139 ],
140 ],
141 ],
142 'isInlineChild' => true,
143 'inlineParentConfig' => [
144 'foreign_label' => 'aField',
145 ],
146 ];
147 $expected = $input;
148 $expected['recordTitle'] = 'aValue';
149 $this->assertSame($expected, $this->subject->addData($input));
150 }
151
152 /**
153 * @test
154 */
155 public function addDataReturnsRecordTitleForInlineChildWithSymmetricLabel()
156 {
157 $input = [
158 'tableName' => 'aTable',
159 'databaseRow' => [
160 'aField' => 'aValue',
161 ],
162 'processedTca' => [
163 'ctrl' => [
164 'label' => 'foo',
165 ],
166 'columns' => [
167 'aField' => [
168 'config' => [
169 'type' => 'input',
170 ],
171 ],
172 ],
173 ],
174 'isInlineChild' => true,
175 'inlineParentConfig' => [
176 'symmetric_label' => 'aField',
177 ],
178 'isOnSymmetricSide' => true,
179 ];
180 $expected = $input;
181 $expected['recordTitle'] = 'aValue';
182 $this->assertSame($expected, $this->subject->addData($input));
183 }
184
185 /**
186 * @test
187 */
188 public function addDataReturnsRecordTitleForUid()
189 {
190 $input = [
191 'tableName' => 'aTable',
192 'databaseRow' => [
193 'uid' => 'NEW56017ee37d10e587251374',
194 ],
195 'processedTca' => [
196 'ctrl' => [
197 'label' => 'uid'
198 ],
199 'columns' => [],
200 ]
201 ];
202
203 /** @var LanguageService|ObjectProphecy $languageService */
204 $languageService = $this->prophesize(LanguageService::class);
205 $GLOBALS['LANG'] = $languageService->reveal();
206 $languageService->sL(Argument::cetera())->willReturnArgument(0);
207
208 $expected = $input;
209 $expected['recordTitle'] = 'NEW56017ee37d10e587251374';
210 $this->assertSame($expected, $this->subject->addData($input));
211 }
212
213 /**
214 * Data provider for addDataReturnsRecordTitleForInputType
215 * Each data set is an array with the following elements:
216 * - TCA field ['config'] section
217 * - Database value for field
218 * - expected title to be generated
219 *
220 * @returns array
221 */
222 public function addDataReturnsRecordTitleForInputTypeDataProvider()
223 {
224 return [
225 'new record' => [
226 [
227 'type' => 'input',
228 ],
229 '',
230 '',
231 ],
232 'plain text input' => [
233 [
234 'type' => 'input',
235 ],
236 'aValue',
237 'aValue',
238 ],
239 'date input' => [
240 [
241 'type' => 'input',
242 'eval' => 'date'
243 ],
244 '978307261',
245 '01-01-01 (-7 days)',
246 ],
247 'date input (dbType: date)' => [
248 [
249 'type' => 'input',
250 'eval' => 'date',
251 'dbType' => 'date'
252 ],
253 '2001-01-01',
254 '01-01-01 (-7 days)',
255 ],
256 'date input (disableAgeDisplay: TRUE)' => [
257 [
258 'type' => 'input',
259 'eval' => 'date',
260 'disableAgeDisplay' => true
261 ],
262 '978307261',
263 '01-01-01',
264 ],
265 'time input' => [
266 [
267 'type' => 'input',
268 'eval' => 'time',
269 ],
270 '44100',
271 '12:15',
272 ],
273 'timesec input' => [
274 [
275 'type' => 'input',
276 'eval' => 'timesec',
277 ],
278 '44130',
279 '12:15:30',
280 ],
281 'datetime input' => [
282 [
283 'type' => 'input',
284 'eval' => 'datetime',
285 'dbType' => 'date'
286 ],
287 '978307261',
288 '01-01-01 00:01',
289 ],
290 'datetime input (dbType: datetime)' => [
291 [
292 'type' => 'input',
293 'eval' => 'datetime',
294 'dbType' => 'datetime'
295 ],
296 '2014-12-31 23:59:59',
297 '31-12-14 23:59',
298 ],
299 ];
300 }
301
302 /**
303 * @test
304 * @dataProvider addDataReturnsRecordTitleForInputTypeDataProvider
305 *
306 * @param array $fieldConfig
307 * @param string $fieldValue
308 * @param string $expectedTitle
309 */
310 public function addDataReturnsRecordTitleForInputType($fieldConfig, $fieldValue, $expectedTitle)
311 {
312 $input = [
313 'tableName' => 'aTable',
314 'databaseRow' => [
315 'uid' => '1',
316 'aField' => $fieldValue,
317 ],
318 'processedTca' => [
319 'ctrl' => [
320 'label' => 'aField'
321 ],
322 'columns' => [
323 'aField' => [
324 'config' => $fieldConfig,
325 ]
326 ],
327 ]
328 ];
329
330 /** @var LanguageService|ObjectProphecy $languageService */
331 $languageService = $this->prophesize(LanguageService::class);
332 $GLOBALS['LANG'] = $languageService->reveal();
333 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')
334 ->willReturn(' min| hrs| days| yrs| min| hour| day| year');
335 $languageService->sL(Argument::cetera())->willReturnArgument(0);
336 $GLOBALS['EXEC_TIME'] = 978912061;
337
338 $expected = $input;
339 $expected['recordTitle'] = $expectedTitle;
340 $this->assertSame($expected, $this->subject->addData($input));
341 }
342
343 /**
344 * @test
345 */
346 public function addDataReturnsRecordTitleWithAlternativeLabel()
347 {
348 $input = [
349 'tableName' => 'aTable',
350 'databaseRow' => [
351 'uid' => '1',
352 'aField' => '',
353 'anotherField' => 'anotherValue',
354 ],
355 'processedTca' => [
356 'ctrl' => [
357 'label' => 'aField',
358 'label_alt' => 'anotherField',
359 ],
360 'columns' => [
361 'aField' => [
362 'config' => [
363 'type' => 'input'
364 ]
365 ],
366 'anotherField' => [
367 'config' => [
368 'type' => 'input'
369 ]
370 ]
371 ],
372 ]
373 ];
374
375 $expected = $input;
376 $expected['recordTitle'] = 'anotherValue';
377 $this->assertSame($expected, $this->subject->addData($input));
378 }
379
380 /**
381 * @test
382 */
383 public function addDataReturnsRecordTitleWithMultipleAlternativeLabels()
384 {
385 $input = [
386 'tableName' => 'aTable',
387 'databaseRow' => [
388 'uid' => '1',
389 'aField' => '',
390 'anotherField' => '',
391 'additionalField' => 'additionalValue'
392 ],
393 'processedTca' => [
394 'ctrl' => [
395 'label' => 'aField',
396 'label_alt' => 'anotherField,additionalField',
397 ],
398 'columns' => [
399 'aField' => [
400 'config' => [
401 'type' => 'input'
402 ]
403 ],
404 'anotherField' => [
405 'config' => [
406 'type' => 'input'
407 ]
408 ],
409 'additionalField' => [
410 'config' => [
411 'type' => 'input'
412 ]
413 ],
414 ],
415 ]
416 ];
417
418 $expected = $input;
419 $expected['recordTitle'] = 'additionalValue';
420 $this->assertSame($expected, $this->subject->addData($input));
421 }
422
423 /**
424 * @test
425 */
426 public function addDataReturnsRecordTitleWithForcedAlternativeLabel()
427 {
428 $input = [
429 'tableName' => 'aTable',
430 'databaseRow' => [
431 'uid' => '1',
432 'aField' => 'aField',
433 'anotherField' => 'anotherField'
434 ],
435 'processedTca' => [
436 'ctrl' => [
437 'label' => 'aField',
438 'label_alt' => 'anotherField',
439 'label_alt_force' => true,
440 ],
441 'columns' => [
442 'aField' => [
443 'config' => [
444 'type' => 'input'
445 ]
446 ],
447 'anotherField' => [
448 'config' => [
449 'type' => 'input'
450 ]
451 ],
452 ],
453 ]
454 ];
455
456 $expected = $input;
457 $expected['recordTitle'] = 'aField, anotherField';
458 $this->assertSame($expected, $this->subject->addData($input));
459 }
460
461 /**
462 * @test
463 */
464 public function addDataReturnsRecordTitleWithMultipleForcedAlternativeLabels()
465 {
466 $input = [
467 'tableName' => 'aTable',
468 'databaseRow' => [
469 'uid' => '1',
470 'aField' => 'aField',
471 'anotherField' => 'anotherField',
472 'additionalField' => 'additionalValue'
473 ],
474 'processedTca' => [
475 'ctrl' => [
476 'label' => 'aField',
477 'label_alt' => 'anotherField,additionalField',
478 'label_alt_force' => true,
479 ],
480 'columns' => [
481 'aField' => [
482 'config' => [
483 'type' => 'input'
484 ]
485 ],
486 'anotherField' => [
487 'config' => [
488 'type' => 'input'
489 ]
490 ],
491 'additionalField' => [
492 'config' => [
493 'type' => 'input'
494 ]
495 ],
496 ],
497 ]
498 ];
499
500 $expected = $input;
501 $expected['recordTitle'] = 'aField, anotherField, additionalValue';
502 $this->assertSame($expected, $this->subject->addData($input));
503 }
504
505 /**
506 * @test
507 */
508 public function addDataReturnsRecordTitleIgnoresEmptyAlternativeLabels()
509 {
510 $input = [
511 'tableName' => 'aTable',
512 'databaseRow' => [
513 'uid' => '1',
514 'aField' => 'aField',
515 'anotherField' => '',
516 'additionalField' => 'additionalValue'
517 ],
518 'processedTca' => [
519 'ctrl' => [
520 'label' => 'aField',
521 'label_alt' => 'anotherField,additionalField',
522 'label_alt_force' => true,
523 ],
524 'columns' => [
525 'aField' => [
526 'config' => [
527 'type' => 'input'
528 ]
529 ],
530 'anotherField' => [
531 'config' => [
532 'type' => 'input'
533 ]
534 ],
535 'additionalField' => [
536 'config' => [
537 'type' => 'input'
538 ]
539 ],
540 ],
541 ]
542 ];
543
544 $expected = $input;
545 $expected['recordTitle'] = 'aField, additionalValue';
546 $this->assertSame($expected, $this->subject->addData($input));
547 }
548
549 /**
550 * @test
551 */
552 public function addDataReturnsRecordTitleForRadioType()
553 {
554 $input = [
555 'tableName' => 'aTable',
556 'databaseRow' => [
557 'uid' => '1',
558 'aField' => '2',
559 ],
560 'processedTca' => [
561 'ctrl' => [
562 'label' => 'aField'
563 ],
564 'columns' => [
565 'aField' => [
566 'config' => [
567 'type' => 'radio',
568 'items' => [
569 ['foo', 1],
570 ['bar', 2],
571 ['baz', 3],
572 ]
573 ]
574 ]
575 ],
576 ]
577 ];
578
579 $expected = $input;
580 $expected['recordTitle'] = 'bar';
581 $this->assertSame($expected, $this->subject->addData($input));
582 }
583
584 /**
585 * Data provider for addDataReturnsRecordTitleForGroupType
586 * Each data set is an array with the following elements:
587 * - TCA field configuration (merged with base config)
588 * - Database value for field
589 * - expected title to be generated
590 *
591 * @returns array
592 */
593 public function addDataReturnsRecordTitleForGroupTypeDataProvider()
594 {
595 return [
596 'new record' => [
597 [
598 'internal_type' => 'db',
599 ],
600 '',
601 ''
602 ],
603 'internal_type: file' => [
604 [
605 'internal_type' => 'file',
606 ],
607 'somePath/aFile.jpg,someOtherPath/anotherFile.png',
608 'somePath/aFile.jpg, someOtherPath/anotherFile.png',
609 ],
610 'internal_type: db, single table, single record' => [
611 [
612 'internal_type' => 'db',
613 'allowed' => 'aTable'
614 ],
615 '1|aValue',
616 'aValue',
617 ],
618 'internal_type: db, single table, multiple records' => [
619 [
620 'internal_type' => 'db',
621 'allowed' => 'aTable'
622 ],
623 '1|aValue,3|anotherValue',
624 'aValue, anotherValue',
625 ],
626 'internal_type: db, multiple tables, single record' => [
627 [
628 'internal_type' => 'db',
629 'allowed' => 'aTable,anotherTable'
630 ],
631 'anotherTable_1|anotherValue',
632 'anotherValue',
633 ],
634 'internal_type: db, multiple tables, multiple records' => [
635 [
636 'internal_type' => 'db',
637 'allowed' => 'aTable,anotherTable'
638 ],
639 'anotherTable_1|anotherValue,aTable_1|aValue',
640 'aValue, anotherValue',
641 ],
642 ];
643 }
644
645 /**
646 * @test
647 * @dataProvider addDataReturnsRecordTitleForGroupTypeDataProvider
648 *
649 * @param array $fieldConfig
650 * @param string $fieldValue
651 * @param string $expectedTitle
652 */
653 public function addDataReturnsRecordTitleForGroupType($fieldConfig, $fieldValue, $expectedTitle)
654 {
655 $input = [
656 'tableName' => 'aTable',
657 'databaseRow' => [
658 'uid' => '1',
659 'aField' => $fieldValue,
660 ],
661 'processedTca' => [
662 'ctrl' => [
663 'label' => 'aField'
664 ],
665 'columns' => [
666 'aField' => [
667 'config' => array_merge(
668 [
669 'type' => 'group',
670 ],
671 $fieldConfig
672 ),
673 ]
674 ],
675 ]
676 ];
677
678 /** @var LanguageService|ObjectProphecy $languageService */
679 $languageService = $this->prophesize(LanguageService::class);
680 $GLOBALS['LANG'] = $languageService->reveal();
681 $languageService->sL(Argument::cetera())->willReturnArgument(0);
682
683 $expected = $input;
684 $expected['recordTitle'] = $expectedTitle;
685 $this->assertSame($expected, $this->subject->addData($input));
686 }
687
688 /**
689 * @test
690 */
691 public function addDataReturnsRecordTitleForGroupTypeWithInternalTypeDb()
692 {
693 $input = [
694 'tableName' => 'aTable',
695 'databaseRow' => [
696 'uid' => '1',
697 'aField' => 'aTable_1|aValue,anotherTable_2|anotherValue',
698 ],
699 'processedTca' => [
700 'ctrl' => [
701 'label' => 'aField'
702 ],
703 'columns' => [
704 'aField' => [
705 'config' => [
706 'type' => 'group',
707 'internal_type' => 'db',
708 'allowed' => 'aTable,anotherTable',
709 ]
710 ]
711 ],
712 ]
713 ];
714
715 $expected = $input;
716 $expected['recordTitle'] = 'aValue, anotherValue';
717 $this->assertSame($expected, $this->subject->addData($input));
718 }
719
720 /**
721 * @test
722 */
723 public function addDataReturnsRecordTitleForSingleCheckboxType()
724 {
725 $input = [
726 'tableName' => 'aTable',
727 'databaseRow' => [
728 'aField' => 1,
729 ],
730 'processedTca' => [
731 'ctrl' => [
732 'label' => 'aField'
733 ],
734 'columns' => [
735 'aField' => [
736 'config' => [
737 'type' => 'check',
738 ]
739 ]
740 ],
741 ]
742 ];
743
744 /** @var LanguageService|ObjectProphecy $languageService */
745 $languageService = $this->prophesize(LanguageService::class);
746 $GLOBALS['LANG'] = $languageService->reveal();
747 $languageService->sL(Argument::cetera())->willReturnArgument(0)->shouldBeCalled();
748
749 $expected = $input;
750 $expected['recordTitle'] = 'LLL:EXT:lang/locallang_common.xlf:yes';
751 $this->assertSame($expected, $this->subject->addData($input));
752 }
753
754 /**
755 * @test
756 */
757 public function addDataReturnsRecordTitleForArrayCheckboxType()
758 {
759 $input = [
760 'tableName' => 'aTable',
761 'databaseRow' => [
762 'aField' => '5'
763 ],
764 'processedTca' => [
765 'ctrl' => [
766 'label' => 'aField'
767 ],
768 'columns' => [
769 'aField' => [
770 'config' => [
771 'type' => 'check',
772 'items' => [
773 ['foo', ''],
774 ['bar', ''],
775 ['baz', ''],
776 ]
777 ]
778 ]
779 ],
780 ]
781 ];
782
783 $expected = $input;
784 $expected['recordTitle'] = 'foo, baz';
785 $this->assertSame($expected, $this->subject->addData($input));
786 }
787
788 /**
789 * @test
790 */
791 public function addDataReturnsEmptyRecordTitleForFlexType()
792 {
793 $input = [
794 'tableName' => 'aTable',
795 'databaseRow' => [
796 'aField' => [
797 'data' => [
798 'sDEF' => [
799 'lDEF' => [
800 'aFlexField' => [
801 'vDEF' => 'aFlexValue',
802 ]
803 ]
804 ]
805 ]
806 ]
807 ],
808 'processedTca' => [
809 'ctrl' => [
810 'label' => 'aField'
811 ],
812 'columns' => [
813 'aField' => [
814 'config' => [
815 'type' => 'flex',
816 'ds' => [
817 'sheets' => [
818 'sDEF' => [
819 'ROOT' => [
820 'type' => 'array',
821 'el' => [
822 'aFlexField' => [
823 'label' => 'Some input field',
824 'config' => [
825 'type' => 'input',
826 ],
827 ],
828 ],
829 ],
830 ],
831 ],
832 ]
833
834 ]
835 ]
836 ],
837 ]
838 ];
839
840 $expected = $input;
841 $expected['recordTitle'] = '';
842 $this->assertSame($expected, $this->subject->addData($input));
843 }
844
845 /**
846 * @test
847 */
848 public function addDataReturnsRecordTitleForSelectType()
849 {
850 $input = [
851 'tableName' => 'aTable',
852 'databaseRow' => [
853 'aField' => [
854 '1',
855 '2'
856 ]
857 ],
858 'processedTca' => [
859 'ctrl' => [
860 'label' => 'aField'
861 ],
862 'columns' => [
863 'aField' => [
864 'config' => [
865 'type' => 'select',
866 'items' => [
867 ['foo', 1, null, null],
868 ['bar', 2, null, null],
869 ['baz', 4, null, null],
870 ]
871 ]
872 ]
873 ],
874 ]
875 ];
876
877 $expected = $input;
878 $expected['recordTitle'] = 'foo, bar';
879 $this->assertSame($expected, $this->subject->addData($input));
880 }
881
882 /**
883 * @test
884 */
885 public function addDataReturnsStrippedAndTrimmedValueForTextType()
886 {
887 $input = [
888 'tableName' => 'aTable',
889 'databaseRow' => [
890 'aField' => '<p> text </p>',
891 ],
892 'processedTca' => [
893 'ctrl' => [
894 'label' => 'aField',
895 ],
896 'columns' => [
897 'aField' => [
898 'config' => [
899 'type' => 'text',
900 ],
901 ],
902 ],
903 ],
904 ];
905
906 $expected = $input;
907 $expected['recordTitle'] = 'text';
908 $this->assertSame($expected, $this->subject->addData($input));
909 }
910 }