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