bc9aeea723ea5363c1105d08318300ae2af98e19
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Category / CategoryRegistryTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Category;
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 use TYPO3\CMS\Core\Utility\GeneralUtility;
17 use TYPO3\CMS\Lang\LanguageService;
18
19 /**
20 * Testcase for CategoryRegistry
21 */
22 class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
23 {
24 /**
25 * @var \TYPO3\CMS\Core\Category\CategoryRegistry
26 */
27 protected $subject;
28
29 /**
30 * @var array
31 */
32 protected $tables;
33
34 /**
35 * Sets up this test suite.
36 */
37 protected function setUp()
38 {
39 $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultCategorizedTables'] = 'pages';
40 $GLOBALS['TCA']['pages']['columns'] = [];
41 $this->subject = new \TYPO3\CMS\Core\Category\CategoryRegistry();
42 $this->tables = [
43 'first' => $this->getUniqueId('first'),
44 'second' => $this->getUniqueId('second')
45 ];
46 foreach ($this->tables as $tableName) {
47 $GLOBALS['TCA'][$tableName] = [
48 'ctrl' => [],
49 'columns' => [],
50 'types' => [
51 '0' => [
52 'showitem' => ''
53 ],
54 '1' => [
55 'showitem' => ''
56 ]
57 ],
58 ];
59 }
60 }
61
62 /**
63 * @test
64 */
65 public function doesAddReturnTrueOnDefinedTable()
66 {
67 $this->assertTrue($this->subject->add('test_extension_a', $this->tables['first'], 'categories'));
68 }
69
70 /**
71 * @test
72 */
73 public function doesAddReturnTrueOnDefinedTableTheFirstTimeAndFalseTheSecondTime()
74 {
75 $this->assertTrue($this->subject->add('test_extension_a', $this->tables['first'], 'categories'));
76 $this->assertFalse($this->subject->add('test_extension_a', $this->tables['first'], 'categories'));
77 }
78
79 /**
80 * @test
81 */
82 public function doesAddThrowExceptionOnEmptyTablename()
83 {
84 $this->expectException(\InvalidArgumentException::class);
85 $this->expectExceptionCode(1369122038);
86
87 $this->subject->add('test_extension_a', '', 'categories');
88 }
89
90 /**
91 * @test
92 */
93 public function doesAddThrowExceptionOnEmptyExtensionKey()
94 {
95 $this->expectException(\InvalidArgumentException::class);
96 $this->expectExceptionCode(1397836158);
97
98 $this->subject->add('', 'foo', 'categories');
99 }
100
101 /**
102 * @test
103 */
104 public function doesAddThrowExceptionOnInvalidTablename()
105 {
106 $this->expectException(\InvalidArgumentException::class);
107 $this->expectExceptionCode(1369122038);
108
109 $this->subject->add('test_extension_a', [], 'categories');
110 }
111
112 /**
113 * @test
114 */
115 public function doesAddThrowExceptionOnInvalidExtensionKey()
116 {
117 $this->expectException(\InvalidArgumentException::class);
118 $this->expectExceptionCode(1397836158);
119
120 $this->subject->add([], 'foo', 'categories');
121 }
122
123 /**
124 * @test
125 */
126 public function areMultipleElementsOfSameExtensionRegistered()
127 {
128 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
129 $this->subject->add('test_extension_a', $this->tables['second'], 'categories');
130 $this->subject->applyTcaForPreRegisteredTables();
131
132 $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['first']]['columns']);
133 $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['second']]['columns']);
134 }
135
136 /**
137 * @test
138 */
139 public function areElementsOfDifferentExtensionsRegistered()
140 {
141 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
142 $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
143 $this->subject->applyTcaForPreRegisteredTables();
144
145 $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['first']]['columns']);
146 $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['second']]['columns']);
147 }
148
149 /**
150 * @test
151 */
152 public function areElementsOfDifferentExtensionsOnSameTableRegistered()
153 {
154 $this->subject->add('test_extension_a', $this->tables['first'], 'categories1');
155 $this->subject->add('test_extension_b', $this->tables['first'], 'categories2');
156 $this->subject->applyTcaForPreRegisteredTables();
157
158 $this->assertArrayHasKey('categories1', $GLOBALS['TCA'][$this->tables['first']]['columns']);
159 $this->assertArrayHasKey('categories2', $GLOBALS['TCA'][$this->tables['first']]['columns']);
160 }
161
162 /**
163 * @test
164 */
165 public function areElementsOfSameExtensionOnSameTableRegistered()
166 {
167 $this->subject->add('test_extension_a', $this->tables['first'], 'categories1');
168 $this->subject->add('test_extension_a', $this->tables['first'], 'categories2');
169 $this->subject->applyTcaForPreRegisteredTables();
170
171 $this->assertArrayHasKey('categories1', $GLOBALS['TCA'][$this->tables['first']]['columns']);
172 $this->assertArrayHasKey('categories2', $GLOBALS['TCA'][$this->tables['first']]['columns']);
173 }
174
175 /**
176 * @test
177 */
178 public function areDatabaseDefinitionsOfAllElementsAvailable()
179 {
180 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
181 $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
182 $this->subject->add('test_extension_c', $this->tables['first'], 'categories');
183 $definitions = $this->subject->getDatabaseTableDefinitions();
184 $matches = [];
185 preg_match_all('#CREATE TABLE\\s*([^ (]+)\\s*\\(\\s*([^ )]+)\\s+int\\(11\\)[^)]+\\);#mis', $definitions, $matches);
186 $this->assertEquals(2, count($matches[0]));
187 $this->assertEquals($matches[1][0], $this->tables['first']);
188 $this->assertEquals($matches[2][0], 'categories');
189 $this->assertEquals($matches[1][1], $this->tables['second']);
190 $this->assertEquals($matches[2][1], 'categories');
191 }
192
193 /**
194 * @test
195 */
196 public function areDatabaseDefinitionsOfParticularExtensionAvailable()
197 {
198 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
199 $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
200 $definitions = $this->subject->getDatabaseTableDefinition('test_extension_a');
201 $matches = [];
202 preg_match_all('#CREATE TABLE\\s*([^ (]+)\\s*\\(\\s*([^ )]+)\\s+int\\(11\\)[^)]+\\);#mis', $definitions, $matches);
203 $this->assertEquals(1, count($matches[0]));
204 $this->assertEquals($matches[1][0], $this->tables['first']);
205 $this->assertEquals($matches[2][0], 'categories');
206 }
207
208 /**
209 * @test
210 */
211 public function areDefaultCategorizedTablesLoaded()
212 {
213 $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultCategorizedTables'] = $this->tables['first'] . ',' . $this->tables['second'];
214 $this->subject->applyTcaForPreRegisteredTables();
215
216 $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['first']]['columns']);
217 $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['second']]['columns']);
218 }
219
220 /**
221 * @test
222 */
223 public function canApplyTca()
224 {
225 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
226 $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
227 $this->subject->applyTcaForPreRegisteredTables();
228
229 $this->assertNotEmpty($GLOBALS['TCA'][$this->tables['first']]['columns']['categories']);
230 $this->assertNotEmpty($GLOBALS['TCA'][$this->tables['second']]['columns']['categories']);
231 }
232
233 /**
234 * @test
235 */
236 public function isRegisteredReturnsTrueIfElementIsAlreadyRegistered()
237 {
238 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
239 $this->assertTrue($this->subject->isRegistered($this->tables['first'], 'categories'));
240 }
241
242 /**
243 * @test
244 */
245 public function isRegisteredReturnsFalseIfElementIsNotRegistered()
246 {
247 $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
248 $this->assertFalse($this->subject->isRegistered($this->tables['first'], '_not_registered'));
249 $this->assertFalse($this->subject->isRegistered($this->tables['second'], 'categories'));
250 }
251
252 /**
253 * @test
254 */
255 public function tabIsAddedForElement()
256 {
257 $this->subject->add('text_extension_a', $this->tables['first']);
258 $this->subject->applyTcaForPreRegisteredTables();
259
260 foreach ($GLOBALS['TCA'][$this->tables['first']]['types'] as $typeConfig) {
261 $this->assertContains('--div--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_category.tabs.category', $typeConfig['showitem']);
262 }
263 }
264
265 /**
266 * @test
267 */
268 public function tabIsNotAddedForElementIfFieldListIsSpecified()
269 {
270 $this->subject->add('text_extension_a', $this->tables['first'], 'categories', ['fieldList' => 'categories']);
271 $this->subject->applyTcaForPreRegisteredTables();
272
273 foreach ($GLOBALS['TCA'][$this->tables['first']]['types'] as $typeConfig) {
274 $this->assertNotContains('--div--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_category.tabs.category', $typeConfig['showitem']);
275 }
276 }
277
278 /**
279 * @test
280 */
281 public function tabIsOnlyAddedForTypesThatAreSpecifiedInTypesList()
282 {
283 $this->subject->add('text_extension_a', $this->tables['first'], 'categories', ['typesList' => '0']);
284 $this->subject->applyTcaForPreRegisteredTables();
285 $this->assertSame('', $GLOBALS['TCA'][$this->tables['first']]['types'][1]['showitem']);
286 }
287
288 /**
289 * @test
290 */
291 public function tabIsAddedOnlyOncePerTable()
292 {
293 $this->subject->add('text_extension_a', $this->tables['first'], 'categories1');
294 $this->subject->add('text_extension_a', $this->tables['first'], 'categories2');
295 $this->subject->applyTcaForPreRegisteredTables();
296
297 foreach ($GLOBALS['TCA'][$this->tables['first']]['types'] as $typeConfig) {
298 $this->assertSame(
299 1, substr_count($typeConfig['showitem'], '--div--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_category.tabs.category')
300 );
301 }
302 }
303
304 /**
305 * @test
306 */
307 public function addAllowsSettingOfTheSameTableFieldTwice()
308 {
309 $this->subject->add('text_extension_a', $this->tables['first'], 'categories1');
310 $result = $this->subject->add('text_extension_a', $this->tables['first'], 'categories1', [], true);
311 $this->assertTrue($result);
312 }
313
314 /**
315 * @test
316 */
317 public function addInitializesMissingTypes()
318 {
319 $this->subject->add('text_extension_a', $this->tables['first'], 'categories1');
320 $GLOBALS['TCA'][$this->tables['first']]['types']['newtypeafterfirstadd'] = ['showitem' => ''];
321 $this->subject->add('text_extension_a', $this->tables['first'], 'categories1', [], true);
322 $this->assertSame(
323 1, substr_count($GLOBALS['TCA'][$this->tables['first']]['types']['newtypeafterfirstadd']['showitem'], '--div--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_category.tabs.category')
324 );
325 }
326
327 /**
328 * @test
329 */
330 public function addAddsOnlyOneSqlString()
331 {
332 $this->subject->add('text_extension_a', $this->tables['first'], 'categories1');
333 $this->subject->add('text_extension_b', $this->tables['first'], 'categories1', [], true);
334 $sqlData = $this->subject->addExtensionCategoryDatabaseSchemaToTablesDefinition([], 'text_extension_a');
335 $this->assertEmpty($sqlData['sqlString'][0]);
336 }
337
338 /**
339 * @test
340 */
341 public function getCategoryFieldItemsReturnsFieldsForStaticTable()
342 {
343 $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageService::class);
344 $this->subject->add('text_extension_a', $this->tables['first']);
345 $this->subject->add('text_extension_a', $this->tables['first'], 'categories2');
346 $configuration = [
347 'config' => [
348 'categoryFieldsTable' => $this->tables['first']
349 ]
350 ];
351 $this->subject->getCategoryFieldItems($configuration);
352 $this->assertEquals([['Categories', 'categories'], ['Categories', 'categories2']], $configuration['items']);
353 }
354
355 /**
356 * @test
357 */
358 public function getCategoryFieldItemsReturnsFieldsForDynamicTables()
359 {
360 $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageService::class);
361 $this->subject->add('text_extension_a', $this->tables['first']);
362 $this->subject->add('text_extension_a', $this->tables['first'], 'categories2');
363 $configuration = [
364 'row' => [
365 'menu_type' => 'categorized_pages',
366 ],
367 'config' => [
368 'categoryFieldsTable' => [
369 [
370 'table' => 'othertable',
371 'activeCondition' => 'FIELD:menu_type:=:categorized_content',
372 ],
373 [
374 'table' => $this->tables['first'],
375 'activeCondition' => 'FIELD:menu_type:=:categorized_pages',
376 ],
377 ],
378 ],
379 ];
380 $this->subject->getCategoryFieldItems($configuration);
381 $this->assertEquals([['Categories', 'categories'], ['Categories', 'categories2']], $configuration['items']);
382 }
383
384 /**
385 * @test
386 */
387 public function getCategoryFieldItemsThrowsExceptionIfConfigMissing()
388 {
389 $this->expectException(\RuntimeException::class);
390 $this->expectExceptionCode(1447273908);
391 $configuration = [];
392 $this->subject->getCategoryFieldItems($configuration);
393 }
394
395 /**
396 * @test
397 */
398 public function getCategoryFieldItemsThrowsExceptionIfTypeIsInvalid()
399 {
400 $this->expectException(\RuntimeException::class);
401 $this->expectExceptionCode(1447274126);
402 $configuration = [
403 'config' => [
404 'categoryFieldsTable' => new \stdClass()
405 ]
406 ];
407 $this->subject->getCategoryFieldItems($configuration);
408 }
409
410 /**
411 * @test
412 */
413 public function getCategoryFieldItemsThrowsExceptionIfTableIsMissing()
414 {
415 $this->expectException(\RuntimeException::class);
416 $this->expectExceptionCode(1447274131);
417 $configuration = [
418 'config' => [
419 'categoryFieldsTable' => [['activeCondition' => 'TRUE']]
420 ]
421 ];
422 $this->subject->getCategoryFieldItems($configuration);
423 }
424
425 /**
426 * @test
427 */
428 public function getCategoryFieldItemsThrowsExceptionIfActiveConditionIsMissing()
429 {
430 $this->expectException(\RuntimeException::class);
431 $this->expectExceptionCode(1480786868);
432 $configuration = [
433 'config' => [
434 'categoryFieldsTable' => [['table' => 'testtable']]
435 ]
436 ];
437 $this->subject->getCategoryFieldItems($configuration);
438 }
439
440 /**
441 * @test
442 */
443 public function getCategoryFieldItemsThrowsExceptionIfNoActiveTableIsFound()
444 {
445 $this->expectException(\RuntimeException::class);
446 $this->expectExceptionCode(1447274507);
447 $configuration = [
448 'row' => [],
449 'config' => [
450 'categoryFieldsTable' => [
451 [
452 'table' => 'testtable',
453 'activeCondition' => 'FALSE',
454 ]
455 ],
456 ]
457 ];
458 $this->subject->getCategoryFieldItems($configuration);
459 }
460
461 /**
462 * @test
463 */
464 public function getCategoryFieldItemsThrowsExceptionIfMultipleTablesAreActive()
465 {
466 $this->expectException(\RuntimeException::class);
467 $this->expectExceptionCode(1480787321);
468 $configuration = [
469 'row' => [
470 'menu_type' => 'categorized_pages',
471 ],
472 'config' => [
473 'categoryFieldsTable' => [
474 [
475 'table' => 'testtable',
476 'activeCondition' => 'FIELD:menu_type:=:categorized_pages'
477 ],
478 [
479 'table' => 'testtable2',
480 'activeCondition' => 'FIELD:menu_type:=:categorized_pages'
481 ]
482 ],
483 ]
484 ];
485 $this->subject->getCategoryFieldItems($configuration);
486 }
487 }