[TASK] Remove tests no longer needed
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Category / CategoryRegistry.php
1 <?php
2 namespace TYPO3\CMS\Core\Category;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2012-2013 Fabien Udriot <fabien.udriot@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Core\Utility\ArrayUtility;
31 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
32
33 /**
34 * Class to register category configurations.
35 *
36 * @author Fabien Udriot <fabien.udriot@typo3.org>
37 * @author Oliver Hader <oliver.hader@typo3.org>
38 */
39 class CategoryRegistry implements \TYPO3\CMS\Core\SingletonInterface {
40
41 /**
42 * @var array
43 */
44 protected $registry = array();
45
46 /**
47 * @var array
48 */
49 protected $extensions = array();
50
51 /**
52 * @var array
53 */
54 protected $addedCategoryTabs = array();
55
56 /**
57 * @var string
58 */
59 protected $template = '';
60
61 /**
62 * Returns a class instance
63 *
64 * @return \TYPO3\CMS\Core\Category\CategoryRegistry
65 */
66 static public function getInstance() {
67 return \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(__CLASS__);
68 }
69
70 /**
71 * Creates this object.
72 */
73 public function __construct() {
74 $this->template = str_repeat(PHP_EOL, 3) . 'CREATE TABLE %s (' . PHP_EOL
75 . ' %s int(11) DEFAULT \'0\' NOT NULL' . PHP_EOL . ');' . str_repeat(PHP_EOL, 3);
76 }
77
78 /**
79 * Adds a new category configuration to this registry.
80 * TCA changes are directly applied
81 *
82 * @param string $extensionKey Extension key to be used
83 * @param string $tableName Name of the table to be registered
84 * @param string $fieldName Name of the field to be registered
85 * @param array $options Additional configuration options
86 * + fieldList: field configuration to be added to showitems
87 * + typesList: list of types that shall visualize the categories field
88 * + position: insert position of the categories field
89 * + label: backend label of the categories field
90 * + fieldConfiguration: TCA field config array to override defaults
91 * @return boolean
92 * @throws \InvalidArgumentException
93 * @throws \RuntimeException
94 */
95 public function add($extensionKey, $tableName, $fieldName = 'categories', array $options = array()) {
96 $didRegister = FALSE;
97 if (empty($tableName) || !is_string($tableName)) {
98 throw new \InvalidArgumentException('No or invalid table name "' . $tableName . '" given.', 1369122038);
99 }
100 if (empty($extensionKey) || !is_string($extensionKey)) {
101 throw new \InvalidArgumentException('No or invalid extension key "' . $extensionKey . '" given.', 1397836158);
102 }
103
104 if (!$this->isRegistered($tableName, $fieldName)) {
105 $this->registry[$tableName][$fieldName] = $options;
106 $this->extensions[$extensionKey][$tableName][$fieldName] = $fieldName;
107
108 if (!isset($GLOBALS['TCA'][$tableName]['columns']) && isset($GLOBALS['TCA'][$tableName]['ctrl']['dynamicConfigFile'])) {
109 // Handle deprecated old style dynamic TCA column loading.
110 ExtensionManagementUtility::loadNewTcaColumnsConfigFiles();
111 }
112
113 if (isset($GLOBALS['TCA'][$tableName]['columns'])) {
114 $this->applyTcaForTableAndField($tableName, $fieldName);
115 $didRegister = TRUE;
116 }
117 }
118
119 return $didRegister;
120 }
121
122 /**
123 * Gets the registered category configurations.
124 *
125 * @deprecated since 6.2 will be removed two versions later - Use ->isRegistered to get information about registered category fields.
126 * @return array
127 */
128 public function get() {
129 \TYPO3\CMS\Core\Utility\GeneralUtility::logDeprecatedFunction();
130 return $this->registry;
131 }
132
133 /**
134 * Gets all extension keys that registered a category configuration.
135 *
136 * @return array
137 */
138 public function getExtensionKeys() {
139 return array_keys($this->extensions);
140 }
141
142 /**
143 * Gets all categorized tables
144 *
145 * @return array
146 */
147 public function getCategorizedTables() {
148 return array_keys($this->registry);
149 }
150
151 /**
152 * Returns a list of category fields for a given table for populating selector "category_field"
153 * in tt_content table (called as itemsProcFunc).
154 *
155 * @param array $configuration Current field configuration
156 * @param \TYPO3\CMS\Backend\Form\FormEngine $formObject Back-reference to the calling object
157 * @throws \UnexpectedValueException
158 * @return void
159 */
160 public function getCategoryFieldsForTable(array &$configuration, \TYPO3\CMS\Backend\Form\FormEngine $formObject) {
161 $table = '';
162 // Define the table being looked up from the type of menu
163 if ($configuration['row']['menu_type'] == 'categorized_pages') {
164 $table = 'pages';
165 } elseif ($configuration['row']['menu_type'] == 'categorized_content') {
166 $table = 'tt_content';
167 }
168 // Return early if no table is defined
169 if (empty($table)) {
170 throw new \UnexpectedValueException('The given menu_type is not supported.', 1381823570);
171 }
172 // Loop on all registries and find entries for the correct table
173 foreach ($this->registry as $tableName => $fields) {
174 if ($tableName === $table) {
175 foreach ($fields as $fieldName => $options) {
176 $fieldLabel = $GLOBALS['LANG']->sL($GLOBALS['TCA'][$tableName]['columns'][$fieldName]['label']);
177 $configuration['items'][] = array($fieldLabel, $fieldName);
178 }
179 }
180 }
181 }
182
183 /**
184 * Tells whether a table has a category configuration in the registry.
185 *
186 * @param string $tableName Name of the table to be looked up
187 * @param string $fieldName Name of the field to be looked up
188 * @return boolean
189 */
190 public function isRegistered($tableName, $fieldName = 'categories') {
191 return isset($this->registry[$tableName][$fieldName]);
192 }
193
194 /**
195 * Generates tables definitions for all registered tables.
196 *
197 * @return string
198 */
199 public function getDatabaseTableDefinitions() {
200 $sql = '';
201 foreach ($this->getExtensionKeys() as $extensionKey) {
202 $sql .= $this->getDatabaseTableDefinition($extensionKey);
203 }
204 return $sql;
205 }
206
207 /**
208 * Generates table definitions for registered tables by an extension.
209 *
210 * @param string $extensionKey Extension key to have the database definitions created for
211 * @return string
212 */
213 public function getDatabaseTableDefinition($extensionKey) {
214 if (!isset($this->extensions[$extensionKey]) || !is_array($this->extensions[$extensionKey])) {
215 return '';
216 }
217 $sql = '';
218
219 foreach ($this->extensions[$extensionKey] as $tableName => $fields) {
220 foreach ($fields as $fieldName) {
221 $sql .= sprintf($this->template, $tableName, $fieldName);
222 }
223 }
224 return $sql;
225 }
226
227 /**
228 * @deprecated Since 6.2.2. This method was never intended to be called by extensions. Is is now deprecated and will be removed without substitution after two versions.
229 */
230 public function applyTca() {
231 \TYPO3\CMS\Core\Utility\GeneralUtility::logDeprecatedFunction();
232 }
233
234 /**
235 * Apply TCA to all registered tables
236 *
237 * @return void
238 * @internal
239 */
240 public function applyTcaForPreRegisteredTables() {
241 $this->registerDefaultCategorizedTables();
242 foreach ($this->registry as $tableName => $fields) {
243 foreach (array_keys($fields) as $fieldName) {
244 $this->applyTcaForTableAndField($tableName, $fieldName);
245 }
246 }
247 }
248
249 /**
250 * Applies the additions directly to the TCA
251 *
252 * @param string $tableName
253 * @param string $fieldName
254 */
255 protected function applyTcaForTableAndField($tableName, $fieldName) {
256 $this->addTcaColumn($tableName, $fieldName, $this->registry[$tableName][$fieldName]);
257 $this->addToAllTCAtypes($tableName, $fieldName, $this->registry[$tableName][$fieldName]);
258 }
259
260 /**
261 * Add default categorized tables to the registry
262 *
263 * @return void
264 */
265 protected function registerDefaultCategorizedTables() {
266 $defaultCategorizedTables = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(
267 ',',
268 $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultCategorizedTables'],
269 TRUE
270 );
271 foreach ($defaultCategorizedTables as $defaultCategorizedTable) {
272 if (!$this->isRegistered($defaultCategorizedTable)) {
273 $this->add('core', $defaultCategorizedTable, 'categories');
274 }
275 }
276 }
277
278 /**
279 * Add a new field into the TCA types -> showitem
280 *
281 * @param string $tableName Name of the table to be categorized
282 * @param string $fieldName Name of the field to be used to store categories
283 * @param array $options Additional configuration options
284 * + fieldList: field configuration to be added to showitems
285 * + typesList: list of types that shall visualize the categories field
286 * + position: insert position of the categories field
287 * @return void
288 */
289 protected function addToAllTCAtypes($tableName, $fieldName, array $options) {
290
291 // Makes sure to add more TCA to an existing structure
292 if (isset($GLOBALS['TCA'][$tableName]['columns'])) {
293
294 if (empty($options['fieldList'])) {
295 $fieldList = $this->addCategoryTab($tableName, $fieldName);
296 } else {
297 $fieldList = $options['fieldList'];
298 }
299
300 $typesList = '';
301 if (!empty($options['typesList'])) {
302 $typesList = $options['typesList'];
303 }
304
305 $position = '';
306 if (!empty($options['position'])) {
307 $position = $options['position'];
308 }
309
310 // Makes the new "categories" field to be visible in TSFE.
311 ExtensionManagementUtility::addToAllTCAtypes($tableName, $fieldList, $typesList, $position);
312
313 }
314 }
315
316 /**
317 * Creates the 'fieldList' string for $fieldName which includes a categories tab.
318 * But only one categories tab is added per table.
319 *
320 * @param string $tableName
321 * @param string $fieldName
322 * @return string
323 */
324 protected function addCategoryTab($tableName, $fieldName) {
325 $fieldList = '';
326 if (!in_array($tableName, $this->addedCategoryTabs)) {
327 $fieldList .= '--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category, ';
328 $this->addedCategoryTabs[] = $tableName;
329 }
330 $fieldList .= $fieldName;
331 return $fieldList;
332 }
333
334 /**
335 * Add a new TCA Column
336 *
337 * @param string $tableName Name of the table to be categorized
338 * @param string $fieldName Name of the field to be used to store categories
339 * @param array $options Additional configuration options
340 * + fieldConfiguration: TCA field config array to override defaults
341 * + label: backend label of the categories field
342 * @return void
343 */
344 protected function addTcaColumn($tableName, $fieldName, array $options) {
345 // Makes sure to add more TCA to an existing structure
346 if (isset($GLOBALS['TCA'][$tableName]['columns'])) {
347 // Take specific label into account
348 $label = 'LLL:EXT:lang/locallang_tca.xlf:sys_category.categories';
349 if (!empty($options['label'])) {
350 $label = $options['label'];
351 }
352
353 // Take specific value of exclude flag into account
354 $exclude = TRUE;
355 if (isset($options['exclude'])) {
356 $exclude = (bool)$options['exclude'];
357 }
358
359 $fieldConfiguration = empty($options['fieldConfiguration']) ? array() : $options['fieldConfiguration'];
360
361 $columns = array(
362 $fieldName => array(
363 'exclude' => $exclude,
364 'label' => $label,
365 'config' => static::getTcaFieldConfiguration($tableName, $fieldName, $fieldConfiguration),
366 ),
367 );
368
369 if (empty($GLOBALS['TCA']['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$tableName])) {
370 $GLOBALS['TCA']['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$tableName] = array();
371 }
372 if (!in_array($fieldName, $GLOBALS['TCA']['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$tableName])) {
373 $GLOBALS['TCA']['sys_category']['columns']['items']['config']['MM_oppositeUsage'][$tableName][] = $fieldName;
374 }
375
376 // Adding fields to an existing table definition
377 ExtensionManagementUtility::addTCAcolumns($tableName, $columns);
378 }
379 }
380
381 /**
382 * Get the config array for given table and field.
383 * This method does NOT take care of adding sql fields, adding the field to TCA types
384 * nor does it set the MM_oppositeUsage in the sys_category TCA. This has to be taken care of manually!
385 *
386 * @param string $tableName The table name
387 * @param string $fieldName The field name (default categories)
388 * @param array $fieldConfigurationOverride Changes to the default configuration
389 * @return array
390 * @api
391 */
392 static public function getTcaFieldConfiguration($tableName, $fieldName = 'categories', array $fieldConfigurationOverride = array()) {
393 // Forges a new field, default name is "categories"
394 $fieldConfiguration = array(
395 'type' => 'select',
396 'foreign_table' => 'sys_category',
397 'foreign_table_where' => ' AND sys_category.sys_language_uid IN (-1, 0) ORDER BY sys_category.sorting ASC',
398 'MM' => 'sys_category_record_mm',
399 'MM_opposite_field' => 'items',
400 'MM_match_fields' => array(
401 'tablenames' => $tableName,
402 'fieldname' => $fieldName,
403 ),
404 'size' => 10,
405 'autoSizeMax' => 50,
406 'maxitems' => 9999,
407 'renderMode' => 'tree',
408 'treeConfig' => array(
409 'parentField' => 'parent',
410 'appearance' => array(
411 'expandAll' => TRUE,
412 'showHeader' => TRUE,
413 'maxLevels' => 99,
414 ),
415 ),
416 );
417
418 // Merge changes to TCA configuration
419 if (!empty($fieldConfigurationOverride)) {
420 ArrayUtility::mergeRecursiveWithOverrule(
421 $fieldConfiguration,
422 $fieldConfigurationOverride
423 );
424 }
425
426 return $fieldConfiguration;
427 }
428
429 /**
430 * A slot method to inject the required category database fields to the
431 * tables definition string
432 *
433 * @param array $sqlString
434 * @return array
435 */
436 public function addCategoryDatabaseSchemaToTablesDefinition(array $sqlString) {
437 $this->registerDefaultCategorizedTables();
438 $sqlString[] = $this->getDatabaseTableDefinitions();
439 return array('sqlString' => $sqlString);
440 }
441
442 /**
443 * A slot method to inject the required category database fields of an
444 * extension to the tables definition string
445 *
446 * @param array $sqlString
447 * @param string $extensionKey
448 * @return array
449 */
450 public function addExtensionCategoryDatabaseSchemaToTablesDefinition(array $sqlString, $extensionKey) {
451 $sqlString[] = $this->getDatabaseTableDefinition($extensionKey);
452 return array('sqlString' => $sqlString, 'extensionKey' => $extensionKey);
453 }
454 }