888ea3c2a433c93879d395016d994f74b51dab4a
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Service / ExtensionService.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Service;
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 TYPO3\CMS\Core\Database\ConnectionPool;
18 use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * Service for determining basic extension params
23 */
24 class ExtensionService implements \TYPO3\CMS\Core\SingletonInterface
25 {
26 const PLUGIN_TYPE_PLUGIN = 'list_type';
27 const PLUGIN_TYPE_CONTENT_ELEMENT = 'CType';
28
29 /**
30 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
31 */
32 protected $objectManager;
33
34 /**
35 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
36 */
37 protected $configurationManager;
38
39 /**
40 * Cache of result for getTargetPidByPlugin()
41 * @var array
42 */
43 protected $targetPidPluginCache = [];
44
45 /**
46 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
47 */
48 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
49 {
50 $this->objectManager = $objectManager;
51 }
52
53 /**
54 * @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
55 */
56 public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
57 {
58 $this->configurationManager = $configurationManager;
59 }
60
61 /**
62 * Determines the plugin namespace of the specified plugin (defaults to "tx_[extensionname]_[pluginname]")
63 * If plugin.tx_$pluginSignature.view.pluginNamespace is set, this value is returned
64 * If pluginNamespace is not specified "tx_[extensionname]_[pluginname]" is returned.
65 *
66 * @param string $extensionName name of the extension to retrieve the namespace for
67 * @param string $pluginName name of the plugin to retrieve the namespace for
68 * @return string plugin namespace
69 */
70 public function getPluginNamespace($extensionName, $pluginName)
71 {
72 $pluginSignature = strtolower($extensionName . '_' . $pluginName);
73 $defaultPluginNamespace = 'tx_' . $pluginSignature;
74 $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
75 if (!isset($frameworkConfiguration['view']['pluginNamespace']) || empty($frameworkConfiguration['view']['pluginNamespace'])) {
76 return $defaultPluginNamespace;
77 }
78 return $frameworkConfiguration['view']['pluginNamespace'];
79 }
80
81 /**
82 * Iterates through the global TypoScript configuration and returns the name of the plugin
83 * that matches specified extensionName, controllerName and actionName.
84 * If no matching plugin was found, NULL is returned.
85 * If more than one plugin matches and the current plugin is not configured to handle the action,
86 * an Exception will be thrown
87 *
88 * @param string $extensionName name of the target extension (UpperCamelCase)
89 * @param string $controllerName name of the target controller (UpperCamelCase)
90 * @param string $actionName name of the target action (lowerCamelCase)
91 * @throws \TYPO3\CMS\Extbase\Exception
92 * @return string name of the target plugin (UpperCamelCase) or NULL if no matching plugin configuration was found
93 */
94 public function getPluginNameByAction($extensionName, $controllerName, $actionName)
95 {
96 $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
97 // check, whether the current plugin is configured to handle the action
98 if ($extensionName === $frameworkConfiguration['extensionName']) {
99 if (isset($frameworkConfiguration['controllerConfiguration'][$controllerName]) && in_array($actionName, $frameworkConfiguration['controllerConfiguration'][$controllerName]['actions'])) {
100 return $frameworkConfiguration['pluginName'];
101 }
102 }
103 $plugins = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'] ?? false;
104 if (!$plugins) {
105 return null;
106 }
107 $pluginNames = [];
108 foreach ($plugins as $pluginName => $pluginConfiguration) {
109 foreach ($pluginConfiguration['controllers'] ?? [] as $pluginControllerName => $pluginControllerActions) {
110 if (strtolower($pluginControllerName) !== strtolower($controllerName)) {
111 continue;
112 }
113 if (in_array($actionName, $pluginControllerActions['actions'])) {
114 $pluginNames[] = $pluginName;
115 }
116 }
117 }
118 if (count($pluginNames) > 1) {
119 throw new \TYPO3\CMS\Extbase\Exception('There is more than one plugin that can handle this request (Extension: "' . $extensionName . '", Controller: "' . $controllerName . '", action: "' . $actionName . '"). Please specify "pluginName" argument', 1280825466);
120 }
121 return !empty($pluginNames) ? $pluginNames[0] : null;
122 }
123
124 /**
125 * Checks if the given action is cacheable or not.
126 *
127 * @param string $extensionName Name of the target extension, without underscores
128 * @param string $pluginName Name of the target plugin
129 * @param string $controllerName Name of the target controller
130 * @param string $actionName Name of the action to be called
131 * @return bool TRUE if the specified plugin action is cacheable, otherwise FALSE
132 */
133 public function isActionCacheable($extensionName, $pluginName, $controllerName, $actionName)
134 {
135 $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
136 if (isset($frameworkConfiguration['controllerConfiguration'][$controllerName]) && is_array($frameworkConfiguration['controllerConfiguration'][$controllerName]) && is_array($frameworkConfiguration['controllerConfiguration'][$controllerName]['nonCacheableActions']) && in_array($actionName, $frameworkConfiguration['controllerConfiguration'][$controllerName]['nonCacheableActions'])) {
137 return false;
138 }
139 return true;
140 }
141
142 /**
143 * Determines the target page of the specified plugin.
144 * If plugin.tx_$pluginSignature.view.defaultPid is set, this value is used as target page id
145 * If defaultPid is set to "auto", a the target pid is determined by loading the tt_content record that contains this plugin
146 * If the page could not be determined, NULL is returned
147 * If defaultPid is "auto" and more than one page contains the specified plugin, an Exception is thrown
148 *
149 * @param string $extensionName name of the extension to retrieve the target PID for
150 * @param string $pluginName name of the plugin to retrieve the target PID for
151 * @throws \TYPO3\CMS\Extbase\Exception
152 * @return int uid of the target page or NULL if target page could not be determined
153 */
154 public function getTargetPidByPlugin($extensionName, $pluginName)
155 {
156 $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
157 if (!isset($frameworkConfiguration['view']['defaultPid']) || empty($frameworkConfiguration['view']['defaultPid'])) {
158 return null;
159 }
160 $pluginSignature = strtolower($extensionName . '_' . $pluginName);
161 if ($frameworkConfiguration['view']['defaultPid'] === 'auto') {
162 if (!array_key_exists($pluginSignature, $this->targetPidPluginCache)) {
163 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
164 ->getQueryBuilderForTable('tt_content');
165 $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
166
167 $pages = $queryBuilder
168 ->select('pid')
169 ->from('tt_content')
170 ->where(
171 $queryBuilder->expr()->eq(
172 'list_type',
173 $queryBuilder->createNamedParameter($pluginSignature, \PDO::PARAM_STR)
174 ),
175 $queryBuilder->expr()->eq(
176 'CType',
177 $queryBuilder->createNamedParameter('list', \PDO::PARAM_STR)
178 ),
179 $queryBuilder->expr()->eq(
180 'sys_language_uid',
181 $queryBuilder->createNamedParameter($GLOBALS['TSFE']->sys_language_uid, \PDO::PARAM_INT)
182 )
183 )
184 ->setMaxResults(2)
185 ->execute()
186 ->fetchAll();
187
188 if (count($pages) > 1) {
189 throw new \TYPO3\CMS\Extbase\Exception('There is more than one "' . $pluginSignature . '" plugin in the current page tree. Please remove one plugin or set the TypoScript configuration "plugin.tx_' . $pluginSignature . '.view.defaultPid" to a fixed page id', 1280773643);
190 }
191 $this->targetPidPluginCache[$pluginSignature] = !empty($pages) ? $pages[0]['pid'] : null;
192 }
193 return $this->targetPidPluginCache[$pluginSignature];
194 }
195 return (int)$frameworkConfiguration['view']['defaultPid'];
196 }
197
198 /**
199 * This returns the name of the first controller of the given plugin.
200 *
201 * @param string $extensionName name of the extension to retrieve the target PID for
202 * @param string $pluginName name of the plugin to retrieve the target PID for
203 * @return string|null
204 */
205 public function getDefaultControllerNameByPlugin($extensionName, $pluginName)
206 {
207 $controllers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'] ?? false;
208 return $controllers ? key($controllers) : null;
209 }
210
211 /**
212 * This returns the name of the first action of the given plugin controller.
213 *
214 * @param string $extensionName name of the extension to retrieve the target PID for
215 * @param string $pluginName name of the plugin to retrieve the target PID for
216 * @param string $controllerName name of the controller to retrieve default action for
217 * @return string|null
218 */
219 public function getDefaultActionNameByPluginAndController($extensionName, $pluginName, $controllerName)
220 {
221 $actions = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName]['actions'] ?? false;
222 return $actions ? current($actions) : null;
223 }
224
225 /**
226 * Resolve the page type number to use for building a link for a specific format
227 *
228 * @param string $extensionName name of the extension that has defined the target page type
229 * @param string $format The format for which to look up the page type
230 * @return int Page type number for target page
231 */
232 public function getTargetPageTypeByFormat($extensionName, $format)
233 {
234 $settings = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, $extensionName);
235 return $settings['view']['formatToPageTypeMapping'][$format] ?? 0;
236 }
237 }