4c647ae705e14a16df0ea1d84331d8840d49fa19
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Imaging / IconRegistry.php
1 <?php
2 namespace TYPO3\CMS\Core\Imaging;
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
17 use Symfony\Component\Finder\Finder;
18 use TYPO3\CMS\Core\Cache\CacheManager;
19 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
20 use TYPO3\CMS\Core\Core\Environment;
21 use TYPO3\CMS\Core\Exception;
22 use TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider;
23 use TYPO3\CMS\Core\Imaging\IconProvider\FontawesomeIconProvider;
24 use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
25 use TYPO3\CMS\Core\SingletonInterface;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Core\Utility\StringUtility;
28
29 /**
30 * Class IconRegistry, which makes it possible to register custom icons
31 * from within an extension.
32 */
33 class IconRegistry implements SingletonInterface
34 {
35 /**
36 * @var bool
37 */
38 protected $fullInitialized = false;
39
40 /**
41 * @var bool
42 */
43 protected $tcaInitialized = false;
44
45 /**
46 * @var bool
47 */
48 protected $flagsInitialized = false;
49
50 /**
51 * @var bool
52 */
53 protected $moduleIconsInitialized = false;
54
55 /**
56 * @var bool
57 */
58 protected $backendIconsInitialized = false;
59
60 /**
61 * Registered icons
62 *
63 * @var array
64 */
65 protected $icons = [];
66
67 /**
68 * Paths to backend icon folders for automatic registration
69 *
70 * @var string[]
71 */
72 protected $backendIconPaths = [
73 'EXT:backend/Resources/Public/Icons/',
74 'EXT:core/Resources/Public/Icons/T3Icons/',
75 'EXT:impexp/Resources/Public/Icons/',
76 'EXT:install/Resources/Public/Icons/'
77 ];
78
79 /**
80 * List of allowed icon file extensions with their Provider class
81 *
82 * @var string[]
83 */
84 protected $backendIconAllowedExtensionsWithProvider = [
85 'png' => BitmapIconProvider::class,
86 'svg' => SvgIconProvider::class
87 ];
88
89 /**
90 * manually registered icons
91 * hopefully obsolete one day
92 *
93 * @var array
94 */
95 protected $staticIcons = [
96
97 /**
98 * Important Information:
99 *
100 * Icons are maintained in an external repository, if new icons are needed
101 * please request them at: https://github.com/typo3/typo3.icons/issues
102 */
103
104 // Actions
105 'actions-wizard-link' => [
106 'provider' => FontawesomeIconProvider::class,
107 'options' => [
108 'name' => 'link'
109 ]
110 ],
111 'actions-wizard-rte' => [
112 'provider' => FontawesomeIconProvider::class,
113 'options' => [
114 'name' => 'arrows-alt'
115 ]
116 ],
117
118 // Apps
119 'apps-pagetree-category-toggle-hide-checked' => [
120 'provider' => FontawesomeIconProvider::class,
121 'options' => [
122 'name' => 'check-square'
123 ]
124 ],
125
126 // Module
127 'module-web' => [
128 'provider' => FontawesomeIconProvider::class,
129 'options' => [
130 'name' => 'file-o'
131 ]
132 ],
133 'module-site' => [
134 'provider' => FontawesomeIconProvider::class,
135 'options' => [
136 'name' => 'globe'
137 ]
138 ],
139 'module-file' => [
140 'provider' => FontawesomeIconProvider::class,
141 'options' => [
142 'name' => 'image'
143 ]
144 ],
145 'module-tools' => [
146 'provider' => FontawesomeIconProvider::class,
147 'options' => [
148 'name' => 'rocket'
149 ]
150 ],
151 'module-system' => [
152 'provider' => FontawesomeIconProvider::class,
153 'options' => [
154 'name' => 'plug'
155 ]
156 ],
157 'module-help' => [
158 'provider' => FontawesomeIconProvider::class,
159 'options' => [
160 'name' => 'question-circle'
161 ]
162 ],
163
164 // Status
165 'status-dialog-information' => [
166 'provider' => FontawesomeIconProvider::class,
167 'options' => [
168 'name' => 'exclamation-circle'
169 ]
170 ],
171 'status-dialog-ok' => [
172 'provider' => FontawesomeIconProvider::class,
173 'options' => [
174 'name' => 'check-circle',
175 ]
176 ],
177 'status-dialog-notification' => [
178 'provider' => FontawesomeIconProvider::class,
179 'options' => [
180 'name' => 'exclamation-circle'
181 ]
182 ],
183 'status-dialog-warning' => [
184 'provider' => FontawesomeIconProvider::class,
185 'options' => [
186 'name' => 'exclamation-triangle'
187 ]
188 ],
189 'status-dialog-error' => [
190 'provider' => FontawesomeIconProvider::class,
191 'options' => [
192 'name' => 'exclamation-circle'
193 ]
194 ],
195 'status-status-checked' => [
196 'provider' => FontawesomeIconProvider::class,
197 'options' => [
198 'name' => 'check',
199 ]
200 ],
201 'status-status-current' => [
202 'provider' => FontawesomeIconProvider::class,
203 'options' => [
204 'name' => 'caret-right',
205 ]
206 ],
207 'status-status-sorting-asc' => [
208 'provider' => FontawesomeIconProvider::class,
209 'options' => [
210 'name' => 'caret-up',
211 ]
212 ],
213 'status-status-sorting-desc' => [
214 'provider' => FontawesomeIconProvider::class,
215 'options' => [
216 'name' => 'caret-down',
217 ]
218 ],
219 'status-status-sorting-light-asc' => [
220 'provider' => FontawesomeIconProvider::class,
221 'options' => [
222 'name' => 'caret-up',
223 ]
224 ],
225 'status-status-sorting-light-desc' => [
226 'provider' => FontawesomeIconProvider::class,
227 'options' => [
228 'name' => 'caret-down',
229 ]
230 ],
231 'status-status-permission-granted' => [
232 'provider' => FontawesomeIconProvider::class,
233 'options' => [
234 'name' => 'check',
235 ]
236 ],
237 'status-status-permission-denied' => [
238 'provider' => FontawesomeIconProvider::class,
239 'options' => [
240 'name' => 'times',
241 ]
242 ],
243
244 // Extensions
245 'extensions-extensionmanager-update-script' => [
246 'provider' => FontawesomeIconProvider::class,
247 'options' => [
248 'name' => 'refresh',
249 ]
250 ],
251 'extensions-scheduler-run-task' => [
252 'provider' => FontawesomeIconProvider::class,
253 'options' => [
254 'name' => 'play-circle',
255 ]
256 ],
257 'extensions-scheduler-run-task-cron' => [
258 'provider' => FontawesomeIconProvider::class,
259 'options' => [
260 'name' => 'clock-o',
261 ]
262 ],
263 'generate-ws-preview-link' => [
264 'provider' => BitmapIconProvider::class,
265 'options' => [
266 'source' => 'EXT:workspaces/Resources/Public/Images/generate-ws-preview-link.png'
267 ]
268 ],
269
270 // Empty
271 'empty-empty' => [
272 'provider' => FontawesomeIconProvider::class,
273 'options' => [
274 'name' => 'empty-empty',
275 ]
276 ],
277
278 // System Information
279 'information-php-version' => [
280 'provider' => FontawesomeIconProvider::class,
281 'options' => [
282 'name' => 'code'
283 ]
284 ],
285 'information-database' => [
286 'provider' => FontawesomeIconProvider::class,
287 'options' => [
288 'name' => 'database'
289 ]
290 ],
291 'information-application-context' => [
292 'provider' => FontawesomeIconProvider::class,
293 'options' => [
294 'name' => 'tasks'
295 ]
296 ],
297 'information-composer-mode' => [
298 'provider' => FontawesomeIconProvider::class,
299 'options' => [
300 'name' => 'music'
301 ]
302 ],
303 'information-git' => [
304 'provider' => FontawesomeIconProvider::class,
305 'options' => [
306 'name' => 'git'
307 ]
308 ],
309 'information-webserver' => [
310 'provider' => FontawesomeIconProvider::class,
311 'options' => [
312 'name' => 'server'
313 ]
314 ],
315 'information-os-linux' => [
316 'provider' => FontawesomeIconProvider::class,
317 'options' => [
318 'name' => 'linux'
319 ]
320 ],
321 'information-os-apple' => [
322 'provider' => FontawesomeIconProvider::class,
323 'options' => [
324 'name' => 'apple'
325 ]
326 ],
327 'information-os-windows' => [
328 'provider' => FontawesomeIconProvider::class,
329 'options' => [
330 'name' => 'windows'
331 ]
332 ],
333
334 // Sysnote
335 'sysnote-type-0' => [
336 'provider' => FontawesomeIconProvider::class,
337 'options' => [
338 'name' => 'sticky-note-o'
339 ]
340 ],
341 'sysnote-type-1' => [
342 'provider' => FontawesomeIconProvider::class,
343 'options' => [
344 'name' => 'cog'
345 ]
346 ],
347 'sysnote-type-2' => [
348 'provider' => FontawesomeIconProvider::class,
349 'options' => [
350 'name' => 'code'
351 ]
352 ],
353 'sysnote-type-3' => [
354 'provider' => FontawesomeIconProvider::class,
355 'options' => [
356 'name' => 'thumb-tack'
357 ]
358 ],
359 'sysnote-type-4' => [
360 'provider' => FontawesomeIconProvider::class,
361 'options' => [
362 'name' => 'check-square'
363 ]
364 ]
365 ];
366
367 /**
368 * Mapping of file extensions to mimetypes
369 *
370 * @var string[]
371 */
372 protected $fileExtensionMapping = [
373 'htm' => 'mimetypes-text-html',
374 'html' => 'mimetypes-text-html',
375 'css' => 'mimetypes-text-css',
376 'js' => 'mimetypes-text-js',
377 'csv' => 'mimetypes-text-csv',
378 'php' => 'mimetypes-text-php',
379 'php6' => 'mimetypes-text-php',
380 'php5' => 'mimetypes-text-php',
381 'php4' => 'mimetypes-text-php',
382 'php3' => 'mimetypes-text-php',
383 'inc' => 'mimetypes-text-php',
384 'ts' => 'mimetypes-text-ts',
385 'typoscript' => 'mimetypes-text-typoscript',
386 'txt' => 'mimetypes-text-text',
387 'class' => 'mimetypes-text-text',
388 'tmpl' => 'mimetypes-text-text',
389 'jpg' => 'mimetypes-media-image',
390 'jpeg' => 'mimetypes-media-image',
391 'gif' => 'mimetypes-media-image',
392 'png' => 'mimetypes-media-image',
393 'bmp' => 'mimetypes-media-image',
394 'tif' => 'mimetypes-media-image',
395 'tiff' => 'mimetypes-media-image',
396 'tga' => 'mimetypes-media-image',
397 'psd' => 'mimetypes-media-image',
398 'eps' => 'mimetypes-media-image',
399 'ai' => 'mimetypes-media-image',
400 'svg' => 'mimetypes-media-image',
401 'pcx' => 'mimetypes-media-image',
402 'avi' => 'mimetypes-media-video',
403 'mpg' => 'mimetypes-media-video',
404 'mpeg' => 'mimetypes-media-video',
405 'mov' => 'mimetypes-media-video',
406 'vimeo' => 'mimetypes-media-video-vimeo',
407 'youtube' => 'mimetypes-media-video-youtube',
408 'wav' => 'mimetypes-media-audio',
409 'mp3' => 'mimetypes-media-audio',
410 'ogg' => 'mimetypes-media-audio',
411 'flac' => 'mimetypes-media-audio',
412 'opus' => 'mimetypes-media-audio',
413 'mid' => 'mimetypes-media-audio',
414 'swf' => 'mimetypes-media-flash',
415 'swa' => 'mimetypes-media-flash',
416 'exe' => 'mimetypes-application',
417 'com' => 'mimetypes-application',
418 't3x' => 'mimetypes-compressed',
419 't3d' => 'mimetypes-compressed',
420 'zip' => 'mimetypes-compressed',
421 'tgz' => 'mimetypes-compressed',
422 'gz' => 'mimetypes-compressed',
423 'pdf' => 'mimetypes-pdf',
424 'doc' => 'mimetypes-word',
425 'dot' => 'mimetypes-word',
426 'docm' => 'mimetypes-word',
427 'docx' => 'mimetypes-word',
428 'dotm' => 'mimetypes-word',
429 'dotx' => 'mimetypes-word',
430 'sxw' => 'mimetypes-word',
431 'rtf' => 'mimetypes-word',
432 'xls' => 'mimetypes-excel',
433 'xlsm' => 'mimetypes-excel',
434 'xlsx' => 'mimetypes-excel',
435 'xltm' => 'mimetypes-excel',
436 'xltx' => 'mimetypes-excel',
437 'sxc' => 'mimetypes-excel',
438 'pps' => 'mimetypes-powerpoint',
439 'ppsx' => 'mimetypes-powerpoint',
440 'ppt' => 'mimetypes-powerpoint',
441 'pptm' => 'mimetypes-powerpoint',
442 'pptx' => 'mimetypes-powerpoint',
443 'potm' => 'mimetypes-powerpoint',
444 'potx' => 'mimetypes-powerpoint',
445 'mount' => 'apps-filetree-mount',
446 'folder' => 'apps-filetree-folder-default',
447 'default' => 'mimetypes-other-other',
448 ];
449
450 /**
451 * Mapping of mime types to icons
452 *
453 * @var string[]
454 */
455 protected $mimeTypeMapping = [
456 'video/*' => 'mimetypes-media-video',
457 'audio/*' => 'mimetypes-media-audio',
458 'image/*' => 'mimetypes-media-image',
459 'text/*' => 'mimetypes-text-text',
460 ];
461
462 /**
463 * Array of deprecated icons, add deprecated icons to this array and remove it from registry
464 * - Index of this array contains the deprecated icon
465 * - Value of each entry may contain a possible new identifier
466 *
467 * Example:
468 * [
469 * 'deprecated-icon-identifier' => 'new-icon-identifier',
470 * 'another-deprecated-identifier' => null,
471 * ]
472 *
473 * @var array
474 */
475 protected $deprecatedIcons = [
476 'status-warning-lock' => 'warning-lock',
477 'status-warning-in-use' => 'warning-in-use',
478 'status-status-reference-hard' => 'status-reference-hard',
479 'status-status-reference-soft' => 'status-reference-soft',
480 'status-status-edit-read-only' => 'status-edit-read-only',
481 'extensions-workspaces-generatepreviewlink' => 'generate-ws-preview-link',
482 't3-form-icon-advanced-password' => 'form-advanced-password',
483 't3-form-icon-checkbox' => 'form-checkbox',
484 't3-form-icon-content-element' => 'form-content-element',
485 't3-form-icon-date-picker' => 'form-date-picker',
486 't3-form-icon-duplicate' => 'actions-duplicate',
487 't3-form-icon-email' => 'form-email',
488 't3-form-icon-fieldset' => 'form-fieldset',
489 't3-form-icon-file-upload' => 'form-file-upload',
490 't3-form-icon-finisher' => 'form-finisher',
491 't3-form-icon-form-element-selector' => 'actions-variable-select',
492 't3-form-icon-gridcontainer' => 'form-gridcontainer',
493 't3-form-icon-gridrow' => 'form-gridrow',
494 't3-form-icon-hidden' => 'form-hidden',
495 't3-form-icon-image-upload' => 'form-image-upload',
496 't3-form-icon-insert-after' => 'actions-form-insert-after',
497 't3-form-icon-insert-in' => 'actions-form-insert-in',
498 't3-form-icon-multi-checkbox' => 'form-multi-checkbox',
499 't3-form-icon-multi-select' => 'form-multi-select',
500 't3-form-icon-number' => 'form-number',
501 't3-form-icon-page' => 'form-page',
502 't3-form-icon-password' => 'form-password',
503 't3-form-icon-radio-button' => 'form-radio-button',
504 't3-form-icon-single-select' => 'form-single-select',
505 't3-form-icon-static-text' => 'form-static-text',
506 't3-form-icon-summary-page' => 'form-summary-page',
507 't3-form-icon-telephone' => 'form-telephone',
508 't3-form-icon-text' => 'form-text',
509 't3-form-icon-textarea' => 'form-textarea',
510 't3-form-icon-url' => 'form-url',
511 't3-form-icon-validator' => 'form-validator',
512 ];
513
514 /**
515 * @var string
516 */
517 protected $defaultIconIdentifier = 'default-not-found';
518
519 /**
520 * @var FrontendInterface
521 */
522 protected static $cache = null;
523
524 /**
525 * The constructor
526 */
527 public function __construct()
528 {
529 $this->initialize();
530 }
531
532 /**
533 * @param FrontendInterface $coreCache
534 * @internal
535 */
536 public static function setCache(FrontendInterface $cache)
537 {
538 static::$cache = $cache;
539 }
540
541 /**
542 * Initialize the registry
543 * This method can be called multiple times, depending on initialization status.
544 * In some cases e.g. TCA is not available, the method must be called multiple times.
545 */
546 protected function initialize()
547 {
548 if (!$this->backendIconsInitialized) {
549 $this->getCachedBackendIcons();
550 }
551 if (!$this->tcaInitialized && !empty($GLOBALS['TCA'])) {
552 $this->registerTCAIcons();
553 }
554 if (!$this->moduleIconsInitialized && !empty($GLOBALS['TBE_MODULES'])) {
555 $this->registerModuleIcons();
556 }
557 if (!$this->flagsInitialized) {
558 $this->registerFlags();
559 }
560 if ($this->backendIconsInitialized
561 && $this->tcaInitialized
562 && $this->moduleIconsInitialized
563 && $this->flagsInitialized) {
564 $this->fullInitialized = true;
565 }
566 }
567
568 /**
569 * Retrieve the icons from cache render them when not cached yet
570 */
571 protected function getCachedBackendIcons()
572 {
573 $cacheIdentifier = 'BackendIcons_' . sha1(TYPO3_version . Environment::getProjectPath() . 'BackendIcons');
574 /** @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend $assetsCache */
575 $assetsCache = static::$cache ?? GeneralUtility::makeInstance(CacheManager::class)->getCache('assets');
576 $cacheEntry = $assetsCache->get($cacheIdentifier);
577
578 if ($cacheEntry !== false) {
579 $this->icons = $cacheEntry;
580 } else {
581 $this->registerBackendIcons();
582 // all found icons should now be present, for historic reasons now merge w/ the statically declared icons
583 $this->icons = array_merge($this->icons, $this->staticIcons);
584 $assetsCache->set($cacheIdentifier, $this->icons);
585 }
586 // if there's now at least one icon registered, consider it successful
587 if (is_array($this->icons) && (count($this->icons) >= count($this->staticIcons))) {
588 $this->backendIconsInitialized = true;
589 }
590 }
591
592 /**
593 * Automatically find and register the core backend icons
594 */
595 protected function registerBackendIcons()
596 {
597 foreach ($this->backendIconPaths as $iconPath) {
598 $absoluteIconFolderPath = GeneralUtility::getFileAbsFileName($iconPath);
599 if ($absoluteIconFolderPath === '' || !is_readable($absoluteIconFolderPath)) {
600 // maybe EXT:path could not be resolved, then ignore
601 continue;
602 }
603
604 $finder = new Finder();
605 $finder
606 ->files()
607 ->in($absoluteIconFolderPath)
608 ->name('/\.(' . implode('|', array_keys($this->backendIconAllowedExtensionsWithProvider)) . ')$/');
609
610 foreach ($finder as $iconFile) {
611 // ignore icons that are used as extension icon in extension manager
612 // @see ExtensionManagementUtility::getExtensionIcon()
613 if (strpos($iconFile->getRelativePathname(), 'Extension.') === 0) {
614 continue;
615 }
616 $iconOptions = [
617 'source' => $iconPath . GeneralUtility::fixWindowsFilePath($iconFile->getRelativePathname())
618 ];
619 // kind of hotfix for now, needs a nicer concept later
620 if (strpos($iconFile->getFilename(), 'spinner') === 0) {
621 $iconOptions['spinning'] = true;
622 }
623
624 $this->registerIcon(
625 $iconFile->getBasename('.' . $iconFile->getExtension()),
626 $this->backendIconAllowedExtensionsWithProvider[$iconFile->getExtension()],
627 $iconOptions
628 );
629 }
630 }
631 }
632
633 /**
634 * @param string $identifier
635 * @return bool
636 */
637 public function isRegistered($identifier)
638 {
639 if (!$this->fullInitialized) {
640 $this->initialize();
641 }
642 return isset($this->icons[$identifier]);
643 }
644
645 /**
646 * @param string $identifier
647 * @return bool
648 */
649 public function isDeprecated($identifier)
650 {
651 return isset($this->deprecatedIcons[$identifier]);
652 }
653
654 /**
655 * @return string
656 */
657 public function getDefaultIconIdentifier()
658 {
659 return $this->defaultIconIdentifier;
660 }
661
662 /**
663 * Registers an icon to be available inside the Icon Factory
664 *
665 * @param string $identifier
666 * @param string $iconProviderClassName
667 * @param array $options
668 *
669 * @throws \InvalidArgumentException
670 */
671 public function registerIcon($identifier, $iconProviderClassName, array $options = [])
672 {
673 if (!in_array(IconProviderInterface::class, class_implements($iconProviderClassName), true)) {
674 throw new \InvalidArgumentException('An IconProvider must implement '
675 . IconProviderInterface::class, 1437425803);
676 }
677 $this->icons[$identifier] = [
678 'provider' => $iconProviderClassName,
679 'options' => $options
680 ];
681 }
682
683 /**
684 * Register an icon for a file extension
685 *
686 * @param string $fileExtension
687 * @param string $iconIdentifier
688 */
689 public function registerFileExtension($fileExtension, $iconIdentifier)
690 {
691 $this->fileExtensionMapping[$fileExtension] = $iconIdentifier;
692 }
693
694 /**
695 * Register an icon for a mime-type
696 *
697 * @param string $mimeType
698 * @param string $iconIdentifier
699 */
700 public function registerMimeTypeIcon($mimeType, $iconIdentifier)
701 {
702 $this->mimeTypeMapping[$mimeType] = $iconIdentifier;
703 }
704
705 /**
706 * Fetches the configuration provided by registerIcon()
707 *
708 * @param string $identifier the icon identifier
709 * @return mixed
710 * @throws Exception
711 */
712 public function getIconConfigurationByIdentifier($identifier)
713 {
714 if (!$this->fullInitialized) {
715 $this->initialize();
716 }
717 if ($this->isDeprecated($identifier)) {
718 $replacement = $this->deprecatedIcons[$identifier] ?? null;
719 if (!empty($replacement)) {
720 $message = 'The icon "%s" is deprecated since TYPO3 v9 and will be removed in TYPO3 v10. Please use "%s" instead.';
721 $arguments = [$identifier, $replacement];
722 $identifier = $replacement;
723 } else {
724 $message = 'The icon "%s" is deprecated since TYPO3 v9 and will be removed in TYPO3 v10.';
725 $arguments = [$identifier];
726 }
727 trigger_error(vsprintf($message, $arguments), E_USER_DEPRECATED);
728 }
729 if (!$this->isRegistered($identifier)) {
730 throw new Exception('Icon with identifier "' . $identifier . '" is not registered"', 1437425804);
731 }
732 return $this->icons[$identifier];
733 }
734
735 /**
736 * @return array
737 */
738 public function getAllRegisteredIconIdentifiers()
739 {
740 if (!$this->fullInitialized) {
741 $this->initialize();
742 }
743 return array_keys($this->icons);
744 }
745
746 /**
747 * @return array
748 */
749 public function getDeprecatedIcons(): array
750 {
751 return $this->deprecatedIcons;
752 }
753
754 /**
755 * @param string $fileExtension
756 * @return string
757 */
758 public function getIconIdentifierForFileExtension($fileExtension)
759 {
760 // If the file extension is not valid use the default one
761 if (!isset($this->fileExtensionMapping[$fileExtension])) {
762 $fileExtension = 'default';
763 }
764 return $this->fileExtensionMapping[$fileExtension];
765 }
766
767 /**
768 * Get iconIdentifier for given mimeType
769 *
770 * @param string $mimeType
771 * @return string|null Returns null if no icon is registered for the mimeType
772 */
773 public function getIconIdentifierForMimeType($mimeType)
774 {
775 if (!isset($this->mimeTypeMapping[$mimeType])) {
776 return null;
777 }
778 return $this->mimeTypeMapping[$mimeType];
779 }
780
781 /**
782 * Calculates the cache identifier based on the current registry
783 *
784 * @return string
785 * @internal
786 */
787 public function getCacheIdentifier(): string
788 {
789 if (!$this->fullInitialized) {
790 $this->initialize();
791 }
792
793 return sha1(json_encode($this->icons));
794 }
795
796 /**
797 * Load icons from TCA for each table and add them as "tcarecords-XX" to $this->icons
798 */
799 protected function registerTCAIcons()
800 {
801 $resultArray = [];
802
803 $tcaTables = array_keys($GLOBALS['TCA'] ?? []);
804 // check every table in the TCA, if an icon is needed
805 foreach ($tcaTables as $tableName) {
806 // This method is only needed for TCA tables where typeicon_classes are not configured
807 $iconIdentifier = 'tcarecords-' . $tableName . '-default';
808 if (
809 isset($this->icons[$iconIdentifier])
810 || !isset($GLOBALS['TCA'][$tableName]['ctrl']['iconfile'])
811 ) {
812 continue;
813 }
814 $resultArray[$iconIdentifier] = $GLOBALS['TCA'][$tableName]['ctrl']['iconfile'];
815 }
816
817 foreach ($resultArray as $iconIdentifier => $iconFilePath) {
818 $iconProviderClass = $this->detectIconProvider($iconFilePath);
819 $this->icons[$iconIdentifier] = [
820 'provider' => $iconProviderClass,
821 'options' => [
822 'source' => $iconFilePath
823 ]
824 ];
825 }
826 $this->tcaInitialized = true;
827 }
828
829 /**
830 * Register module icons
831 */
832 protected function registerModuleIcons()
833 {
834 $moduleConfiguration = $GLOBALS['TBE_MODULES']['_configuration'];
835 foreach ($moduleConfiguration as $moduleKey => $singleModuleConfiguration) {
836 $iconIdentifier = !empty($singleModuleConfiguration['iconIdentifier'])
837 ? $singleModuleConfiguration['iconIdentifier']
838 : null;
839
840 if ($iconIdentifier !== null) {
841 // iconIdentifier found, icon is registered, continue
842 continue;
843 }
844
845 $iconPath = !empty($singleModuleConfiguration['icon'])
846 ? $singleModuleConfiguration['icon']
847 : null;
848 $iconProviderClass = $this->detectIconProvider($iconPath);
849 $iconIdentifier = 'module-icon-' . $moduleKey;
850
851 $this->icons[$iconIdentifier] = [
852 'provider' => $iconProviderClass,
853 'options' => [
854 'source' => $iconPath
855 ]
856 ];
857 }
858 $this->moduleIconsInitialized = true;
859 }
860
861 /**
862 * Register flags
863 */
864 protected function registerFlags()
865 {
866 $iconFolder = 'EXT:core/Resources/Public/Icons/Flags/';
867 $files = [
868 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ',
869 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ',
870 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CS', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ',
871 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ',
872 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'EU',
873 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR',
874 'GA', 'GB-ENG', 'GB-NIR', 'GB-SCT', 'GB-WLS', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY',
875 'HK', 'HM', 'HN', 'HR', 'HT', 'HU',
876 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT',
877 'JE', 'JM', 'JO', 'JP',
878 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW', 'KY', 'KZ',
879 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY',
880 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ',
881 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ',
882 'OM',
883 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY',
884 'QA', 'QC',
885 'RE', 'RO', 'RS', 'RU', 'RW',
886 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ',
887 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ',
888 'UA', 'UG', 'UM', 'US', 'UY', 'UZ',
889 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU',
890 'WF', 'WS',
891 'YE', 'YT',
892 'ZA', 'ZM', 'ZW',
893 // Special Flags
894 'catalonia',
895 'multiple',
896 'en-us-gb'
897 ];
898 foreach ($files as $file) {
899 $identifier = strtolower($file);
900 $this->icons['flags-' . $identifier] = [
901 'provider' => BitmapIconProvider::class,
902 'options' => [
903 'source' => $iconFolder . $file . '.png'
904 ]
905 ];
906 }
907 $this->flagsInitialized = true;
908 }
909
910 /**
911 * Detect the IconProvider of an icon
912 *
913 * @param string $iconReference
914 * @return string
915 */
916 public function detectIconProvider($iconReference)
917 {
918 if (StringUtility::endsWith(strtolower($iconReference), 'svg')) {
919 return SvgIconProvider::class;
920 }
921 return BitmapIconProvider::class;
922 }
923 }