‪TYPO3CMS  ‪main
TcaCheckboxItemsTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
29 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
30 
31 final class ‪TcaCheckboxItemsTest extends UnitTestCase
32 {
33  protected function ‪tearDown(): void
34  {
35  GeneralUtility::purgeInstances();
36  parent::tearDown();
37  }
38 
39  public static function ‪checkboxConfigurationDataProvider(): array
40  {
41  return [
42  'simpleCheckboxConfig' => [
43  'input' => [
44  'tableName' => 'foo',
45  'processedTca' => [
46  'columns' => [
47  'aField' => [
48  'config' => [
49  'type' => 'check',
50  'items' => [
51  0 => [
52  'label' => 'foo',
53  ],
54  ],
55  ],
56  ],
57  ],
58  ],
59  ],
60  'expected' => [
61  'tableName' => 'foo',
62  'processedTca' => [
63  'columns' => [
64  'aField' => [
65  'config' => [
66  'type' => 'check',
67  'items' => [
68  0 => [
69  'label' => 'foo',
70  'invertStateDisplay' => false,
71  ],
72  ],
73  ],
74  ],
75  ],
76  ],
77  ],
78  ],
79  'brokenSimpleCheckboxConfig' => [
80  'input' => [
81  'tableName' => 'foo',
82  'processedTca' => [
83  'columns' => [
84  'aField' => [
85  'config' => [
86  'type' => 'check',
87  'items' => [
88  0 => [
89  'label' => 'foo',
90  'bar',
91  'baz',
92  ],
93  ],
94  ],
95  ],
96  ],
97  ],
98  ],
99  'expected' => [
100  'tableName' => 'foo',
101  'processedTca' => [
102  'columns' => [
103  'aField' => [
104  'config' => [
105  'type' => 'check',
106  'items' => [
107  0 => [
108  'label' => 'foo',
109  'invertStateDisplay' => false,
110  ],
111  ],
112  ],
113  ],
114  ],
115  ],
116  ],
117  ],
118  'toggleCheckboxConfig' => [
119  'input' => [
120  'tableName' => 'foo',
121  'processedTca' => [
122  'columns' => [
123  'aField' => [
124  'config' => [
125  'type' => 'check',
126  'renderType' => 'checkboxToggle',
127  'items' => [
128  0 => [
129  'label' => 'foo',
130  'labelChecked' => 'Enabled',
131  'labelUnchecked' => 'Disabled',
132  ],
133  ],
134  ],
135  ],
136  ],
137  ],
138  ],
139  'expected' => [
140  'tableName' => 'foo',
141  'processedTca' => [
142  'columns' => [
143  'aField' => [
144  'config' => [
145  'type' => 'check',
146  'renderType' => 'checkboxToggle',
147  'items' => [
148  0 => [
149  'label' => 'foo',
150  'invertStateDisplay' => false,
151  ],
152  ],
153  ],
154  ],
155  ],
156  ],
157  ],
158  ],
159  'inverted_toggleCheckboxConfig' => [
160  'input' => [
161  'tableName' => 'foo',
162  'processedTca' => [
163  'columns' => [
164  'aField' => [
165  'config' => [
166  'type' => 'check',
167  'renderType' => 'checkboxToggle',
168  'items' => [
169  0 => [
170  'label' => 'foo',
171  'labelChecked' => 'Enabled',
172  'labelUnchecked' => 'Disabled',
173  'invertStateDisplay' => true,
174  ],
175  ],
176  ],
177  ],
178  ],
179  ],
180  ],
181  'expected' => [
182  'tableName' => 'foo',
183  'processedTca' => [
184  'columns' => [
185  'aField' => [
186  'config' => [
187  'type' => 'check',
188  'renderType' => 'checkboxToggle',
189  'items' => [
190  0 => [
191  'label' => 'foo',
192  'invertStateDisplay' => true,
193  ],
194  ],
195  ],
196  ],
197  ],
198  ],
199  ],
200  ],
201  'labeledCheckboxConfig' => [
202  'input' => [
203  'tableName' => 'foo',
204  'processedTca' => [
205  'columns' => [
206  'aField' => [
207  'config' => [
208  'type' => 'check',
209  'renderType' => 'checkboxLabeledToggle',
210  'items' => [
211  0 => [
212  'label' => 'foo',
213  'labelChecked' => 'Enabled',
214  'labelUnchecked' => 'Disabled',
215  ],
216  ],
217  ],
218  ],
219  ],
220  ],
221  ],
222  'expected' => [
223  'tableName' => 'foo',
224  'processedTca' => [
225  'columns' => [
226  'aField' => [
227  'config' => [
228  'type' => 'check',
229  'renderType' => 'checkboxLabeledToggle',
230  'items' => [
231  0 => [
232  'label' => 'foo',
233  'labelChecked' => 'Enabled',
234  'labelUnchecked' => 'Disabled',
235  'invertStateDisplay' => false,
236  ],
237  ],
238  ],
239  ],
240  ],
241  ],
242  ],
243  ],
244  'inverted_labeledCheckboxConfig' => [
245  'input' => [
246  'tableName' => 'foo',
247  'processedTca' => [
248  'columns' => [
249  'aField' => [
250  'config' => [
251  'type' => 'check',
252  'renderType' => 'checkboxLabeledToggle',
253  'items' => [
254  0 => [
255  'label' => 'foo',
256  'labelChecked' => 'Enabled',
257  'labelUnchecked' => 'Disabled',
258  'invertStateDisplay' => true,
259  ],
260  ],
261  ],
262  ],
263  ],
264  ],
265  ],
266  'expected' => [
267  'tableName' => 'foo',
268  'processedTca' => [
269  'columns' => [
270  'aField' => [
271  'config' => [
272  'type' => 'check',
273  'renderType' => 'checkboxLabeledToggle',
274  'items' => [
275  0 => [
276  'label' => 'foo',
277  'labelChecked' => 'Enabled',
278  'labelUnchecked' => 'Disabled',
279  'invertStateDisplay' => true,
280  ],
281  ],
282  ],
283  ],
284  ],
285  ],
286  ],
287  ],
288  'iconCheckboxConfig' => [
289  'input' => [
290  'tableName' => 'foo',
291  'processedTca' => [
292  'columns' => [
293  'aField' => [
294  'config' => [
295  'type' => 'check',
296  'renderType' => 'checkboxIconToggle',
297  'items' => [
298  0 => [
299  'label' => 'foo',
300  'labelChecked' => 'Enabled',
301  'labelUnchecked' => 'Disabled',
302  'iconIdentifierChecked' => 'styleguide-icon-toggle-checked',
303  'iconIdentifierUnchecked' => 'styleguide-icon-toggle-checked',
304  ],
305  ],
306  ],
307  ],
308  ],
309  ],
310  ],
311  'expected' => [
312  'tableName' => 'foo',
313  'processedTca' => [
314  'columns' => [
315  'aField' => [
316  'config' => [
317  'type' => 'check',
318  'renderType' => 'checkboxIconToggle',
319  'items' => [
320  0 => [
321  'label' => 'foo',
322  'iconIdentifierChecked' => 'styleguide-icon-toggle-checked',
323  'iconIdentifierUnchecked' => 'styleguide-icon-toggle-checked',
324  'invertStateDisplay' => false,
325  ],
326  ],
327  ],
328  ],
329  ],
330  ],
331  ],
332  ],
333  'inverted_iconCheckboxConfig' => [
334  'input' => [
335  'tableName' => 'foo',
336  'processedTca' => [
337  'columns' => [
338  'aField' => [
339  'config' => [
340  'type' => 'check',
341  'renderType' => 'checkboxIconToggle',
342  'items' => [
343  0 => [
344  'label' => 'foo',
345  'labelChecked' => 'Enabled',
346  'labelUnchecked' => 'Disabled',
347  'iconIdentifierChecked' => 'styleguide-icon-toggle-checked',
348  'iconIdentifierUnchecked' => 'styleguide-icon-toggle-checked',
349  'invertStateDisplay' => true,
350  ],
351  ],
352  ],
353  ],
354  ],
355  ],
356  ],
357  'expected' => [
358  'tableName' => 'foo',
359  'processedTca' => [
360  'columns' => [
361  'aField' => [
362  'config' => [
363  'type' => 'check',
364  'renderType' => 'checkboxIconToggle',
365  'items' => [
366  0 => [
367  'label' => 'foo',
368  'iconIdentifierChecked' => 'styleguide-icon-toggle-checked',
369  'iconIdentifierUnchecked' => 'styleguide-icon-toggle-checked',
370  'invertStateDisplay' => true,
371  ],
372  ],
373  ],
374  ],
375  ],
376  ],
377  ],
378  ],
379  ];
380  }
381 
382  #[DataProvider('checkboxConfigurationDataProvider')]
383  #[Test]
384  public function ‪addDataKeepExistingItems(array $input, array $expected): void
385  {
386  $languageService = $this->createMock(LanguageService::class);
387  ‪$GLOBALS['LANG'] = $languageService;
388  $languageService->method('sL')->with(self::anything())->willReturnArgument(0);
389 
390  self::assertSame($expected, (new ‪TcaCheckboxItems())->addData($input));
391  }
392 
393  #[Test]
395  {
396  $input = [
397  'processedTca' => [
398  'columns' => [
399  'aField' => [
400  'config' => [
401  'type' => 'check',
402  'items' => [
403  0 => 'aoeu',
404  ],
405  ],
406  ],
407  ],
408  ],
409  'tableName' => 'foo',
410  ];
411 
412  $languageService = $this->createMock(LanguageService::class);
413  ‪$GLOBALS['LANG'] = $languageService;
414  $languageService->method('sL')->with(self::anything())->willReturnArgument(0);
415 
416  $this->expectException(\UnexpectedValueException::class);
417  $this->expectExceptionCode(1440499337);
418  (new ‪TcaCheckboxItems())->addData($input);
419  }
420 
421  #[Test]
423  {
424  $input = [
425  'processedTca' => [
426  'columns' => [
427  'aField' => [
428  'config' => [
429  'type' => 'check',
430  'items' => [
431  0 => [
432  'funnyKey' => 'funnyValue',
433  ],
434  ],
435  ],
436  ],
437  ],
438  ],
439  'tableName' => 'foo',
440  ];
441 
442  $languageService = $this->createMock(LanguageService::class);
443  ‪$GLOBALS['LANG'] = $languageService;
444  $languageService->method('sL')->with(self::anything())->willReturnArgument(0);
445 
446  $this->expectException(\UnexpectedValueException::class);
447  $this->expectExceptionCode(1440499338);
448  (new ‪TcaCheckboxItems())->addData($input);
449  }
450 
451  #[Test]
452  public function ‪addDataTranslatesItemLabels(): void
453  {
454  $input = [
455  'processedTca' => [
456  'columns' => [
457  'aField' => [
458  'config' => [
459  'type' => 'check',
460  'items' => [
461  0 => [
462  'label' => 'aLabel',
463  ],
464  ],
465  ],
466  ],
467  ],
468  ],
469  'tableName' => 'foo',
470  ];
471 
472  $languageService = $this->createMock(LanguageService::class);
473  ‪$GLOBALS['LANG'] = $languageService;
474 
475  $languageService->expects(self::atLeastOnce())->method('sL')->with('aLabel')->willReturn('translated');
476 
477  $expected = $input;
478  $expected['processedTca']['columns']['aField']['config']['items'][0]['label'] = 'translated';
479  $expected['processedTca']['columns']['aField']['config']['items'][0]['invertStateDisplay'] = false;
480 
481  self::assertSame($expected, (new ‪TcaCheckboxItems())->addData($input));
482  }
483 
484  #[Test]
485  public function ‪addDataCallsItemsProcFunc(): void
486  {
487  $input = [
488  'tableName' => 'aTable',
489  'inlineParentUid' => 1,
490  'inlineParentTableName' => 'aTable',
491  'inlineParentFieldName' => 'aField',
492  'inlineParentConfig' => [],
493  'inlineTopMostParentUid' => 1,
494  'inlineTopMostParentTableName' => 'topMostTable',
495  'inlineTopMostParentFieldName' => 'topMostField',
496  'databaseRow' => [],
497  'effectivePid' => 42,
498  'site' => new ‪Site('aSite', 456, []),
499  'processedTca' => [
500  'columns' => [
501  'aField' => [
502  'config' => [
503  'type' => 'check',
504  'items' => [],
505  'itemsProcFunc' => static function (array $parameters, $pObj) {
506  $parameters['items'] = [
507  ['foo'],
508  ];
509  },
510  ],
511  ],
512  ],
513  ],
514  ];
515 
516  $languageService = $this->createMock(LanguageService::class);
517  ‪$GLOBALS['LANG'] = $languageService;
518  $languageService->method('sL')->with(self::anything())->willReturnArgument(0);
519 
520  $items = (new ‪TcaCheckboxItems())->addData($input)['processedTca']['columns']['aField']['config']['items'];
521 
522  self::assertCount(1, $items);
523  self::assertSame('foo', $items[0]['label']);
524  }
525 
526  #[Test]
528  {
529  $input = [
530  'tableName' => 'aTable',
531  'inlineParentUid' => 1,
532  'inlineParentTableName' => 'aTable',
533  'inlineParentFieldName' => 'aField',
534  'inlineParentConfig' => ['config' => 'someValue'],
535  'inlineTopMostParentUid' => 1,
536  'inlineTopMostParentTableName' => 'topMostTable',
537  'inlineTopMostParentFieldName' => 'topMostField',
538  'databaseRow' => [
539  'aField' => 'aValue',
540  ],
541  'effectivePid' => 42,
542  'site' => new ‪Site('aSite', 456, []),
543  'pageTsConfig' => [
544  'TCEFORM.' => [
545  'aTable.' => [
546  'aField.' => [
547  'itemsProcFunc.' => [
548  'itemParamKey' => 'itemParamValue',
549  ],
550  ],
551  ],
552  ],
553  ],
554  'flexParentDatabaseRow' => [
555  'aParentDatabaseRowFieldName' => 'aParentDatabaseRowFieldValue',
556  ],
557  'processedTca' => [
558  'columns' => [
559  'aField' => [
560  'config' => [
561  'type' => 'check',
562  'aKey' => 'aValue',
563  'items' => [
564  0 => [
565  'label' => 'foo',
566  'invertStateDisplay' => false,
567  ],
568  ],
569  'itemsProcFunc' => static function (array $parameters, $pObj) {
570  if (
571  $parameters['items'][0]['label'] !== 'foo'
572  || $parameters['items'][0]['invertStateDisplay'] !== false
573  || $parameters['config']['aKey'] !== 'aValue'
574  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
575  || $parameters['table'] !== 'aTable'
576  || $parameters['row'] !== [ 'aField' => 'aValue' ]
577  || $parameters['field'] !== 'aField'
578  || $parameters['flexParentDatabaseRow']['aParentDatabaseRowFieldName'] !== 'aParentDatabaseRowFieldValue'
579  || $parameters['inlineParentUid'] !== 1
580  || $parameters['inlineParentTableName'] !== 'aTable'
581  || $parameters['inlineParentFieldName'] !== 'aField'
582  || $parameters['inlineParentConfig'] !== ['config' => 'someValue']
583  || $parameters['inlineTopMostParentUid'] !== 1
584  || $parameters['inlineTopMostParentTableName'] !== 'topMostTable'
585  || $parameters['inlineTopMostParentFieldName'] !== 'topMostField'
586  ) {
587  throw new \UnexpectedValueException('broken', 1476109402);
588  }
589  },
590  ],
591  ],
592  ],
593  ],
594  ];
595 
596  $languageService = $this->createMock(LanguageService::class);
597  ‪$GLOBALS['LANG'] = $languageService;
598  $languageService->method('sL')->with(self::anything())->willReturnArgument(0);
599  $flashMessage = $this->createMock(FlashMessage::class);
600  GeneralUtility::addInstance(FlashMessage::class, $flashMessage);
601  $flashMessageService = $this->createMock(FlashMessageService::class);
602  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService);
603  $flashMessageQueue = $this->createMock(FlashMessageQueue::class);
604  $flashMessageService->method('getMessageQueueByIdentifier')->with(self::anything())->willReturn($flashMessageQueue);
605 
606  // itemsProcFunc must NOT have raised an exception
607  $flashMessageQueue->expects(self::never())->method('enqueue');
608 
609  (new ‪TcaCheckboxItems())->addData($input);
610  }
611 
612  #[Test]
614  {
615  $input = [
616  'tableName' => 'aTable',
617  'inlineParentUid' => 1,
618  'inlineParentTableName' => 'aTable',
619  'inlineParentFieldName' => 'aField',
620  'inlineParentConfig' => [],
621  'inlineTopMostParentUid' => 1,
622  'inlineTopMostParentTableName' => 'topMostTable',
623  'inlineTopMostParentFieldName' => 'topMostField',
624  'databaseRow' => [
625  'aField' => 'aValue',
626  ],
627  'effectivePid' => 42,
628  'site' => new ‪Site('aSite', 456, []),
629  'pageTsConfig' => [
630  'TCEFORM.' => [
631  'aTable.' => [
632  'aField.' => [
633  'itemsProcFunc.' => [
634  'itemParamKey' => 'itemParamValue',
635  ],
636  ],
637  ],
638  ],
639  ],
640  'processedTca' => [
641  'columns' => [
642  'aField' => [
643  'config' => [
644  'type' => 'check',
645  'aKey' => 'aValue',
646  'items' => [
647  0 => [
648  'label' => 'foo',
649  'value' => 'bar',
650  ],
651  ],
652  'itemsProcFunc' => static function (array $parameters, $pObj) {
653  throw new \UnexpectedValueException('anException', 1438604329);
654  },
655  ],
656  ],
657  ],
658  ],
659  ];
660 
661  $languageService = $this->createMock(LanguageService::class);
662  $languageService->method('sL')->with(self::anything())->willReturn('');
663  ‪$GLOBALS['LANG'] = $languageService;
664  $flashMessage = $this->createMock(FlashMessage::class);
665  GeneralUtility::addInstance(FlashMessage::class, $flashMessage);
666  $flashMessageService = $this->createMock(FlashMessageService::class);
667  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService);
668  $flashMessageQueue = $this->createMock(FlashMessageQueue::class);
669  $flashMessageService->method('getMessageQueueByIdentifier')->with(self::anything())->willReturn($flashMessageQueue);
670 
671  $flashMessageQueue->expects(self::atLeastOnce())->method('enqueue');
672 
673  (new ‪TcaCheckboxItems())->addData($input);
674  }
675 
676  #[Test]
678  {
679  $input = [
680  'tableName' => 'aTable',
681  'processedTca' => [
682  'columns' => [
683  'aField' => [
684  'config' => [
685  'type' => 'check',
686  'items' => [
687  0 => [
688  'label' => 'aLabel',
689  ],
690  ],
691  ],
692  ],
693  ],
694  ],
695  'pageTsConfig' => [
696  'TCEFORM.' => [
697  'aTable.' => [
698  'aField.' => [
699  'altLabels.' => [
700  0 => 'labelOverride',
701  ],
702  ],
703  ],
704  ],
705  ],
706  ];
707 
708  $languageService = $this->createMock(LanguageService::class);
709  ‪$GLOBALS['LANG'] = $languageService;
710  $series = [
711  'aLabel',
712  'labelOverride',
713  ];
714  $languageService->method('sL')->willReturnCallback(function (string $input) use (&$series): string {
715  self::assertSame(array_shift($series), $input);
716  return $input;
717  });
718 
719  $expected = $input;
720  $expected['processedTca']['columns']['aField']['config']['items'][0]['label'] = 'labelOverride';
721  $expected['processedTca']['columns']['aField']['config']['items'][0]['invertStateDisplay'] = false;
722 
723  self::assertSame($expected, (new ‪TcaCheckboxItems())->addData($input));
724  }
725 }
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataTranslatesItemLabelsFromPageTsConfig
‪addDataTranslatesItemLabelsFromPageTsConfig()
Definition: TcaCheckboxItemsTest.php:677
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataThrowsExceptionIfItemsAreNoArray
‪addDataThrowsExceptionIfItemsAreNoArray()
Definition: TcaCheckboxItemsTest.php:394
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataKeepExistingItems
‪addDataKeepExistingItems(array $input, array $expected)
Definition: TcaCheckboxItemsTest.php:384
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\checkboxConfigurationDataProvider
‪static checkboxConfigurationDataProvider()
Definition: TcaCheckboxItemsTest.php:39
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest
Definition: TcaCheckboxItemsTest.php:32
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataCallsItemsProcFunc
‪addDataCallsItemsProcFunc()
Definition: TcaCheckboxItemsTest.php:485
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataThrowsExceptionIfItemLabelIsNotSet
‪addDataThrowsExceptionIfItemLabelIsNotSet()
Definition: TcaCheckboxItemsTest.php:422
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataItemsProcFuncReceivesParameters
‪addDataItemsProcFuncReceivesParameters()
Definition: TcaCheckboxItemsTest.php:527
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataTranslatesItemLabels
‪addDataTranslatesItemLabels()
Definition: TcaCheckboxItemsTest.php:452
‪TYPO3\CMS\Backend\Form\FormDataProvider\TcaCheckboxItems
Definition: TcaCheckboxItems.php:24
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:29
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\tearDown
‪tearDown()
Definition: TcaCheckboxItemsTest.php:33
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider
Definition: DatabaseDefaultLanguagePageRowTest.php:18
‪TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider\TcaCheckboxItemsTest\addDataItemsProcFuncEnqueuesFlashMessageOnException
‪addDataItemsProcFuncEnqueuesFlashMessageOnException()
Definition: TcaCheckboxItemsTest.php:613