‪TYPO3CMS  11.5
FlexFormToolsTest.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 Doctrine\DBAL\Result;
21 use Prophecy\Argument;
22 use Prophecy\PhpUnit\ProphecyTrait;
37 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
55 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
56 
60 class ‪FlexFormToolsTest extends UnitTestCase
61 {
62  use ProphecyTrait;
63 
67  protected ‪$resetSingletonInstances = true;
68 
72  public function ‪setUp(): void
73  {
74  parent::setUp();
75  // Underlying static GeneralUtility::xml2array() uses caches that have to be mocked here
76  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
77  $cacheProphecy = $this->prophesize(FrontendInterface::class);
78  $cacheManagerProphecy->getCache('runtime')->willReturn($cacheProphecy->reveal());
79  $cacheProphecy->get(Argument::cetera())->willReturn(false);
80  $cacheProphecy->set(Argument::cetera())->willReturn(false);
81  GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
82  }
83 
88  {
89  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
90  DataStructureIdentifierPreProcessHookThrowException::class,
91  ];
92  $this->expectException(\RuntimeException::class);
93  $this->expectExceptionCode(1478098527);
94  (new ‪FlexFormTools())->getDataStructureIdentifier([], 'aTableName', 'aFieldName', []);
95  }
96 
101  {
102  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
103  DataStructureIdentifierPreProcessHookReturnString::class,
104  ];
105  $this->expectException(\RuntimeException::class);
106  $this->expectExceptionCode(1478096535);
107  (new ‪FlexFormTools())->getDataStructureIdentifier([], 'aTableName', 'aFieldName', []);
108  }
109 
114  {
115  $fieldTca = [
116  'config' => [
117  'ds' => [
118  'default' => '<T3DataStructure>...',
119  ],
120  ],
121  ];
122  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
123  DataStructureIdentifierPreProcessHookReturnEmptyArray::class,
124  ];
125  $expected = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
126  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []));
127  }
128 
133  {
134  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
135  DataStructureIdentifierPreProcessHookReturnArray::class,
136  ];
137  $expected = '{"type":"myExtension","further":"data"}';
138  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier([], 'aTableName', 'aFieldName', []));
139  }
140 
145  {
146  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
147  DataStructureIdentifierPreProcessHookReturnEmptyArray::class,
148  DataStructureIdentifierPreProcessHookReturnArray::class,
149  DataStructureIdentifierPreProcessHookThrowException::class,
150  ];
151  $expected = '{"type":"myExtension","further":"data"}';
152  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier([], 'aTableName', 'aFieldName', []));
153  }
154 
159  {
160  $fieldTca = [
161  'config' => [
162  'ds' => [
163  'default' => '<T3DataStructure>...',
164  ],
165  ],
166  ];
167  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
168  DataStructureIdentifierPostProcessHookThrowException::class,
169  ];
170  $this->expectException(\RuntimeException::class);
171  $this->expectExceptionCode(1478342067);
172  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []);
173  }
174 
179  {
180  $fieldTca = [
181  'config' => [
182  'ds' => [
183  'default' => '<T3DataStructure>...',
184  ],
185  ],
186  ];
187  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
188  DataStructureIdentifierPostProcessHookReturnString::class,
189  ];
190  $this->expectException(\RuntimeException::class);
191  $this->expectExceptionCode(1478350835);
192  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []);
193  }
194 
199  {
200  $fieldTca = [
201  'config' => [
202  'ds' => [
203  'default' => '<T3DataStructure>...',
204  ],
205  ],
206  ];
207  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
208  DataStructureIdentifierPostProcessHookReturnEmptyArray::class,
209  ];
210  $this->expectException(\RuntimeException::class);
211  $this->expectExceptionCode(1478350835);
212  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []);
213  }
214 
219  {
220  $fieldTca = [
221  'config' => [
222  'ds' => [
223  'default' => '<T3DataStructure>...',
224  ],
225  ],
226  ];
227  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
228  DataStructureIdentifierPostProcessHookReturnArray::class,
229  ];
230  $expected = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default","myExtensionData":"foo"}';
231  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []));
232  }
233 
238  {
239  $fieldTca = [
240  'config' => [
241  'ds' => 'someStringOnly',
242  // no ds_pointerField,
243  ],
244  ];
245  $this->expectException(\RuntimeException::class);
246  $this->expectExceptionCode(1463826960);
247  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []);
248  }
249 
254  {
255  $fieldTca = [
256  'config' => [
257  'ds' => [
258  'default' => '<T3DataStructure>...',
259  ],
260  ],
261  ];
262  $expected = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
263  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []));
264  }
265 
270  {
271  $fieldTca = [
272  'config' => [
273  'ds' => [],
274  ],
275  ];
276  $this->expectException(InvalidTcaException::class);
277  $this->expectExceptionCode(1463652560);
278  self::assertSame('default', (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []));
279  }
280 
285  {
286  $fieldTca = [
287  'config' => [
288  'ds' => [],
289  'ds_pointerField' => 'first,second,third',
290  ],
291  ];
292  $this->expectException(\RuntimeException::class);
293  $this->expectExceptionCode(1463577497);
294  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', []);
295  }
296 
301  {
302  $fieldTca = [
303  'config' => [
304  'ds' => [],
305  'ds_pointerField' => 'notExist',
306  ],
307  ];
308  $row = [
309  'foo' => '',
310  ];
311  $this->expectException(\RuntimeException::class);
312  $this->expectExceptionCode(1463578899);
313  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
314  }
315 
320  {
321  $fieldTca = [
322  'config' => [
323  'ds' => [],
324  'ds_pointerField' => 'notExist,second',
325  ],
326  ];
327  $row = [
328  'second' => '',
329  ];
330  $this->expectException(\RuntimeException::class);
331  $this->expectExceptionCode(1463578899);
332  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
333  }
334 
339  {
340  $fieldTca = [
341  'config' => [
342  'ds' => [],
343  'ds_pointerField' => 'first,notExist',
344  ],
345  ];
346  $row = [
347  'first' => '',
348  ];
349  $this->expectException(\RuntimeException::class);
350  $this->expectExceptionCode(1463578900);
351  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
352  }
353 
358  {
359  $fieldTca = [
360  'config' => [
361  'ds' => [
362  'thePointerValue' => 'FILE:...',
363  ],
364  'ds_pointerField' => 'aField',
365  ],
366  ];
367  $row = [
368  'aField' => 'thePointerValue',
369  ];
370  $expected = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"thePointerValue"}';
371  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row));
372  }
373 
378  {
379  $fieldTca = [
380  'config' => [
381  'ds' => [
382  'default' => 'theDataStructure',
383  ],
384  'ds_pointerField' => 'aField',
385  ],
386  ];
387  $row = [
388  'aField' => 'thePointerValue',
389  ];
390  $expected = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
391  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row));
392  }
393 
398  {
399  $fieldTca = [
400  'config' => [
401  'ds' => [
402  'aDifferentDataStructure' => 'aDataStructure',
403  ],
404  'ds_pointerField' => 'aField',
405  ],
406  ];
407  $row = [
408  'uid' => 23,
409  'aField' => 'aNotDefinedDataStructure',
410  ];
411  $this->expectException(InvalidSinglePointerFieldException::class);
412  $this->expectExceptionCode(1463653197);
413  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
414  }
415 
420  {
421  return [
422  'direct match of two fields' => [
423  [
424  // $row
425  'firstField' => 'firstValue',
426  'secondField' => 'secondValue',
427  ],
428  [
429  // registered data structure names
430  'firstValue,secondValue' => '',
431  ],
432  // expected name
433  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"firstValue,secondValue"}',
434  ],
435  'match on first field, * for second' => [
436  [
437  'firstField' => 'firstValue',
438  'secondField' => 'secondValue',
439  ],
440  [
441  'firstValue,*' => '',
442  ],
443  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"firstValue,*"}',
444  ],
445  'match on second field, * for first' => [
446  [
447  'firstField' => 'firstValue',
448  'secondField' => 'secondValue',
449  ],
450  [
451  '*,secondValue' => '',
452  ],
453  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"*,secondValue"}',
454  ],
455  'match on first field only' => [
456  [
457  'firstField' => 'firstValue',
458  'secondField' => 'secondValue',
459  ],
460  [
461  'firstValue' => '',
462  ],
463  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"firstValue"}',
464  ],
465  'fallback to default' => [
466  [
467  'firstField' => 'firstValue',
468  'secondField' => 'secondValue',
469  ],
470  [
471  'default' => '',
472  ],
473  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}',
474  ],
475  'chain falls through with no match on second value to *' => [
476  [
477  'firstField' => 'firstValue',
478  'secondField' => 'noMatch',
479  ],
480  [
481  'firstValue,secondValue' => '',
482  'firstValue,*' => '',
483  ],
484  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"firstValue,*"}',
485  ],
486  'chain falls through with no match on first value to *' => [
487  [
488  'firstField' => 'noMatch',
489  'secondField' => 'secondValue',
490  ],
491  [
492  'firstValue,secondValue' => '',
493  '*,secondValue' => '',
494  ],
495  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"*,secondValue"}',
496  ],
497  'chain falls through with no match on any field to default' => [
498  [
499  'firstField' => 'noMatch',
500  'secondField' => 'noMatchToo',
501  ],
502  [
503  'firstValue,secondValue' => '',
504  'secondValue,*' => '',
505  'default' => '',
506  ],
507  '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}',
508  ],
509  ];
510  }
511 
516  public function ‪getDataStructureIdentifierReturnsValidNameForTwoFieldCombinations(array $row, array $ds, string $expected): void
517  {
518  $fieldTca = [
519  'config' => [
520  'ds' => $ds,
521  'ds_pointerField' => 'firstField,secondField',
522  ],
523  ];
524  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row));
525  }
526 
531  {
532  $fieldTca = [
533  'config' => [
534  'ds' => [
535  'firstValue,secondValue' => '',
536  ],
537  'ds_pointerField' => 'firstField,secondField',
538  ],
539  ];
540  $row = [
541  'uid' => 23,
542  'firstField' => 'noMatch',
543  'secondField' => 'noMatchToo',
544  ];
545  $this->expectException(InvalidCombinedPointerFieldException::class);
546  $this->expectExceptionCode(1463678524);
547  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
548  }
549 
554  {
555  $fieldTca = [
556  'config' => [
557  'ds_pointerField' => 'tx_templavoila_ds',
558  'ds_pointerField_searchParent' => 'pid',
559  ],
560  ];
561  $row = [
562  'uid' => 23,
563  'pid' => 42,
564  'tx_templavoila_ds' => null,
565  ];
566 
567  // Prophecies and revelations for a lot of the database stack classes
568  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
569  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
570  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
571  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
572  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
573  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
574  $statementProphecy = $this->prophesize(Result::class);
575 
576  // Register connection pool revelation in framework, this is the entry point used by system under test
577  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
578 
579  // Simulate method call flow on database objects and verify correct query is built
580  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
581  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
582  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
583  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
584  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
585  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
586  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
587  $queryBuilderProphecy->createNamedParameter(42, 1)->willReturn(42);
588  $expressionBuilderProphecy->eq('uid', 42)->shouldBeCalled()->willReturn('uid = 42');
589  $queryBuilderProphecy->where('uid = 42')->shouldBeCalled()->willReturn($queryBuilderRevelation);
590  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
591 
592  // Error case that is tested here: Do not return a valid parent row from db -> exception should be thrown
593  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderProphecy);
594  $this->expectException(InvalidParentRowException::class);
595  $this->expectExceptionCode(1463833794);
596  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
597  }
598 
603  {
604  ‪$GLOBALS['BE_USER'] = new ‪BackendUserAuthentication();
605 
606  $fieldTca = [
607  'config' => [
608  'ds_pointerField' => 'tx_templavoila_ds',
609  'ds_pointerField_searchParent' => 'pid',
610  ],
611  ];
612  $initialRow = [
613  'uid' => 3,
614  'pid' => 2,
615  'tx_templavoila_ds' => null,
616  ];
617  $secondRow = [
618  'uid' => 2,
619  'pid' => 1,
620  'tx_templavoila_ds' => null,
621  ];
622  $thirdRow = [
623  'uid' => 1,
624  'pid' => 3,
625  'tx_templavoila_ds' => null,
626  ];
627 
628  // Prophecies and revelations for a lot of the database stack classes
629  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
630  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
631  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
632  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
633  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
634  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
635  $statementProphecy = $this->prophesize(Result::class);
636 
637  // Register connection pool revelation in framework, this is the entry point used by system under test
638  // Two queries are done, so we need two instances
639  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
640  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
641 
642  // Simulate method call flow on database objects and verify correct query is built
643  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
644  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
645  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
646  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
647  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
648  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
649  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
650  $queryBuilderProphecy->createNamedParameter(2, 1)->willReturn(2);
651  $queryBuilderProphecy->createNamedParameter(1, 1)->willReturn(1);
652  $expressionBuilderProphecy->eq('uid', 2)->shouldBeCalled()->willReturn('uid = 2');
653  $expressionBuilderProphecy->eq('uid', 1)->shouldBeCalled()->willReturn('uid = 1');
654  $queryBuilderProphecy->where('uid = 2')->shouldBeCalled()->willReturn($queryBuilderRevelation);
655  $queryBuilderProphecy->where('uid = 1')->shouldBeCalled()->willReturn($queryBuilderRevelation);
656  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
657  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderProphecy);
658 
659  // First db call returns $secondRow, second returns $thirdRow, which points back to $initialRow -> exception
660  $statementProphecy->fetchOne()->willReturn(1);
661  $statementProphecy->fetchAssociative()->willReturn($secondRow, $thirdRow);
662 
663  $this->expectException(InvalidParentRowLoopException::class);
664  $this->expectExceptionCode(1464110956);
665  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $initialRow);
666  }
667 
672  {
673  ‪$GLOBALS['BE_USER'] = new ‪BackendUserAuthentication();
674 
675  $fieldTca = [
676  'config' => [
677  'ds_pointerField' => 'tx_templavoila_ds',
678  'ds_pointerField_searchParent' => 'pid',
679  ],
680  ];
681  $initialRow = [
682  'uid' => 3,
683  'pid' => 2,
684  'tx_templavoila_ds' => null,
685  ];
686  $secondRow = [
687  'uid' => 2,
688  'pid' => 1,
689  'tx_templavoila_ds' => null,
690  ];
691  $thirdRow = [
692  'uid' => 1,
693  'pid' => 0,
694  'tx_templavoila_ds' => null,
695  ];
696 
697  // Prophecies and revelations for a lot of the database stack classes
698  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
699  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
700  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
701  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
702  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
703  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
704  $statementProphecy = $this->prophesize(Result::class);
705 
706  // Register connection pool revelation in framework, this is the entry point used by system under test
707  // Two queries are done, so we need two instances
708  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
709  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
710 
711  // Simulate method call flow on database objects and verify correct query is built
712  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
713  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
714  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
715  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
716  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
717  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
718  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
719  $queryBuilderProphecy->createNamedParameter(2, 1)->willReturn(2);
720  $queryBuilderProphecy->createNamedParameter(1, 1)->willReturn(1);
721  $expressionBuilderProphecy->eq('uid', 2)->shouldBeCalled()->willReturn('uid = 2');
722  $expressionBuilderProphecy->eq('uid', 1)->shouldBeCalled()->willReturn('uid = 1');
723  $queryBuilderProphecy->where('uid = 2')->shouldBeCalled()->willReturn($queryBuilderRevelation);
724  $queryBuilderProphecy->where('uid = 1')->shouldBeCalled()->willReturn($queryBuilderRevelation);
725  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
726  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderRevelation);
727  $statementProphecy->fetchOne()->shouldBeCalled()->willReturn(1);
728 
729  // First db call returns $secondRow, second returns $thirdRow. $thirdRow has pid 0 and still no ds -> exception
730  $statementProphecy->fetchAssociative()->willReturn($secondRow, $thirdRow);
731 
732  $this->expectException(InvalidParentRowRootException::class);
733  $this->expectExceptionCode(1464112555);
734  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $initialRow);
735  }
736 
741  {
742  $fieldTca = [
743  'config' => [
744  'ds_pointerField' => 'aPointerField',
745  ],
746  ];
747  $row = [
748  'aPointerField' => null,
749  ];
750  $this->expectException(InvalidPointerFieldValueException::class);
751  $this->expectExceptionCode(1464114011);
752  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
753  }
754 
759  {
760  $fieldTca = [
761  'config' => [
762  'ds_pointerField' => 'aPointerField',
763  ],
764  ];
765  $row = [
766  'aPointerField' => 3,
767  ];
768  $this->expectException(InvalidTcaException::class);
769  $this->expectExceptionCode(1464115639);
770  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
771  }
772 
777  {
778  $fieldTca = [
779  'config' => [
780  'ds_pointerField' => 'aPointerField',
781  'ds_tableField' => 'misconfigured',
782  ],
783  ];
784  $row = [
785  'aPointerField' => 3,
786  ];
787  $this->expectException(InvalidTcaException::class);
788  $this->expectExceptionCode(1464116002);
789  (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row);
790  }
791 
796  {
797  $fieldTca = [
798  'config' => [
799  'ds_pointerField' => 'aPointerField',
800  ],
801  ];
802  $row = [
803  'uid' => 42,
804  'aPointerField' => '<T3DataStructure>...',
805  ];
806  $expected = '{"type":"record","tableName":"aTableName","uid":42,"fieldName":"aPointerField"}';
807  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row));
808  }
809 
814  {
815  ‪$GLOBALS['BE_USER'] = new ‪BackendUserAuthentication();
816 
817  $fieldTca = [
818  'config' => [
819  'ds_pointerField' => 'tx_templavoila_ds',
820  'ds_pointerField_searchParent' => 'pid',
821  ],
822  ];
823  $initialRow = [
824  'uid' => 3,
825  'pid' => 2,
826  'tx_templavoila_ds' => null,
827  ];
828  $secondRow = [
829  'uid' => 2,
830  'pid' => 1,
831  'tx_templavoila_ds' => 0,
832  ];
833  $thirdRow = [
834  'uid' => 1,
835  'pid' => 0,
836  'tx_templavoila_ds' => '<T3DataStructure>...',
837  ];
838 
839  // Prophecies and revelations for a lot of the database stack classes
840  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
841  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
842  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
843  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
844  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
845  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
846  $statementProphecy = $this->prophesize(Result::class);
847 
848  // Register connection pool revelation in framework, this is the entry point used by system under test
849  // Two queries are done, so we need two instances
850  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
851  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
852 
853  // Simulate method call flow on database objects and verify correct query is built
854  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
855  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
856  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
857  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
858  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
859  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
860  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
861  $queryBuilderProphecy->createNamedParameter(2, 1)->willReturn(2);
862  $queryBuilderProphecy->createNamedParameter(1, 1)->willReturn(1);
863  $expressionBuilderProphecy->eq('uid', 2)->shouldBeCalled()->willReturn('uid = 2');
864  $expressionBuilderProphecy->eq('uid', 1)->shouldBeCalled()->willReturn('uid = 1');
865  $queryBuilderProphecy->where('uid = 2')->shouldBeCalled()->willReturn($queryBuilderRevelation);
866  $queryBuilderProphecy->where('uid = 1')->shouldBeCalled()->willReturn($queryBuilderRevelation);
867  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
868  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderRevelation);
869  $statementProphecy->fetchOne()->shouldBeCalled()->willReturn(1);
870 
871  // First db call returns $secondRow, second returns $thirdRow. $thirdRow resolves ds
872  $statementProphecy->fetchAssociative()->willReturn($secondRow, $thirdRow);
873 
874  $expected = '{"type":"record","tableName":"aTableName","uid":1,"fieldName":"tx_templavoila_ds"}';
875  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $initialRow));
876  }
877 
882  {
883  ‪$GLOBALS['BE_USER'] = new ‪BackendUserAuthentication();
884 
885  $fieldTca = [
886  'config' => [
887  'ds_pointerField' => 'tx_templavoila_ds',
888  'ds_pointerField_searchParent' => 'pid',
889  ],
890  ];
891  $initialRow = [
892  'uid' => 3,
893  'pid' => 2,
894  'tx_templavoila_ds' => null,
895  ];
896  $secondRow = [
897  'uid' => 2,
898  'pid' => 1,
899  'tx_templavoila_ds' => '<T3DataStructure>...',
900  ];
901 
902  // Prophecies and revelations for a lot of the database stack classes
903  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
904  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
905  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
906  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
907  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
908  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
909  $statementProphecy = $this->prophesize(Result::class);
910 
911  // Register connection pool revelation in framework, this is the entry point used by system under test
912  // Two queries are done, so we need two instances
913  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
914 
915  // Simulate method call flow on database objects and verify correct query is built
916  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
917  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
918  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
919  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
920  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
921  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
922  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
923  $queryBuilderProphecy->createNamedParameter(2, 1)->willReturn(2);
924  $expressionBuilderProphecy->eq('uid', 2)->shouldBeCalled()->willReturn('uid = 2');
925  $queryBuilderProphecy->where('uid = 2')->shouldBeCalled()->willReturn($queryBuilderRevelation);
926  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderRevelation);
927  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
928  $statementProphecy->fetchOne()->shouldBeCalled()->willReturn(1);
929 
930  // First db call returns $secondRow. $secondRow resolves DS and does not look further up
931  $statementProphecy->fetchAssociative()->willReturn($secondRow);
932 
933  $expected = '{"type":"record","tableName":"aTableName","uid":2,"fieldName":"tx_templavoila_ds"}';
934  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $initialRow));
935  }
936 
941  {
942  ‪$GLOBALS['BE_USER'] = new ‪BackendUserAuthentication();
943 
944  $fieldTca = [
945  'config' => [
946  'ds_pointerField' => 'tx_templavoila_ds',
947  'ds_pointerField_searchParent' => 'pid',
948  'ds_pointerField_searchParent_subField' => 'tx_templavoila_next_ds',
949  ],
950  ];
951  $initialRow = [
952  'uid' => 3,
953  'pid' => 2,
954  'tx_templavoila_ds' => null,
955  'tx_templavoila_next_ds' => null,
956  ];
957  $secondRow = [
958  'uid' => 2,
959  'pid' => 1,
960  'tx_templavoila_ds' => '<T3DataStructure>...',
961  'tx_templavoila_next_ds' => 'anotherDataStructure',
962  ];
963 
964  // Prophecies and revelations for a lot of the database stack classes
965  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
966  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
967  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
968  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
969  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
970  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
971  $statementProphecy = $this->prophesize(Result::class);
972 
973  // Register connection pool revelation in framework, this is the entry point used by system under test
974  // Two queries are done, so we need two instances
975  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
976 
977  // Simulate method call flow on database objects and verify correct query is built
978  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
979  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
980  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
981  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
982  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
983  $queryBuilderProphecy->addSelect('tx_templavoila_next_ds')->shouldBeCalled();
984  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
985  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
986  $queryBuilderProphecy->createNamedParameter(2, 1)->willReturn(2);
987  $expressionBuilderProphecy->eq('uid', 2)->shouldBeCalled()->willReturn('uid = 2');
988  $queryBuilderProphecy->where('uid = 2')->shouldBeCalled()->willReturn($queryBuilderRevelation);
989  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderRevelation);
990  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
991  $statementProphecy->fetchOne()->shouldBeCalled()->willReturn(1);
992 
993  // First db call returns $secondRow. $secondRow resolves DS and does not look further up
994  $statementProphecy->fetchAssociative()->willReturn($secondRow);
995 
996  $expected = '{"type":"record","tableName":"aTableName","uid":2,"fieldName":"tx_templavoila_next_ds"}';
997  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $initialRow));
998  }
999 
1004  {
1005  $fieldTca = [
1006  'config' => [
1007  'ds_pointerField' => 'aPointerField',
1008  'ds_tableField' => 'foreignTableName:foreignTableField',
1009  ],
1010  ];
1011  $row = [
1012  'uid' => 3,
1013  'pid' => 2,
1014  'aPointerField' => 42,
1015  ];
1016  $expected = '{"type":"record","tableName":"foreignTableName","uid":42,"fieldName":"foreignTableField"}';
1017  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $row));
1018  }
1019 
1024  {
1025  ‪$GLOBALS['BE_USER'] = new ‪BackendUserAuthentication();
1026 
1027  $fieldTca = [
1028  'config' => [
1029  'ds_pointerField' => 'tx_templavoila_ds',
1030  'ds_pointerField_searchParent' => 'pid',
1031  'ds_pointerField_searchParent_subField' => 'tx_templavoila_next_ds',
1032  'ds_tableField' => 'foreignTableName:foreignTableField',
1033  ],
1034  ];
1035  $initialRow = [
1036  'uid' => 3,
1037  'pid' => 2,
1038  'tx_templavoila_ds' => null,
1039  'tx_templavoila_next_ds' => null,
1040  ];
1041  $secondRow = [
1042  'uid' => 2,
1043  'pid' => 1,
1044  'tx_templavoila_ds' => '<T3DataStructure>...',
1045  'tx_templavoila_next_ds' => '42',
1046  ];
1047 
1048  // Prophecies and revelations for a lot of the database stack classes
1049  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
1050  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
1051  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
1052  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
1053  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
1054  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
1055  $statementProphecy = $this->prophesize(Result::class);
1056 
1057  // Register connection pool revelation in framework, this is the entry point used by system under test
1058  // Two queries are done, so we need two instances
1059  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
1060 
1061  // Simulate method call flow on database objects and verify correct query is built
1062  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1063  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
1064  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
1065  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
1066  $queryBuilderProphecy->select('uid', 'pid', 'tx_templavoila_ds')->shouldBeCalled();
1067  $queryBuilderProphecy->addSelect('tx_templavoila_next_ds')->shouldBeCalled();
1068  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1069  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
1070  $queryBuilderProphecy->createNamedParameter(2, 1)->willReturn(2);
1071  $expressionBuilderProphecy->eq('uid', 2)->shouldBeCalled()->willReturn('uid = 2');
1072  $queryBuilderProphecy->where('uid = 2')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1073  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
1074  $queryBuilderProphecy->count('uid')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1075  $statementProphecy->fetchOne()->shouldBeCalled()->willReturn(1);
1076 
1077  // First db call returns $secondRow. $secondRow resolves DS and does not look further up
1078  $statementProphecy->fetchAssociative()->willReturn($secondRow);
1079 
1080  $expected = '{"type":"record","tableName":"foreignTableName","uid":42,"fieldName":"foreignTableField"}';
1081  self::assertSame($expected, (new ‪FlexFormTools())->getDataStructureIdentifier($fieldTca, 'aTableName', 'aFieldName', $initialRow));
1082  }
1083 
1088  {
1089  $this->expectException(InvalidIdentifierException::class);
1090  $this->expectExceptionCode(1478100828);
1091  (new ‪FlexFormTools())->parseDataStructureByIdentifier('');
1092  }
1093 
1098  {
1099  $this->expectException(\RuntimeException::class);
1100  $this->expectExceptionCode(1478345642);
1101  (new ‪FlexFormTools())->parseDataStructureByIdentifier('egon');
1102  }
1103 
1108  {
1109  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1110  DataStructureParsePreProcessHookThrowException::class,
1111  ];
1112  $this->expectException(\RuntimeException::class);
1113  $this->expectExceptionCode(1478112411);
1114  (new ‪FlexFormTools())->parseDataStructureByIdentifier('{"some":"input"}');
1115  }
1116 
1121  {
1122  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1123  DataStructureParsePreProcessHookReturnObject::class,
1124  ];
1125  $this->expectException(\RuntimeException::class);
1126  $this->expectExceptionCode(1478168512);
1127  (new ‪FlexFormTools())->parseDataStructureByIdentifier('{"some":"input"}');
1128  }
1129 
1134  {
1135  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1136  DataStructureParsePreProcessHookReturnEmptyString::class,
1137  ];
1138  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1139  <T3DataStructure>
1140  <sheets></sheets>
1141  </T3DataStructure>
1142  ';
1143  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1144  $expected = [
1145  'sheets' => '',
1146  ];
1147  self::assertSame($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1148  }
1149 
1154  {
1155  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1156  DataStructureParsePreProcessHookReturnString::class,
1157  ];
1158  $identifier = '{"type":"myExtension"}';
1159  $expected = [
1160  'sheets' => '',
1161  ];
1162  self::assertSame($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1163  }
1164 
1169  {
1170  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1171  DataStructureParsePreProcessHookReturnEmptyString::class,
1172  DataStructureParsePreProcessHookReturnString::class,
1173  DataStructureParsePreProcessHookThrowException::class,
1174  ];
1175  $identifier = '{"type":"myExtension"}';
1176  $expected = [
1177  'sheets' => '',
1178  ];
1179  self::assertSame($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1180  }
1181 
1186  {
1187  $this->expectException(InvalidIdentifierException::class);
1188  $this->expectExceptionCode(1478104554);
1189  (new ‪FlexFormTools())->parseDataStructureByIdentifier('{"type":"bernd"}');
1190  }
1191 
1196  {
1197  $this->expectException(\RuntimeException::class);
1198  $this->expectExceptionCode(1478113471);
1199  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName"}';
1200  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1201  }
1202 
1207  {
1208  $this->expectException(InvalidIdentifierException::class);
1209  $this->expectExceptionCode(1478105491);
1210  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1211  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1212  }
1213 
1218  {
1219  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1220  <T3DataStructure>
1221  <sheets></sheets>
1222  </T3DataStructure>
1223  ';
1224  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1225  $expected = [
1226  'sheets' => '',
1227  ];
1228  self::assertSame($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1229  }
1230 
1235  {
1236  $this->expectException(\RuntimeException::class);
1237  $this->expectExceptionCode(1478113873);
1238  $identifier = '{"type":"record","tableName":"foreignTableName","uid":42}';
1239  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1240  }
1241 
1246  {
1247  // Prophecies and revelations for a lot of the database stack classes
1248  $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
1249  $queryBuilderRevelation = $queryBuilderProphecy->reveal();
1250  $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
1251  $queryRestrictionContainerProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
1252  $queryRestrictionContainerRevelation = $queryRestrictionContainerProphecy->reveal();
1253  $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
1254  $statementProphecy = $this->prophesize(Result::class);
1255 
1256  // Register connection pool revelation in framework, this is the entry point used by system under test
1257  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
1258 
1259  // Simulate method call flow on database objects and verify correct query is built
1260  $connectionPoolProphecy->getQueryBuilderForTable('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1261  $queryRestrictionContainerProphecy->removeAll()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
1262  $queryRestrictionContainerProphecy->add(Argument::cetera())->shouldBeCalled();
1263  $queryBuilderProphecy->getRestrictions()->shouldBeCalled()->willReturn($queryRestrictionContainerRevelation);
1264  $queryBuilderProphecy->select('dataprot')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1265  $queryBuilderProphecy->from('aTableName')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1266  $queryBuilderProphecy->expr()->shouldBeCalled()->willReturn($expressionBuilderProphecy->reveal());
1267  $queryBuilderProphecy->createNamedParameter(42, 1)->willReturn(42);
1268  $expressionBuilderProphecy->eq('uid', 42)->shouldBeCalled()->willReturn('uid = 42');
1269  $queryBuilderProphecy->where('uid = 42')->shouldBeCalled()->willReturn($queryBuilderRevelation);
1270  $queryBuilderProphecy->executeQuery()->shouldBeCalled()->willReturn($statementProphecy->reveal());
1271  $statementProphecy->fetchOne()->willReturn('
1272  <T3DataStructure>
1273  <sheets></sheets>
1274  </T3DataStructure>
1275  ');
1276  $identifier = '{"type":"record","tableName":"aTableName","uid":42,"fieldName":"dataprot"}';
1277  $expected = [
1278  'sheets' => '',
1279  ];
1280  self::assertSame($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1281  }
1282 
1287  {
1288  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default']
1289  = 'FILE:EXT:core/Does/Not/Exist.xml';
1290  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1291  $this->expectException(\RuntimeException::class);
1292  $this->expectExceptionCode(1478105826);
1293  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1294  }
1295 
1299  public function ‪parseDataStructureByIdentifierFetchesFromFile(): void
1300  {
1301  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default']
1302  = ' FILE:EXT:core/Tests/Unit/Configuration/FlexForm/Fixtures/DataStructureWithSheet.xml ';
1303  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1304  $expected = [
1305  'sheets' => [
1306  'sDEF' => [
1307  'ROOT' => [
1308  'type' => 'array',
1309  'el' => [
1310  'aFlexField' => [
1311  'TCEforms' => [
1312  'label' => 'aFlexFieldLabel',
1313  'config' => [
1314  'type' => 'input',
1315  ],
1316  ],
1317  ],
1318  ],
1319  'TCEforms' => [
1320  'sheetTitle' => 'aTitle',
1321  ],
1322  ],
1323  ],
1324  ],
1325  ];
1326  self::assertEquals($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1327  }
1328 
1333  {
1334  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1335  <T3DataStructure>
1336  <sheets>
1337  <bar>
1338  </sheets>
1339  </T3DataStructure>
1340  ';
1341  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1342  $this->expectException(InvalidIdentifierException::class);
1343  $this->expectExceptionCode(1478106090);
1344  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1345  }
1346 
1351  {
1352  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1353  <T3DataStructure>
1354  <ROOT></ROOT>
1355  <sheets></sheets>
1356  </T3DataStructure>
1357  ';
1358  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1359  $this->expectException(\RuntimeException::class);
1360  $this->expectExceptionCode(1440676540);
1361  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1362  }
1363 
1368  {
1369  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1370  <T3DataStructure>
1371  <ROOT>
1372  <TCEforms>
1373  <sheetTitle>aTitle</sheetTitle>
1374  </TCEforms>
1375  <type>array</type>
1376  <el>
1377  <aFlexField>
1378  <TCEforms>
1379  <label>aFlexFieldLabel</label>
1380  <config>
1381  <type>input</type>
1382  </config>
1383  </TCEforms>
1384  </aFlexField>
1385  </el>
1386  </ROOT>
1387  </T3DataStructure>
1388  ';
1389  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1390  $expected = [
1391  'sheets' => [
1392  'sDEF' => [
1393  'ROOT' => [
1394  'type' => 'array',
1395  'el' => [
1396  'aFlexField' => [
1397  'TCEforms' => [
1398  'label' => 'aFlexFieldLabel',
1399  'config' => [
1400  'type' => 'input',
1401  ],
1402  ],
1403  ],
1404  ],
1405  'TCEforms' => [
1406  'sheetTitle' => 'aTitle',
1407  ],
1408  ],
1409  ],
1410  ],
1411  ];
1412  self::assertEquals($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1413  }
1414 
1419  {
1420  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1421  <T3DataStructure>
1422  <sheets>
1423  <aSheet>
1424  EXT:core/Tests/Unit/Configuration/FlexForm/Fixtures/DataStructureOfSingleSheet.xml
1425  </aSheet>
1426  </sheets>
1427  </T3DataStructure>
1428  ';
1429  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1430  $expected = [
1431  'sheets' => [
1432  'aSheet' => [
1433  'ROOT' => [
1434  'type' => 'array',
1435  'el' => [
1436  'aFlexField' => [
1437  'TCEforms' => [
1438  'label' => 'aFlexFieldLabel',
1439  'config' => [
1440  'type' => 'input',
1441  ],
1442  ],
1443  ],
1444  ],
1445  'TCEforms' => [
1446  'sheetTitle' => 'aTitle',
1447  ],
1448  ],
1449  ],
1450  ],
1451  ];
1452  self::assertEquals($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1453  }
1454 
1459  {
1460  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1461  <T3DataStructure>
1462  <sheets>
1463  <aSheet>
1464  FILE:EXT:core/Tests/Unit/Configuration/FlexForm/Fixtures/DataStructureOfSingleSheet.xml
1465  </aSheet>
1466  </sheets>
1467  </T3DataStructure>
1468  ';
1469  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1470  $expected = [
1471  'sheets' => [
1472  'aSheet' => [
1473  'ROOT' => [
1474  'type' => 'array',
1475  'el' => [
1476  'aFlexField' => [
1477  'TCEforms' => [
1478  'label' => 'aFlexFieldLabel',
1479  'config' => [
1480  'type' => 'input',
1481  ],
1482  ],
1483  ],
1484  ],
1485  'TCEforms' => [
1486  'sheetTitle' => 'aTitle',
1487  ],
1488  ],
1489  ],
1490  ],
1491  ];
1492  self::assertEquals($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1493  }
1494 
1499  {
1500  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1501  <T3DataStructure>
1502  <sheets></sheets>
1503  </T3DataStructure>
1504  ';
1505  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1506  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1507  DataStructureParsePostProcessHookThrowException::class,
1508  ];
1509  $this->expectException(\RuntimeException::class);
1510  $this->expectExceptionCode(1478351691);
1511  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1512  }
1513 
1518  {
1519  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1520  <T3DataStructure>
1521  <sheets></sheets>
1522  </T3DataStructure>
1523  ';
1524  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1525  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1526  DataStructureParsePostProcessHookReturnString::class,
1527  ];
1528  $this->expectException(\RuntimeException::class);
1529  $this->expectExceptionCode(1478350806);
1530  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1531  }
1532 
1537  {
1538  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1539  <T3DataStructure>
1540  <sheets></sheets>
1541  </T3DataStructure>
1542  ';
1543  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1544  ‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][FlexFormTools::class]['flexParsing'] = [
1545  DataStructureParsePostProcessHookReturnArray::class,
1546  ];
1547  $expected = [
1548  'sheets' => [
1549  'foo' => 'bar',
1550  ],
1551  ];
1552  self::assertSame($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1553  }
1554 
1559  {
1560  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1561  <T3DataStructure>
1562  <ROOT>
1563  <TCEforms>
1564  <sheetTitle>aTitle</sheetTitle>
1565  </TCEforms>
1566  <type>array</type>
1567  <el>
1568  <category>
1569  <TCEforms>
1570  <label>Single category</label>
1571  <config>
1572  <type>category</type>
1573  <relationship>oneToOne</relationship>
1574  </config>
1575  </TCEforms>
1576  </category>
1577  <categories>
1578  <TCEforms>
1579  <config>
1580  <type>category</type>
1581  </config>
1582  </TCEforms>
1583  </categories>
1584  </el>
1585  </ROOT>
1586  </T3DataStructure>
1587  ';
1588  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1589  $expected = [
1590  'sheets' => [
1591  'sDEF' => [
1592  'ROOT' => [
1593  'type' => 'array',
1594  'el' => [
1595  'category' => [
1596  'TCEforms' => [
1597  'label' => 'Single category',
1598  'config' => [
1599  'type' => 'category',
1600  'relationship' => 'oneToOne',
1601  'foreign_table' => 'sys_category',
1602  'foreign_table_where' => ' AND {#sys_category}.{#sys_language_uid} IN (-1, 0)',
1603  'maxitems' => 1,
1604  'size' => 20,
1605  'default' => 0,
1606  ],
1607  ],
1608  ],
1609  'categories' => [
1610  'TCEforms' => [
1611  'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_category.categories',
1612  'config' => [
1613  'type' => 'category',
1614  'relationship' => 'oneToMany',
1615  'foreign_table' => 'sys_category',
1616  'foreign_table_where' => ' AND {#sys_category}.{#sys_language_uid} IN (-1, 0)',
1617  'maxitems' => 99999,
1618  'size' => 20,
1619  ],
1620  ],
1621  ],
1622  ],
1623  'TCEforms' => [
1624  'sheetTitle' => 'aTitle',
1625  ],
1626  ],
1627  ],
1628  ],
1629  ];
1630  self::assertEquals($expected, (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier));
1631  }
1632 
1637  {
1638  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1639  <T3DataStructure>
1640  <ROOT>
1641  <TCEforms>
1642  <sheetTitle>aTitle</sheetTitle>
1643  </TCEforms>
1644  <type>array</type>
1645  <el>
1646  <categories>
1647  <TCEforms>
1648  <config>
1649  <type>category</type>
1650  <relationship>manyToMany</relationship>
1651  </config>
1652  </TCEforms>
1653  </categories>
1654  </el>
1655  </ROOT>
1656  </T3DataStructure>
1657  ';
1658  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1659 
1660  $this->expectException(\UnexpectedValueException::class);
1661  $this->expectExceptionCode(1627640208);
1662 
1663  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1664  }
1665 
1670  {
1671  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1672  <T3DataStructure>
1673  <ROOT>
1674  <TCEforms>
1675  <sheetTitle>aTitle</sheetTitle>
1676  </TCEforms>
1677  <type>array</type>
1678  <el>
1679  <categories>
1680  <TCEforms>
1681  <config>
1682  <type>category</type>
1683  <relationship>oneToOne</relationship>
1684  <maxitems>12</maxitems>
1685  </config>
1686  </TCEforms>
1687  </categories>
1688  </el>
1689  </ROOT>
1690  </T3DataStructure>
1691  ';
1692  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1693 
1694  $this->expectException(\UnexpectedValueException::class);
1695  $this->expectExceptionCode(1627640209);
1696 
1697  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1698  }
1699 
1704  {
1705  ‪$GLOBALS['TCA']['aTableName']['columns']['aFieldName']['config']['ds']['default'] = '
1706  <T3DataStructure>
1707  <ROOT>
1708  <TCEforms>
1709  <sheetTitle>aTitle</sheetTitle>
1710  </TCEforms>
1711  <type>array</type>
1712  <el>
1713  <categories>
1714  <TCEforms>
1715  <config>
1716  <type>category</type>
1717  <maxitems>1</maxitems>
1718  </config>
1719  </TCEforms>
1720  </categories>
1721  </el>
1722  </ROOT>
1723  </T3DataStructure>
1724  ';
1725  $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
1726 
1727  $this->expectException(\UnexpectedValueException::class);
1728  $this->expectExceptionCode(1627640210);
1729 
1730  (new ‪FlexFormTools())->parseDataStructureByIdentifier($identifier);
1731  }
1732 
1737  {
1738  $dataStruct = [
1739  'dummy_field' => [
1740  'TCEforms' => [
1741  'config' => [],
1742  ],
1743  ],
1744  ];
1745  $pA = [
1746  'vKeys' => ['ES'],
1747  'callBackMethod_value' => 'dummy',
1748  ];
1749  $editData = [];
1750  $subject = $this->getMockBuilder(FlexFormTools::class)
1751  ->onlyMethods(['executeCallBackMethod'])
1752  ->getMock();
1753  $subject->expects(self::never())->method('executeCallBackMethod');
1754  $subject->traverseFlexFormXMLData_recurse($dataStruct, $editData, $pA);
1755  }
1756 
1761  {
1762  $dataStruct = [
1763  'dummy_field' => [
1764  'type' => 'array',
1765  'el' => 'field_not_in_data',
1766  ],
1767  ];
1768  $pA = [
1769  'vKeys' => ['ES'],
1770  'callBackMethod_value' => 'dummy',
1771  ];
1772  $editData = [
1773  'field' => [
1774  'el' => 'dummy',
1775  ],
1776  ];
1777  $editData2 = [];
1778  $subject = $this->createMock(FlexFormTools::class);
1779  self::assertEquals(
1780  $subject->traverseFlexFormXMLData_recurse($dataStruct, $editData, $pA),
1781  $subject->traverseFlexFormXMLData_recurse($dataStruct, $editData2, $pA)
1782  );
1783  }
1784 }
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierResolvesRecordSyntaxPointer
‪parseDataStructureByIdentifierResolvesRecordSyntaxPointer()
Definition: FlexFormToolsTest.php:1243
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfParentRowLookupFails
‪getDataStructureIdentifierThrowsExceptionIfParentRowLookupFails()
Definition: FlexFormToolsTest.php:551
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierPostProcessHookCanEnrichIdentifier
‪getDataStructureIdentifierPostProcessHookCanEnrichIdentifier()
Definition: FlexFormToolsTest.php:216
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionWithEmptyString
‪parseDataStructureByIdentifierThrowsExceptionWithEmptyString()
Definition: FlexFormToolsTest.php:1085
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePreProcessHookThrowException
Definition: DataStructureParsePreProcessHookThrowException.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPostProcessHookReturnsEmptyArray
‪getDataStructureIdentifierThrowsExceptionIfPostProcessHookReturnsEmptyArray()
Definition: FlexFormToolsTest.php:196
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidParentRowException
Definition: InvalidParentRowException.php:22
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:36
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\traverseFlexFormXmlDataRecurseDoesNotFailOnNotExistingArrayField
‪traverseFlexFormXmlDataRecurseDoesNotFailOnNotExistingArrayField()
Definition: FlexFormToolsTest.php:1758
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionIfPostProcessHookReturnsNoArray
‪parseDataStructureByIdentifierThrowsExceptionIfPostProcessHookReturnsNoArray()
Definition: FlexFormToolsTest.php:1515
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsPointerFieldValueIfDataStructureExists
‪getDataStructureIdentifierReturnsPointerFieldValueIfDataStructureExists()
Definition: FlexFormToolsTest.php:355
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\traverseFlexFormXmlDataRecurseDoesNotFailOnNotExistingField
‪traverseFlexFormXmlDataRecurseDoesNotFailOnNotExistingField()
Definition: FlexFormToolsTest.php:1734
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierCallsRegisteredPostProcessHook
‪getDataStructureIdentifierCallsRegisteredPostProcessHook()
Definition: FlexFormToolsTest.php:156
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPointerFieldStringHasMoreThanTwoFields
‪getDataStructureIdentifierThrowsExceptionIfPointerFieldStringHasMoreThanTwoFields()
Definition: FlexFormToolsTest.php:282
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionForInvalidSyntax
‪parseDataStructureByIdentifierThrowsExceptionForInvalidSyntax()
Definition: FlexFormToolsTest.php:1183
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsDefaultIfDsIsSetButNoDsPointerField
‪getDataStructureIdentifierReturnsDefaultIfDsIsSetButNoDsPointerField()
Definition: FlexFormToolsTest.php:251
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierPreparesCategoryField
‪parseDataStructureByIdentifierPreparesCategoryField()
Definition: FlexFormToolsTest.php:1556
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPointerFieldSWithTwoFieldsFirstDoesNotExist
‪getDataStructureIdentifierThrowsExceptionIfPointerFieldSWithTwoFieldsFirstDoesNotExist()
Definition: FlexFormToolsTest.php:317
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePostProcessHookReturnArray
Definition: DataStructureParsePostProcessHookReturnArray.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPreProcessHookThrowException
Definition: DataStructureIdentifierPreProcessHookThrowException.php:24
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidCombinedPointerFieldException
Definition: InvalidCombinedPointerFieldException.php:21
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierFetchesFromFile
‪parseDataStructureByIdentifierFetchesFromFile()
Definition: FlexFormToolsTest.php:1297
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierCallsPostProcessHook
‪parseDataStructureByIdentifierCallsPostProcessHook()
Definition: FlexFormToolsTest.php:1496
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidSinglePointerFieldException
Definition: InvalidSinglePointerFieldException.php:21
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfNoValidPointerFoundUntilRoot
‪getDataStructureIdentifierThrowsExceptionIfNoValidPointerFoundUntilRoot()
Definition: FlexFormToolsTest.php:669
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsEsxceptionOnInvalidMaxitemsForOneToOne
‪parseDataStructureByIdentifierThrowsEsxceptionOnInvalidMaxitemsForOneToOne()
Definition: FlexFormToolsTest.php:1667
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPostProcessHookThrowException
Definition: DataStructureIdentifierPostProcessHookThrowException.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest
Definition: FlexFormToolsTest.php:61
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierCallsRegisteredHook
‪parseDataStructureByIdentifierCallsRegisteredHook()
Definition: FlexFormToolsTest.php:1105
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePostProcessHookReturnString
Definition: DataStructureParsePostProcessHookReturnString.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPointerFieldSWithTwoFieldsSecondDoesNotExist
‪getDataStructureIdentifierThrowsExceptionIfPointerFieldSWithTwoFieldsSecondDoesNotExist()
Definition: FlexFormToolsTest.php:336
‪TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface
Definition: QueryRestrictionContainerInterface.php:25
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPostProcessHookReturnArray
Definition: DataStructureIdentifierPostProcessHookReturnArray.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierUsesCasualLogicIfHookReturnsNoIdentifier
‪parseDataStructureByIdentifierUsesCasualLogicIfHookReturnsNoIdentifier()
Definition: FlexFormToolsTest.php:1131
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionsIfNoDsPointerFieldIsSetAndDefaultDoesNotExist
‪getDataStructureIdentifierThrowsExceptionsIfNoDsPointerFieldIsSetAndDefaultDoesNotExist()
Definition: FlexFormToolsTest.php:267
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierIfIdentifierDoesNotResolveToArray
‪parseDataStructureByIdentifierIfIdentifierDoesNotResolveToArray()
Definition: FlexFormToolsTest.php:1095
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionIfHookReturnsNoString
‪parseDataStructureByIdentifierThrowsExceptionIfHookReturnsNoString()
Definition: FlexFormToolsTest.php:1118
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfReservedPointerValueIsIntegerButDsFieldNameIsNotConfigured
‪getDataStructureIdentifierThrowsExceptionIfReservedPointerValueIsIntegerButDsFieldNameIsNotConfigured()
Definition: FlexFormToolsTest.php:756
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsEsxceptionOnInvalidMaxitems
‪parseDataStructureByIdentifierThrowsEsxceptionOnInvalidMaxitems()
Definition: FlexFormToolsTest.php:1701
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidNameForTwoFieldCombinationsDataProvider
‪getDataStructureIdentifierReturnsValidNameForTwoFieldCombinationsDataProvider()
Definition: FlexFormToolsTest.php:417
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfDsIsNotAnArrayAndNoDsPointerField
‪getDataStructureIdentifierThrowsExceptionIfDsIsNotAnArrayAndNoDsPointerField()
Definition: FlexFormToolsTest.php:235
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidIdentifierForParentLookupAndBreaksLoop
‪getDataStructureIdentifierReturnsValidIdentifierForParentLookupAndBreaksLoop()
Definition: FlexFormToolsTest.php:879
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePreProcessHookReturnObject
Definition: DataStructureParsePreProcessHookReturnObject.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidIdentifierForParentLookupAndPrefersSubField
‪getDataStructureIdentifierReturnsValidIdentifierForParentLookupAndPrefersSubField()
Definition: FlexFormToolsTest.php:938
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPostProcessHookReturnEmptyArray
Definition: DataStructureIdentifierPostProcessHookReturnEmptyArray.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePreProcessHookReturnEmptyString
Definition: DataStructureParsePreProcessHookReturnEmptyString.php:24
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidParentRowRootException
Definition: InvalidParentRowRootException.php:21
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfDsTableFieldIsMisconfigured
‪getDataStructureIdentifierThrowsExceptionIfDsTableFieldIsMisconfigured()
Definition: FlexFormToolsTest.php:774
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfParentRowsFormALoop
‪getDataStructureIdentifierThrowsExceptionIfParentRowsFormALoop()
Definition: FlexFormToolsTest.php:600
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierParsesDataStructureReturnedByHook
‪parseDataStructureByIdentifierParsesDataStructureReturnedByHook()
Definition: FlexFormToolsTest.php:1151
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionIfDataStructureFileDoesNotExist
‪parseDataStructureByIdentifierThrowsExceptionIfDataStructureFileDoesNotExist()
Definition: FlexFormToolsTest.php:1284
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidIdentifierException
Definition: InvalidIdentifierException.php:21
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierResolvesExtReferenceForSingleSheetsWithFilePrefix
‪parseDataStructureByIdentifierResolvesExtReferenceForSingleSheetsWithFilePrefix()
Definition: FlexFormToolsTest.php:1456
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionForInvalidTcaSyntaxPointer
‪parseDataStructureByIdentifierThrowsExceptionForInvalidTcaSyntaxPointer()
Definition: FlexFormToolsTest.php:1204
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsStringFromPreProcessHook
‪getDataStructureIdentifierReturnsStringFromPreProcessHook()
Definition: FlexFormToolsTest.php:130
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPreProcessHookReturnsNoArray
‪getDataStructureIdentifierThrowsExceptionIfPreProcessHookReturnsNoArray()
Definition: FlexFormToolsTest.php:98
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierResolvesExtReferenceForSingleSheets
‪parseDataStructureByIdentifierResolvesExtReferenceForSingleSheets()
Definition: FlexFormToolsTest.php:1416
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPreProcessHookReturnEmptyArray
Definition: DataStructureIdentifierPreProcessHookReturnEmptyArray.php:24
‪TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools
Definition: FlexFormTools.php:40
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierPostProcessHookManipulatesDataStructure
‪parseDataStructureByIdentifierPostProcessHookManipulatesDataStructure()
Definition: FlexFormToolsTest.php:1534
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionForInvalidXmlStructure
‪parseDataStructureByIdentifierThrowsExceptionForInvalidXmlStructure()
Definition: FlexFormToolsTest.php:1330
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidIdentifierForPointerField
‪getDataStructureIdentifierReturnsValidIdentifierForPointerField()
Definition: FlexFormToolsTest.php:793
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\$resetSingletonInstances
‪bool $resetSingletonInstances
Definition: FlexFormToolsTest.php:65
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfNoValidPointerValueFound
‪getDataStructureIdentifierThrowsExceptionIfNoValidPointerValueFound()
Definition: FlexFormToolsTest.php:738
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\setUp
‪setUp()
Definition: FlexFormToolsTest.php:70
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsStringFromFirstMatchingPreProcessHook
‪getDataStructureIdentifierReturnsStringFromFirstMatchingPreProcessHook()
Definition: FlexFormToolsTest.php:142
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidTcaException
Definition: InvalidTcaException.php:23
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierParsesDataStructureFromFirstMatchingHook
‪parseDataStructureByIdentifierParsesDataStructureFromFirstMatchingHook()
Definition: FlexFormToolsTest.php:1166
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierCreatesDefaultSheet
‪parseDataStructureByIdentifierCreatesDefaultSheet()
Definition: FlexFormToolsTest.php:1365
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePostProcessHookThrowException
Definition: DataStructureParsePostProcessHookThrowException.php:24
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidPointerFieldValueException
Definition: InvalidPointerFieldValueException.php:21
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPreProcessHookReturnString
Definition: DataStructureIdentifierPreProcessHookReturnString.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPreProcessHookReturnArray
Definition: DataStructureIdentifierPreProcessHookReturnArray.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsDefaultIfPointerFieldValueDoesNotExist
‪getDataStructureIdentifierReturnsDefaultIfPointerFieldValueDoesNotExist()
Definition: FlexFormToolsTest.php:375
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionIfStructureHasBothSheetAndRoot
‪parseDataStructureByIdentifierThrowsExceptionIfStructureHasBothSheetAndRoot()
Definition: FlexFormToolsTest.php:1348
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPostProcessHookReturnsNoArray
‪getDataStructureIdentifierThrowsExceptionIfPostProcessHookReturnsNoArray()
Definition: FlexFormToolsTest.php:176
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierUsesCasualLogicIfPreProcessHookReturnsNoIdentifier
‪getDataStructureIdentifierUsesCasualLogicIfPreProcessHookReturnsNoIdentifier()
Definition: FlexFormToolsTest.php:111
‪TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidParentRowLoopException
Definition: InvalidParentRowLoopException.php:21
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidIdentifierForParentLookup
‪getDataStructureIdentifierReturnsValidIdentifierForParentLookup()
Definition: FlexFormToolsTest.php:811
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierResolvesTcaSyntaxPointer
‪parseDataStructureByIdentifierResolvesTcaSyntaxPointer()
Definition: FlexFormToolsTest.php:1215
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierCallsRegisteredPreProcessHook
‪getDataStructureIdentifierCallsRegisteredPreProcessHook()
Definition: FlexFormToolsTest.php:85
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionOnInvalidCategoryRelationship
‪parseDataStructureByIdentifierThrowsExceptionOnInvalidCategoryRelationship()
Definition: FlexFormToolsTest.php:1634
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidIdentifierForTableAndFieldPointerWithParentLookup
‪getDataStructureIdentifierReturnsValidIdentifierForTableAndFieldPointerWithParentLookup()
Definition: FlexFormToolsTest.php:1021
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPointerFieldValueDoesNotExistAndDefaultToo
‪getDataStructureIdentifierThrowsExceptionIfPointerFieldValueDoesNotExistAndDefaultToo()
Definition: FlexFormToolsTest.php:395
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureIdentifierPostProcessHookReturnString
Definition: DataStructureIdentifierPostProcessHookReturnString.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionForIncompleteTcaSyntax
‪parseDataStructureByIdentifierThrowsExceptionForIncompleteTcaSyntax()
Definition: FlexFormToolsTest.php:1193
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionIfPointerFieldWithStringSingleFieldDoesNotExist
‪getDataStructureIdentifierThrowsExceptionIfPointerFieldWithStringSingleFieldDoesNotExist()
Definition: FlexFormToolsTest.php:298
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\Fixtures\DataStructureParsePreProcessHookReturnString
Definition: DataStructureParsePreProcessHookReturnString.php:24
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidNameForTwoFieldCombinations
‪getDataStructureIdentifierReturnsValidNameForTwoFieldCombinations(array $row, array $ds, string $expected)
Definition: FlexFormToolsTest.php:514
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierThrowsExceptionForTwoFieldsWithNoMatchAndNoDefault
‪getDataStructureIdentifierThrowsExceptionForTwoFieldsWithNoMatchAndNoDefault()
Definition: FlexFormToolsTest.php:528
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\getDataStructureIdentifierReturnsValidIdentifierForTableAndFieldPointer
‪getDataStructureIdentifierReturnsValidIdentifierForTableAndFieldPointer()
Definition: FlexFormToolsTest.php:1001
‪TYPO3\CMS\Core\Tests\Unit\Configuration\FlexForm\FlexFormToolsTest\parseDataStructureByIdentifierThrowsExceptionForIncompleteRecordSyntax
‪parseDataStructureByIdentifierThrowsExceptionForIncompleteRecordSyntax()
Definition: FlexFormToolsTest.php:1232