2 namespace TYPO3\CMS\Backend\Domain\Repository\Module
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Backend\Utility\BackendUtility
;
18 use TYPO3\CMS\Core\Imaging\Icon
;
19 use TYPO3\CMS\Core\Imaging\IconFactory
;
20 use TYPO3\CMS\Core\Utility\GeneralUtility
;
23 * Repository for backend module menu
24 * compiles all data from $GLOBALS[TBE_MODULES]
26 class BackendModuleRepository
implements \TYPO3\CMS\Core\SingletonInterface
29 * @var \TYPO3\CMS\Backend\Module\ModuleStorage
31 protected $moduleStorage;
34 * Constructs the module menu and gets the Singleton instance of the menu
36 public function __construct()
38 $this->moduleStorage
= GeneralUtility
::makeInstance(\TYPO3\CMS\Backend\Module\ModuleStorage
::class);
40 $rawData = $this->getRawModuleMenuData();
42 $this->convertRawModuleDataToModuleMenuObject($rawData);
43 $this->createMenuEntriesForTbeModulesExt();
47 * loads all module information in the module storage
49 * @param array $excludeGroupNames
50 * @return \SplObjectStorage
52 public function loadAllowedModules(array $excludeGroupNames = array())
54 if (empty($excludeGroupNames)) {
55 return $this->moduleStorage
->getEntries();
58 $modules = new \
SplObjectStorage();
59 foreach ($this->moduleStorage
->getEntries() as $moduleGroup) {
60 if (!in_array($moduleGroup->getName(), $excludeGroupNames, true)) {
61 if ($moduleGroup->getChildren()->count() > 0) {
62 $modules->attach($moduleGroup);
71 * @param string $groupName
72 * @return \SplObjectStorage|FALSE
74 public function findByGroupName($groupName = '')
76 foreach ($this->moduleStorage
->getEntries() as $moduleGroup) {
77 if ($moduleGroup->getName() === $groupName) {
86 * Finds a module menu entry by name
89 * @return \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule|bool
91 public function findByModuleName($name)
93 $entries = $this->moduleStorage
->getEntries();
94 $entry = $this->findByModuleNameInGivenEntries($name, $entries);
99 * Finds a module menu entry by name in a given storage
101 * @param string $name
102 * @param \SplObjectStorage $entries
103 * @return \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule|bool
105 public function findByModuleNameInGivenEntries($name, \SplObjectStorage
$entries)
107 foreach ($entries as $entry) {
108 if ($entry->getName() === $name) {
111 $children = $entry->getChildren();
112 if (!empty($children)) {
113 $childRecord = $this->findByModuleNameInGivenEntries($name, $children);
114 if ($childRecord !== false) {
123 * Creates the module menu object structure from the raw data array
125 * @param array $rawModuleData
128 protected function convertRawModuleDataToModuleMenuObject(array $rawModuleData)
130 foreach ($rawModuleData as $module) {
131 $entry = $this->createEntryFromRawData($module);
132 if (isset($module['subitems']) && !empty($module['subitems'])) {
133 foreach ($module['subitems'] as $subitem) {
134 $subEntry = $this->createEntryFromRawData($subitem);
135 $entry->addChild($subEntry);
138 $this->moduleStorage
->attachEntry($entry);
143 * Creates a menu entry object from an array
145 * @param array $module
146 * @return \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule
148 protected function createEntryFromRawData(array $module)
150 /** @var $entry \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule */
151 $entry = \TYPO3\CMS\Core\Utility\GeneralUtility
::makeInstance(\TYPO3\CMS\Backend\Domain\Model\Module\BackendModule
::class);
152 if (!empty($module['name']) && is_string($module['name'])) {
153 $entry->setName($module['name']);
155 if (!empty($module['title']) && is_string($module['title'])) {
156 $entry->setTitle($this->getLanguageService()->sL($module['title']));
158 if (!empty($module['onclick']) && is_string($module['onclick'])) {
159 $entry->setOnClick($module['onclick']);
161 if (!empty($module['link']) && is_string($module['link'])) {
162 $entry->setLink($module['link']);
163 } elseif (empty($module['link']) && !empty($module['path']) && is_string($module['path'])) {
164 $entry->setLink($module['path']);
166 if (!empty($module['description']) && is_string($module['description'])) {
167 $entry->setDescription($module['description']);
169 if (!empty($module['icon'])) {
170 $entry->setIcon($module['icon']);
172 if (!empty($module['navigationComponentId']) && is_string($module['navigationComponentId'])) {
173 $entry->setNavigationComponentId($module['navigationComponentId']);
175 if (!empty($module['navigationFrameScript']) && is_string($module['navigationFrameScript'])) {
176 $entry->setNavigationFrameScript($module['navigationFrameScript']);
177 } elseif (!empty($module['parentNavigationFrameScript']) && is_string($module['parentNavigationFrameScript'])) {
178 $entry->setNavigationFrameScript($module['parentNavigationFrameScript']);
180 if (!empty($module['navigationFrameScriptParam']) && is_string($module['navigationFrameScriptParam'])) {
181 $entry->setNavigationFrameScriptParameters($module['navigationFrameScriptParam']);
187 * Creates the "third level" menu entries (submodules for the info module for
188 * example) from the TBE_MODULES_EXT array
192 protected function createMenuEntriesForTbeModulesExt()
194 foreach ($GLOBALS['TBE_MODULES_EXT'] as $mainModule => $tbeModuleExt) {
195 list($main) = explode('_', $mainModule);
196 $mainEntry = $this->findByModuleName($main);
197 if ($mainEntry === false) {
201 $subEntries = $mainEntry->getChildren();
202 if (empty($subEntries)) {
205 $matchingSubEntry = $this->findByModuleName($mainModule);
206 if ($matchingSubEntry !== false) {
207 if (isset($tbeModuleExt['MOD_MENU']) && isset($tbeModuleExt['MOD_MENU']['function'])) {
208 foreach ($tbeModuleExt['MOD_MENU']['function'] as $subModule) {
209 $entry = $this->createEntryFromRawData($subModule);
210 $matchingSubEntry->addChild($entry);
218 * Return language service instance
220 * @return \TYPO3\CMS\Lang\LanguageService
222 protected function getLanguageService()
224 return $GLOBALS['LANG'];
228 * loads the module menu from the moduleloader based on $GLOBALS['TBE_MODULES']
229 * and compiles an array with all the data needed for menu etc.
233 public function getRawModuleMenuData()
235 // Loads the backend modules available for the logged in user.
236 $moduleLoader = GeneralUtility
::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader
::class);
237 $moduleLoader->observeWorkspaces
= true;
238 $moduleLoader->load($GLOBALS['TBE_MODULES']);
239 $loadedModules = $moduleLoader->modules
;
243 // Unset modules that are meant to be hidden from the menu.
244 $loadedModules = $this->removeHiddenModules($loadedModules);
245 $dummyScript = BackendUtility
::getModuleUrl('dummy');
246 foreach ($loadedModules as $moduleName => $moduleData) {
248 if (!is_array($moduleData['sub'])) {
249 $moduleLink = $moduleData['script'];
251 $moduleLink = GeneralUtility
::resolveBackPath($moduleLink);
252 $moduleKey = 'modmenu_' . $moduleName;
253 $modules[$moduleKey] = array(
254 'name' => $moduleName,
255 'title' => $GLOBALS['LANG']->moduleLabels
['tabs'][$moduleName . '_tab'],
256 'onclick' => 'top.goToModule(' . GeneralUtility
::quoteJSvalue($moduleName) . ');',
257 'icon' => $this->getModuleIcon($moduleName . '_tab', $moduleData),
258 'link' => $moduleLink,
259 'description' => $GLOBALS['LANG']->moduleLabels
['labels'][$moduleKey . 'label']
261 if (!is_array($moduleData['sub']) && $moduleData['script'] !== $dummyScript) {
262 // Work around for modules with own main entry, but being self the only submodule
263 $modules[$moduleKey]['subitems'][$moduleKey] = array(
264 'name' => $moduleName,
265 'title' => $GLOBALS['LANG']->moduleLabels
['tabs'][$moduleName . '_tab'],
266 'onclick' => 'top.goToModule(' . GeneralUtility
::quoteJSvalue($moduleName) . ');',
267 'icon' => $this->getModuleIcon($moduleName . '_tab', $moduleData),
268 'link' => $moduleLink,
269 'originalLink' => $moduleLink,
270 'description' => $GLOBALS['LANG']->moduleLabels
['labels'][$moduleKey . 'label'],
271 'navigationFrameScript' => null,
272 'navigationFrameScriptParam' => null,
273 'navigationComponentId' => null
275 } elseif (is_array($moduleData['sub'])) {
276 foreach ($moduleData['sub'] as $submoduleName => $submoduleData) {
277 if (isset($submoduleData['script'])) {
278 $submoduleLink = GeneralUtility
::resolveBackPath($submoduleData['script']);
280 $submoduleLink = BackendUtility
::getModuleUrl($submoduleData['name']);
282 $submoduleKey = $moduleName . '_' . $submoduleName . '_tab';
283 $submoduleDescription = $GLOBALS['LANG']->moduleLabels
['labels'][$submoduleKey . 'label'];
284 $originalLink = $submoduleLink;
285 $navigationFrameScript = $submoduleData['navFrameScript'];
286 $modules[$moduleKey]['subitems'][$submoduleKey] = array(
287 'name' => $moduleName . '_' . $submoduleName,
288 'title' => $GLOBALS['LANG']->moduleLabels
['tabs'][$submoduleKey],
289 'onclick' => 'top.goToModule(' . GeneralUtility
::quoteJSvalue($moduleName . '_' . $submoduleName) . ');',
290 'icon' => $this->getModuleIcon($submoduleKey, $submoduleData),
291 'link' => $submoduleLink,
292 'originalLink' => $originalLink,
293 'description' => $submoduleDescription,
294 'navigationFrameScript' => $navigationFrameScript,
295 'navigationFrameScriptParam' => $submoduleData['navFrameScriptParam'],
296 'navigationComponentId' => $submoduleData['navigationComponentId']
298 // if the main module has a navframe script, inherit to the submodule,
299 // but only if it is not disabled explicitly (option is set to FALSE)
300 if ($moduleData['navFrameScript'] && $submoduleData['inheritNavigationComponentFromMainModule'] !== false) {
301 $modules[$moduleKey]['subitems'][$submoduleKey]['parentNavigationFrameScript'] = $moduleData['navFrameScript'];
310 * Reads User configuration from options.hideModules and removes
311 * modules accordingly.
313 * @param array $loadedModules
316 protected function removeHiddenModules($loadedModules)
318 $hiddenModules = $GLOBALS['BE_USER']->getTSConfig('options.hideModules');
320 // Hide modules if set in userTS.
321 if (!empty($hiddenModules['value'])) {
322 $hiddenMainModules = explode(',', $hiddenModules['value']);
323 foreach ($hiddenMainModules as $hiddenMainModule) {
324 unset($loadedModules[trim($hiddenMainModule)]);
328 // Hide sub-modules if set in userTS.
329 if (!empty($hiddenModules['properties']) && is_array($hiddenModules['properties'])) {
330 foreach ($hiddenModules['properties'] as $mainModuleName => $subModules) {
331 $hiddenSubModules = explode(',', $subModules);
332 foreach ($hiddenSubModules as $hiddenSubModule) {
333 unset($loadedModules[$mainModuleName]['sub'][trim($hiddenSubModule)]);
338 return $loadedModules;
342 * gets the module icon and its size
344 * @param string $moduleKey Module key
345 * @param array $moduleData the compiled data associated with it
346 * @return string Icon data, either sprite or <img> tag
348 protected function getModuleIcon($moduleKey, $moduleData)
352 // add as a sprite icon
353 if (!empty($moduleData['iconIdentifier'])) {
354 $iconFactory = GeneralUtility
::makeInstance(IconFactory
::class);
355 $icon = $iconFactory->getIcon($moduleData['iconIdentifier'])->render();
356 } elseif (!empty($GLOBALS['LANG']->moduleLabels
['tabs_images'][$moduleKey])) {
357 $imageReference = $GLOBALS['LANG']->moduleLabels
['tabs_images'][$moduleKey];
358 $iconFileRelative = $this->getModuleIconRelative($imageReference);
359 if (!empty($iconFileRelative)) {
360 $iconTitle = $GLOBALS['LANG']->moduleLabels
['tabs'][$moduleKey];
361 $iconSizes = @getimagesize
($this->getModuleIconAbsolute($imageReference));
362 $icon = '<img src="' . $iconFileRelative . '" ' . $iconSizes[3] . ' title="' . htmlspecialchars($iconTitle) . '" alt="' . htmlspecialchars($iconTitle) . '" />';
369 * Returns the filename readable for the script from PATH_typo3.
370 * That means absolute names are just returned while relative names are
371 * prepended with the path pointing back to typo3/ dir
373 * @param string $iconFilename Icon filename
374 * @return string Icon filename with absolute path
375 * @see getModuleIconRelative()
377 protected function getModuleIconAbsolute($iconFilename)
379 if (!GeneralUtility
::isAbsPath($iconFilename)) {
380 $iconFilename = PATH_typo3
. $iconFilename;
382 return $iconFilename;
386 * Returns relative path to the icon filename for use in img-tags
388 * @param string $iconFilename Icon filename
389 * @return string Icon filename with relative path
390 * @see getModuleIconAbsolute()
392 protected function getModuleIconRelative($iconFilename)
394 if (GeneralUtility
::isAbsPath($iconFilename)) {
395 $iconFilename = '../' . \TYPO3\CMS\Core\Utility\PathUtility
::stripPathSitePrefix($iconFilename);
397 return $iconFilename;