Completed
Push — master ( 03f531...2f3661 )
by
unknown
17:31
created

ExtensionService::injectConfigurationManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Extbase\Service;
19
20
use TYPO3\CMS\Core\Context\Context;
21
use TYPO3\CMS\Core\Database\ConnectionPool;
22
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
23
use TYPO3\CMS\Core\SingletonInterface;
24
use TYPO3\CMS\Core\Utility\GeneralUtility;
25
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
26
use TYPO3\CMS\Extbase\Exception;
27
28
/**
29
 * Service for determining basic extension params
30
 * @internal only to be used within Extbase, not part of TYPO3 Core API.
31
 */
32
class ExtensionService implements SingletonInterface
33
{
34
    /**
35
     * @var ConfigurationManagerInterface
36
     */
37
    protected $configurationManager;
38
39
    /**
40
     * Cache of result for getTargetPidByPlugin()
41
     * @var array
42
     */
43
    protected $targetPidPluginCache = [];
44
45
    /**
46
     * @param ConfigurationManagerInterface $configurationManager
47
     */
48
    public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager): void
49
    {
50
        $this->configurationManager = $configurationManager;
51
    }
52
53
    /**
54
     * Determines the plugin namespace of the specified plugin (defaults to "tx_[extensionname]_[pluginname]")
55
     * If plugin.tx_$pluginSignature.view.pluginNamespace is set, this value is returned
56
     * If pluginNamespace is not specified "tx_[extensionname]_[pluginname]" is returned.
57
     *
58
     * @param string|null $extensionName name of the extension to retrieve the namespace for
59
     * @param string|null $pluginName name of the plugin to retrieve the namespace for
60
     * @return string plugin namespace
61
     */
62
    public function getPluginNamespace(?string $extensionName, ?string $pluginName): string
63
    {
64
        // todo: with $extensionName and $pluginName being null, tx__ will be returned here which is questionable.
65
        // todo: find out, if and why this case could happen and maybe avoid this methods being called with null
66
        // todo: arguments afterwards.
67
        $pluginSignature = strtolower($extensionName . '_' . $pluginName);
68
        $defaultPluginNamespace = 'tx_' . $pluginSignature;
69
        $frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
70
        if (!isset($frameworkConfiguration['view']['pluginNamespace']) || empty($frameworkConfiguration['view']['pluginNamespace'])) {
71
            return $defaultPluginNamespace;
72
        }
73
        return $frameworkConfiguration['view']['pluginNamespace'];
74
    }
75
76
    /**
77
     * Iterates through the global TypoScript configuration and returns the name of the plugin
78
     * that matches specified extensionName, controllerName and actionName.
79
     * If no matching plugin was found, NULL is returned.
80
     * If more than one plugin matches and the current plugin is not configured to handle the action,
81
     * an Exception will be thrown
82
     *
83
     * @param string $extensionName name of the target extension (UpperCamelCase)
84
     * @param string $controllerName name of the target controller (UpperCamelCase)
85
     * @param string|null $actionName name of the target action (lowerCamelCase)
86
     * @throws \TYPO3\CMS\Extbase\Exception
87
     * @return string|null name of the target plugin (UpperCamelCase) or NULL if no matching plugin configuration was found
88
     */
89
    public function getPluginNameByAction(string $extensionName, string $controllerName, ?string $actionName): ?string
90
    {
91
        // check, whether the current plugin is configured to handle the action
92
        if (($pluginName = $this->getPluginNameFromFrameworkConfiguration($extensionName, $controllerName, $actionName)) !== null) {
93
            return $pluginName;
94
        }
95
96
        $plugins = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'] ?? false;
97
        if (!$plugins) {
98
            return null;
99
        }
100
        $pluginNames = [];
101
        foreach ($plugins as $pluginName => $pluginConfiguration) {
102
            $controllers = $pluginConfiguration['controllers'] ?? [];
103
            $controllerAliases = array_column($controllers, 'actions', 'alias');
104
105
            foreach ($controllerAliases as $pluginControllerName => $pluginControllerActions) {
106
                if (strtolower($pluginControllerName) !== strtolower($controllerName)) {
107
                    continue;
108
                }
109
                if (in_array($actionName, $pluginControllerActions, true)) {
110
                    $pluginNames[] = $pluginName;
111
                }
112
            }
113
        }
114
        if (count($pluginNames) > 1) {
115
            throw new Exception('There is more than one plugin that can handle this request (Extension: "' . $extensionName . '", Controller: "' . $controllerName . '", action: "' . $actionName . '"). Please specify "pluginName" argument', 1280825466);
116
        }
117
        return !empty($pluginNames) ? $pluginNames[0] : null;
118
    }
119
120
    private function getPluginNameFromFrameworkConfiguration(string $extensionName, string $controllerAlias, ?string $actionName): ?string
