TYPO3 CMS  TYPO3_8-7
TcaSelectItemsTest.php
Go to the documentation of this file.
1 <?php
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 
36 
40 class TcaSelectItemsTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
41 {
45  protected $subject;
46 
50  protected $singletonInstances = [];
51 
52  protected function setUp()
53  {
54  $this->singletonInstances = GeneralUtility::getSingletonInstances();
55  $this->subject = new TcaSelectItems();
56  }
57 
58  protected function tearDown()
59  {
61  GeneralUtility::resetSingletonInstances($this->singletonInstances);
62  parent::tearDown();
63  }
64 
72  protected function mockDatabaseConnection($tableName = 'fTable')
73  {
74  $connectionProphet = $this->prophesize(Connection::class);
75  $connectionProphet->quote(Argument::cetera())->will(function ($arguments) {
76  return "'" . $arguments[0] . "'";
77  });
78  $connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
79  return '`' . $arguments[0] . '`';
80  });
81 
82  $restrictionProphet = $this->prophesize(DefaultRestrictionContainer::class);
83  $restrictionProphet->removeAll()->willReturn($restrictionProphet->reveal());
84  $restrictionProphet->add(Argument::cetera())->willReturn($restrictionProphet->reveal());
85 
86  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
87  $queryBuilderProphet->expr()->willReturn(
88  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
89  );
90  $queryBuilderProphet->getRestrictions()->willReturn($restrictionProphet->reveal());
91  $queryBuilderProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
92  return '`' . $arguments[0] . '`';
93  });
94 
95  $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
96  $connectionPoolProphet->getConnectionForTable($tableName)
97  ->willReturn($connectionProphet->reveal());
98  $connectionPoolProphet->getQueryBuilderForTable($tableName)
99  ->shouldBeCalled()
100  ->willReturn($queryBuilderProphet->reveal());
101 
102  return [$queryBuilderProphet, $connectionPoolProphet, $connectionProphet, $restrictionProphet];
103  }
104 
109  protected function mockDatabaseConnectionForProcessSelectField()
110  {
111  list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection('foreignTable');
112 
114  $statementProphet = $this->prophesize(Statement::class);
115  $statementProphet->fetch()->shouldBeCalled();
116 
117  $queryBuilderProphet->select('foreignTable.uid')
118  ->shouldBeCalled()
119  ->willReturn($queryBuilderProphet->reveal());
120  $queryBuilderProphet->from('foreignTable')
121  ->shouldBeCalled()
122  ->willReturn($queryBuilderProphet->reveal());
123  $queryBuilderProphet->from('pages')
124  ->shouldBeCalled()
125  ->willReturn($queryBuilderProphet->reveal());
126  $queryBuilderProphet->where('')
127  ->shouldBeCalled()
128  ->willReturn($queryBuilderProphet->reveal());
129  $queryBuilderProphet->andWhere(' 1=1')
130  ->shouldBeCalled()
131  ->willReturn($queryBuilderProphet->reveal());
132  $queryBuilderProphet->andWhere('`pages.uid` = `foreignTable.pid`')
133  ->shouldBeCalled()
134  ->willReturn($queryBuilderProphet->reveal());
135  $queryBuilderProphet->execute()
136  ->shouldBeCalled()
137  ->willReturn($statementProphet->reveal());
138 
139  // Two instances are needed due to the push/pop behavior of addInstance()
140  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
141  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
142  }
143 
147  public function addDataKeepExistingItems()
148  {
149  $input = [
150  'processedTca' => [
151  'columns' => [
152  'aField' => [
153  'config' => [
154  'type' => 'radio',
155  'items' => [
156  0 => [
157  'foo',
158  'bar',
159  ],
160  ],
161  ],
162  ],
163  'anotherField' => [
164  'config' => [
165  'type' => 'group',
166  'items' => [
167  0 => [
168  'foo',
169  'bar',
170  ],
171  ],
172  ],
173  ],
174  ],
175  ],
176  ];
177  $languageService = $this->prophesize(LanguageService::class);
178  $GLOBALS['LANG'] = $languageService->reveal();
179  $languageService->sL(Argument::cetera())->willReturnArgument(0);
180 
181  $expected = $input;
182  $this->assertSame($expected, $this->subject->addData($input));
183  }
184 
189  {
190  $input = [
191  'processedTca' => [
192  'columns' => [
193  'aField' => [
194  'config' => [
195  'type' => 'select',
196  'renderType' => 'selectSingle',
197  'items' => [
198  0 => 'foo',
199  ],
200  ],
201  ],
202  ],
203  ],
204  ];
205 
206  $this->expectException(\UnexpectedValueException::class);
207  $this->expectExceptionCode(1439288036);
208 
209  $this->subject->addData($input);
210  }
211 
215  public function addDataTranslatesItemLabels()
216  {
217  $input = [
218  'databaseRow' => [
219  'aField' => 'aValue',
220  ],
221  'processedTca' => [
222  'columns' => [
223  'aField' => [
224  'config' => [
225  'type' => 'select',
226  'renderType' => 'selectSingle',
227  'items' => [
228  0 => [
229  0 => 'aLabel',
230  1 => 'aValue',
231  ],
232  ],
233  'maxitems' => 99999,
234  ],
235  ],
236  ],
237  ],
238  ];
239 
241  $languageService = $this->prophesize(LanguageService::class);
242  $GLOBALS['LANG'] = $languageService->reveal();
243  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
244 
245  $languageService->sL('aLabel')->shouldBeCalled()->willReturn('translated');
246 
247  $expected = $input;
248  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'translated';
249  $expected['processedTca']['columns']['aField']['config']['items'][0][2] = null;
250  $expected['processedTca']['columns']['aField']['config']['items'][0][3] = null;
251 
252  $expected['databaseRow']['aField'] = ['aValue'];
253 
254  $this->assertSame($expected, $this->subject->addData($input));
255  }
256 
260  public function addDataKeepsIconFromItem()
261  {
262  $input = [
263  'databaseRow' => [
264  'aField' => 'aValue',
265  ],
266  'processedTca' => [
267  'columns' => [
268  'aField' => [
269  'config' => [
270  'type' => 'select',
271  'renderType' => 'selectSingle',
272  'items' => [
273  0 => [
274  0 => 'aLabel',
275  1 => 'aValue',
276  2 => 'an-icon-reference',
277  3 => null,
278  ],
279  ],
280  'maxitems' => 99999,
281  ],
282  ],
283  ],
284  ],
285  ];
286 
288  $languageService = $this->prophesize(LanguageService::class);
289  $GLOBALS['LANG'] = $languageService->reveal();
290  $languageService->sL(Argument::cetera())->willReturnArgument(0);
291 
292  $expected = $input;
293  $expected['databaseRow']['aField'] = ['aValue'];
294 
295  $this->assertSame($expected, $this->subject->addData($input));
296  }
297 
302  {
303  $input = [
304  'tableName' => 'aTable',
305  'processedTca' => [
306  'columns' => [
307  'aField' => [
308  'config' => [
309  'type' => 'select',
310  'renderType' => 'selectSingle',
311  'special' => 'anUnknownValue',
312  ],
313  ],
314  ],
315  ],
316  ];
317 
318  $this->expectException(\UnexpectedValueException::class);
319  $this->expectExceptionCode(1439298496);
320 
321  $this->subject->addData($input);
322  }
323 
327  public function addDataAddsTablesWithSpecialTables()
328  {
329  $input = [
330  'databaseRow' => [
331  'aField' => '',
332  ],
333  'tableName' => 'aTable',
334  'processedTca' => [
335  'columns' => [
336  'aField' => [
337  'config' => [
338  'type' => 'select',
339  'renderType' => 'selectSingle',
340  'special' => 'tables',
341  'maxitems' => 99999,
342  ],
343  ],
344  ],
345  ],
346  ];
347  $GLOBALS['TCA'] = [
348  'notInResult' => [
349  'ctrl' => [
350  'adminOnly' => true,
351  ],
352  ],
353  'aTable' => [
354  'ctrl' => [
355  'title' => 'aTitle',
356  ],
357  ],
358  ];
359  $GLOBALS['TCA_DESCR']['aTable']['columns']['']['description'] = 'aDescription';
360 
362  $languageService = $this->prophesize(LanguageService::class);
363  $GLOBALS['LANG'] = $languageService->reveal();
364  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
365  $languageService->sL(Argument::containingString('INVALID VALUE'))->willReturnArgument(0);
366 
367  $languageService->sL('aTitle')->shouldBeCalled()->willReturnArgument(0);
368  $languageService->loadSingleTableDescription('aTable')->shouldBeCalled();
369 
370  $expected = $input;
371  $expected['databaseRow']['aField'] = [];
372  $expected['processedTca']['columns']['aField']['config']['items'] = [
373  0 => [
374  0 => 'aTitle',
375  1 => 'aTable',
376  2 => 'default-not-found',
377  3 => [
378  'description' => 'aDescription',
379  ],
380  ]
381  ];
382 
383  $this->assertSame($expected, $this->subject->addData($input));
384  }
385 
389  public function addDataAddsTablesWithSpecialPageTypes()
390  {
391  $input = [
392  'databaseRow' => [
393  'aField' => 'aValue',
394  ],
395  'tableName' => 'aTable',
396  'processedTca' => [
397  'columns' => [
398  'aField' => [
399  'config' => [
400  'type' => 'select',
401  'renderType' => 'selectSingle',
402  'special' => 'pagetypes',
403  'items' => [],
404  'maxitems' => 99999,
405  ],
406  ],
407  ],
408  ],
409  ];
410  $GLOBALS['TCA'] = [
411  'pages' => [
412  'columns' => [
413  'doktype' => [
414  'config' => [
415  'items' => [
416  0 => [
417  0 => 'aLabel',
418  1 => 'aValue',
419  ],
420  ],
421  ],
422  ],
423  ],
424  ],
425  ];
426 
428  $languageService = $this->prophesize(LanguageService::class);
429  $GLOBALS['LANG'] = $languageService->reveal();
430  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
431 
432  $languageService->sL('aLabel')->shouldBeCalled()->willReturnArgument(0);
433 
434  $expected = $input;
435  $expected['databaseRow']['aField'] = ['aValue'];
436  $expected['processedTca']['columns']['aField']['config']['items'] = [
437  0 => [
438  0 => 'aLabel',
439  1 => 'aValue',
440  2 => 'default-not-found',
441  3 => null,
442  ]
443  ];
444 
445  $this->assertSame($expected, $this->subject->addData($input));
446  }
447 
452  {
453  return [
454  'Table with exclude and non exclude field returns exclude item' => [
455  [
456  // input tca
457  'fooTable' => [
458  'ctrl' => [
459  'title' => 'fooTableTitle',
460  ],
461  'columns' => [
462  'bar' => [
463  'label' => 'barColumnTitle',
464  'exclude' => 1
465  ],
466  'baz' => [
467  'label' => 'bazColumnTitle',
468  ],
469  ],
470  ],
471  ],
472  [
473  // expected items
474  0 => [
475  0 => 'fooTableTitle',
476  1 => '--div--',
477  2 => 'default-not-found',
478  3 => null,
479  ],
480  1 => [
481  0 => 'barColumnTitle (bar)',
482  1 => 'fooTable:bar',
483  2 => 'empty-empty',
484  3 => null,
485  ],
486  ],
487  ],
488  'Root level table with ignored root level restriction returns exclude item' => [
489  [
490  // input tca
491  'fooTable' => [
492  'ctrl' => [
493  'title' => 'fooTableTitle',
494  'rootLevel' => true,
495  'security' => [
496  'ignoreRootLevelRestriction' => true,
497  ],
498  ],
499  'columns' => [
500  'bar' => [
501  'label' => 'barColumnTitle',
502  'exclude' => true,
503  ],
504  ],
505  ],
506  ],
507  [
508  // expected items
509  0 => [
510  0 => 'fooTableTitle',
511  1 => '--div--',
512  2 => 'default-not-found',
513  3 => null,
514  ],
515  1 => [
516  0 => 'barColumnTitle (bar)',
517  1 => 'fooTable:bar',
518  2 => 'empty-empty',
519  3 => null,
520  ],
521  ],
522  ],
523  'Root level table without ignored root level restriction returns no item' => [
524  [
525  // input tca
526  'fooTable' => [
527  'ctrl' => [
528  'title' => 'fooTableTitle',
529  'rootLevel' => true,
530  ],
531  'columns' => [
532  'bar' => [
533  'label' => 'barColumnTitle',
534  'exclude' => true,
535  ],
536  ],
537  ],
538  ],
539  [
540  // no items
541  ],
542  ],
543  'Admin table returns no item' => [
544  [
545  // input tca
546  'fooTable' => [
547  'ctrl' => [
548  'title' => 'fooTableTitle',
549  'adminOnly' => true,
550  ],
551  'columns' => [
552  'bar' => [
553  'label' => 'barColumnTitle',
554  'exclude' => true,
555  ],
556  ],
557  ],
558  ],
559  [
560  // no items
561  ],
562  ],
563  ];
564  }
565 
570  public function addDataAddsExcludeFieldsWithSpecialExclude($tca, $expectedItems)
571  {
572  $input = [
573  'tableName' => 'aTable',
574  'databaseRow' => [],
575  'processedTca' => [
576  'columns' => [
577  'aField' => [
578  'config' => [
579  'type' => 'select',
580  'renderType' => 'selectSingle',
581  'special' => 'exclude',
582  ],
583  ],
584  ],
585  ],
586  ];
587  $GLOBALS['TCA'] = $tca;
588 
590  $languageService = $this->prophesize(LanguageService::class);
591  $GLOBALS['LANG'] = $languageService->reveal();
592  $languageService->loadSingleTableDescription(Argument::cetera())->willReturn(null);
593  $languageService->sL(Argument::cetera())->willReturnArgument(0);
594 
595  $result = $this->subject->addData($input);
596 
597  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
598  }
599 
603  public function addDataAddsExcludeFieldsFromFlexWithSpecialExclude()
604  {
605  $input = [
606  'tableName' => 'aTable',
607  'databaseRow' => [],
608  'processedTca' => [
609  'columns' => [
610  'aField' => [
611  'config' => [
612  'type' => 'select',
613  'renderType' => 'selectSingle',
614  'special' => 'exclude',
615  ],
616  ],
617  ],
618  ],
619  ];
620 
621  $GLOBALS['TCA'] = [
622  'fooTable' => [
623  'ctrl' => [
624  'title' => 'fooTableTitle',
625  ],
626  'columns' => [
627  'aFlexField' => [
628  'label' => 'aFlexFieldTitle',
629  'config' => [
630  'type' => 'flex',
631  'title' => 'title',
632  'ds' => [
633  'dummy' => '
634  <T3DataStructure>
635  <ROOT>
636  <type>array</type>
637  <el>
638  <input1>
639  <TCEforms>
640  <label>flexInputLabel</label>
641  <exclude>1</exclude>
642  <config>
643  <type>input</type>
644  <size>23</size>
645  </config>
646  </TCEforms>
647  </input1>
648  </el>
649  </ROOT>
650  </T3DataStructure>
651  ',
652  ],
653  ],
654  ],
655  ],
656  ],
657  ];
658 
660  $languageService = $this->prophesize(LanguageService::class);
661  $GLOBALS['LANG'] = $languageService->reveal();
662  $languageService->loadSingleTableDescription(Argument::cetera())->willReturn(null);
663  $languageService->sL(Argument::cetera())->willReturnArgument(0);
664 
665  $expectedItems = [
666  0 => [
667  0 => 'fooTableTitle aFlexFieldTitle dummy',
668  1 => '--div--',
669  2 => 'default-not-found',
670  3 => null,
671  ],
672  1 => [
673  0 => 'flexInputLabel (input1)',
674  1 => 'fooTable:aFlexField;dummy;sDEF;input1',
675  2 => 'empty-empty',
676  3 => null,
677  ],
678  ];
679 
680  $result = $this->subject->addData($input);
681 
682  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
683  }
684 
688  public function addDataAddsExplicitAllowFieldsWithSpecialExplicitValues()
689  {
690  $input = [
691  'tableName' => 'aTable',
692  'databaseRow' => [],
693  'processedTca' => [
694  'columns' => [
695  'aField' => [
696  'config' => [
697  'type' => 'select',
698  'renderType' => 'selectSingle',
699  'special' => 'explicitValues',
700  ],
701  ],
702  ],
703  ],
704  ];
705 
706  $GLOBALS['TCA'] = [
707  'fooTable' => [
708  'ctrl' => [
709  'title' => 'fooTableTitle',
710  ],
711  'columns' => [
712  'aField' => [
713  'label' => 'aFieldTitle',
714  'config' => [
715  'type' => 'select',
716  'renderType' => 'selectSingle',
717  'authMode' => 'explicitAllow',
718  'items' => [
719  0 => [
720  'anItemTitle',
721  'anItemValue',
722  ],
723  ]
724  ],
725  ],
726  ],
727  ],
728  ];
729 
731  $languageService = $this->prophesize(LanguageService::class);
732  $GLOBALS['LANG'] = $languageService->reveal();
733  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
734  $languageService->sL(Argument::cetera())->willReturnArgument(0);
735 
736  $expectedItems = [
737  0 => [
738  0 => 'fooTableTitle: aFieldTitle',
739  1 => '--div--',
740  2 => null,
741  3 => null,
742  ],
743  1 => [
744  0 => '[allowMe] anItemTitle',
745  1 => 'fooTable:aField:anItemValue:ALLOW',
746  2 => 'status-status-permission-granted',
747  3 => null,
748  ],
749  ];
750 
751  $result = $this->subject->addData($input);
752 
753  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
754  }
755 
759  public function addDataAddsExplicitDenyFieldsWithSpecialExplicitValues()
760  {
761  $input = [
762  'tableName' => 'aTable',
763  'databaseRow' => [],
764  'processedTca' => [
765  'columns' => [
766  'aField' => [
767  'config' => [
768  'type' => 'select',
769  'renderType' => 'selectSingle',
770  'special' => 'explicitValues',
771  ],
772  ],
773  ],
774  ],
775  ];
776 
777  $GLOBALS['TCA'] = [
778  'fooTable' => [
779  'ctrl' => [
780  'title' => 'fooTableTitle',
781  ],
782  'columns' => [
783  'aField' => [
784  'label' => 'aFieldTitle',
785  'config' => [
786  'type' => 'select',
787  'renderType' => 'selectSingle',
788  'authMode' => 'explicitDeny',
789  'items' => [
790  0 => [
791  'anItemTitle',
792  'anItemValue',
793  ],
794  ]
795  ],
796  ],
797  ],
798  ],
799  ];
800 
802  $languageService = $this->prophesize(LanguageService::class);
803  $GLOBALS['LANG'] = $languageService->reveal();
804  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
805  $languageService->sL(Argument::cetera())->willReturnArgument(0);
806 
807  $expectedItems = [
808  0 => [
809  0 => 'fooTableTitle: aFieldTitle',
810  1 => '--div--',
811  2 => null,
812  3 => null,
813  ],
814  1 => [
815  0 => '[denyMe] anItemTitle',
816  1 => 'fooTable:aField:anItemValue:DENY',
817  2 => 'status-status-permission-denied',
818  3 => null,
819  ],
820  ];
821 
822  $result = $this->subject->addData($input);
823 
824  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
825  }
826 
830  public function addDataAddsExplicitIndividualAllowFieldsWithSpecialExplicitValues()
831  {
832  $input = [
833  'tableName' => 'aTable',
834  'databaseRow' => [],
835  'processedTca' => [
836  'columns' => [
837  'aField' => [
838  'config' => [
839  'type' => 'select',
840  'renderType' => 'selectSingle',
841  'special' => 'explicitValues',
842  ],
843  ],
844  ],
845  ],
846  ];
847 
848  $GLOBALS['TCA'] = [
849  'fooTable' => [
850  'ctrl' => [
851  'title' => 'fooTableTitle',
852  ],
853  'columns' => [
854  'aField' => [
855  'label' => 'aFieldTitle',
856  'config' => [
857  'type' => 'select',
858  'renderType' => 'selectSingle',
859  'authMode' => 'individual',
860  'items' => [
861  0 => [
862  'aItemTitle',
863  'aItemValue',
864  null,
865  null,
866  'EXPL_ALLOW',
867  ],
868  // 1 is not selectable as allow and is always allowed
869  1 => [
870  'bItemTitle',
871  'bItemValue',
872  ],
873  2 => [
874  'cItemTitle',
875  'cItemValue',
876  null,
877  null,
878  'EXPL_ALLOW',
879  ],
880  ]
881  ],
882  ],
883  ],
884  ],
885  ];
886 
888  $languageService = $this->prophesize(LanguageService::class);
889  $GLOBALS['LANG'] = $languageService->reveal();
890  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.allow')->shouldBeCalled()->willReturn('allowMe');
891  $languageService->sL(Argument::cetera())->willReturnArgument(0);
892 
893  $expectedItems = [
894  0 => [
895  0 => 'fooTableTitle: aFieldTitle',
896  1 => '--div--',
897  2 => null,
898  3 => null,
899  ],
900  1 => [
901  0 => '[allowMe] aItemTitle',
902  1 => 'fooTable:aField:aItemValue:ALLOW',
903  2 => 'status-status-permission-granted',
904  3 => null,
905  ],
906  2 => [
907  0 => '[allowMe] cItemTitle',
908  1 => 'fooTable:aField:cItemValue:ALLOW',
909  2 => 'status-status-permission-granted',
910  3 => null,
911  ],
912  ];
913 
914  $result = $this->subject->addData($input);
915 
916  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
917  }
918 
922  public function addDataAddsExplicitIndividualDenyFieldsWithSpecialExplicitValues()
923  {
924  $input = [
925  'tableName' => 'aTable',
926  'databaseRow' => [],
927  'processedTca' => [
928  'columns' => [
929  'aField' => [
930  'config' => [
931  'type' => 'select',
932  'renderType' => 'selectSingle',
933  'special' => 'explicitValues',
934  ],
935  ],
936  ],
937  ],
938  ];
939 
940  $GLOBALS['TCA'] = [
941  'fooTable' => [
942  'ctrl' => [
943  'title' => 'fooTableTitle',
944  ],
945  'columns' => [
946  'aField' => [
947  'label' => 'aFieldTitle',
948  'config' => [
949  'type' => 'select',
950  'renderType' => 'selectSingle',
951  'authMode' => 'individual',
952  'items' => [
953  0 => [
954  'aItemTitle',
955  'aItemValue',
956  null,
957  null,
958  'EXPL_DENY',
959  ],
960  // 1 is not selectable as allow and is always allowed
961  1 => [
962  'bItemTitle',
963  'bItemValue',
964  ],
965  2 => [
966  'cItemTitle',
967  'cItemValue',
968  null,
969  null,
970  'EXPL_DENY',
971  ],
972  ]
973  ],
974  ],
975  ],
976  ],
977  ];
978 
980  $languageService = $this->prophesize(LanguageService::class);
981  $GLOBALS['LANG'] = $languageService->reveal();
982  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.deny')->shouldBeCalled()->willReturn('denyMe');
983  $languageService->sL(Argument::cetera())->willReturnArgument(0);
984 
985  $expectedItems = [
986  0 => [
987  0 => 'fooTableTitle: aFieldTitle',
988  1 => '--div--',
989  2 => null,
990  3 => null,
991  ],
992  1 => [
993  0 => '[denyMe] aItemTitle',
994  1 => 'fooTable:aField:aItemValue:DENY',
995  2 => 'status-status-permission-denied',
996  3 => null,
997  ],
998  2 => [
999  0 => '[denyMe] cItemTitle',
1000  1 => 'fooTable:aField:cItemValue:DENY',
1001  2 => 'status-status-permission-denied',
1002  3 => null,
1003  ],
1004  ];
1005 
1006  $result = $this->subject->addData($input);
1007 
1008  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1009  }
1010 
1014  public function addDataAddsLanguagesWithSpecialLanguages()
1015  {
1016  $input = [
1017  'tableName' => 'aTable',
1018  'databaseRow' => [],
1019  'processedTca' => [
1020  'columns' => [
1021  'aField' => [
1022  'config' => [
1023  'type' => 'select',
1024  'renderType' => 'selectSingle',
1025  'special' => 'languages',
1026  ],
1027  ],
1028  ],
1029  ],
1030  'systemLanguageRows' => [
1031  0 => [
1032  'title' => 'aLangTitle',
1033  'uid' => 42,
1034  'flagIconIdentifier' => 'aFlag.gif',
1035  ],
1036  ],
1037  ];
1038 
1040  $languageService = $this->prophesize(LanguageService::class);
1041  $GLOBALS['LANG'] = $languageService->reveal();
1042  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1043 
1044  $expectedItems = [
1045  0 => [
1046  0 => 'aLangTitle [42]',
1047  1 => 42,
1048  2 => 'aFlag.gif',
1049  3 => null,
1050  ],
1051  ];
1052 
1053  $result = $this->subject->addData($input);
1054 
1055  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1056  }
1057 
1061  public function addDataAddsCustomOptionsWithSpecialCustom()
1062  {
1063  $input = [
1064  'tableName' => 'aTable',
1065  'databaseRow' => [],
1066  'processedTca' => [
1067  'columns' => [
1068  'aField' => [
1069  'config' => [
1070  'type' => 'select',
1071  'renderType' => 'selectSingle',
1072  'special' => 'custom',
1073  ],
1074  ],
1075  ],
1076  ],
1077  ];
1078 
1080  $languageService = $this->prophesize(LanguageService::class);
1081  $GLOBALS['LANG'] = $languageService->reveal();
1082  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1083 
1084  $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'] = [
1085  'aKey' => [
1086  'header' => 'aHeader',
1087  'items' => [
1088  'anItemKey' => [
1089  0 => 'anItemTitle',
1090  ],
1091  'anotherKey' => [
1092  0 => 'anotherTitle',
1093  1 => 'status-status-permission-denied',
1094  2 => 'aDescription',
1095  ],
1096  ],
1097  ]
1098  ];
1099 
1100  $expectedItems = [
1101  0 => [
1102  0 => 'aHeader',
1103  1 => '--div--',
1104  null,
1105  null,
1106  ],
1107  1 => [
1108  0 => 'anItemTitle',
1109  1 => 'aKey:anItemKey',
1110  2 => 'empty-empty',
1111  3 => null,
1112  ],
1113  2 => [
1114  0 => 'anotherTitle',
1115  1 => 'aKey:anotherKey',
1116  2 => 'status-status-permission-denied',
1117  3 => [ 'description' => 'aDescription' ],
1118  ],
1119  ];
1120 
1121  $result = $this->subject->addData($input);
1122 
1123  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1124  }
1125 
1129  public function addDataAddsGroupItemsWithSpecialModListGroup()
1130  {
1131  $input = [
1132  'tableName' => 'aTable',
1133  'databaseRow' => [],
1134  'processedTca' => [
1135  'columns' => [
1136  'aField' => [
1137  'config' => [
1138  'type' => 'select',
1139  'renderType' => 'selectSingle',
1140  'special' => 'modListGroup',
1141  ],
1142  ],
1143  ],
1144  ],
1145  ];
1146 
1147  $GLOBALS['TBE_MODULES'] = [];
1148 
1150  $languageService = $this->prophesize(LanguageService::class);
1151  $GLOBALS['LANG'] = $languageService->reveal();
1152  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1153 
1155  $moduleLoaderProphecy = $this->prophesize(ModuleLoader::class);
1156  GeneralUtility::addInstance(ModuleLoader::class, $moduleLoaderProphecy->reveal());
1157  $moduleLoaderProphecy->load([])->shouldBeCalled();
1158  $moduleLoaderProphecy->modListGroup = [
1159  'aModule',
1160  ];
1161  $moduleLoaderProphecy->modules = [
1162  'aModule' => [
1163  'iconIdentifier' => 'empty-empty'
1164  ]
1165  ];
1166  $moduleLoaderProphecy->getLabelsForModule('aModule')->shouldBeCalled()->willReturn([
1167  'shortdescription' => 'aModuleTabLabel',
1168  'description' => 'aModuleTabDescription',
1169  'title' => 'aModuleLabel'
1170  ]);
1171 
1172  $expectedItems = [
1173  0 => [
1174  0 => 'aModuleLabel',
1175  1 => 'aModule',
1176  2 => 'empty-empty',
1177  3 => [
1178  'title' => 'aModuleTabLabel',
1179  'description' => 'aModuleTabDescription',
1180  ],
1181  ],
1182  ];
1183 
1184  $result = $this->subject->addData($input);
1185 
1186  $result['processedTca']['columns']['aField']['config']['items'][0][2] = str_replace([CR, LF, TAB], ['', '', ''], $result['processedTca']['columns']['aField']['config']['items'][0][2]);
1187  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1188  }
1189 
1193  public function addDataAddsFileItemsWithConfiguredFileFolder()
1194  {
1195  $directory = $this->getUniqueId('typo3temp/var/tests/test-') . '/';
1196  $input = [
1197  'tableName' => 'aTable',
1198  'databaseRow' => [],
1199  'processedTca' => [
1200  'columns' => [
1201  'aField' => [
1202  'config' => [
1203  'type' => 'select',
1204  'renderType' => 'selectSingle',
1205  'fileFolder' => $directory,
1206  'fileFolder_extList' => 'gif',
1207  'fileFolder_recursions' => 1,
1208  ],
1209  ],
1210  ],
1211  ],
1212  ];
1213 
1215  $languageService = $this->prophesize(LanguageService::class);
1216  $GLOBALS['LANG'] = $languageService->reveal();
1217  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1218 
1219  mkdir(PATH_site . $directory);
1220  $this->testFilesToDelete[] = PATH_site . $directory;
1221  touch(PATH_site . $directory . 'anImage.gif');
1222  touch(PATH_site . $directory . 'aFile.txt');
1223  mkdir(PATH_site . $directory . '/subdir');
1224  touch(PATH_site . $directory . '/subdir/anotherImage.gif');
1225 
1226  $expectedItems = [
1227  0 => [
1228  0 => 'anImage.gif',
1229  1 => 'anImage.gif',
1230  2 => PATH_site . $directory . 'anImage.gif',
1231  3 => null,
1232  ],
1233  1 => [
1234  0 => 'subdir/anotherImage.gif',
1235  1 => 'subdir/anotherImage.gif',
1236  2 => PATH_site . $directory . 'subdir/anotherImage.gif',
1237  3 => null,
1238  ],
1239  ];
1240 
1241  $result = $this->subject->addData($input);
1242 
1243  $this->assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
1244  }
1245 
1250  {
1251  $input = [
1252  'tableName' => 'aTable',
1253  'databaseRow' => [],
1254  'processedTca' => [
1255  'columns' => [
1256  'aField' => [
1257  'config' => [
1258  'type' => 'select',
1259  'renderType' => 'selectSingle',
1260  'fileFolder' => 'EXT:non_existing/Resources/Public/',
1261  ],
1262  ],
1263  ],
1264  ],
1265  ];
1266 
1267  $this->expectException(\RuntimeException::class);
1268  $this->expectExceptionCode(1479399227);
1269  $this->subject->addData($input);
1270  }
1271 
1275  public function addDataAddsItemsByAddItemsFromPageTsConfig()
1276  {
1277  $input = [
1278  'databaseRow' => [
1279  'aField' => '',
1280  ],
1281  'tableName' => 'aTable',
1282  'processedTca' => [
1283  'columns' => [
1284  'aField' => [
1285  'config' => [
1286  'type' => 'select',
1287  'renderType' => 'selectSingle',
1288  'items' => [
1289  0 => [
1290  0 => 'keepMe',
1291  1 => 'keep',
1292  null,
1293  null,
1294  ],
1295  ],
1296  'maxitems' => 99999,
1297  ],
1298  ],
1299  ]
1300  ],
1301  'pageTsConfig' => [
1302  'TCEFORM.' => [
1303  'aTable.' => [
1304  'aField.' => [
1305  'addItems.' => [
1306  '1' => 'addMe'
1307  ],
1308  ],
1309  ],
1310  ],
1311  ],
1312  ];
1313 
1315  $languageService = $this->prophesize(LanguageService::class);
1316  $GLOBALS['LANG'] = $languageService->reveal();
1317  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1318 
1319  $expected = $input;
1320  $expected['databaseRow']['aField'] = [];
1321  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1322  0 => 'addMe',
1323  1 => '1',
1324  null,
1325  null,
1326  ];
1327 
1328  $this->assertEquals($expected, $this->subject->addData($input));
1329  }
1330 
1334  public function addDataAddsItemsByAddItemsWithDuplicateValuesFromPageTsConfig()
1335  {
1336  $input = [
1337  'databaseRow' => [
1338  'aField' => '',
1339  ],
1340  'tableName' => 'aTable',
1341  'processedTca' => [
1342  'columns' => [
1343  'aField' => [
1344  'config' => [
1345  'type' => 'select',
1346  'renderType' => 'selectSingle',
1347  'items' => [
1348  0 => [
1349  0 => 'keepMe',
1350  1 => 'keep',
1351  null,
1352  null,
1353  ],
1354  ],
1355  'maxitems' => 99999,
1356  ],
1357  ],
1358  ]
1359  ],
1360  'pageTsConfig' => [
1361  'TCEFORM.' => [
1362  'aTable.' => [
1363  'aField.' => [
1364  'addItems.' => [
1365  'keep' => 'addMe'
1366  ],
1367  ],
1368  ],
1369  ],
1370  ],
1371  ];
1372 
1374  $languageService = $this->prophesize(LanguageService::class);
1375  $GLOBALS['LANG'] = $languageService->reveal();
1376  $languageService->sL(Argument::cetera())->willReturnArgument(0);
1377 
1378  $expected = $input;
1379  $expected['databaseRow']['aField'] = [];
1380  $expected['processedTca']['columns']['aField']['config']['items'][1] = [
1381  0 => 'addMe',
1382  1 => 'keep',
1383  null,
1384  null,
1385  ];
1386 
1387  $this->assertEquals($expected, $this->subject->addData($input));
1388  }
1389 
1394  {
1395  return [
1396  'replace REC_FIELD' => [
1397  'AND fTable.title=\'###REC_FIELD_rowField###\'',
1398  [
1399  ['fTable.title=\'rowFieldValue\''],
1400  [' 1=1'],
1401  ['`pages.uid` = `fTable.pid`']
1402  ],
1403  [],
1404  ],
1405  'replace REC_FIELD within FlexForm' => [
1406  'AND fTable.title=###REC_FIELD_rowFieldFlexForm###',
1407  [
1408  ['fTable.title=\'rowFieldFlexFormValue\''],
1409  [' 1=1'],
1410  ['`pages.uid` = `fTable.pid`']
1411  ],
1412  [
1413  'databaseRow' => [
1414  'rowFieldThree' => [
1415  0 => 'rowFieldThreeValue'
1416  ]
1417  ],
1418  'flexParentDatabaseRow' => [
1419  'rowFieldFlexForm' => [
1420  0 => 'rowFieldFlexFormValue'
1421  ]
1422  ],
1423  ],
1424  ],
1425  'replace REC_FIELD fullQuote' => [
1426  'AND fTable.title=###REC_FIELD_rowField###',
1427  [
1428  ['fTable.title=\'rowFieldValue\''],
1429  [' 1=1'],
1430  ['`pages.uid` = `fTable.pid`']
1431  ],
1432  [],
1433  ],
1434  'replace REC_FIELD fullQuoteWithArray' => [
1435  'AND fTable.title=###REC_FIELD_rowFieldThree###',
1436  [
1437  ['fTable.title=\'rowFieldThreeValue\''],
1438  [' 1=1'],
1439  ['`pages.uid` = `fTable.pid`']
1440  ],
1441  [
1442  'databaseRow' => [
1443  'rowFieldThree' => [
1444  0 => 'rowFieldThreeValue'
1445  ]
1446  ],
1447  ],
1448  ],
1449  'replace REC_FIELD multiple markers' => [
1450  'AND fTable.title=\'###REC_FIELD_rowField###\' AND fTable.pid=###REC_FIELD_rowFieldTwo###',
1451  [
1452  ['fTable.title=\'rowFieldValue\' AND fTable.pid=\'rowFieldTwoValue\''],
1453  [' 1=1'],
1454  ['`pages.uid` = `fTable.pid`']
1455  ],
1456  [],
1457  ],
1458  'replace CURRENT_PID' => [
1459  'AND fTable.uid=###CURRENT_PID###',
1460  [
1461  ['fTable.uid=43'],
1462  [' 1=1'],
1463  ['`pages.uid` = `fTable.pid`']
1464  ],
1465  [],
1466  ],
1467  'replace CURRENT_PID within FlexForm' => [
1468  'AND fTable.uid=###CURRENT_PID###',
1469  [
1470  ['fTable.uid=77'],
1471  [' 1=1'],
1472  ['`pages.uid` = `fTable.pid`']
1473  ],
1474  [
1475  'flexParentDatabaseRow' => [
1476  'pid' => '77',
1477  ],
1478  ],
1479  ],
1480  'replace CURRENT_PID integer cast' => [
1481  'AND fTable.uid=###CURRENT_PID###',
1482  [
1483  ['fTable.uid=431'],
1484  [' 1=1'],
1485  ['`pages.uid` = `fTable.pid`']
1486  ],
1487  [
1488  'effectivePid' => '431string',
1489  ],
1490  ],
1491  'replace THIS_UID' => [
1492  'AND fTable.uid=###THIS_UID###',
1493  [
1494  ['fTable.uid=42'],
1495  [' 1=1'],
1496  ['`pages.uid` = `fTable.pid`']
1497  ],
1498  [],
1499  ],
1500  'replace THIS_UID integer cast' => [
1501  'AND fTable.uid=###THIS_UID###',
1502  [
1503  ['fTable.uid=421'],
1504  [' 1=1'],
1505  ['`pages.uid` = `fTable.pid`']
1506  ],
1507  [
1508  'databaseRow' => [
1509  'uid' => '421string',
1510  ],
1511  ],
1512  ],
1513  'replace SITEROOT' => [
1514  'AND fTable.uid=###SITEROOT###',
1515  [
1516  ['fTable.uid=44'],
1517  [' 1=1'],
1518  ['`pages.uid` = `fTable.pid`']
1519  ],
1520  [],
1521  ],
1522  'replace SITEROOT integer cast' => [
1523  'AND fTable.uid=###SITEROOT###',
1524  [
1525  ['fTable.uid=441'],
1526  [' 1=1'],
1527  ['`pages.uid` = `fTable.pid`']
1528  ],
1529  [
1530  'rootline' => [
1531  1 => [
1532  'uid' => '441string',
1533  ],
1534  ],
1535  ],
1536  ],
1537  'replace PAGE_TSCONFIG_ID' => [
1538  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1539  [
1540  ['fTable.uid=45'],
1541  [' 1=1'],
1542  ['`pages.uid` = `fTable.pid`']
1543  ],
1544  [
1545  'pageTsConfig' => [
1546  'TCEFORM.' => [
1547  'aTable.' => [
1548  'aField.' => [
1549  'PAGE_TSCONFIG_ID' => '45',
1550  ],
1551  ],
1552  ],
1553  ],
1554  ],
1555  ],
1556  'replace PAGE_TSCONFIG_ID integer cast' => [
1557  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1558  [
1559  ['fTable.uid=451'],
1560  [' 1=1'],
1561  ['`pages.uid` = `fTable.pid`']
1562  ],
1563  [
1564  'pageTsConfig' => [
1565  'TCEFORM.' => [
1566  'aTable.' => [
1567  'aField.' => [
1568  'PAGE_TSCONFIG_ID' => '451string'
1569  ],
1570  ],
1571  ],
1572  ],
1573  ],
1574  ],
1575  'replace PAGE_TSCONFIG_STR' => [
1576  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1577  [
1578  ['fTable.uid=\'46\''],
1579  [' 1=1'],
1580  ['`pages.uid` = `fTable.pid`']
1581  ],
1582  [
1583  'pageTsConfig' => [
1584  'TCEFORM.' => [
1585  'aTable.' => [
1586  'aField.' => [
1587  'PAGE_TSCONFIG_STR' => '46',
1588  ],
1589  ],
1590  ],
1591  ],
1592  ],
1593  ],
1594  'replace PAGE_TSCONFIG_IDLIST' => [
1595  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1596  [
1597  ['fTable.uid IN (47,48)'],
1598  [' 1=1'],
1599  ['`pages.uid` = `fTable.pid`']
1600  ],
1601  [
1602  'pageTsConfig' => [
1603  'TCEFORM.' => [
1604  'aTable.' => [
1605  'aField.' => [
1606  'PAGE_TSCONFIG_IDLIST' => '47,48',
1607  ],
1608  ],
1609  ],
1610  ],
1611  ],
1612  ],
1613  'replace PAGE_TSCONFIG_IDLIST cleans list' => [
1614  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1615  [
1616  ['fTable.uid IN (471,481)'],
1617  [' 1=1'],
1618  ['`pages.uid` = `fTable.pid`']
1619  ],
1620  [
1621  'pageTsConfig' => [
1622  'TCEFORM.' => [
1623  'aTable.' => [
1624  'aField.' => [
1625  'PAGE_TSCONFIG_IDLIST' => 'a, 471, b, 481, c',
1626  ],
1627  ],
1628  ],
1629  ],
1630  ],
1631  ],
1632  'deprecated flexHack PAGE_TSCONFIG_ID is substituted' => [
1633  'AND fTable.uid=###PAGE_TSCONFIG_ID###',
1634  [
1635  ['fTable.uid=123'],
1636  [' 1=1'],
1637  ['`pages.uid` = `fTable.pid`']
1638  ],
1639  [
1640  'pageTsConfig' => [
1641  'flexHack.' => [
1642  'PAGE_TSCONFIG_ID' => '123',
1643  ],
1644  ],
1645  ],
1646  ],
1647  'deprecated flexHack PAGE_TSCONFIG_IDLIST is substituted' => [
1648  'AND fTable.uid IN (###PAGE_TSCONFIG_IDLIST###)',
1649  [
1650  ['fTable.uid IN (123,124)'],
1651  [' 1=1'],
1652  ['`pages.uid` = `fTable.pid`']
1653  ],
1654  [
1655  'pageTsConfig' => [
1656  'flexHack.' => [
1657  'PAGE_TSCONFIG_IDLIST' => '123,124',
1658  ],
1659  ],
1660  ],
1661  ],
1662  'deprecated flexHack PAGE_TSCONFIG_STR is substituted' => [
1663  'AND fTable.uid=\'###PAGE_TSCONFIG_STR###\'',
1664  [
1665  ['fTable.uid=\'aString\''],
1666  [' 1=1'],
1667  ['`pages.uid` = `fTable.pid`']
1668  ],
1669  [
1670  'pageTsConfig' => [
1671  'flexHack.' => [
1672  'PAGE_TSCONFIG_STR' => 'aString',
1673  ],
1674  ],
1675  ],
1676  ],
1677  ];
1678  }
1679 
1684  public function addDataReplacesMarkersInForeignTableClause($foreignTableWhere, $expectedWhere, array $inputOverride)
1685  {
1686  $input = [
1687  'tableName' => 'aTable',
1688  'effectivePid' => 43,
1689  'databaseRow' => [
1690  'uid' => 42,
1691  'rowField' => 'rowFieldValue',
1692  'rowFieldTwo' => 'rowFieldTwoValue',
1693  ],
1694  'processedTca' => [
1695  'columns' => [
1696  'aField' => [
1697  'config' => [
1698  'type' => 'select',
1699  'renderType' => 'selectSingle',
1700  'foreign_table' => 'fTable',
1701  'foreign_table_where' => $foreignTableWhere,
1702  ],
1703  ],
1704  ]
1705  ],
1706  'rootline' => [
1707  2 => [
1708  'uid' => 999,
1709  'is_siteroot' => 0,
1710  ],
1711  1 => [
1712  'uid' => 44,
1713  'is_siteroot' => 1,
1714  ],
1715  0 => [
1716  'uid' => 0,
1717  'is_siteroot' => null,
1718  ],
1719  ],
1720  'pageTsConfig' => [],
1721  ];
1722  ArrayUtility::mergeRecursiveWithOverrule($input, $inputOverride);
1723 
1724  $GLOBALS['TCA']['fTable'] = [];
1725 
1726  list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection();
1727 
1729  $statementProphet = $this->prophesize(Statement::class);
1730 
1731  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1732  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1733  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1734  $queryBuilderProphet->where(...array_shift($expectedWhere))->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1735  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
1736 
1737  while ($constraint = array_shift($expectedWhere)) {
1738  $queryBuilderProphet->andWhere(...$constraint)
1739  ->shouldBeCalled()
1740  ->willReturn($queryBuilderProphet->reveal());
1741  }
1742 
1743  // Two instances are needed due to the push/pop behavior of addInstance()
1744  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1745  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1746 
1748  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1749  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1750  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1751 
1752  $this->subject->addData($input);
1753  }
1754 
1759  {
1760  $input = [
1761  'tableName' => 'aTable',
1762  'processedTca' => [
1763  'columns' => [
1764  'aField' => [
1765  'config' => [
1766  'type' => 'select',
1767  'renderType' => 'selectSingle',
1768  'foreign_table' => 'fTable',
1769  ],
1770  ],
1771  ]
1772  ],
1773  ];
1774 
1775  $this->expectException(\UnexpectedValueException::class);
1776  $this->expectExceptionCode(1439569743);
1777 
1778  $this->subject->addData($input);
1779  }
1780 
1784  public function addDataForeignTableSplitsGroupOrderAndLimit()
1785  {
1786  $input = [
1787  'tableName' => 'aTable',
1788  'databaseRow' => [],
1789  'processedTca' => [
1790  'columns' => [
1791  'aField' => [
1792  'config' => [
1793  'type' => 'select',
1794  'renderType' => 'selectSingle',
1795  'foreign_table' => 'fTable',
1796  'foreign_table_where' => '
1797  AND ftable.uid=1
1798  GROUP BY groupField1, groupField2
1799  ORDER BY orderField
1800  LIMIT 1,2',
1801  ],
1802  ],
1803  ]
1804  ],
1805  'rootline' => [],
1806  ];
1807 
1808  $GLOBALS['TCA']['fTable'] = [];
1809 
1811  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1812  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1813  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1814 
1815  list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection();
1816 
1818  $statementProphet = $this->prophesize(Statement::class);
1819 
1820  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1821  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1822  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1823  $queryBuilderProphet->groupBy('groupField1', 'groupField2')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1824  $queryBuilderProphet->addOrderBy('orderField', null)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1825  $queryBuilderProphet->setFirstResult(1)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1826  $queryBuilderProphet->setMaxResults(2)->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1827  $queryBuilderProphet->where('ftable.uid=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1828  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1829  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1830  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
1831 
1832  // Two instances are needed due to the push/pop behavior of addInstance()
1833  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1834  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1835 
1836  $this->subject->addData($input);
1837  }
1838 
1842  public function addDataForeignTableQueuesFlashMessageOnDatabaseError()
1843  {
1844  $input = [
1845  'databaseRow' => [
1846  'aField' => '',
1847  ],
1848  'tableName' => 'aTable',
1849  'processedTca' => [
1850  'columns' => [
1851  'aField' => [
1852  'config' => [
1853  'type' => 'select',
1854  'renderType' => 'selectSingle',
1855  'foreign_table' => 'fTable',
1856  'items' => [
1857  0 => [
1858  0 => 'itemLabel',
1859  1 => 'itemValue',
1860  2 => null,
1861  3 => null,
1862  ],
1863  ],
1864  'maxitems' => 99999,
1865  ],
1866  ],
1867  ]
1868  ],
1869  'rootline' => [],
1870  ];
1871 
1872  $GLOBALS['TCA']['fTable'] = [];
1873 
1875  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1876  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1877  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1878 
1880  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1881  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1882  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1883 
1884  list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection();
1885 
1887  $statementProphet = $this->prophesize(Statement::class);
1888 
1889  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1890  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1891  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1892  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1893  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1894  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1895 
1896  $prevException = new DBALException('Invalid table name', 1476045274);
1897  $exception = new DBALException('Driver error', 1476045971, $prevException);
1898 
1899  $queryBuilderProphet->execute()->shouldBeCalled()->willThrow($exception);
1900 
1901  // Two instances are needed due to the push/pop behavior of addInstance()
1902  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1903  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1904 
1906  $flashMessage = $this->prophesize(FlashMessage::class);
1907  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
1909  $flashMessageService = $this->prophesize(FlashMessageService::class);
1910  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
1912  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
1913  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
1914 
1915  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
1916 
1917  $expected = $input;
1918  $expected['databaseRow']['aField'] = [];
1919 
1920  $this->assertEquals($expected, $this->subject->addData($input));
1921  }
1922 
1926  public function addDataForeignTableHandlesForeignTableRows()
1927  {
1928  $input = [
1929  'databaseRow' => [
1930  'aField' => '',
1931  ],
1932  'tableName' => 'aTable',
1933  'processedTca' => [
1934  'columns' => [
1935  'aField' => [
1936  'config' => [
1937  'type' => 'select',
1938  'renderType' => 'selectSingle',
1939  'foreign_table' => 'fTable',
1940  'foreign_table_prefix' => 'aPrefix',
1941  'items' => [],
1942  'maxitems' => 99999,
1943  ],
1944  ],
1945  ]
1946  ],
1947  'rootline' => [],
1948  ];
1949 
1950  $GLOBALS['TCA']['fTable'] = [];
1951 
1953  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
1954  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
1955  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
1956 
1958  $languageServiceProphecy = $this->prophesize(LanguageService::class);
1959  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
1960  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
1961 
1962  list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection();
1963 
1965  $statementProphet = $this->prophesize(Statement::class);
1966 
1967  $queryBuilderProphet->select('fTable.uid')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1968  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1969  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1970  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1971  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1972  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
1973  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
1974 
1975  // Two instances are needed due to the push/pop behavior of addInstance()
1976  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1977  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
1978 
1979  $counter = 0;
1980  $statementProphet->fetch()->shouldBeCalled()->will(function ($args) use (&$counter) {
1981  $counter++;
1982  if ($counter >= 3) {
1983  return false;
1984  }
1985  return [
1986  'uid' => $counter,
1987  'aValue' => 'bar,',
1988  ];
1989  });
1990 
1991  $expected = $input;
1992  $expected['processedTca']['columns']['aField']['config']['items'] = [
1993  0 => [
1994  0 => 'aPrefix[LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
1995  1 => 1,
1996  2 => 'default-not-found',
1997  3 => null,
1998  ],
1999  1 => [
2000  0 => 'aPrefix[LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.no_title]',
2001  1 => 2,
2002  2 => 'default-not-found',
2003  3 => null,
2004  ],
2005  ];
2006 
2007  $expected['databaseRow']['aField'] = [];
2008 
2009  $this->assertEquals($expected, $this->subject->addData($input));
2010  }
2011 
2015  public function addDataForeignTableResolvesIconFromSelicon()
2016  {
2017  $input = [
2018  'databaseRow' => [
2019  'aField' => '',
2020  ],
2021  'tableName' => 'aTable',
2022  'processedTca' => [
2023  'columns' => [
2024  'aField' => [
2025  'config' => [
2026  'type' => 'select',
2027  'renderType' => 'selectSingle',
2028  'foreign_table' => 'fTable',
2029  'maxitems' => 99999,
2030  ],
2031  ],
2032  ]
2033  ],
2034  'rootline' => [],
2035  ];
2036 
2037  // Fake the foreign_table
2038  $GLOBALS['TCA']['fTable'] = [
2039  'ctrl' => [
2040  'label' => 'icon',
2041  'selicon_field' => 'icon',
2042  'selicon_field_path' => 'uploads/media',
2043  ],
2044  'columns' =>[
2045  'icon' => [],
2046  ],
2047  ];
2048 
2050  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2051  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2052  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2053 
2055  $languageServiceProphecy = $this->prophesize(LanguageService::class);
2056  $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
2057  $languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
2058 
2059  list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection();
2060 
2062  $statementProphet = $this->prophesize(Statement::class);
2063 
2064  $queryBuilderProphet->select('fTable.uid', 'fTable.icon')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2065  $queryBuilderProphet->from('fTable')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2066  $queryBuilderProphet->from('pages')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2067  $queryBuilderProphet->where('')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2068  $queryBuilderProphet->andWhere(' 1=1')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2069  $queryBuilderProphet->andWhere('`pages.uid` = `fTable.pid`')->shouldBeCalled()->willReturn($queryBuilderProphet->reveal());
2070  $queryBuilderProphet->execute()->shouldBeCalled()->willReturn($statementProphet->reveal());
2071 
2072  // Two instances are needed due to the push/pop behavior of addInstance()
2073  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2074  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
2075 
2076  // Query returns one row, then false on second call
2077  $foreignTableRowResultOne = [
2078  'uid' => 1,
2079  'icon' => 'foo.jpg',
2080  ];
2081  $statementProphet->fetch()->shouldBeCalled()->willReturn($foreignTableRowResultOne, false);
2082 
2083  $expected = $input;
2084  $expected['processedTca']['columns']['aField']['config']['items'] = [
2085  0 => [
2086  0 => 'foo.jpg',
2087  1 => 1,
2088  2 => 'uploads/media/foo.jpg', // combination of selicon_field_path and the row value of field 'icon'
2089  3 => null,
2090  ],
2091  ];
2092  $expected['databaseRow']['aField'] = [];
2093 
2094  $this->assertEquals($expected, $this->subject->addData($input));
2095  }
2096 
2100  public function addDataRemovesItemsByKeepItemsPageTsConfig()
2101  {
2102  $input = [
2103  'databaseRow' => [
2104  'aField' => '',
2105  ],
2106  'tableName' => 'aTable',
2107  'processedTca' => [
2108  'columns' => [
2109  'aField' => [
2110  'config' => [
2111  'type' => 'select',
2112  'renderType' => 'selectSingle',
2113  'items' => [
2114  0 => [
2115  0 => 'keepMe',
2116  1 => 'keep',
2117  null,
2118  null,
2119  ],
2120  1 => [
2121  0 => 'removeMe',
2122  1 => 'remove',
2123  ],
2124  2 => [
2125  0 => 'removeMe',
2126  1 => 0,
2127  ],
2128  ],
2129  'maxitems' => 99999,
2130  ],
2131  ],
2132  ]
2133  ],
2134  'pageTsConfig' => [
2135  'TCEFORM.' => [
2136  'aTable.' => [
2137  'aField.' => [
2138  'keepItems' => 'keep',
2139  ],
2140  ],
2141  ],
2142  ],
2143  ];
2144 
2146  $languageService = $this->prophesize(LanguageService::class);
2147  $GLOBALS['LANG'] = $languageService->reveal();
2148  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2149 
2150  $expected = $input;
2151  $expected['databaseRow']['aField'] = [];
2152  unset(
2153  $expected['processedTca']['columns']['aField']['config']['items'][1],
2154  $expected['processedTca']['columns']['aField']['config']['items'][2]
2155  );
2156 
2157  $this->assertEquals($expected, $this->subject->addData($input));
2158  }
2159 
2163  public function addDataRemovesAllItemsByEmptyKeepItemsPageTsConfig()
2164  {
2165  $input = [
2166  'databaseRow' => [
2167  'aField' => '',
2168  ],
2169  'tableName' => 'aTable',
2170  'processedTca' => [
2171  'columns' => [
2172  'aField' => [
2173  'config' => [
2174  'type' => 'select',
2175  'renderType' => 'selectSingle',
2176  'items' => [
2177  0 => [
2178  0 => 'keepMe',
2179  1 => 'keep',
2180  null,
2181  null,
2182  ],
2183  1 => [
2184  0 => 'removeMe',
2185  1 => 'remove',
2186  ],
2187  ],
2188  'maxitems' => 99999,
2189  ],
2190  ],
2191  ]
2192  ],
2193  'pageTsConfig' => [
2194  'TCEFORM.' => [
2195  'aTable.' => [
2196  'aField.' => [
2197  'keepItems' => '',
2198  ],
2199  ],
2200  ],
2201  ],
2202  ];
2203 
2205  $languageService = $this->prophesize(LanguageService::class);
2206  $GLOBALS['LANG'] = $languageService->reveal();
2207  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2208 
2209  $expected = $input;
2210  $expected['databaseRow']['aField'] = [];
2211  $expected['processedTca']['columns']['aField']['config']['items'] = [];
2212 
2213  $this->assertEquals($expected, $this->subject->addData($input));
2214  }
2215 
2219  public function addDataEvaluatesKeepItemsBeforeAddItemsFromPageTsConfig()
2220  {
2221  $input = [
2222  'databaseRow' => [
2223  'aField' => '',
2224  ],
2225  'tableName' => 'aTable',
2226  'processedTca' => [
2227  'columns' => [
2228  'aField' => [
2229  'config' => [
2230  'type' => 'select',
2231  'renderType' => 'selectSingle',
2232  'items' => [
2233  0 => [
2234  0 => 'keepMe',
2235  1 => '1',
2236  null,
2237  null,
2238  ],
2239  1 => [
2240  0 => 'removeMe',
2241  1 => 'remove',
2242  ],
2243  ],
2244  'maxitems' => 99999,
2245  ],
2246  ],
2247  ]
2248  ],
2249  'pageTsConfig' => [
2250  'TCEFORM.' => [
2251  'aTable.' => [
2252  'aField.' => [
2253  'keepItems' => '1',
2254  'addItems.' => [
2255  '1' => 'addItem #1',
2256  '12' => 'addItem #12',
2257  ],
2258  ],
2259  ],
2260  ],
2261  ],
2262  ];
2263 
2265  $languageService = $this->prophesize(LanguageService::class);
2266  $GLOBALS['LANG'] = $languageService->reveal();
2267  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2268 
2269  $expected = $input;
2270  $expected['databaseRow']['aField'] = [];
2271  $expected['processedTca']['columns']['aField']['config']['items'] = [
2272  0 => [
2273  0 => 'keepMe',
2274  1 => '1',
2275  null,
2276  null,
2277  ],
2278  1 => [
2279  0 => 'addItem #1',
2280  1 => '1',
2281  null,
2282  null,
2283  ],
2284  2 => [
2285  0 => 'addItem #12',
2286  1 => '12',
2287  null,
2288  null,
2289  ],
2290  ];
2291 
2292  $this->assertEquals($expected, $this->subject->addData($input));
2293  }
2294 
2298  public function addDataRemovesItemsByRemoveItemsPageTsConfig()
2299  {
2300  $input = [
2301  'databaseRow' => [
2302  'aField' => ''
2303  ],
2304  'tableName' => 'aTable',
2305  'processedTca' => [
2306  'columns' => [
2307  'aField' => [
2308  'config' => [
2309  'type' => 'select',
2310  'renderType' => 'selectSingle',
2311  'items' => [
2312  0 => [
2313  0 => 'keepMe',
2314  1 => 'keep',
2315  null,
2316  null,
2317  ],
2318  1 => [
2319  0 => 'removeMe',
2320  1 => 'remove',
2321  ],
2322  2 => [
2323  0 => 'keep me',
2324  1 => 0,
2325  null,
2326  null,
2327  ],
2328  ],
2329  'maxitems' => 99999,
2330  ],
2331  ],
2332  ]
2333  ],
2334  'pageTsConfig' => [
2335  'TCEFORM.' => [
2336  'aTable.' => [
2337  'aField.' => [
2338  'removeItems' => 'remove',
2339  ],
2340  ],
2341  ],
2342  ],
2343  ];
2344 
2346  $languageService = $this->prophesize(LanguageService::class);
2347  $GLOBALS['LANG'] = $languageService->reveal();
2348  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2349 
2350  $expected = $input;
2351  $expected['databaseRow']['aField'] = [];
2352  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2353  $expected['processedTca']['columns']['aField']['config']['items'] = array_values($expected['processedTca']['columns']['aField']['config']['items']);
2354  $this->assertEquals($expected, $this->subject->addData($input));
2355  }
2356 
2360  public function addDataRemovesItemsByZeroValueRemoveItemsPageTsConfig()
2361  {
2362  $input = [
2363  'databaseRow' => [
2364  'aField' => ''
2365  ],
2366  'tableName' => 'aTable',
2367  'processedTca' => [
2368  'columns' => [
2369  'aField' => [
2370  'config' => [
2371  'type' => 'select',
2372  'renderType' => 'selectSingle',
2373  'items' => [
2374  0 => [
2375  0 => 'keepMe',
2376  1 => 'keep',
2377  null,
2378  null,
2379  ],
2380  1 => [
2381  0 => 'keepMe',
2382  1 => 'keepMe2',
2383  null,
2384  null,
2385  ],
2386  2 => [
2387  0 => 'remove me',
2388  1 => 0,
2389  ],
2390  ],
2391  'maxitems' => 99999,
2392  ],
2393  ],
2394  ]
2395  ],
2396  'pageTsConfig' => [
2397  'TCEFORM.' => [
2398  'aTable.' => [
2399  'aField.' => [
2400  'removeItems' => '0',
2401  ],
2402  ],
2403  ],
2404  ],
2405  ];
2406 
2408  $languageService = $this->prophesize(LanguageService::class);
2409  $GLOBALS['LANG'] = $languageService->reveal();
2410  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2411 
2412  $expected = $input;
2413  $expected['databaseRow']['aField'] = [];
2414  unset($expected['processedTca']['columns']['aField']['config']['items'][2]);
2415  $this->assertEquals($expected, $this->subject->addData($input));
2416  }
2417 
2421  public function addDataRemovesItemsAddedByAddItemsFromPageTsConfigByRemoveItemsPageTsConfig()
2422  {
2423  $input = [
2424  'databaseRow' => [
2425  'aField' => ''
2426  ],
2427  'tableName' => 'aTable',
2428  'processedTca' => [
2429  'columns' => [
2430  'aField' => [
2431  'config' => [
2432  'type' => 'select',
2433  'renderType' => 'selectSingle',
2434  'items' => [
2435  0 => [
2436  0 => 'keepMe',
2437  1 => 'keep',
2438  null,
2439  null,
2440  ],
2441  1 => [
2442  0 => 'removeMe',
2443  1 => 'remove',
2444  ],
2445  ],
2446  'maxitems' => 99999,
2447  ],
2448  ],
2449  ]
2450  ],
2451  'pageTsConfig' => [
2452  'TCEFORM.' => [
2453  'aTable.' => [
2454  'aField.' => [
2455  'removeItems' => 'remove,add',
2456  'addItems.' => [
2457  'add' => 'addMe'
2458  ]
2459  ],
2460  ],
2461  ],
2462  ],
2463  ];
2464 
2466  $languageService = $this->prophesize(LanguageService::class);
2467  $GLOBALS['LANG'] = $languageService->reveal();
2468  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2469 
2470  $expected = $input;
2471  $expected['databaseRow']['aField'] = [];
2472  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2473 
2474  $this->assertEquals($expected, $this->subject->addData($input));
2475  }
2476 
2480  public function addDataRemovesItemsByLanguageFieldUserRestriction()
2481  {
2482  $input = [
2483  'databaseRow' => [
2484  'aField' => 'aValue,remove'
2485  ],
2486  'tableName' => 'aTable',
2487  'processedTca' => [
2488  'ctrl' => [
2489  'languageField' => 'aField',
2490  ],
2491  'columns' => [
2492  'aField' => [
2493  'config' => [
2494  'type' => 'select',
2495  'renderType' => 'selectSingle',
2496  'items' => [
2497  0 => [
2498  0 => 'keepMe',
2499  1 => 'keep',
2500  null,
2501  null,
2502  ],
2503  1 => [
2504  0 => 'removeMe',
2505  1 => 'remove',
2506  ],
2507  ],
2508  'maxitems' => 99999,
2509  ],
2510  ],
2511  ]
2512  ],
2513  ];
2514 
2516  $languageService = $this->prophesize(LanguageService::class);
2517  $GLOBALS['LANG'] = $languageService->reveal();
2518  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2519  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2520 
2522  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2523  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2524  $backendUserProphecy->checkLanguageAccess('keep')->shouldBeCalled()->willReturn(true);
2525  $backendUserProphecy->checkLanguageAccess('remove')->shouldBeCalled()->willReturn(false);
2526 
2527  $expected = $input;
2528  $expected['databaseRow']['aField'] = [];
2529  $expected['processedTca']['columns']['aField']['config']['items'] = [
2530  [ '[ INVALID VALUE "aValue" ]', 'aValue', null, null ],
2531  [ 'keepMe', 'keep', null, null ],
2532  ];
2533 
2534  $this->assertEquals($expected, $this->subject->addData($input));
2535  }
2536 
2540  public function addDataRemovesItemsByUserAuthModeRestriction()
2541  {
2542  $input = [
2543  'databaseRow' => [
2544  'aField' => 'keep,remove'
2545  ],
2546  'tableName' => 'aTable',
2547  'processedTca' => [
2548  'columns' => [
2549  'aField' => [
2550  'config' => [
2551  'type' => 'select',
2552  'renderType' => 'selectSingle',
2553  'authMode' => 'explicitAllow',
2554  'items' => [
2555  0 => [
2556  0 => 'keepMe',
2557  1 => 'keep',
2558  null,
2559  null,
2560  ],
2561  1 => [
2562  0 => 'removeMe',
2563  1 => 'remove',
2564  ],
2565  ],
2566  'maxitems' => 99999,
2567  ],
2568  ],
2569  ]
2570  ],
2571  ];
2572 
2574  $languageService = $this->prophesize(LanguageService::class);
2575  $GLOBALS['LANG'] = $languageService->reveal();
2576  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2577 
2579  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2580  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2581  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'keep', 'explicitAllow')->shouldBeCalled()->willReturn(true);
2582  $backendUserProphecy->checkAuthMode('aTable', 'aField', 'remove', 'explicitAllow')->shouldBeCalled()->willReturn(false);
2583 
2584  $expected = $input;
2585  $expected['databaseRow']['aField'] = ['keep'];
2586  unset($expected['processedTca']['columns']['aField']['config']['items'][1]);
2587 
2588  $this->assertEquals($expected, $this->subject->addData($input));
2589  }
2590 
2594  public function addDataKeepsAllPagesDoktypesForAdminUser()
2595  {
2596  $input = [
2597  'databaseRow' => [
2598  'doktype' => 'keep'
2599  ],
2600  'tableName' => 'pages',
2601  'processedTca' => [
2602  'columns' => [
2603  'doktype' => [
2604  'config' => [
2605  'type' => 'select',
2606  'renderType' => 'selectSingle',
2607  'items' => [
2608  0 => [
2609  0 => 'keepMe',
2610  1 => 'keep',
2611  null,
2612  null,
2613  ],
2614  ],
2615  'maxitems' => 99999,
2616  ],
2617  ],
2618  ],
2619  ],
2620  ];
2621 
2623  $languageService = $this->prophesize(LanguageService::class);
2624  $GLOBALS['LANG'] = $languageService->reveal();
2625  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2626 
2628  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2629  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2630  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(true);
2631 
2632  $expected = $input;
2633  $expected['databaseRow']['doktype'] = ['keep'];
2634 
2635  $this->assertEquals($expected, $this->subject->addData($input));
2636  }
2637 
2641  public function addDataKeepsAllowedPageTypesForNonAdminUser()
2642  {
2643  $input = [
2644  'databaseRow' => [
2645  'doktype' => 'keep',
2646  ],
2647  'tableName' => 'pages',
2648  'processedTca' => [
2649  'columns' => [
2650  'doktype' => [
2651  'config' => [
2652  'type' => 'select',
2653  'renderType' => 'selectSingle',
2654  'items' => [
2655  0 => [
2656  0 => 'keepMe',
2657  1 => 'keep',
2658  null,
2659  null,
2660  ],
2661  1 => [
2662  0 => 'removeMe',
2663  1 => 'remove',
2664  ],
2665  ],
2666  'maxitems' => 99999,
2667  ],
2668  ],
2669  ],
2670  ],
2671  ];
2672 
2674  $languageService = $this->prophesize(LanguageService::class);
2675  $GLOBALS['LANG'] = $languageService->reveal();
2676  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2677 
2679  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2680  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2681  $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(false);
2682  $backendUserProphecy->groupData = [
2683  'pagetypes_select' => 'foo,keep,anotherAllowedDoktype',
2684  ];
2685 
2686  $expected = $input;
2687  $expected['databaseRow']['doktype'] = ['keep'];
2688  unset($expected['processedTca']['columns']['doktype']['config']['items'][1]);
2689 
2690  $this->assertEquals($expected, $this->subject->addData($input));
2691  }
2692 
2696  public function addDataCallsItemsProcFunc()
2697  {
2698  $input = [
2699  'tableName' => 'aTable',
2700  'databaseRow' => [
2701  'aField' => 'aValue'
2702  ],
2703  'processedTca' => [
2704  'columns' => [
2705  'aField' => [
2706  'config' => [
2707  'type' => 'select',
2708  'renderType' => 'selectSingle',
2709  'items' => [],
2710  'itemsProcFunc' => function (array $parameters, $pObj) {
2711  $parameters['items'] = [
2712  0 => [
2713  0 => 'aLabel',
2714  1 => 'aValue',
2715  2 => null,
2716  3 => null,
2717  ],
2718  ];
2719  },
2720  ],
2721  ],
2722  ],
2723  ],
2724  ];
2725 
2727  $languageService = $this->prophesize(LanguageService::class);
2728  $GLOBALS['LANG'] = $languageService->reveal();
2729  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2730 
2731  $expected = $input;
2732  $expected['databaseRow']['aField'] = ['aValue'];
2733  $expected['processedTca']['columns']['aField']['config'] = [
2734  'type' => 'select',
2735  'renderType' => 'selectSingle',
2736  'items' => [
2737  0 => [
2738  0 => 'aLabel',
2739  1 => 'aValue',
2740  2 => null,
2741  3 => null,
2742  ],
2743  ],
2744  'maxitems' => 99999,
2745  ];
2746 
2747  $this->assertSame($expected, $this->subject->addData($input));
2748  }
2749 
2753  public function addDataItemsProcFuncReceivesParameters()
2754  {
2755  $input = [
2756  'tableName' => 'aTable',
2757  'databaseRow' => [
2758  'aField' => 'aValue',
2759  ],
2760  'pageTsConfig' => [
2761  'TCEFORM.' => [
2762  'aTable.' => [
2763  'aField.' => [
2764  'itemsProcFunc.' => [
2765  'itemParamKey' => 'itemParamValue',
2766  ],
2767  ]
2768  ],
2769  ],
2770  ],
2771  'processedTca' => [
2772  'columns' => [
2773  'aField' => [
2774  'config' => [
2775  'type' => 'select',
2776  'renderType' => 'selectSingle',
2777  'aKey' => 'aValue',
2778  'items' => [
2779  0 => [
2780  0 => 'aLabel',
2781  1 => 'aValue',
2782  ],
2783  ],
2784  'itemsProcFunc' => function (array $parameters, $pObj) {
2785  if ($parameters['items'] !== [ 0 => [ 'aLabel', 'aValue'] ]
2786  || $parameters['config']['aKey'] !== 'aValue'
2787  || $parameters['TSconfig'] !== [ 'itemParamKey' => 'itemParamValue' ]
2788  || $parameters['table'] !== 'aTable'
2789  || $parameters['row'] !== [ 'aField' => 'aValue' ]
2790  || $parameters['field'] !== 'aField'
2791  ) {
2792  throw new \UnexpectedValueException('broken', 1476109436);
2793  }
2794  },
2795  ],
2796  ],
2797  ],
2798  ],
2799  ];
2800 
2801  $languageService = $this->prophesize(LanguageService::class);
2802  $GLOBALS['LANG'] = $languageService->reveal();
2803  $languageService->sL(Argument::cetera())->willReturnArgument(0);
2805  $flashMessage = $this->prophesize(FlashMessage::class);
2806  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2808  $flashMessageService = $this->prophesize(FlashMessageService::class);
2809  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2811  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2812  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2813 
2814  // itemsProcFunc must NOT have raised an exception
2815  $flashMessageQueue->enqueue($flashMessage)->shouldNotBeCalled();
2816 
2817  $this->subject->addData($input);
2818  }
2819 
2823  public function addDataItemsProcFuncEnqueuesFlashMessageOnException()
2824  {
2825  $input = [
2826  'tableName' => 'aTable',
2827  'databaseRow' => [
2828  'aField' => 'aValue',
2829  ],
2830  'pageTsConfig' => [
2831  'TCEFORM.' => [
2832  'aTable.' => [
2833  'aField.' => [
2834  'itemsProcFunc.' => [
2835  'itemParamKey' => 'itemParamValue',
2836  ],
2837  ]
2838  ],
2839  ],
2840  ],
2841  'processedTca' => [
2842  'columns' => [
2843  'aField' => [
2844  'config' => [
2845  'type' => 'select',
2846  'renderType' => 'selectSingle',
2847  'aKey' => 'aValue',
2848  'items' => [
2849  0 => [
2850  0 => 'aLabel',
2851  1 => 'aValue',
2852  ],
2853  ],
2854  'itemsProcFunc' => function (array $parameters, $pObj) {
2855  throw new \UnexpectedValueException('anException', 1476109437);
2856  },
2857  ],
2858  ],
2859  ],
2860  ],
2861  ];
2862 
2863  $languageService = $this->prophesize(LanguageService::class);
2864  $GLOBALS['LANG'] = $languageService->reveal();
2866  $flashMessage = $this->prophesize(FlashMessage::class);
2867  GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());
2869  $flashMessageService = $this->prophesize(FlashMessageService::class);
2870  GeneralUtility::setSingletonInstance(FlashMessageService::class, $flashMessageService->reveal());
2872  $flashMessageQueue = $this->prophesize(FlashMessageQueue::class);
2873  $flashMessageService->getMessageQueueByIdentifier(Argument::cetera())->willReturn($flashMessageQueue->reveal());
2874 
2875  $flashMessageQueue->enqueue($flashMessage)->shouldBeCalled();
2876 
2877  $this->subject->addData($input);
2878  }
2879 
2883  public function addDataTranslatesItemLabelsFromPageTsConfig()
2884  {
2885  $input = [
2886  'databaseRow' => [
2887  'aField' => 'aValue',
2888  ],
2889  'tableName' => 'aTable',
2890  'processedTca' => [
2891  'columns' => [
2892  'aField' => [
2893  'config' => [
2894  'type' => 'select',
2895  'renderType' => 'selectSingle',
2896  'items' => [
2897  0 => [
2898  0 => 'aLabel',
2899  1 => 'aValue',
2900  null,
2901  null,
2902  ],
2903  ],
2904  'maxitems' => 99999,
2905  ],
2906  ],
2907  ],
2908  ],
2909  'pageTsConfig' => [
2910  'TCEFORM.' => [
2911  'aTable.' => [
2912  'aField.' => [
2913  'altLabels.' => [
2914  'aValue' => 'labelOverride',
2915  ],
2916  ]
2917  ],
2918  ],
2919  ],
2920  ];
2921 
2923  $languageService = $this->prophesize(LanguageService::class);
2924  $GLOBALS['LANG'] = $languageService->reveal();
2925  $languageService->sL('aLabel')->willReturnArgument(0);
2926  $languageService->sL('labelOverride')->shouldBeCalled()->willReturnArgument(0);
2927  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
2928 
2929  $expected = $input;
2930  $expected['databaseRow']['aField'] = ['aValue'];
2931  $expected['processedTca']['columns']['aField']['config']['items'][0][0] = 'labelOverride';
2932 
2933  $this->assertSame($expected, $this->subject->addData($input));
2934  $this->subject->addData($input);
2935  }
2936 
2940  public function processSelectFieldValueSetsMmForeignRelationValues()
2941  {
2942  $GLOBALS['TCA']['foreignTable'] = [];
2943 
2945  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
2946  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
2947  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
2948 
2949  $this->mockDatabaseConnectionForProcessSelectField();
2950 
2951  $input = [
2952  'tableName' => 'aTable',
2953  'databaseRow' => [
2954  'uid' => 42,
2955  // Two connected rows
2956  'aField' => 2,
2957  ],
2958  'processedTca' => [
2959  'columns' => [
2960  'aField' => [
2961  'config' => [
2962  'type' => 'select',
2963  'renderType' => 'selectSingle',
2964  'maxitems' => 999,
2965  'foreign_table' => 'foreignTable',
2966  'MM' => 'aTable_foreignTable_mm',
2967  'items' => [],
2968  ],
2969  ],
2970  ],
2971  ],
2972  ];
2973  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
2975  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
2976  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
2977 
2978  $relationHandlerUids = [
2979  23,
2980  24
2981  ];
2982 
2983  $relationHandlerProphecy->start(2, 'foreignTable', 'aTable_foreignTable_mm', 42, 'aTable', $fieldConfig)->shouldBeCalled();
2984  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
2985 
2986  $expected = $input;
2987  $expected['databaseRow']['aField'] = $relationHandlerUids;
2988 
2989  $this->assertEquals($expected, $this->subject->addData($input));
2990  }
2991 
2995  public function processSelectFieldValueSetsForeignRelationValues()
2996  {
2997  $GLOBALS['TCA']['foreignTable'] = [];
2998 
3000  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3001  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3002  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3003 
3004  $this->mockDatabaseConnectionForProcessSelectField();
3005 
3006  $input = [
3007  'tableName' => 'aTable',
3008  'databaseRow' => [
3009  'uid' => 42,
3010  // Two connected rows
3011  'aField' => '22,23,24,25',
3012  ],
3013  'processedTca' => [
3014  'columns' => [
3015  'aField' => [
3016  'config' => [
3017  'type' => 'select',
3018  'renderType' => 'selectSingle',
3019  'maxitems' => 999,
3020  'foreign_table' => 'foreignTable',
3021  'items' => [],
3022  ],
3023  ],
3024  ],
3025  ],
3026  ];
3027  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
3029  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3030  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3031 
3032  $relationHandlerUids = [
3033  23,
3034  24
3035  ];
3036 
3037  $relationHandlerProphecy->start('22,23,24,25', 'foreignTable', '', 42, 'aTable', $fieldConfig)->shouldBeCalled();
3038  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
3039 
3040  $expected = $input;
3041  $expected['databaseRow']['aField'] = $relationHandlerUids;
3042 
3043  $this->assertEquals($expected, $this->subject->addData($input));
3044  }
3045 
3049  public function processSelectFieldValueRemovesInvalidDynamicValues()
3050  {
3051  $languageService = $this->prophesize(LanguageService::class);
3052  $GLOBALS['LANG'] = $languageService->reveal();
3053  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3054 
3055  $GLOBALS['TCA']['foreignTable'] = [];
3056 
3058  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3059  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3060  $backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
3061 
3062  $this->mockDatabaseConnectionForProcessSelectField();
3063 
3064  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3065  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3066  $relationHandlerProphecy->start(Argument::cetera())->shouldBeCalled();
3067  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldBeCalled()->willReturn([1]);
3068 
3069  $input = [
3070  'tableName' => 'aTable',
3071  'databaseRow' => [
3072  'aField' => '1,2,bar,foo',
3073  ],
3074  'processedTca' => [
3075  'columns' => [
3076  'aField' => [
3077  'config' => [
3078  'type' => 'select',
3079  'renderType' => 'selectSingleBox',
3080  'foreign_table' => 'foreignTable',
3081  'maxitems' => 999,
3082  'items' => [
3083  ['foo', 'foo', null, null],
3084  ],
3085  ],
3086  ],
3087  ],
3088  ],
3089  ];
3090 
3091  $expected = $input;
3092  $expected['databaseRow']['aField'] = [1, 'foo'];
3093 
3094  $this->assertEquals($expected, $this->subject->addData($input));
3095  }
3096 
3101  {
3102  $languageService = $this->prophesize(LanguageService::class);
3103  $GLOBALS['LANG'] = $languageService->reveal();
3104  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3105 
3106  $input = [
3107  'tableName' => 'aTable',
3108  'databaseRow' => [
3109  'aField' => 'foo,bar',
3110  ],
3111  'processedTca' => [
3112  'columns' => [
3113  'aField' => [
3114  'config' => [
3115  'type' => 'select',
3116  'renderType' => 'selectSingle',
3117  'maxitems' => 999,
3118  'items' => [
3119  ['foo', 'foo', null, null],
3120  ['bar', 'bar', null, null],
3121  ],
3122  ],
3123  ],
3124  ],
3125  ],
3126  ];
3127 
3128  $expected = $input;
3129  $expected['databaseRow']['aField'] = [
3130  'foo',
3131  'bar'
3132  ];
3133 
3134  $this->assertEquals($expected, $this->subject->addData($input));
3135  }
3136 
3141  {
3142  $languageService = $this->prophesize(LanguageService::class);
3143  $GLOBALS['LANG'] = $languageService->reveal();
3144  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3145 
3146  $input = [
3147  'tableName' => 'aTable',
3148  'databaseRow' => [
3149  'aField' => '',
3150  ],
3151  'processedTca' => [
3152  'columns' => [
3153  'aField' => [
3154  'config' => [
3155  'type' => 'select',
3156  'renderType' => 'selectSingle',
3157  'maxitems' => 99999,
3158  'items' => [],
3159  ],
3160  ],
3161  ],
3162  ],
3163  ];
3164 
3165  $expected = $input;
3166  $expected['databaseRow']['aField'] = [];
3167 
3168  $this->assertEquals($expected, $this->subject->addData($input));
3169  }
3170 
3175  {
3176  $languageService = $this->prophesize(LanguageService::class);
3177  $GLOBALS['LANG'] = $languageService->reveal();
3178  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3179 
3180  $input = [
3181  'tableName' => 'aTable',
3182  'databaseRow' => [
3183  'aField' => 'b,,c',
3184  ],
3185  'processedTca' => [
3186  'columns' => [
3187  'aField' => [
3188  'config' => [
3189  'type' => 'select',
3190  'renderType' => 'selectSingle',
3191  'maxitems' => 999,
3192  'items' => [
3193  ['a', '', null, null],
3194  ['b', 'b', null, null],
3195  ['c', 'c', null, null],
3196  ],
3197  ],
3198  ],
3199  ],
3200  ],
3201  ];
3202 
3203  $expected = $input;
3204  $expected['databaseRow']['aField'] = [
3205  'b',
3206  'c',
3207  ];
3208 
3209  $this->assertEquals($expected, $this->subject->addData($input));
3210  }
3211 
3216  {
3217  $languageService = $this->prophesize(LanguageService::class);
3218  $GLOBALS['LANG'] = $languageService->reveal();
3219  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3220 
3221  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3222  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3223  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3224  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3225 
3226  $input = [
3227  'tableName' => 'aTable',
3228  'databaseRow' => [
3229  'aField' => 'foo',
3230  ],
3231  'processedTca' => [
3232  'columns' => [
3233  'aField' => [
3234  'config' => [
3235  'type' => 'select',
3236  'renderType' => 'selectSingle',
3237  'maxitems' => 999,
3238  'items' => [
3239  ['foo', 'foo', null, null],
3240  ],
3241  ],
3242  ],
3243  ],
3244  ],
3245  ];
3246 
3247  $expected = $input;
3248  $expected['databaseRow']['aField'] = ['foo'];
3249 
3250  $this->assertEquals($expected, $this->subject->addData($input));
3251  }
3252 
3257  {
3258  $languageService = $this->prophesize(LanguageService::class);
3259  $GLOBALS['LANG'] = $languageService->reveal();
3260  $languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue')->willReturn('INVALID VALUE "%s"');
3261  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3262 
3263  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3264  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3265  $relationHandlerProphecy->start(Argument::cetera())->shouldNotBeCalled();
3266  $relationHandlerProphecy->getValueArray(Argument::cetera())->shouldNotBeCalled();
3267 
3268  $input = [
3269  'tableName' => 'aTable',
3270  'databaseRow' => [
3271  'aField' => '1,2,bar,foo',
3272  ],
3273  'processedTca' => [
3274  'columns' => [
3275  'aField' => [
3276  'config' => [
3277  'type' => 'select',
3278  'renderType' => 'selectSingle',
3279  'maxitems' => 99999,
3280  'items' => [
3281  ['foo', 'foo', null, null],
3282  ],
3283  ],
3284  ],
3285  ],
3286  ],
3287  ];
3288 
3289  $expected = $input;
3290  $expected['databaseRow']['aField'] = ['foo'];
3291  $expected['processedTca']['columns']['aField']['config']['items'] = [
3292  ['[ INVALID VALUE "bar" ]', 'bar', null, null],
3293  ['[ INVALID VALUE "2" ]', '2', null, null],
3294  ['[ INVALID VALUE "1" ]', '1', null, null],
3295  ['foo', 'foo', null, null],
3296  ];
3297  $this->assertEquals($expected, $this->subject->addData($input));
3298  }
3299 
3304  {
3305  $languageService = $this->prophesize(LanguageService::class);
3306  $GLOBALS['LANG'] = $languageService->reveal();
3307  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3308 
3309  $input = [
3310  'tableName' => 'aTable',
3311  'databaseRow' => [
3312  'aField' => '1,foo,foo,2,bar',
3313  ],
3314  'processedTca' => [
3315  'columns' => [
3316  'aField' => [
3317  'config' => [
3318  'type' => 'select',
3319  'renderType' => 'selectSingle',
3320  'multiple' => true,
3321  'maxitems' => 999,
3322  'items' => [
3323  ['1', '1', null, null],
3324  ['foo', 'foo', null, null],
3325  ['bar', 'bar', null, null],
3326  ['2', '2', null, null],
3327  ],
3328  ],
3329  ],
3330  ],
3331  ],
3332  ];
3333 
3334  $expected = $input;
3335  $expected['databaseRow']['aField'] = [
3336  '1',
3337  'foo',
3338  'foo',
3339  '2',
3340  'bar'
3341  ];
3342 
3343  $this->assertEquals($expected, $this->subject->addData($input));
3344  }
3345 
3350  {
3351  $languageService = $this->prophesize(LanguageService::class);
3352  $GLOBALS['LANG'] = $languageService->reveal();
3353  $languageService->sL(Argument::cetera())->willReturnArgument(0);
3354 
3355  $input = [
3356  'tableName' => 'aTable',
3357  'databaseRow' => [
3358  'aField' => '1,foo,foo,2,bar',
3359  ],
3360  'processedTca' => [
3361  'columns' => [
3362  'aField' => [
3363  'config' => [
3364  'type' => 'select',
3365  'renderType' => 'selectSingle',
3366  'multiple' => false,
3367  'maxitems' => 999,
3368  'items' => [
3369  ['1', '1', null, null],
3370  ['foo', 'foo', null, null],
3371  ['bar', 'bar', null, null],
3372  ['2', '2', null, null],
3373  ],
3374  ],
3375  ],
3376  ],
3377  ],
3378  ];
3379 
3380  $expected = $input;
3381  $expected['databaseRow']['aField'] = [
3382  0 => '1',
3383  1 => 'foo',
3384  3 => '2',
3385  4 => 'bar',
3386  ];
3387 
3388  $this->assertEquals($expected, $this->subject->addData($input));
3389  }
3390 
3397  {
3398  return [
3399  'Relation with MM table and new status with default values' => [
3400  [
3401  'tableName' => 'aTable',
3402  'command' => 'new',
3403  'databaseRow' => [
3404  'uid' => 'NEW1234',
3405  'aField' => '24,35',
3406  ],
3407  'processedTca' => [
3408  'columns' => [
3409  'aField' => [
3410  'config' => [
3411  'type' => 'select',
3412  'renderType' => 'selectSingle',
3413  'maxitems' => 999,
3414  'MM' => 'mm_aTable_foreignTable',
3415  'foreign_table' => 'foreignTable',
3416  'items' => [],
3417  ],
3418  ],
3419  ],
3420  ],
3421  ],
3422  [
3423  'MM' => ''
3424  ],
3425  [
3426  24, 35
3427  ]
3428  ],
3429  'Relation with MM table and item array in list but no new status' => [
3430  [
3431  'tableName' => 'aTable',
3432  'databaseRow' => [
3433  'uid' => 'NEW1234',
3434  'aField' => '24,35',
3435  ],
3436  'processedTca' => [
3437  'columns' => [
3438  'aField' => [
3439  'config' => [
3440  'type' => 'select',
3441  'renderType' => 'selectSingle',
3442  'maxitems' => 999,
3443  'MM' => 'mm_aTable_foreignTable',
3444  'foreign_table' => 'foreignTable',
3445  'items' => [],
3446  ],
3447  ],
3448  ],
3449  ],
3450  ],
3451  [],
3452  []
3453  ],
3454  'Relation with MM table and maxitems = 1 processes field value (item count)' => [
3455  [
3456  'tableName' => 'aTable',
3457  'databaseRow' => [
3458  'uid' => 42,
3459  // MM relation with one item has 1 in field value
3460  'aField' => 1,
3461  ],
3462  'processedTca' => [
3463  'columns' => [
3464  'aField' => [
3465  'config' => [
3466  'type' => 'select',
3467  'renderType' => 'selectSingle',
3468  'maxitems' => 1,
3469  'MM' => 'mm_aTable_foreignTable',
3470  'foreign_table' => 'foreignTable',
3471  'items' => [],
3472  ],
3473  ],
3474  ],
3475  ],
3476  ],
3477  [],
3478  [
3479  24
3480  ]
3481  ],
3482  'Relation with MM table and maxitems = 1 results in empty array if no items are set' => [
3483  [
3484  'tableName' => 'aTable',
3485  'databaseRow' => [
3486  'uid' => 58,
3487  // MM relation with no items has 0 in field value
3488  'aField' => 0,
3489  ],
3490  'processedTca' => [
3491  'columns' => [
3492  'aField' => [
3493  'config' => [
3494  'type' => 'select',
3495  'renderType' => 'selectSingle',
3496  'maxitems' => 1,
3497  'MM' => 'mm_aTable_foreignTable',
3498  'foreign_table' => 'foreignTable',
3499  'items' => [],
3500  ],
3501  ],
3502  ],
3503  ],
3504  ],
3505  [],
3506  []
3507  ]
3508  ];
3509  }
3510 
3519  public function processSelectFieldSetsCorrectValuesForMmRelations(array $input, array $overrideRelationHandlerSettings, array $relationHandlerUids)
3520  {
3521  $field = $input['databaseRow']['aField'];
3522  $foreignTable = isset($overrideRelationHandlerSettings['foreign_table']) ? $overrideRelationHandlerSettings['foreign_table'] : $input['processedTca']['columns']['aField']['config']['foreign_table'];
3523  $mmTable = isset($overrideRelationHandlerSettings['MM']) ? $overrideRelationHandlerSettings['MM'] : $input['processedTca']['columns']['aField']['config']['MM'];
3524  $uid = $input['databaseRow']['uid'];
3525  $tableName = $input['tableName'];
3526  $fieldConfig = $input['processedTca']['columns']['aField']['config'];
3527 
3528  $GLOBALS['TCA'][$foreignTable] = [];
3529 
3531  $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
3532  $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
3533  $backendUserProphecy->getPagePermsClause(Argument::cetera())->willReturn(' 1=1');
3534 
3535  $this->mockDatabaseConnectionForProcessSelectField();
3536 
3538  $relationHandlerProphecy = $this->prophesize(RelationHandler::class);
3539  GeneralUtility::addInstance(RelationHandler::class, $relationHandlerProphecy->reveal());
3540 
3541  $relationHandlerProphecy->start($field, $foreignTable, $mmTable, $uid, $tableName, $fieldConfig)->shouldBeCalled();
3542  $relationHandlerProphecy->getValueArray()->shouldBeCalled()->willReturn($relationHandlerUids);
3543 
3544  $expected = $input;
3545  $expected['databaseRow']['aField'] = $relationHandlerUids;
3546 
3547  $this->assertEquals($expected, $this->subject->addData($input));
3548  }
3549 }
static addInstance($className, $instance)
static setSingletonInstance($className, SingletonInterface $instance)
static makeInstance($className,... $constructorArguments)
static resetSingletonInstances(array $newSingletonInstances)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']