Completed
Push — master ( abb405...0346f6 )
by
unknown
18:42 queued 02:27
created

ExtensionService::getPluginNamespace()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 2
nop 2
dl 0
loc 12
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
        $frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
92
        // check, whether the current plugin is configured to handle the action
93
        if (!empty($frameworkConfiguration['extensionName']) && $extensionName === $frameworkConfiguration['extensionName']) {
94
            if (isset($frameworkConfiguration['controllerConfiguration'][$controllerName]) && in_array($actionName, $frameworkConfiguration['controllerConfiguration'][$controllerName]['actions'], true)) {
95
                return $frameworkConfiguration['pluginName'];
96
            }
97
        }
98
        $plugins = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'] ?? false;
99
        if (!$plugins) {
100
            return null;
101
        }
102
        $pluginNames = [];
103
        foreach ($plugins as $pluginName => $pluginConfiguration) {
104
            $controllers = $pluginConfiguration['controllers'] ?? [];
105
            $controllerAliases = array_column($controllers, 'actions', 'alias');
106
107
            foreach ($controllerAliases as $pluginControllerName => $pluginControllerActions) {
108
                if (strtolower($pluginControllerName) !== strtolower($controllerName)) {
109
                    continue;
110
                }
111
                if (in_array($actionName, $pluginControllerActions, true)) {
112
                    $pluginNames[] = $pluginName;
113
                }
114
            }
115
        }
116
        if (count($pluginNames) > 1) {
117
            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);
118
        }
119
        return !empty($pluginNames) ? $pluginNames[0] : null;
120
    }
121
122
    /**
123
     * Determines the target page of the specified plugin.
124
     * If plugin.tx_$pluginSignature.view.defaultPid is set, this value is used as target page id
125
     * If defaultPid is set to "auto", a the target pid is determined by loading the tt_content record that contains this plugin
126
     * If the page could not be determined, NULL is returned
127
     * If defaultPid is "auto" and more than one page contains the specified plugin, an Exception is thrown
128
     *
129
     * @param string $extensionName name of the extension to retrieve the target PID for
130
     * @param string $pluginName name of the plugin to retrieve the target PID for
131
     * @throws \TYPO3\CMS\Extbase\Exception
132
     * @return int|null uid of the target page or NULL if target page could not be determined
133
     */
134
    public function getTargetPidByPlugin(string $extensionName, string $pluginName): ?int
135
    {
136
        $frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName, $pluginName);
137
        if (!isset($frameworkConfiguration['view']['defaultPid']) || empty($frameworkConfiguration['view']['defaultPid'])) {
138
            return null;
139
        }
140
        $pluginSignature = strtolower($extensionName . '_' . $pluginName);
141
        if ($frameworkConfiguration['view']['defaultPid'] === 'auto') {
142
            if (!array_key_exists($pluginSignature, $this->targetPidPluginCache)) {
143
                $languageId = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id', 0);
144
                $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
145
                    ->getQueryBuilderForTable('tt_content');
146
                $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
147
148
                $pages = $queryBuilder
149
                    ->select('pid')
150
                    ->from('tt_content')
151
                    ->where(
152
                        $queryBuilder->expr()->eq(
153
                            'list_type',
154
                            $queryBuilder->createNamedParameter($pluginSignature, \PDO::PARAM_STR)
155
                        ),
156
                        $queryBuilder->expr()->eq(
157
                            'CType',
158
                            $queryBuilder->createNamedParameter('list', \PDO::PARAM_STR)
159
                        ),
160
                        $queryBuilder->expr()->eq(
161
                            'sys_language_uid',
162
                            $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
163
                        )
164
                    )
165
                    ->setMaxResults(2)
166
                    ->execute()
167
                    ->fetchAll();
168
169
                if (count($pages) > 1) {
170
                    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);
171
                }
172
                $this->targetPidPluginCache[$pluginSignature] = !empty($pages) ? (int)$pages[0]['pid'] : null;
173
            }
174
            return $this->targetPidPluginCache[$pluginSignature];
175
        }
176
        return (int)$frameworkConfiguration['view']['defaultPid'];
177
    }
178
179
    /**
180
     * This returns the name of the first controller of the given plugin.
181
     *
182
     * @param string $extensionName name of the extension to retrieve the target PID for
183
     * @param string $pluginName name of the plugin to retrieve the target PID for
184
     * @return string|null
185
     */
186
    public function getDefaultControllerNameByPlugin(string $extensionName, string $pluginName): ?string
187
    {
188
        $controllers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'] ?? [];
189
        $controllerAliases = array_column($controllers, 'alias');
190
        $defaultControllerName = (string)($controllerAliases[0] ?? '');
191
        return $defaultControllerName !== '' ? $defaultControllerName : null;
192
    }
193
194
    /**
195
     * This returns the name of the first action of the given plugin controller.
196
     *
197
     * @param string $extensionName name of the extension to retrieve the target PID for
198
     * @param string $pluginName name of the plugin to retrieve the target PID for
199
     * @param string $controllerName name of the controller to retrieve default action for
200
     * @return string|null
201
     */
202
    public function getDefaultActionNameByPluginAndController(string $extensionName, string $pluginName, string $controllerName): ?string
203
    {
204
        $controllers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'] ?? [];
205
        $controllerActionsByAlias = array_column($controllers, 'actions', 'alias');
206
        $actions = $controllerActionsByAlias[$controllerName] ?? [];
207
        $defaultActionName = (string)($actions[0] ?? '');
208
        return $defaultActionName !== '' ? $defaultActionName : null;
209
    }
210
211
    /**
212
     * Resolve the page type number to use for building a link for a specific format
213
     *
214
     * @param string|null $extensionName name of the extension that has defined the target page type
215
     * @param string $format The format for which to look up the page type
216
     * @return int Page type number for target page
217
     */
218
    public function getTargetPageTypeByFormat(?string $extensionName, string $format): int
219
    {
220
        // Default behaviour
221
        $settings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName);
222
        $formatToPageTypeMapping = $settings['view']['formatToPageTypeMapping'] ?? [];
223
        $formatToPageTypeMapping = is_array($formatToPageTypeMapping) ? $formatToPageTypeMapping : [];
224
        return (int)($formatToPageTypeMapping[$format] ?? 0);
225
    }
226
}
227