[FOLLOWUP][BUGFIX] mergeIfNotBlank for recordTitle and tcaType
[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 TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithOneAllowedTableFixture;
19 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithMultipleAllowedTablesFixture;
20 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForSelectWithMMRelationFixture;
21 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\LabelFromItemListMergedReturnsCorrectFieldsFixture;
22 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ExcludeFieldsReturnsCorrectFieldListFixture;
23 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ExcludeFieldsReturnsCorrectListWithFlexFormFieldsFixture;
24 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
25 use TYPO3\CMS\Core\Charset\CharsetConverter;
26 use TYPO3\CMS\Core\Database\DatabaseConnection;
27 use TYPO3\CMS\Core\Tests\UnitTestCase;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29 use TYPO3\CMS\Lang\LanguageService;
30
31 /**
32 * Test case
33 */
34 class BackendUtilityTest extends UnitTestCase {
35
36 ///////////////////////////////////////
37 // Tests concerning calcAge
38 ///////////////////////////////////////
39 /**
40 * Data provider for calcAge function
41 *
42 * @return array
43 */
44 public function calcAgeDataProvider() {
45 return array(
46 'Single year' => array(
47 'seconds' => 60 * 60 * 24 * 365,
48 'expectedLabel' => '1 year'
49 ),
50 'Plural years' => array(
51 'seconds' => 60 * 60 * 24 * 365 * 2,
52 'expectedLabel' => '2 yrs'
53 ),
54 'Single negative year' => array(
55 'seconds' => 60 * 60 * 24 * 365 * -1,
56 'expectedLabel' => '-1 year'
57 ),
58 'Plural negative years' => array(
59 'seconds' => 60 * 60 * 24 * 365 * 2 * -1,
60 'expectedLabel' => '-2 yrs'
61 ),
62 'Single day' => array(
63 'seconds' => 60 * 60 * 24,
64 'expectedLabel' => '1 day'
65 ),
66 'Plural days' => array(
67 'seconds' => 60 * 60 * 24 * 2,
68 'expectedLabel' => '2 days'
69 ),
70 'Single negative day' => array(
71 'seconds' => 60 * 60 * 24 * -1,
72 'expectedLabel' => '-1 day'
73 ),
74 'Plural negative days' => array(
75 'seconds' => 60 * 60 * 24 * 2 * -1,
76 'expectedLabel' => '-2 days'
77 ),
78 'Single hour' => array(
79 'seconds' => 60 * 60,
80 'expectedLabel' => '1 hour'
81 ),
82 'Plural hours' => array(
83 'seconds' => 60 * 60 * 2,
84 'expectedLabel' => '2 hrs'
85 ),
86 'Single negative hour' => array(
87 'seconds' => 60 * 60 * -1,
88 'expectedLabel' => '-1 hour'
89 ),
90 'Plural negative hours' => array(
91 'seconds' => 60 * 60 * 2 * -1,
92 'expectedLabel' => '-2 hrs'
93 ),
94 'Single minute' => array(
95 'seconds' => 60,
96 'expectedLabel' => '1 min'
97 ),
98 'Plural minutes' => array(
99 'seconds' => 60 * 2,
100 'expectedLabel' => '2 min'
101 ),
102 'Single negative minute' => array(
103 'seconds' => 60 * -1,
104 'expectedLabel' => '-1 min'
105 ),
106 'Plural negative minutes' => array(
107 'seconds' => 60 * 2 * -1,
108 'expectedLabel' => '-2 min'
109 ),
110 'Zero seconds' => array(
111 'seconds' => 0,
112 'expectedLabel' => '0 min'
113 )
114 );
115 }
116
117 /**
118 * @test
119 * @dataProvider calcAgeDataProvider
120 * @param int $seconds
121 * @param string $expectedLabel
122 */
123 public function calcAgeReturnsExpectedValues($seconds, $expectedLabel) {
124 $this->assertSame($expectedLabel, BackendUtility::calcAge($seconds));
125 }
126
127 ///////////////////////////////////////
128 // Tests concerning getProcessedValue
129 ///////////////////////////////////////
130 /**
131 * @test
132 * @see http://forge.typo3.org/issues/20994
133 */
134 public function getProcessedValueForZeroStringIsZero() {
135 $GLOBALS['TCA'] = array(
136 'tt_content' => array(
137 'columns' => array(
138 'header' => array(
139 'config' => array(
140 'type' => 'input',
141 ),
142 ),
143 ),
144 ),
145 );
146 $this->assertEquals('0', BackendUtility::getProcessedValue('tt_content', 'header', '0'));
147 }
148
149 /**
150 * @test
151 */
152 public function getProcessedValueForGroup() {
153 $GLOBALS['TCA'] = array(
154 'tt_content' => array(
155 'columns' => array(
156 'multimedia' => array(
157 'config' => array(
158 'type' => 'group',
159 ),
160 ),
161 ),
162 ),
163 );
164 $this->assertSame('1, 2', BackendUtility::getProcessedValue('tt_content', 'multimedia', '1,2'));
165 }
166
167 /**
168 * @test
169 */
170 public function getProcessedValueForGroupWithOneAllowedTable() {
171 $GLOBALS['TCA'] = array(
172 'tt_content' => array(
173 'columns' => array(
174 'pages' => array(
175 'config' => array(
176 'type' => 'group',
177 'allowed' => 'pages',
178 'internal_type' => 'db',
179 'maxitems' => 22,
180 'minitems' => 0,
181 'show_thumbs' => 1,
182 'size' => 3,
183 ),
184 ),
185 ),
186 ),
187 );
188
189 $this->assertSame('Page 1, Page 2', ProcessedValueForGroupWithOneAllowedTableFixture::getProcessedValue('tt_content', 'pages', '1,2'));
190 }
191
192 /**
193 * @test
194 */
195 public function getProcessedValueForGroupWithMultipleAllowedTables() {
196 $GLOBALS['TCA'] = array(
197 'index_config' => array(
198 'columns' => array(
199 'indexcfgs' => array(
200 'config' => array(
201 'type' => 'group',
202 'internal_type' => 'db',
203 'allowed' => 'index_config,pages',
204 'size' => 5,
205 ),
206 ),
207 ),
208 ),
209 );
210
211 $this->assertSame('Page 1, Configuration 2', ProcessedValueForGroupWithMultipleAllowedTablesFixture::getProcessedValue('index_config', 'indexcfgs', 'pages_1,index_config_2'));
212 }
213
214 /**
215 * @test
216 */
217 public function getProcessedValueForSelectWithMMRelation() {
218 $GLOBALS['TYPO3_DB'] = $this->getMock(DatabaseConnection::class, array(), array(), '', FALSE);
219 $GLOBALS['TYPO3_DB']->expects($this->any())->method('fullQuoteStr')
220 ->will($this->returnCallback(
221 function($quoteStr) {
222 return "'" . $quoteStr . "'";
223 }
224 ));
225 $GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTquery')->will($this->returnValue(0));
226 $GLOBALS['TYPO3_DB']->expects($this->any())->method('sql_free_result');
227 $GLOBALS['TYPO3_DB']->expects($this->any())->method('sql_fetch_assoc')
228 ->will($this->returnCallback(
229 function() {
230 static $called = 0;
231 ++$called;
232 switch ($called) {
233 // SELECT * FROM sys_category_record_mm
234 case 1:
235 return array(
236 'uid_local' => 1, // uid of a sys_category record
237 'uid_foreign' => 1, // uid of a pages record
238 );
239 case 2:
240 return array(
241 'uid_local' => 2, // uid of a sys_category record
242 'uid_foreign' => 1, // uid of a pages record
243 );
244 case 3:
245 return NULL;
246 // SELECT * FROM sys_catgory
247 case 4:
248 return array(
249 'uid' => 1,
250 'title' => 'Category 1',
251 );
252 case 5:
253 return array(
254 'uid' => 2,
255 'title' => 'Category 2',
256 );
257 case 6:
258 return NULL;
259 }
260 return NULL;
261 }
262 ));
263
264 $GLOBALS['TCA'] = array(
265 'pages' => array(
266 'columns' => array(
267 'categories' => array(
268 'config' => array(
269 'type' => 'select',
270 'foreign_table' => 'sys_category',
271 'MM' => 'sys_category_record_mm',
272 'MM_match_fields' => array(
273 'fieldname' => 'categories',
274 'tablesnames' => 'pages',
275 ),
276 'MM_opposite_field' => 'items',
277 ),
278 ),
279 ),
280 ),
281 'sys_category' => array(
282 'columns' => array(
283 'items' => array(
284 'config' => array(
285 'type' => 'group',
286 'internal_type' => 'db',
287 'allowed' => '*',
288 'MM' => 'sys_category_record_mm',
289 'MM_oppositeUsage' => array(),
290 )
291 )
292 ),
293 ),
294 );
295
296 $this->assertSame('Category 1; Category 2', ProcessedValueForSelectWithMMRelationFixture::getProcessedValue('pages', 'categories', '2', 0, FALSE, FALSE, 1));
297 }
298
299 /**
300 * Tests concerning getCommonSelectFields
301 */
302
303 /**
304 * Data provider for getCommonSelectFieldsReturnsCorrectFields
305 *
306 * @return array The test data with $table, $prefix, $presetFields, $tca, $expectedFields
307 */
308 public function getCommonSelectFieldsReturnsCorrectFieldsDataProvider() {
309 return array(
310 'only uid' => array(
311 'table' => 'test_table',
312 'prefix' => '',
313 'presetFields' => array(),
314 'tca' => array(),
315 'expectedFields' => 'uid'
316 ),
317 'label set' => array(
318 'table' => 'test_table',
319 'prefix' => '',
320 'presetFields' => array(),
321 'tca' => array(
322 'ctrl' => array(
323 'label' => 'label'
324 )
325 ),
326 'expectedFields' => 'uid,label'
327 ),
328 'label_alt set' => array(
329 'table' => 'test_table',
330 'prefix' => '',
331 'presetFields' => array(),
332 'tca' => array(
333 'ctrl' => array(
334 'label_alt' => 'label,label2'
335 )
336 ),
337 'expectedFields' => 'uid,label,label2'
338 ),
339 'versioningWS set' => array(
340 'table' => 'test_table',
341 'prefix' => '',
342 'presetFields' => array(),
343 'tca' => array(
344 'ctrl' => array(
345 'versioningWS' => '2'
346 )
347 ),
348 'expectedFields' => 'uid,t3ver_id,t3ver_state,t3ver_wsid,t3ver_count'
349 ),
350 'selicon_field set' => array(
351 'table' => 'test_table',
352 'prefix' => '',
353 'presetFields' => array(),
354 'tca' => array(
355 'ctrl' => array(
356 'selicon_field' => 'field'
357 )
358 ),
359 'expectedFields' => 'uid,field'
360 ),
361 'typeicon_column set' => array(
362 'table' => 'test_table',
363 'prefix' => '',
364 'presetFields' => array(),
365 'tca' => array(
366 'ctrl' => array(
367 'typeicon_column' => 'field'
368 )
369 ),
370 'expectedFields' => 'uid,field'
371 ),
372 'enablecolumns set' => array(
373 'table' => 'test_table',
374 'prefix' => '',
375 'presetFields' => array(),
376 'tca' => array(
377 'ctrl' => array(
378 'enablecolumns' => array(
379 'disabled' => 'hidden',
380 'starttime' => 'start',
381 'endtime' => 'stop',
382 'fe_group' => 'groups'
383 )
384 )
385 ),
386 'expectedFields' => 'uid,hidden,start,stop,groups'
387 ),
388 'label set to uid' => array(
389 'table' => 'test_table',
390 'prefix' => '',
391 'presetFields' => array(),
392 'tca' => array(
393 'ctrl' => array(
394 'label' => 'uid'
395 )
396 ),
397 'expectedFields' => 'uid'
398 )
399 );
400 }
401
402 /**
403 * @test
404 * @dataProvider getCommonSelectFieldsReturnsCorrectFieldsDataProvider
405 * @param string $table
406 * @param string $prefix
407 * @param array $presetFields
408 * @param array $tca
409 * @param string $expectedFields
410 */
411 public function getCommonSelectFieldsReturnsCorrectFields($table, $prefix = '', array $presetFields, array $tca, $expectedFields = '') {
412 $GLOBALS['TCA'][$table] = $tca;
413 $selectFields = BackendUtility::getCommonSelectFields($table, $prefix, $presetFields);
414 $this->assertEquals($selectFields, $expectedFields);
415 }
416
417 /**
418 * Tests concerning getLabelFromItemlist
419 */
420
421 /**
422 * Data provider for getLabelFromItemlistReturnsCorrectFields
423 *
424 * @return array The test data with $table, $col, $key, $expectedLabel
425 */
426 public function getLabelFromItemlistReturnsCorrectFieldsDataProvider() {
427 return array(
428 'item set' => array(
429 'table' => 'tt_content',
430 'col' => 'menu_type',
431 'key' => '1',
432 'tca' => array(
433 'columns' => array(
434 'menu_type' => array(
435 'config' => array(
436 'items' => array(
437 array('Item 1', '0'),
438 array('Item 2', '1'),
439 array('Item 3', '3')
440 )
441 )
442 )
443 )
444 ),
445 'expectedLabel' => 'Item 2'
446 ),
447 'item set twice' => array(
448 'table' => 'tt_content',
449 'col' => 'menu_type',
450 'key' => '1',
451 'tca' => array(
452 'columns' => array(
453 'menu_type' => array(
454 'config' => array(
455 'items' => array(
456 array('Item 1', '0'),
457 array('Item 2a', '1'),
458 array('Item 2b', '1'),
459 array('Item 3', '3')
460 )
461 )
462 )
463 )
464 ),
465 'expectedLabel' => 'Item 2a'
466 ),
467 'item not found' => array(
468 'table' => 'tt_content',
469 'col' => 'menu_type',
470 'key' => '5',
471 'tca' => array(
472 'columns' => array(
473 'menu_type' => array(
474 'config' => array(
475 'items' => array(
476 array('Item 1', '0'),
477 array('Item 2', '1'),
478 array('Item 3', '2')
479 )
480 )
481 )
482 )
483 ),
484 'expectedLabel' => NULL
485 )
486 );
487 }
488
489 /**
490 * @test
491 * @dataProvider getLabelFromItemlistReturnsCorrectFieldsDataProvider
492 * @param string $table
493 * @param string $col
494 * @param string $key
495 * @param array $tca
496 * @param string $expectedLabel
497 */
498 public function getLabelFromItemlistReturnsCorrectFields($table, $col = '', $key = '', array $tca, $expectedLabel = '') {
499 $GLOBALS['TCA'][$table] = $tca;
500 $label = BackendUtility::getLabelFromItemlist($table, $col, $key);
501 $this->assertEquals($label, $expectedLabel);
502 }
503
504 /**
505 * Tests concerning getLabelFromItemListMerged
506 */
507
508 /**
509 * Data provider for getLabelFromItemListMerged
510 *
511 * @return array The test data with $pageId, $table, $column, $key, $expectedLabel
512 */
513 public function getLabelFromItemListMergedReturnsCorrectFieldsDataProvider() {
514 return array(
515 'no field found' => array(
516 'pageId' => '123',
517 'table' => 'tt_content',
518 'col' => 'menu_type',
519 'key' => '10',
520 'tca' => array(
521 'columns' => array(
522 'menu_type' => array(
523 'config' => array(
524 'items' => array(
525 array('Item 1', '0'),
526 array('Item 2', '1'),
527 array('Item 3', '3')
528 )
529 )
530 )
531 )
532 ),
533 'expectedLabel' => ''
534 ),
535 'no tsconfig set' => array(
536 'pageId' => '123',
537 'table' => 'tt_content',
538 'col' => 'menu_type',
539 'key' => '1',
540 'tca' => array(
541 'columns' => array(
542 'menu_type' => array(
543 'config' => array(
544 'items' => array(
545 array('Item 1', '0'),
546 array('Item 2', '1'),
547 array('Item 3', '3')
548 )
549 )
550 )
551 )
552 ),
553 'expectedLabel' => 'Item 2'
554 )
555 );
556 }
557
558 /**
559 * @test
560 * @dataProvider getLabelFromItemListMergedReturnsCorrectFieldsDataProvider
561 * @param int $pageId
562 * @param string $table
563 * @param string $column
564 * @param string $key
565 * @param array $tca
566 * @param string $expectedLabel
567 */
568 public function getLabelFromItemListMergedReturnsCorrectFields($pageId, $table, $column = '', $key = '', array $tca, $expectedLabel = '') {
569 $GLOBALS['TCA'][$table] = $tca;
570
571 $this->assertEquals($expectedLabel, LabelFromItemListMergedReturnsCorrectFieldsFixture::getLabelFromItemListMerged($pageId, $table, $column, $key));
572 }
573
574 /**
575 * Tests concerning getFuncCheck
576 */
577
578 /**
579 * @test
580 */
581 public function getFuncCheckReturnsInputTagWithValueAttribute() {
582 $this->assertStringMatchesFormat('<input %Svalue="1"%S/>', BackendUtility::getFuncCheck('params', 'test', TRUE));
583 }
584
585 /*
586 * Tests concerning getLabelsFromItemsList
587 */
588
589 /**
590 * @return array
591 */
592 public function getLabelsFromItemsListDataProvider() {
593 return array(
594 'return value if found' => array(
595 'foobar', // table
596 'someColumn', // col
597 'foo, bar', // keyList
598 array( // TCA
599 'columns' => array(
600 'someColumn' => array(
601 'config' => array(
602 'items' => array(
603 '0' => array('aFooLabel', 'foo'),
604 '1' => array('aBarLabel', 'bar')
605 )
606 )
607 )
608 )
609 ),
610 array(), // page TSconfig
611 'aFooLabel, aBarLabel' // expected
612 ),
613 'page TSconfig overrules TCA' => array(
614 'foobar', // table
615 'someColumn', // col
616 'foo,bar, add', // keyList
617 array( // TCA
618 'columns' => array(
619 'someColumn' => array(
620 'config' => array(
621 'items' => array(
622 '0' => array('aFooLabel', 'foo'),
623 '1' => array('aBarLabel', 'bar')
624 )
625 )
626 )
627 )
628 ),
629 array( // page TSconfig
630 'addItems.' => array('add' => 'aNewLabel'),
631 'altLabels.' => array('bar' => 'aBarDiffLabel'),
632 ),
633 'aFooLabel, aBarDiffLabel, aNewLabel' // expected
634 )
635 );
636 }
637
638 /**
639 * @test
640 * @dataProvider getLabelsFromItemsListDataProvider
641 * @param string $table
642 * @param string $col
643 * @param string $keyList
644 * @param array $tca
645 * @param array $pageTsConfig
646 * @param string $expectedLabel
647 */
648 public function getLabelsFromItemsListReturnsCorrectValue($table, $col, $keyList, $tca, array $pageTsConfig, $expectedLabel) {
649 // Stub LanguageService and let sL() return the same value that came in again
650 $GLOBALS['LANG'] = $this->getMock(LanguageService::class, array(), array(), '', FALSE);
651 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
652
653 $GLOBALS['TCA'][$table] = $tca;
654 $label = BackendUtility::getLabelsFromItemsList($table, $col, $keyList,$pageTsConfig);
655 $this->assertEquals($expectedLabel, $label);
656 }
657
658 /**
659 * @test
660 */
661 public function getProcessedValueReturnsLabelsForExistingValuesSolely() {
662 $table = 'foobar';
663 $col = 'someColumn';
664 $tca = array(
665 'columns' => array(
666 'someColumn' => array(
667 'config' => array(
668 'type' => 'select',
669 'items' => array(
670 '0' => array('aFooLabel', 'foo'),
671 '1' => array('aBarLabel', 'bar')
672 )
673 )
674 )
675 )
676 );
677 // Stub LanguageService and let sL() return the same value that came in again
678 $GLOBALS['LANG'] = $this->getMock(LanguageService::class, array(), array(), '', FALSE);
679 $GLOBALS['LANG']->charSet = 'utf-8';
680 $GLOBALS['LANG']->csConvObj = $this->getMock(CharsetConverter::class);
681 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
682
683 $GLOBALS['LANG']->csConvObj->expects($this->any())->method('crop')->will($this->returnArgument(1));
684
685 $GLOBALS['TCA'][$table] = $tca;
686 $label = BackendUtility::getProcessedValue($table, $col, 'foo,invalidKey,bar');
687 $this->assertEquals('aFooLabel, aBarLabel', $label);
688 }
689
690 /**
691 * @test
692 */
693 public function getProcessedValueReturnsPlainValueIfItemIsNotFound() {
694 $table = 'foobar';
695 $col = 'someColumn';
696 $tca = array(
697 'columns' => array(
698 'someColumn' => array(
699 'config' => array(
700 'type' => 'select',
701 'items' => array(
702 '0' => array('aFooLabel', 'foo')
703 )
704 )
705 )
706 )
707 );
708 // Stub LanguageService and let sL() return the same value that came in again
709 $GLOBALS['LANG'] = $this->getMock(LanguageService::class, array(), array(), '', FALSE);
710 $GLOBALS['LANG']->charSet = 'utf-8';
711 $GLOBALS['LANG']->csConvObj = $this->getMock(CharsetConverter::class);
712 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
713
714 $GLOBALS['LANG']->csConvObj->expects($this->any())->method('crop')->will($this->returnArgument(1));
715
716 $GLOBALS['TCA'][$table] = $tca;
717 $label = BackendUtility::getProcessedValue($table, $col, 'invalidKey');
718 $this->assertEquals('invalidKey', $label);
719 }
720
721 /**
722 * Tests concerning getExcludeFields
723 */
724
725 /**
726 * @return array
727 */
728 public function getExcludeFieldsDataProvider() {
729 return array(
730 'getExcludeFields does not return fields not configured as exclude field' => array(
731 array(
732 'tx_foo' => array(
733 'ctrl' => array(
734 'title' => 'foo',
735 ),
736 'columns' => array(
737 'bar' => array(
738 'label' => 'bar',
739 'exclude' => 1
740 ),
741 'baz' => array(
742 'label' => 'bar',
743 ),
744 )
745 )
746 ),
747 array(
748 array(
749 'foo: bar',
750 'tx_foo:bar',
751 ),
752 )
753 ),
754 'getExcludeFields returns fields from root level tables if root level restriction should be ignored' => array(
755 array(
756 'tx_foo' => array(
757 'ctrl' => array(
758 'title' => 'foo',
759 'rootLevel' => TRUE,
760 'security' => array(
761 'ignoreRootLevelRestriction' => TRUE,
762 ),
763 ),
764 'columns' => array(
765 'bar' => array(
766 'label' => 'bar',
767 'exclude' => 1
768 ),
769 )
770 )
771 ),
772 array(
773 array(
774 'foo: bar',
775 'tx_foo:bar',
776 ),
777 )
778 ),
779 'getExcludeFields does not return fields from root level tables' => array(
780 array(
781 'tx_foo' => array(
782 'ctrl' => array(
783 'title' => 'foo',
784 'rootLevel' => TRUE,
785 ),
786 'columns' => array(
787 'bar' => array(
788 'label' => 'bar',
789 'exclude' => 1
790 ),
791 )
792 )
793 ),
794 array()
795 ),
796 'getExcludeFields does not return fields from admin only level tables' => array(
797 array(
798 'tx_foo' => array(
799 'ctrl' => array(
800 'title' => 'foo',
801 'adminOnly' => TRUE,
802 ),
803 'columns' => array(
804 'bar' => array(
805 'label' => 'bar',
806 'exclude' => 1
807 ),
808 )
809 )
810 ),
811 array()
812 ),
813 );
814 }
815
816 /**
817 * @param $tca
818 * @param $expected
819 *
820 * @test
821 * @dataProvider getExcludeFieldsDataProvider
822 */
823 public function getExcludeFieldsReturnsCorrectFieldList($tca, $expected) {
824 $GLOBALS['TCA'] = $tca;
825
826 // Stub LanguageService and let sL() return the same value that came in again
827 $GLOBALS['LANG'] = $this->getMock(LanguageService::class, array(), array(), '', FALSE);
828 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
829
830 $this->assertSame($expected, ExcludeFieldsReturnsCorrectFieldListFixture::getExcludeFields());
831 }
832
833 /**
834 * @test
835 */
836 public function getExcludeFieldsReturnsCorrectListWithFlexFormFields() {
837 $GLOBALS['TCA'] = array(
838 'tx_foo' => array(
839 'ctrl' => array(
840 'title' => 'foo'
841 ),
842 'columns' => array(
843 'foo' => array(
844 'label' => 'foo',
845 'exclude' => 1
846 ),
847 'bar' => array(
848 'label' => 'bar',
849 'exclude' => 1
850 ),
851 'abarfoo' => array(
852 'label' => 'abarfoo',
853 'config' => array(
854 'type' => 'flex',
855 'ds' => array(
856 '*,dummy' => '',
857 )
858 )
859 )
860 )
861 ),
862 'tx_foobar' => array(
863 'ctrl' => array(
864 'title' => 'foobar'
865 ),
866 'columns' => array(
867 'foo' => array(
868 'label' => 'foo',
869 'exclude' => 1
870 ),
871 'bar' => array(
872 'label' => 'bar',
873 'exclude' => 1
874 )
875 )
876 ),
877 'tx_bar' => array(
878 'ctrl' => array(
879 'title' => 'bar'
880 ),
881 'columns' => array(
882 'foo' => array(
883 'label' => 'foo',
884 'exclude' => 1
885 ),
886 'bar' => array(
887 'label' => 'bar',
888 'exclude' => 1
889 )
890 )
891 )
892 );
893
894 $expectedResult = array(
895 array(
896 'bar: bar',
897 'tx_bar:bar'
898 ),
899 array(
900 'bar: foo',
901 'tx_bar:foo'
902 ),
903 array(
904 'abarfoo dummy: The Title:',
905 'tx_foo:abarfoo;dummy;sGeneral;xmlTitle'
906 ),
907 array(
908 'foo: bar',
909 'tx_foo:bar'
910 ),
911 array(
912 'foo: foo',
913 'tx_foo:foo'
914 ),
915 array(
916 'foobar: bar',
917 'tx_foobar:bar'
918 ),
919 array(
920 'foobar: foo',
921 'tx_foobar:foo'
922 ),
923 );
924
925 // Stub LanguageService and let sL() return the same value that came in again
926 $GLOBALS['LANG'] = $this->getMock(LanguageService::class, array(), array(), '', FALSE);
927 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
928
929 $this->assertSame($expectedResult, ExcludeFieldsReturnsCorrectListWithFlexFormFieldsFixture::getExcludeFields());
930 }
931
932 /**
933 * Tests concerning viewOnClick
934 */
935
936 /**
937 * @test
938 */
939 public function viewOnClickReturnsOnClickCodeWithAlternativeUrl() {
940 // Make sure the hook inside viewOnClick is not fired. This may be removed if unit tests
941 // bootstrap does not initialize TYPO3_CONF_VARS anymore.
942 unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass']);
943
944 $alternativeUrl = 'https://typo3.org/about/typo3-the-cms/the-history-of-typo3/#section';
945 $onclickCode = 'var previewWin = window.open(' . GeneralUtility::quoteJSvalue($alternativeUrl) . ',\'newTYPO3frontendWindow\');';
946 $this->assertStringMatchesFormat(
947 $onclickCode,
948 BackendUtility::viewOnClick(NULL, NULL, NULL, NULL, $alternativeUrl, NULL, FALSE)
949 );
950 }
951
952 /**
953 * Tests concerning replaceMarkersInWhereClause
954 */
955
956 /**
957 * @return array
958 */
959 public function replaceMarkersInWhereClauseDataProvider() {
960 return array(
961 'replaceMarkersInWhereClause replaces record field marker with quoted string' => array(
962 ' AND dummytable.title=\'###REC_FIELD_dummyfield###\'',
963 array(
964 '_THIS_ROW' => array(
965 'dummyfield' => 'Hello World'
966 )
967 ),
968 ' AND dummytable.title=\'Hello World\''
969 ),
970 'replaceMarkersInWhereClause replaces record field marker with fullquoted string' => array(
971 ' AND dummytable.title=###REC_FIELD_dummyfield###',
972 array(
973 '_THIS_ROW' => array(
974 'dummyfield' => 'Hello World'
975 )
976 ),
977 ' AND dummytable.title=\'Hello World\''
978 ),
979 'replaceMarkersInWhereClause replaces multiple record field markers' => array(
980 ' AND dummytable.title=\'###REC_FIELD_dummyfield###\' AND dummytable.pid=###REC_FIELD_pid###',
981 array(
982 '_THIS_ROW' => array(
983 'dummyfield' => 'Hello World',
984 'pid' => 42
985 )
986 ),
987 ' AND dummytable.title=\'Hello World\' AND dummytable.pid=\'42\''
988 ),
989 'replaceMarkersInWhereClause replaces current pid with integer' => array(
990 ' AND dummytable.uid=###CURRENT_PID###',
991 array(
992 '_CURRENT_PID' => 42
993 ),
994 ' AND dummytable.uid=42'
995 ),
996 'replaceMarkersInWhereClause replaces current pid with string' => array(
997 ' AND dummytable.uid=###CURRENT_PID###',
998 array(
999 '_CURRENT_PID' => '42string'
1000 ),
1001 ' AND dummytable.uid=42'
1002 ),
1003 'replaceMarkersInWhereClause replaces current record uid with integer' => array(
1004 ' AND dummytable.uid=###THIS_UID###',
1005 array(
1006 '_THIS_UID' => 42
1007 ),
1008 ' AND dummytable.uid=42'
1009 ),
1010 'replaceMarkersInWhereClause replaces current record uid with string' => array(
1011 ' AND dummytable.uid=###THIS_UID###',
1012 array(
1013 '_THIS_UID' => '42string'
1014 ),
1015 ' AND dummytable.uid=42'
1016 ),
1017 'replaceMarkersInWhereClause replaces current record cid with integer' => array(
1018 ' AND dummytable.uid=###THIS_CID###',
1019 array(
1020 '_THIS_CID' => 42
1021 ),
1022 ' AND dummytable.uid=42'
1023 ),
1024 'replaceMarkersInWhereClause replaces current record cid with string' => array(
1025 ' AND dummytable.uid=###THIS_CID###',
1026 array(
1027 '_THIS_CID' => '42string'
1028 ),
1029 ' AND dummytable.uid=42'
1030 ),
1031 'replaceMarkersInWhereClause replaces storage pid with integer' => array(
1032 ' AND dummytable.uid=###STORAGE_PID###',
1033 array(
1034 '_STORAGE_PID' => 42
1035 ),
1036 ' AND dummytable.uid=42'
1037 ),
1038 'replaceMarkersInWhereClause replaces storage pid with string' => array(
1039 ' AND dummytable.uid=###STORAGE_PID###',
1040 array(
1041 '_STORAGE_PID' => '42string'
1042 ),
1043 ' AND dummytable.uid=42'
1044 ),
1045 'replaceMarkersInWhereClause replaces siteroot uid with integer' => array(
1046 ' AND dummytable.uid=###SITEROOT###',
1047 array(
1048 '_SITEROOT' => 42
1049 ),
1050 ' AND dummytable.uid=42'
1051 ),
1052 'replaceMarkersInWhereClause replaces siteroot uid with string' => array(
1053 ' AND dummytable.uid=###SITEROOT###',
1054 array(
1055 '_SITEROOT' => '42string'
1056 ),
1057 ' AND dummytable.uid=42'
1058 ),
1059 'replaceMarkersInWhereClause replaces page tsconfig id with integer' => array(
1060 ' AND dummytable.uid=###PAGE_TSCONFIG_ID###',
1061 array(
1062 'dummyfield' => array(
1063 'PAGE_TSCONFIG_ID' => 42
1064 )
1065 ),
1066 ' AND dummytable.uid=42'
1067 ),
1068 'replaceMarkersInWhereClause replaces page tsconfig id with string' => array(
1069 ' AND dummytable.uid=###PAGE_TSCONFIG_ID###',
1070 array(
1071 'dummyfield' => array(
1072 'PAGE_TSCONFIG_ID' => '42string'
1073 )
1074 ),
1075 ' AND dummytable.uid=42'
1076 ),
1077 'replaceMarkersInWhereClause replaces page tsconfig string' => array(
1078 ' AND dummytable.title=\'###PAGE_TSCONFIG_STR###\'',
1079 array(
1080 'dummyfield' => array(
1081 'PAGE_TSCONFIG_STR' => '42'
1082 )
1083 ),
1084 ' AND dummytable.title=\'42\''
1085 ),
1086 'replaceMarkersInWhereClause replaces all markers' => array(
1087 ' AND dummytable.title=\'###REC_FIELD_dummyfield###\'' .
1088 ' AND dummytable.uid=###REC_FIELD_uid###' .
1089 ' AND dummytable.pid=###CURRENT_PID###' .
1090 ' AND dummytable.l18n_parent=###THIS_UID###' .
1091 ' AND dummytable.cid=###THIS_CID###' .
1092 ' AND dummytable.storage_pid=###STORAGE_PID###' .
1093 ' AND dummytable.siteroot=###SITEROOT###' .
1094 ' AND dummytable.config_uid=###PAGE_TSCONFIG_ID###' .
1095 ' AND dummytable.idlist IN (###PAGE_TSCONFIG_IDLIST###)' .
1096 ' AND dummytable.string=\'###PAGE_TSCONFIG_STR###\'',
1097 array(
1098 '_THIS_ROW' => array(
1099 'dummyfield' => 'Hello World',
1100 'uid' => 42
1101 ),
1102 '_CURRENT_PID' => '1',
1103 '_THIS_UID' => 2,
1104 '_THIS_CID' => 3,
1105 '_STORAGE_PID' => 4,
1106 '_SITEROOT' => 5,
1107 'dummyfield' => array(
1108 'PAGE_TSCONFIG_ID' => 6,
1109 'PAGE_TSCONFIG_IDLIST' => '1,2,3',
1110 'PAGE_TSCONFIG_STR' => 'string'
1111 )
1112 ),
1113 ' AND dummytable.title=\'Hello World\' AND dummytable.uid=\'42\' AND dummytable.pid=1' .
1114 ' AND dummytable.l18n_parent=2 AND dummytable.cid=3 AND dummytable.storage_pid=4' .
1115 ' AND dummytable.siteroot=5 AND dummytable.config_uid=6 AND dummytable.idlist IN (1,2,3)' .
1116 ' AND dummytable.string=\'string\'',
1117 ),
1118 );
1119 }
1120
1121 /**
1122 * @test
1123 * @dataProvider replaceMarkersInWhereClauseDataProvider
1124 * @param string $whereClause
1125 * @param array $tsConfig
1126 * @param string $expected
1127 * @throws \PHPUnit_Framework_Exception
1128 */
1129 public function replaceMarkersInWhereClauseReturnsValidWhereClause($whereClause, array $tsConfig, $expected) {
1130 // Mock TYPO3_DB and let it return same values that came in
1131 $GLOBALS['TYPO3_DB'] = $this->getMock(DatabaseConnection::class, array(), array(), '', FALSE);
1132 $GLOBALS['TYPO3_DB']->expects($this->any())->method('quoteStr')->will($this->returnArgument(0));
1133 $GLOBALS['TYPO3_DB']->expects($this->any())->method('fullQuoteStr')
1134 ->will($this->returnCallback(
1135 function($quoteStr) {
1136 return "'" . $quoteStr . "'";
1137 }
1138 ));
1139 $GLOBALS['TYPO3_DB']->expects($this->any())->method('cleanIntList')->will($this->returnArgument(0));
1140 $this->assertSame($expected, BackendUtility::replaceMarkersInWhereClause($whereClause, 'dummytable', 'dummyfield', $tsConfig));
1141 }
1142
1143 /**
1144 * @test
1145 */
1146 public function replaceMarkersInWhereClauseCleansIdList() {
1147 $GLOBALS['TYPO3_DB'] = $this->getMock(DatabaseConnection::class, array(), array(), '', FALSE);
1148 $GLOBALS['TYPO3_DB']->expects($this->once())->method('cleanIntList')->with('1,a,2,b,3,c');
1149 $where = ' AND dummytable.uid IN (###PAGE_TSCONFIG_IDLIST###)';
1150 $tsConfig = array(
1151 'dummyfield' => array(
1152 'PAGE_TSCONFIG_IDLIST' => '1,a,2,b,3,c'
1153 ),
1154 );
1155 BackendUtility::replaceMarkersInWhereClause($where, 'dummytable', 'dummyfield', $tsConfig);
1156 }
1157
1158 /**
1159 * @test
1160 */
1161 public function getModTSconfigIgnoresValuesFromUserTsConfigIfNoSet() {
1162 $completeConfiguration = array(
1163 'value' => 'bar',
1164 'properties' => array(
1165 'permissions.' => array(
1166 'file.' => array(
1167 'default.' => array('readAction' => '1'),
1168 '1.' => array('writeAction' => '1'),
1169 '0.' => array('readAction' => '0'),
1170 ),
1171 )
1172 )
1173 );
1174
1175 $GLOBALS['BE_USER'] = $this->getMock(BackendUserAuthentication::class, array(), array(), '', FALSE);
1176 $GLOBALS['BE_USER']->expects($this->at(0))->method('getTSConfig')->will($this->returnValue($completeConfiguration));
1177 $GLOBALS['BE_USER']->expects($this->at(1))->method('getTSConfig')->will($this->returnValue(array('value' => NULL, 'properties' => NULL)));
1178
1179 $className = $this->getUniqueId('BackendUtility');
1180 /** @var \PHPUnit_Framework_MockObject_MockObject|BackendUtility $subject */
1181 $subject = __NAMESPACE__ . '\\' . $className;
1182 eval(
1183 'namespace ' . __NAMESPACE__ . ';' .
1184 'class ' . $className . ' extends \\TYPO3\\CMS\\Backend\\Utility\\BackendUtility {' .
1185 ' static public function getPagesTSconfig($id, $rootLine = NULL, $returnPartArray = false) {' .
1186 ' return array();' .
1187 ' }' .
1188 '}'
1189 );
1190
1191 $this->assertSame($completeConfiguration, $subject::getModTSconfig(42, 'notrelevant'));
1192 }
1193
1194 /**
1195 * Data provider for replaceL10nModeFieldsReplacesFields
1196 * @return array
1197 */
1198 public function replaceL10nModeFieldsReplacesFieldsDataProvider() {
1199 return array(
1200 'same table: mergeIfNotBlank' => array(
1201 'foo',
1202 array(
1203 'origUid' => 1,
1204 'field2' => 'fdas',
1205 'field3' => 'trans',
1206 ),
1207 array(
1208 'foo' => array(
1209 'ctrl' => array(
1210 'transOrigPointerTable' => '',
1211 'transOrigPointerField' => 'origUid'
1212 ),
1213 'columns' => array(
1214 'field2' => array('l10n_mode' => 'mergeIfNotBlank'),
1215 'field3' => array('l10n_mode' => 'mergeIfNotBlank')
1216 )
1217 )
1218 ),
1219 array(
1220 'origUid' => 0,
1221 'field2' => 'basic',
1222 'field3' => '',
1223 ),
1224 array(
1225 'origUid' => 1,
1226 'field2' => 'fdas',
1227 'field3' => 'trans',
1228 )
1229 ),
1230 'other table: mergeIfNotBlank' => array(
1231 'foo',
1232 array(
1233 'origUid' => 1,
1234 'field2' => '',
1235 'field3' => 'trans',
1236 ),
1237 array(
1238 'foo' => array(
1239 'ctrl' => array(
1240 'transOrigPointerTable' => 'bar',
1241 'transOrigPointerField' => 'origUid'
1242 )
1243 ),
1244 'bar' => array(
1245 'columns' => array(
1246 'field2' => array('l10n_mode' => 'mergeIfNotBlank'),
1247 'field3' => array('l10n_mode' => 'mergeIfNotBlank')
1248 )
1249 )
1250 ),
1251 array(
1252 'origUid' => 0,
1253 'field2' => 'basic',
1254 'field3' => '',
1255 ),
1256 array(
1257 'origUid' => 1,
1258 'field2' => 'basic',
1259 'field3' => 'trans',
1260 )
1261 ),
1262 'same table: exclude' => array(
1263 'foo',
1264 array(
1265 'origUid' => 1,
1266 'field2' => 'fdas',
1267 'field3' => 'trans',
1268 ),
1269 array(
1270 'foo' => array(
1271 'ctrl' => array(
1272 'transOrigPointerTable' => '',
1273 'transOrigPointerField' => 'origUid'
1274 ),
1275 'columns' => array(
1276 'field2' => array('l10n_mode' => 'exclude'),
1277 'field3' => array('l10n_mode' => 'exclude')
1278 )
1279 )
1280 ),
1281 array(
1282 'origUid' => 0,
1283 'field2' => 'basic',
1284 'field3' => '',
1285 ),
1286 array(
1287 'origUid' => 1,
1288 'field2' => 'basic',
1289 'field3' => '',
1290 )
1291 ),
1292 'other table: exclude' => array(
1293 'foo',
1294 array(
1295 'origUid' => 1,
1296 'field2' => 'fdas',
1297 'field3' => 'trans',
1298 ),
1299 array(
1300 'foo' => array(
1301 'ctrl' => array(
1302 'transOrigPointerTable' => 'bar',
1303 'transOrigPointerField' => 'origUid'
1304 )
1305 ),
1306 'bar' => array(
1307 'columns' => array(
1308 'field2' => array('l10n_mode' => 'exclude'),
1309 'field3' => array('l10n_mode' => 'exclude')
1310 )
1311 )
1312 ),
1313 array(
1314 'origUid' => 0,
1315 'field2' => 'basic',
1316 'field3' => '',
1317 ),
1318 array(
1319 'origUid' => 1,
1320 'field2' => 'basic',
1321 'field3' => '',
1322 )
1323 ),
1324 );
1325 }
1326
1327 /**
1328 * @test
1329 * @dataProvider replaceL10nModeFieldsReplacesFieldsDataProvider
1330 * @param string $table
1331 * @param array $row
1332 * @param array $tca
1333 * @param array $originalRow
1334 * @param array $expected
1335 * @throws \InvalidArgumentException
1336 * @throws \PHPUnit_Framework_Exception
1337 */
1338 public function replaceL10nModeFieldsReplacesFields($table, array $row, array $tca, array $originalRow, $expected) {
1339 $GLOBALS['TCA'] = $tca;
1340 $GLOBALS['TYPO3_DB'] = $this->getMock(DatabaseConnection::class);
1341 $GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTgetSingleRow')->will($this->returnValue($originalRow));
1342
1343 /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|BackendUtility $subject */
1344 $subject = $this->getAccessibleMock(BackendUtility::class, array('dummy'));
1345 $this->assertSame($expected, $subject->_call('replaceL10nModeFields', $table, $row));
1346 }
1347
1348 /**
1349 * @test
1350 */
1351 public function getSpecConfPartsSplitsDefaultExtras() {
1352 $defaultExtras = 'nowrap:wizards[foo|bar]:anotherDefaultExtras:some[other|setting|with|parameters]';
1353 $expected = array(
1354 'nowrap' => 1,
1355 'wizards' => array(
1356 'parameters' => array(
1357 0 => 'foo',
1358 1 => 'bar',
1359 ),
1360 ),
1361 'anotherDefaultExtras' => 1,
1362 'some' => array(
1363 'parameters' => array(
1364 0 => 'other',
1365 1 => 'setting',
1366 2 => 'with',
1367 3 => 'parameters',
1368 ),
1369 ),
1370 );
1371 $this->assertEquals($expected, BackendUtility::getSpecConfParts($defaultExtras));
1372 }
1373
1374 }