121
    {
122
        if ($actionName === null) {
123
            return null;
124
        }
125
126
        $frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
127
128
        if (!is_string($pluginName = ($frameworkConfiguration['pluginName'] ?? null))) {
129
            return null;
130
        }
131
132
        $configuredExtensionName = $frameworkConfiguration['extensionName'] ?? '';
133
        $configuredExtensionName = is_string($configuredExtensionName) ? $configuredExtensionName : '';
134
135
        if ($configuredExtensionName === '' || $configuredExtensionName !== $extensionName) {
136
            return null;
137
        }
138
139
        $configuredControllers = $frameworkConfiguration['controllerConfiguration'] ?? [];
140
        $configuredControllers = is_array($configuredControllers) ? $configuredControllers : [];
141
142
        $configuredActionsByControllerAliases = array_column($configuredControllers, 'actions', 'alias');
143
144
        $actions = $configuredActionsByControllerAliases[$controllerAlias] ?? [];
145
        $actions = is_array($actions) ? $actions : [];
146
147
        return in_array($actionName, $actions, true) ? $pluginName : null;
148
    }
149
150
    /**
151
     * Determines the target page of the specified plugin.
152
     * If plugin.tx_$pluginSignature.view.defaultPid is set, this value is used as target page id
153
     * If defaultPid is set to "auto", a the target pid is determined by loading the tt_content record that contains this plugin
154
     * If the page could not be determined, NULL is returned
155
     * If defaultPid is "auto" and more than one page contains the specified plugin, an Exception is thrown
156
     *
157
     * @param string $extensionName name of the extension to retrieve the target PID for
158
     * @param string $pluginName name of the plugin to retrieve the target PID for
159
     * @throws \TYPO3\CMS\Extbase\Exception
160
     * @return int|null uid of the target page or NULL if target page could not be determined
161
     */
162
    public function getTargetPidByPlugin(string $extensionName, string $pluginName): ?int
163
    {
164
        $frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
165
        if (!isset($frameworkConfiguration['view']['defaultPid']) || empty($frameworkConfiguration['view']['defaultPid'])) {
166
            return null;
167
        }
168
        $pluginSignature = strtolower($extensionName . '_' . $pluginName);
169
        if ($frameworkConfiguration['view']['defaultPid'] === 'auto') {
170
            if (!array_key_exists($pluginSignature, $this->targetPidPluginCache)) {
171
                $languageId = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id', 0);
172
                $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
173
                    ->getQueryBuilderForTable('tt_content');
174
                $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
175
176
                $pages = $queryBuilder
177
                    ->select('pid')
178
                    ->from('tt_content')
179
                    ->where(
180
                        $queryBuilder->expr()->eq(
181
                            'list_type',
182
                            $queryBuilder->createNamedParameter($pluginSignature, \PDO::PARAM_STR)
183
                        ),
184
                        $queryBuilder->expr()->eq(
185
                            'CType',
186
                            $queryBuilder->createNamedParameter('list', \PDO::PARAM_STR)
187
                        ),
188
                        $queryBuilder->expr()->eq(
189
                            'sys_language_uid',
190
                            $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
191
                        )
192
                    )
193
                    ->setMaxResults(2)
194
                    ->execute()
195
                    ->fetchAll();
196
197
                if (count($pages) > 1) {
198
                    throw new 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);
199
                }
200
                $this->targetPidPluginCache[$pluginSignature] = !empty($pages) ? (int)$pages[0]['pid'] : null;
201
            }
202
            return $this->targetPidPluginCache[$pluginSignature];
203
        }
204
        return (int)$frameworkConfiguration['view']['defaultPid'];
205
    }
206
207
    /**
208
     * This returns the name of the first controller of the given plugin.
209
     *
210
     * @param string $extensionName name of the extension to retrieve the target PID for
211
     * @param string $pluginName name of the plugin to retrieve the target PID for
212
     * @return string|null
213
     */
214
    public function getDefaultControllerNameByPlugin(string $extensionName, string $pluginName): ?string
215
    {
216
        $controllers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'] ?? [];
217
        $controllerAliases = array_column($controllers, 'alias');
218
        $defaultControllerName = (string)($controllerAliases[0] ?? '');
219
        return $defaultControllerName !== '' ? $defaultControllerName : null;
220
    }
221
222
    /**
223
     * This returns the name of the first action of the given plugin controller.
224
     *
225
     * @param string $extensionName name of the extension to retrieve the target PID for
226
     * @param string $pluginName name of the plugin to retrieve the target PID for
227
     * @param string $controllerName name of the controller to retrieve default action for
228
     * @return string|null
229
     */
230
    public function getDefaultActionNameByPluginAndController(string $extensionName, string $pluginName, string $controllerName): ?string
231
    {
232
        $controllers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'] ?? [];
233
        $controllerActionsByAlias = array_column($controllers, 'actions', 'alias');
234
        $actions = $controllerActionsByAlias[$controllerName] ?? [];
235
        $defaultActionName = (string)($actions[0] ?? '');
236
        return $defaultActionName !== '' ? $defaultActionName : null;
237
    }
238
239
    /**
240
     * Resolve the page type number to use for building a link for a specific format
241
     *
242
     * @param string|null $extensionName name of the extension that has defined the target page type
243
     * @param string $format The format for which to look up the page type
244
     * @return int Page type number for target page
245
     */
246
    public function getTargetPageTypeByFormat(?string $extensionName, string $format): int
247
    {
248
        // Default behaviour
249
        $settings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName);
250
        $formatToPageTypeMapping = $settings['view']['formatToPageTypeMapping'] ?? [];
251
        $formatToPageTypeMapping = is_array($formatToPageTypeMapping) ? $formatToPageTypeMapping : [];
252
        return (int)($formatToPageTypeMapping[$format] ?? 0);
253
    }
254
}
255