[TASK] Cleanup TCA
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Utility / BackendUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Backend\Tests\Unit\Utility;
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\Tests\Unit\Utility\Fixtures\BackendUtilityFixture;
20 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\LabelFromItemListMergedReturnsCorrectFieldsFixture;
21 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithMultipleAllowedTablesFixture;
22 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithOneAllowedTableFixture;
23 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForSelectWithMMRelationFixture;
24 use TYPO3\CMS\Backend\Utility\BackendUtility;
25 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26 use TYPO3\CMS\Core\Database\Connection;
27 use TYPO3\CMS\Core\Database\ConnectionPool;
28 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
29 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
30 use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
31 use TYPO3\CMS\Core\Database\RelationHandler;
32 use TYPO3\CMS\Core\Tests\UnitTestCase;
33 use TYPO3\CMS\Core\Utility\GeneralUtility;
34 use TYPO3\CMS\Lang\LanguageService;
35
36 /**
37 * Test case
38 */
39 class BackendUtilityTest extends UnitTestCase
40 {
41 ///////////////////////////////////////
42 // Tests concerning calcAge
43 ///////////////////////////////////////
44 /**
45 * Data provider for calcAge function
46 *
47 * @return array
48 */
49 public function calcAgeDataProvider()
50 {
51 return array(
52 'Single year' => array(
53 'seconds' => 60 * 60 * 24 * 365,
54 'expectedLabel' => '1 year'
55 ),
56 'Plural years' => array(
57 'seconds' => 60 * 60 * 24 * 365 * 2,
58 'expectedLabel' => '2 yrs'
59 ),
60 'Single negative year' => array(
61 'seconds' => 60 * 60 * 24 * 365 * -1,
62 'expectedLabel' => '-1 year'
63 ),
64 'Plural negative years' => array(
65 'seconds' => 60 * 60 * 24 * 365 * 2 * -1,
66 'expectedLabel' => '-2 yrs'
67 ),
68 'Single day' => array(
69 'seconds' => 60 * 60 * 24,
70 'expectedLabel' => '1 day'
71 ),
72 'Plural days' => array(
73 'seconds' => 60 * 60 * 24 * 2,
74 'expectedLabel' => '2 days'
75 ),
76 'Single negative day' => array(
77 'seconds' => 60 * 60 * 24 * -1,
78 'expectedLabel' => '-1 day'
79 ),
80 'Plural negative days' => array(
81 'seconds' => 60 * 60 * 24 * 2 * -1,
82 'expectedLabel' => '-2 days'
83 ),
84 'Single hour' => array(
85 'seconds' => 60 * 60,
86 'expectedLabel' => '1 hour'
87 ),
88 'Plural hours' => array(
89 'seconds' => 60 * 60 * 2,
90 'expectedLabel' => '2 hrs'
91 ),
92 'Single negative hour' => array(
93 'seconds' => 60 * 60 * -1,
94 'expectedLabel' => '-1 hour'
95 ),
96 'Plural negative hours' => array(
97 'seconds' => 60 * 60 * 2 * -1,
98 'expectedLabel' => '-2 hrs'
99 ),
100 'Single minute' => array(
101 'seconds' => 60,
102 'expectedLabel' => '1 min'
103 ),
104 'Plural minutes' => array(
105 'seconds' => 60 * 2,
106 'expectedLabel' => '2 min'
107 ),
108 'Single negative minute' => array(
109 'seconds' => 60 * -1,
110 'expectedLabel' => '-1 min'
111 ),
112 'Plural negative minutes' => array(
113 'seconds' => 60 * 2 * -1,
114 'expectedLabel' => '-2 min'
115 ),
116 'Zero seconds' => array(
117 'seconds' => 0,
118 'expectedLabel' => '0 min'
119 )
120 );
121 }
122
123 /**
124 * @test
125 * @dataProvider calcAgeDataProvider
126 *
127 * @param int $seconds
128 * @param string $expectedLabel
129 */
130 public function calcAgeReturnsExpectedValues($seconds, $expectedLabel)
131 {
132 $this->assertSame($expectedLabel, BackendUtility::calcAge($seconds));
133 }
134
135 ///////////////////////////////////////
136 // Tests concerning getProcessedValue
137 ///////////////////////////////////////
138 /**
139 * @test
140 * @see http://forge.typo3.org/issues/20994
141 */
142 public function getProcessedValueForZeroStringIsZero()
143 {
144 $GLOBALS['TCA'] = array(
145 'tt_content' => array(
146 'columns' => array(
147 'header' => array(
148 'config' => array(
149 'type' => 'input',
150 ),
151 ),
152 ),
153 ),
154 );
155 $this->assertEquals('0', BackendUtility::getProcessedValue('tt_content', 'header', '0'));
156 }
157
158 /**
159 * @test
160 */
161 public function getProcessedValueForGroup()
162 {
163 $GLOBALS['TCA'] = array(
164 'tt_content' => array(
165 'columns' => array(
166 'multimedia' => array(
167 'config' => array(
168 'type' => 'group',
169 ),
170 ),
171 ),
172 ),
173 );
174 $this->assertSame('1, 2', BackendUtility::getProcessedValue('tt_content', 'multimedia', '1,2'));
175 }
176
177 /**
178 * @test
179 */
180 public function getProcessedValueForGroupWithOneAllowedTable()
181 {
182 $GLOBALS['TCA'] = array(
183 'tt_content' => array(
184 'columns' => array(
185 'pages' => array(
186 'config' => array(
187 'type' => 'group',
188 'allowed' => 'pages',
189 'internal_type' => 'db',
190 'maxitems' => 22,
191 'minitems' => 0,
192 'show_thumbs' => true,
193 'size' => 3,
194 ),
195 ),
196 ),
197 ),
198 );
199
200 $this->assertSame('Page 1, Page 2', ProcessedValueForGroupWithOneAllowedTableFixture::getProcessedValue('tt_content', 'pages', '1,2'));
201 }
202
203 /**
204 * @test
205 */
206 public function getProcessedValueForGroupWithMultipleAllowedTables()
207 {
208 $GLOBALS['TCA'] = array(
209 'index_config' => array(
210 'columns' => array(
211 'indexcfgs' => array(
212 'config' => array(
213 'type' => 'group',
214 'internal_type' => 'db',
215 'allowed' => 'index_config,pages',
216 'size' => 5,
217 ),
218 ),
219 ),
220 ),
221 );
222
223 $this->assertSame('Page 1, Configuration 2', ProcessedValueForGroupWithMultipleAllowedTablesFixture::getProcessedValue('index_config', 'indexcfgs', 'pages_1,index_config_2'));
224 }
225
226 /**
227 * Prepare a mock database setup for a Doctrine connection
228 * and return an array of all prophets to set expectations upon.
229 *
230 * @param string $tableName
231 * @return array
232 */
233 protected function mockDatabaseConnection($tableName = 'sys_category')
234 {
235 $connectionProphet = $this->prophesize(Connection::class);
236 $connectionProphet->quote(Argument::cetera())->will(function ($arguments) {
237 return "'" . $arguments[0] . "'";
238 });
239 $connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
240 return '`' . $arguments[0] . '`';
241 });
242
243 $restrictionProphet = $this->prophesize(DefaultRestrictionContainer::class);
244 $restrictionProphet->removeAll()->willReturn($restrictionProphet->reveal());
245 $restrictionProphet->add(Argument::cetera())->willReturn($restrictionProphet->reveal());
246
247 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
248 $queryBuilderProphet->expr()->willReturn(
249 GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
250 );
251 $queryBuilderProphet->getRestrictions()->willReturn($restrictionProphet->reveal());
252 $queryBuilderProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
253 return '`' . $arguments[0] . '`';
254 });
255
256 $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
257 $connectionPoolProphet->getConnectionForTable($tableName)
258 ->willReturn($connectionProphet->reveal());
259 $connectionPoolProphet->getQueryBuilderForTable($tableName)
260 ->shouldBeCalled()
261 ->willReturn($queryBuilderProphet->reveal());
262
263 return [$queryBuilderProphet, $connectionPoolProphet, $connectionProphet, $restrictionProphet];
264 }
265
266 /**
267 * @test
268 */
269 public function getProcessedValueForSelectWithMMRelation()
270 {
271 /** @var RelationHandler|ObjectProphecy $relationHandlerProphet */
272 $relationHandlerProphet = $this->prophesize(RelationHandler::class);
273 $relationHandlerProphet->start(Argument::cetera())->shouldBeCalled();
274
275 $relationHandlerInstance = $relationHandlerProphet->reveal();
276 $relationHandlerInstance->tableArray['sys_category'] = [1, 2];
277
278 list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection('sys_category');
279 $statementProphet = $this->prophesize(\Doctrine\DBAL\Driver\Statement::class);
280 $statementProphet->fetch()->shouldBeCalled()->willReturn(
281 [
282 'uid' => 1,
283 'title' => 'Category 1',
284 ],
285 [
286 'uid' => 2,
287 'title' => 'Category 2',
288 ],
289 false
290 );
291
292 /** @var QueryBuilder|ObjectProphecy $queryBuilderProphet */
293 $queryBuilderProphet->select('uid', 'sys_category.title')->willReturn($queryBuilderProphet->reveal());
294 $queryBuilderProphet->from('sys_category')->willReturn($queryBuilderProphet->reveal());
295 $queryBuilderProphet->where('`uid` IN (1, 2)')->willReturn($queryBuilderProphet->reveal());
296 $queryBuilderProphet->execute()->willReturn($statementProphet->reveal());
297
298 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerInstance);
299 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
300
301 $GLOBALS['TCA'] = array(
302 'pages' => array(
303 'columns' => array(
304 'categories' => array(
305 'config' => array(
306 'type' => 'select',
307 'foreign_table' => 'sys_category',
308 'MM' => 'sys_category_record_mm',
309 'MM_match_fields' => array(
310 'fieldname' => 'categories',
311 'tablesnames' => 'pages',
312 ),
313 'MM_opposite_field' => 'items',
314 ),
315 ),
316 ),
317 ),
318 'sys_category' => array(
319 'ctrl' => array('label' => 'title'),
320 'columns' => array(
321 'items' => array(
322 'config' => array(
323 'type' => 'group',
324 'internal_type' => 'db',
325 'allowed' => '*',
326 'MM' => 'sys_category_record_mm',
327 'MM_oppositeUsage' => array(),
328 )
329 )
330 ),
331 ),
332 );
333
334 $this->assertSame(
335 'Category 1; Category 2',
336 ProcessedValueForSelectWithMMRelationFixture::getProcessedValue(
337 'pages',
338 'categories',
339 '2',
340 0,
341 false,
342 false,
343 1
344 )
345 );
346 }
347
348 /**
349 * @test
350 */
351 public function getProcessedValueDisplaysAgeForDateInputFieldsIfSettingAbsent()
352 {
353 /** @var ObjectProphecy $languageServiceProphecy */
354 $languageServiceProphecy = $this->prophesize(LanguageService::class);
355 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
356 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
357
358 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 8, 30, 2015);
359
360 $GLOBALS['TCA'] = [
361 'tt_content' => [
362 'columns' => [
363 'date' => [
364 'config' => [
365 'type' => 'input',
366 'eval' => 'date',
367 ],
368 ],
369 ],
370 ],
371 ];
372 $this->assertSame('28-08-15 (-2 days)', BackendUtility::getProcessedValue('tt_content', 'date', mktime(0, 0, 0, 8, 28, 2015)));
373 }
374
375 /**
376 * @return array
377 */
378 public function inputTypeDateDisplayOptions()
379 {
380 return [
381 'typeSafe Setting' => [
382 true,
383 '28-08-15',
384 ],
385 'non typesafe setting' => [
386 1,
387 '28-08-15',
388 ],
389 'setting disabled typesafe' => [
390 false,
391 '28-08-15 (-2 days)',
392 ],
393 'setting disabled not typesafe' => [
394 0,
395 '28-08-15 (-2 days)',
396 ],
397 ];
398 }
399
400 /**
401 * @test
402 *
403 * @dataProvider inputTypeDateDisplayOptions
404 *
405 * @param string $input
406 * @param string $expected
407 */
408 public function getProcessedValueHandlesAgeDisplayCorrectly($input, $expected)
409 {
410 /** @var ObjectProphecy $languageServiceProphecy */
411 $languageServiceProphecy = $this->prophesize(LanguageService::class);
412 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
413 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
414
415 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 8, 30, 2015);
416
417 $GLOBALS['TCA'] = [
418 'tt_content' => [
419 'columns' => [
420 'date' => [
421 'config' => [
422 'type' => 'input',
423 'eval' => 'date',
424 'disableAgeDisplay' => $input,
425 ],
426 ],
427 ],
428 ],
429 ];
430 $this->assertSame($expected, BackendUtility::getProcessedValue('tt_content', 'date', mktime(0, 0, 0, 8, 28, 2015)));
431 }
432
433 /**
434 * Tests concerning getCommonSelectFields
435 */
436
437 /**
438 * Data provider for getCommonSelectFieldsReturnsCorrectFields
439 *
440 * @return array The test data with $table, $prefix, $presetFields, $tca, $expectedFields
441 */
442 public function getCommonSelectFieldsReturnsCorrectFieldsDataProvider()
443 {
444 return array(
445 'only uid' => array(
446 'table' => 'test_table',
447 'prefix' => '',
448 'presetFields' => array(),
449 'tca' => array(),
450 'expectedFields' => 'uid'
451 ),
452 'label set' => array(
453 'table' => 'test_table',
454 'prefix' => '',
455 'presetFields' => array(),
456 'tca' => array(
457 'ctrl' => array(
458 'label' => 'label'
459 )
460 ),
461 'expectedFields' => 'uid,label'
462 ),
463 'label_alt set' => array(
464 'table' => 'test_table',
465 'prefix' => '',
466 'presetFields' => array(),
467 'tca' => array(
468 'ctrl' => array(
469 'label_alt' => 'label,label2'
470 )
471 ),
472 'expectedFields' => 'uid,label,label2'
473 ),
474 'versioningWS set' => array(
475 'table' => 'test_table',
476 'prefix' => '',
477 'presetFields' => array(),
478 'tca' => array(
479 'ctrl' => array(
480 'versioningWS' => true
481 )
482 ),
483 'expectedFields' => 'uid,t3ver_id,t3ver_state,t3ver_wsid,t3ver_count'
484 ),
485 'selicon_field set' => array(
486 'table' => 'test_table',
487 'prefix' => '',
488 'presetFields' => array(),
489 'tca' => array(
490 'ctrl' => array(
491 'selicon_field' => 'field'
492 )
493 ),
494 'expectedFields' => 'uid,field'
495 ),
496 'typeicon_column set' => array(
497 'table' => 'test_table',
498 'prefix' => '',
499 'presetFields' => array(),
500 'tca' => array(
501 'ctrl' => array(
502 'typeicon_column' => 'field'
503 )
504 ),
505 'expectedFields' => 'uid,field'
506 ),
507 'enablecolumns set' => array(
508 'table' => 'test_table',
509 'prefix' => '',
510 'presetFields' => array(),
511 'tca' => array(
512 'ctrl' => array(
513 'enablecolumns' => array(
514 'disabled' => 'hidden',
515 'starttime' => 'start',
516 'endtime' => 'stop',
517 'fe_group' => 'groups'
518 )
519 )
520 ),
521 'expectedFields' => 'uid,hidden,start,stop,groups'
522 ),
523 'label set to uid' => array(
524 'table' => 'test_table',
525 'prefix' => '',
526 'presetFields' => array(),
527 'tca' => array(
528 'ctrl' => array(
529 'label' => 'uid'
530 )
531 ),
532 'expectedFields' => 'uid'
533 )
534 );
535 }
536
537 /**
538 * @test
539 * @dataProvider getCommonSelectFieldsReturnsCorrectFieldsDataProvider
540 *
541 * @param string $table
542 * @param string $prefix
543 * @param array $presetFields
544 * @param array $tca
545 * @param string $expectedFields
546 */
547 public function getCommonSelectFieldsReturnsCorrectFields($table, $prefix = '', array $presetFields, array $tca, $expectedFields = '')
548 {
549 $GLOBALS['TCA'][$table] = $tca;
550 $selectFields = BackendUtility::getCommonSelectFields($table, $prefix, $presetFields);
551 $this->assertEquals($selectFields, $expectedFields);
552 }
553
554 /**
555 * Tests concerning getLabelFromItemlist
556 */
557
558 /**
559 * Data provider for getLabelFromItemlistReturnsCorrectFields
560 *
561 * @return array The test data with $table, $col, $key, $expectedLabel
562 */
563 public function getLabelFromItemlistReturnsCorrectFieldsDataProvider()
564 {
565 return array(
566 'item set' => array(
567 'table' => 'tt_content',
568 'col' => 'menu_type',
569 'key' => '1',
570 'tca' => array(
571 'columns' => array(
572 'menu_type' => array(
573 'config' => array(
574 'items' => array(
575 array('Item 1', '0'),
576 array('Item 2', '1'),
577 array('Item 3', '3')
578 )
579 )
580 )
581 )
582 ),
583 'expectedLabel' => 'Item 2'
584 ),
585 'item set twice' => array(
586 'table' => 'tt_content',
587 'col' => 'menu_type',
588 'key' => '1',
589 'tca' => array(
590 'columns' => array(
591 'menu_type' => array(
592 'config' => array(
593 'items' => array(
594 array('Item 1', '0'),
595 array('Item 2a', '1'),
596 array('Item 2b', '1'),
597 array('Item 3', '3')
598 )
599 )
600 )
601 )
602 ),
603 'expectedLabel' => 'Item 2a'
604 ),
605 'item not found' => array(
606 'table' => 'tt_content',
607 'col' => 'menu_type',
608 'key' => '5',
609 'tca' => array(
610 'columns' => array(
611 'menu_type' => array(
612 'config' => array(
613 'items' => array(
614 array('Item 1', '0'),
615 array('Item 2', '1'),
616 array('Item 3', '2')
617 )
618 )
619 )
620 )
621 ),
622 'expectedLabel' => null
623 )
624 );
625 }
626
627 /**
628 * @test
629 * @dataProvider getLabelFromItemlistReturnsCorrectFieldsDataProvider
630 *
631 * @param string $table
632 * @param string $col
633 * @param string $key
634 * @param array $tca
635 * @param string $expectedLabel
636 */
637 public function getLabelFromItemlistReturnsCorrectFields($table, $col = '', $key = '', array $tca, $expectedLabel = '')
638 {
639 $GLOBALS['TCA'][$table] = $tca;
640 $label = BackendUtility::getLabelFromItemlist($table, $col, $key);
641 $this->assertEquals($label, $expectedLabel);
642 }
643
644 /**
645 * Tests concerning getLabelFromItemListMerged
646 */
647
648 /**
649 * Data provider for getLabelFromItemListMerged
650 *
651 * @return array The test data with $pageId, $table, $column, $key, $expectedLabel
652 */
653 public function getLabelFromItemListMergedReturnsCorrectFieldsDataProvider()
654 {
655 return array(
656 'no field found' => array(
657 'pageId' => '123',
658 'table' => 'tt_content',
659 'col' => 'menu_type',
660 'key' => '10',
661 'tca' => array(
662 'columns' => array(
663 'menu_type' => array(
664 'config' => array(
665 'items' => array(
666 array('Item 1', '0'),
667 array('Item 2', '1'),
668 array('Item 3', '3')
669 )
670 )
671 )
672 )
673 ),
674 'expectedLabel' => ''
675 ),
676 'no tsconfig set' => array(
677 'pageId' => '123',
678 'table' => 'tt_content',
679 'col' => 'menu_type',
680 'key' => '1',
681 'tca' => array(
682 'columns' => array(
683 'menu_type' => array(
684 'config' => array(
685 'items' => array(
686 array('Item 1', '0'),
687 array('Item 2', '1'),
688 array('Item 3', '3')
689 )
690 )
691 )
692 )
693 ),
694 'expectedLabel' => 'Item 2'
695 )
696 );
697 }
698
699 /**
700 * @test
701 * @dataProvider getLabelFromItemListMergedReturnsCorrectFieldsDataProvider
702 *
703 * @param int $pageId
704 * @param string $table
705 * @param string $column
706 * @param string $key
707 * @param array $tca
708 * @param string $expectedLabel
709 */
710 public function getLabelFromItemListMergedReturnsCorrectFields($pageId, $table, $column = '', $key = '', array $tca, $expectedLabel = '')
711 {
712 $GLOBALS['TCA'][$table] = $tca;
713
714 $this->assertEquals($expectedLabel, LabelFromItemListMergedReturnsCorrectFieldsFixture::getLabelFromItemListMerged($pageId, $table, $column, $key));
715 }
716
717 /**
718 * Tests concerning getFuncCheck
719 */
720
721 /**
722 * @test
723 */
724 public function getFuncCheckReturnsInputTagWithValueAttribute()
725 {
726 $this->assertStringMatchesFormat('<input %Svalue="1"%S/>', BackendUtility::getFuncCheck('params', 'test', true));
727 }
728
729 /*
730 * Tests concerning getLabelsFromItemsList
731 */
732
733 /**
734 * @return array
735 */
736 public function getLabelsFromItemsListDataProvider()
737 {
738 return array(
739 'return value if found' => array(
740 'foobar', // table
741 'someColumn', // col
742 'foo, bar', // keyList
743 array( // TCA
744 'columns' => array(
745 'someColumn' => array(
746 'config' => array(
747 'items' => array(
748 '0' => array('aFooLabel', 'foo'),
749 '1' => array('aBarLabel', 'bar')
750 )
751 )
752 )
753 )
754 ),
755 array(), // page TSconfig
756 'aFooLabel, aBarLabel' // expected
757 ),
758 'page TSconfig overrules TCA' => array(
759 'foobar', // table
760 'someColumn', // col
761 'foo,bar, add', // keyList
762 array( // TCA
763 'columns' => array(
764 'someColumn' => array(
765 'config' => array(
766 'items' => array(
767 '0' => array('aFooLabel', 'foo'),
768 '1' => array('aBarLabel', 'bar')
769 )
770 )
771 )
772 )
773 ),
774 array( // page TSconfig
775 'addItems.' => array('add' => 'aNewLabel'),
776 'altLabels.' => array('bar' => 'aBarDiffLabel'),
777 ),
778 'aFooLabel, aBarDiffLabel, aNewLabel' // expected
779 )
780 );
781 }
782
783 /**
784 * @test
785 * @dataProvider getLabelsFromItemsListDataProvider
786 *
787 * @param string $table
788 * @param string $col
789 * @param string $keyList
790 * @param array $tca
791 * @param array $pageTsConfig
792 * @param string $expectedLabel
793 */
794 public function getLabelsFromItemsListReturnsCorrectValue($table, $col, $keyList, $tca, array $pageTsConfig, $expectedLabel)
795 {
796 // Stub LanguageService and let sL() return the same value that came in again
797 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
798 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
799
800 $GLOBALS['TCA'][$table] = $tca;
801 $label = BackendUtility::getLabelsFromItemsList($table, $col, $keyList, $pageTsConfig);
802 $this->assertEquals($expectedLabel, $label);
803 }
804
805 /**
806 * @test
807 */
808 public function getProcessedValueReturnsLabelsForExistingValuesSolely()
809 {
810 $table = 'foobar';
811 $col = 'someColumn';
812 $tca = array(
813 'columns' => array(
814 'someColumn' => array(
815 'config' => array(
816 'type' => 'select',
817 'items' => array(
818 '0' => array('aFooLabel', 'foo'),
819 '1' => array('aBarLabel', 'bar')
820 )
821 )
822 )
823 )
824 );
825 // Stub LanguageService and let sL() return the same value that came in again
826 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
827 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
828
829 $GLOBALS['TCA'][$table] = $tca;
830 $label = BackendUtility::getProcessedValue($table, $col, 'foo,invalidKey,bar');
831 $this->assertEquals('aFooLabel, aBarLabel', $label);
832 }
833
834 /**
835 * @test
836 */
837 public function getProcessedValueReturnsPlainValueIfItemIsNotFound()
838 {
839 $table = 'foobar';
840 $col = 'someColumn';
841 $tca = array(
842 'columns' => array(
843 'someColumn' => array(
844 'config' => array(
845 'type' => 'select',
846 'items' => array(
847 '0' => array('aFooLabel', 'foo')
848 )
849 )
850 )
851 )
852 );
853 // Stub LanguageService and let sL() return the same value that came in again
854 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
855 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
856
857 $GLOBALS['TCA'][$table] = $tca;
858 $label = BackendUtility::getProcessedValue($table, $col, 'invalidKey');
859 $this->assertEquals('invalidKey', $label);
860 }
861
862 /**
863 * Tests concerning viewOnClick
864 */
865
866 /**
867 * @test
868 */
869 public function viewOnClickReturnsOnClickCodeWithAlternativeUrl()
870 {
871 // Make sure the hook inside viewOnClick is not fired. This may be removed if unit tests
872 // bootstrap does not initialize TYPO3_CONF_VARS anymore.
873 unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass']);
874
875 $alternativeUrl = 'https://typo3.org/about/typo3-the-cms/the-history-of-typo3/#section';
876 $onclickCode = 'var previewWin = window.open(' . GeneralUtility::quoteJSvalue($alternativeUrl) . ',\'newTYPO3frontendWindow\');';
877 $this->assertStringMatchesFormat(
878 $onclickCode,
879 BackendUtility::viewOnClick(null, null, null, null, $alternativeUrl, null, false)
880 );
881 }
882
883 /**
884 * @test
885 */
886 public function getModTSconfigIgnoresValuesFromUserTsConfigIfNoSet()
887 {
888 $completeConfiguration = array(
889 'value' => 'bar',
890 'properties' => array(
891 'permissions.' => array(
892 'file.' => array(
893 'default.' => array('readAction' => '1'),
894 '1.' => array('writeAction' => '1'),
895 '0.' => array('readAction' => '0'),
896 ),
897 )
898 )
899 );
900
901 $GLOBALS['BE_USER'] = $this->createMock(BackendUserAuthentication::class);
902 $GLOBALS['BE_USER']->expects($this->at(0))->method('getTSConfig')->will($this->returnValue($completeConfiguration));
903 $GLOBALS['BE_USER']->expects($this->at(1))->method('getTSConfig')->will($this->returnValue(array('value' => null, 'properties' => null)));
904
905 $this->assertSame($completeConfiguration, BackendUtilityFixture::getModTSconfig(42, 'notrelevant'));
906 }
907
908 /**
909 * Data provider for replaceL10nModeFieldsReplacesFields
910 *
911 * @return array
912 */
913 public function replaceL10nModeFieldsReplacesFieldsDataProvider()
914 {
915 return array(
916 'same table: mergeIfNotBlank' => array(
917 'foo',
918 array(
919 'origUid' => 1,
920 'field2' => 'fdas',
921 'field3' => 'trans',
922 ),
923 array(
924 'foo' => array(
925 'ctrl' => array(
926 'transOrigPointerTable' => '',
927 'transOrigPointerField' => 'origUid'
928 ),
929 'columns' => array(
930 'field2' => array('l10n_mode' => 'mergeIfNotBlank'),
931 'field3' => array('l10n_mode' => 'mergeIfNotBlank')
932 )
933 )
934 ),
935 array(
936 'origUid' => 0,
937 'field2' => 'basic',
938 'field3' => '',
939 ),
940 array(
941 'origUid' => 1,
942 'field2' => 'fdas',
943 'field3' => 'trans',
944 )
945 ),
946 'other table: mergeIfNotBlank' => array(
947 'foo',
948 array(
949 'origUid' => 1,
950 'field2' => '',
951 'field3' => 'trans',
952 ),
953 array(
954 'foo' => array(
955 'ctrl' => array(
956 'transOrigPointerTable' => 'bar',
957 'transOrigPointerField' => 'origUid'
958 )
959 ),
960 'bar' => array(
961 'columns' => array(
962 'field2' => array('l10n_mode' => 'mergeIfNotBlank'),
963 'field3' => array('l10n_mode' => 'mergeIfNotBlank')
964 )
965 )
966 ),
967 array(
968 'origUid' => 0,
969 'field2' => 'basic',
970 'field3' => '',
971 ),
972 array(
973 'origUid' => 1,
974 'field2' => 'basic',
975 'field3' => 'trans',
976 )
977 ),
978 'same table: exclude' => array(
979 'foo',
980 array(
981 'origUid' => 1,
982 'field2' => 'fdas',
983 'field3' => 'trans',
984 ),
985 array(
986 'foo' => array(
987 'ctrl' => array(
988 'transOrigPointerTable' => '',
989 'transOrigPointerField' => 'origUid'
990 ),
991 'columns' => array(
992 'field2' => array('l10n_mode' => 'exclude'),
993 'field3' => array('l10n_mode' => 'exclude')
994 )
995 )
996 ),
997 array(
998 'origUid' => 0,
999 'field2' => 'basic',
1000 'field3' => '',
1001 ),
1002 array(
1003 'origUid' => 1,
1004 'field2' => 'basic',
1005 'field3' => '',
1006 )
1007 ),
1008 'other table: exclude' => array(
1009 'foo',
1010 array(
1011 'origUid' => 1,
1012 'field2' => 'fdas',
1013 'field3' => 'trans',
1014 ),
1015 array(
1016 'foo' => array(
1017 'ctrl' => array(
1018 'transOrigPointerTable' => 'bar',
1019 'transOrigPointerField' => 'origUid'
1020 )
1021 ),
1022 'bar' => array(
1023 'columns' => array(
1024 'field2' => array('l10n_mode' => 'exclude'),
1025 'field3' => array('l10n_mode' => 'exclude')
1026 )
1027 )
1028 ),
1029 array(
1030 'origUid' => 0,
1031 'field2' => 'basic',
1032 'field3' => '',
1033 ),
1034 array(
1035 'origUid' => 1,
1036 'field2' => 'basic',
1037 'field3' => '',
1038 )
1039 ),
1040 );
1041 }
1042
1043 /**
1044 * @test
1045 * @dataProvider replaceL10nModeFieldsReplacesFieldsDataProvider
1046 *
1047 * @param string $table
1048 * @param array $row
1049 * @param array $tca
1050 * @param array $originalRow
1051 * @param array $expected
1052 *
1053 * @throws \InvalidArgumentException
1054 * @throws \PHPUnit_Framework_Exception
1055 */
1056 public function replaceL10nModeFieldsReplacesFields($table, array $row, array $tca, array $originalRow, $expected)
1057 {
1058 if (!empty($tca[$table]['ctrl']['transOrigPointerTable'])) {
1059 $tableName = $tca[$table]['ctrl']['transOrigPointerTable'];
1060 } else {
1061 $tableName = $table;
1062 }
1063
1064 list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection($tableName);
1065
1066 $statementProphet = $this->prophesize(\Doctrine\DBAL\Driver\Statement::class);
1067 $statementProphet->fetch()->willReturn($originalRow, false);
1068
1069 $queryBuilderProphet->select('*')
1070 ->shouldBeCalled()
1071 ->willReturn($queryBuilderProphet->reveal());
1072 $queryBuilderProphet->from($tableName)
1073 ->shouldBeCalled()
1074 ->willReturn($queryBuilderProphet->reveal());
1075 $queryBuilderProphet->where('`uid` = ' . $row['origUid'])
1076 ->shouldBeCalled()
1077 ->willReturn($queryBuilderProphet->reveal());
1078 $queryBuilderProphet->execute()
1079 ->shouldBeCalled()
1080 ->willReturn($statementProphet->reveal());
1081
1082 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1083
1084 $GLOBALS['TCA'] = $tca;
1085
1086 /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|BackendUtility $subject */
1087 $subject = $this->getAccessibleMock(BackendUtility::class, array('dummy'));
1088 $this->assertSame($expected, $subject->_call('replaceL10nModeFields', $table, $row));
1089 }
1090
1091 /**
1092 * @test
1093 */
1094 public function getSpecConfPartsSplitsDefaultExtras()
1095 {
1096 $defaultExtras = 'nowrap:wizards[foo|bar]:anotherDefaultExtras:some[other|setting|with|parameters]';
1097 $expected = array(
1098 'nowrap' => 1,
1099 'wizards' => array(
1100 'parameters' => array(
1101 0 => 'foo',
1102 1 => 'bar',
1103 ),
1104 ),
1105 'anotherDefaultExtras' => 1,
1106 'some' => array(
1107 'parameters' => array(
1108 0 => 'other',
1109 1 => 'setting',
1110 2 => 'with',
1111 3 => 'parameters',
1112 ),
1113 ),
1114 );
1115 $this->assertEquals($expected, BackendUtility::getSpecConfParts($defaultExtras));
1116 }
1117
1118 /**
1119 * @test
1120 */
1121 public function dateTimeAgeReturnsCorrectValues()
1122 {
1123 /** @var ObjectProphecy|LanguageService $languageServiceProphecy */
1124 $languageServiceProphecy = $this->prophesize(LanguageService::class);
1125 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
1126 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1127 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 3, 23, 2016);
1128
1129 $this->assertSame('24-03-16 00:00 (-1 day)', BackendUtility::dateTimeAge($GLOBALS['EXEC_TIME'] + 86400));
1130 $this->assertSame('24-03-16 (-1 day)', BackendUtility::dateTimeAge($GLOBALS['EXEC_TIME'] + 86400, 1, 'date'));
1131 }
1132 }