[TASK] Deprecate BaseScriptClass and AbstractFunctionModule
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Module / BaseScriptClass.php
1 <?php
2 namespace TYPO3\CMS\Backend\Module;
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\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Localization\LanguageService;
20 use TYPO3\CMS\Core\Messaging\FlashMessage;
21 use TYPO3\CMS\Core\Messaging\FlashMessageService;
22 use TYPO3\CMS\Core\Page\PageRenderer;
23 use TYPO3\CMS\Core\Type\Bitmask\Permission;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26 /**
27 * Parent class for 'ScriptClasses' in backend modules.
28 *
29 * EXAMPLE PROTOTYPE
30 *
31 * As for examples there are lots of them if you search for classes which extends \TYPO3\CMS\Backend\Module\BaseScriptClass
32 * However you can see a prototype example of how a module might use this class in an index.php file typically hosting a backend module.
33 *
34 * NOTICE: This example only outlines the basic structure of how this class is used.
35 * You should consult the documentation and other real-world examples for some actual things to do when building modules.
36 *
37 * TYPICAL SETUP OF A BACKEND MODULE:
38 *
39 * PrototypeController EXTENDS THE CLASS \TYPO3\CMS\Backend\Module\BaseScriptClass with a main() function:
40 *
41 * namespace Vendor\Prototype\Controller;
42 *
43 * class PrototypeController extends \TYPO3\CMS\Backend\Module\BaseScriptClass {
44 * public function __construct() {
45 * $this->getLanguageService()->includeLLFile('EXT:prototype/Resources/Private/Language/locallang.xlf');
46 * $this->getBackendUser()->modAccess($GLOBALS['MCONF'], TRUE);
47 * }
48 * }
49 *
50 * MAIN FUNCTION - HERE YOU CREATE THE MODULE CONTENT IN $this->content
51 * public function main() {
52 * TYPICALLY THE INTERNAL VAR, $this->doc is instantiated like this:
53 * $this->doc = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
54 * ... AND OF COURSE A LOT OF OTHER THINGS GOES ON - LIKE PUTTING CONTENT INTO $this->content
55 * $this->content='';
56 * }
57 *
58 * MAKE INSTANCE OF THE SCRIPT CLASS AND CALL init()
59 * $GLOBALS['SOBE'] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\Vendor\Prototype\Controller\PrototypeController::class);
60 * $GLOBALS['SOBE']->init();
61 *
62 *
63 * THEN WE WILL CHECK IF THERE IS A 'SUBMODULE' REGISTERED TO BE INITIALIZED AS WELL:
64 * $GLOBALS['SOBE']->checkExtObj();
65 *
66 * THEN WE CALL THE main() METHOD AND THIS SHOULD SPARK THE CREATION OF THE MODULE OUTPUT.
67 * $GLOBALS['SOBE']->main();
68 *
69 * @deprecated since v9, will be removed in v10
70 */
71 class BaseScriptClass
72 {
73 /**
74 * Loaded with the global array $MCONF which holds some module configuration from the conf.php file of backend modules.
75 *
76 * @see init()
77 * @var array
78 */
79 public $MCONF = [];
80
81 /**
82 * The integer value of the GET/POST var, 'id'. Used for submodules to the 'Web' module (page id)
83 *
84 * @see init()
85 * @var int
86 */
87 public $id;
88
89 /**
90 * The value of GET/POST var, 'CMD'
91 *
92 * @see init()
93 * @var mixed
94 */
95 public $CMD;
96
97 /**
98 * A WHERE clause for selection records from the pages table based on read-permissions of the current backend user.
99 *
100 * @see init()
101 * @var string
102 */
103 public $perms_clause;
104
105 /**
106 * The module menu items array. Each key represents a key for which values can range between the items in the array of that key.
107 *
108 * @see init()
109 * @var array
110 */
111 public $MOD_MENU = [
112 'function' => []
113 ];
114
115 /**
116 * Current settings for the keys of the MOD_MENU array
117 *
118 * @see $MOD_MENU
119 * @var array
120 */
121 public $MOD_SETTINGS = [];
122
123 /**
124 * Module TSconfig based on PAGE TSconfig / USER TSconfig
125 *
126 * @see menuConfig()
127 * @var array
128 */
129 public $modTSconfig;
130
131 /**
132 * If type is 'ses' then the data is stored as session-lasting data. This means that it'll be wiped out the next time the user logs in.
133 * Can be set from extension classes of this class before the init() function is called.
134 *
135 * @see menuConfig(), \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()
136 * @var string
137 */
138 public $modMenu_type = '';
139
140 /**
141 * dontValidateList can be used to list variables that should not be checked if their value is found in the MOD_MENU array. Used for dynamically generated menus.
142 * Can be set from extension classes of this class before the init() function is called.
143 *
144 * @see menuConfig(), \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()
145 * @var string
146 */
147 public $modMenu_dontValidateList = '';
148
149 /**
150 * List of default values from $MOD_MENU to set in the output array (only if the values from MOD_MENU are not arrays)
151 * Can be set from extension classes of this class before the init() function is called.
152 *
153 * @see menuConfig(), \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()
154 * @var string
155 */
156 public $modMenu_setDefaultList = '';
157
158 /**
159 * Contains module configuration parts from TBE_MODULES_EXT if found
160 *
161 * @see handleExternalFunctionValue()
162 * @var array
163 */
164 public $extClassConf;
165
166 /**
167 * Generally used for accumulating the output content of backend modules
168 *
169 * @var string
170 */
171 public $content = '';
172
173 /**
174 * @var \TYPO3\CMS\Backend\Template\DocumentTemplate
175 */
176 public $doc;
177
178 /**
179 * May contain an instance of a 'Function menu module' which connects to this backend module.
180 *
181 * @see checkExtObj()
182 * @var AbstractFunctionModule
183 */
184 public $extObj;
185
186 /**
187 * @var PageRenderer
188 */
189 protected $pageRenderer;
190
191 /**
192 * Constructor deprecates the class
193 */
194 public function __construct()
195 {
196 trigger_error(
197 'Class BaseScriptClass is deprecated and will be removed in TYPO3 v10',
198 E_USER_DEPRECATED
199 );
200 }
201
202 /**
203 * Initializes the backend module by setting internal variables, initializing the menu.
204 *
205 * @see menuConfig()
206 */
207 public function init()
208 {
209 // Name might be set from outside
210 if (!$this->MCONF['name']) {
211 $this->MCONF = $GLOBALS['MCONF'];
212 }
213 $this->id = (int)GeneralUtility::_GP('id');
214 $this->CMD = GeneralUtility::_GP('CMD');
215 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
216 $this->menuConfig();
217 $this->handleExternalFunctionValue();
218 }
219
220 /**
221 * Initializes the internal MOD_MENU array setting and unsetting items based on various conditions. It also merges in external menu items from the global array TBE_MODULES_EXT (see mergeExternalItems())
222 * Then MOD_SETTINGS array is cleaned up (see \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData()) so it contains only valid values. It's also updated with any SET[] values submitted.
223 * Also loads the modTSconfig internal variable.
224 *
225 * @see init(), $MOD_MENU, $MOD_SETTINGS, \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData(), mergeExternalItems()
226 */
227 public function menuConfig()
228 {
229 // Page / user TSconfig settings and blinding of menu-items
230 $this->modTSconfig['properties'] = BackendUtility::getPagesTSconfig($this->id)['mod.'][$this->MCONF['name'] . '.'] ?? [];
231 $this->MOD_MENU['function'] = $this->mergeExternalItems($this->MCONF['name'], 'function', $this->MOD_MENU['function']);
232 $blindActions = $this->modTSconfig['properties']['menu.']['function.'] ?? [];
233 foreach ($blindActions as $key => $value) {
234 if (!$value && array_key_exists($key, $this->MOD_MENU['function'])) {
235 unset($this->MOD_MENU['function'][$key]);
236 }
237 }
238 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->MCONF['name'], $this->modMenu_type, $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
239 }
240
241 /**
242 * Merges menu items from global array $TBE_MODULES_EXT
243 *
244 * @param string $modName Module name for which to find value
245 * @param string $menuKey Menu key, eg. 'function' for the function menu.
246 * @param array $menuArr The part of a MOD_MENU array to work on.
247 * @return array Modified array part.
248 * @access private
249 * @see \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction(), menuConfig()
250 */
251 public function mergeExternalItems($modName, $menuKey, $menuArr)
252 {
253 $mergeArray = $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey];
254 if (is_array($mergeArray)) {
255 foreach ($mergeArray as $k => $v) {
256 if (((string)$v['ws'] === '' || $this->getBackendUser()->workspace === 0 && GeneralUtility::inList($v['ws'], 'online')) || $this->getBackendUser()->workspace === -1 && GeneralUtility::inList($v['ws'], 'offline') || $this->getBackendUser()->workspace > 0 && GeneralUtility::inList($v['ws'], 'custom')) {
257 $menuArr[$k] = $this->getLanguageService()->sL($v['title']);
258 }
259 }
260 }
261 return $menuArr;
262 }
263
264 /**
265 * Loads $this->extClassConf with the configuration for the CURRENT function of the menu.
266 *
267 * @param string $MM_key The key to MOD_MENU for which to fetch configuration. 'function' is default since it is first and foremost used to get information per "extension object" (I think that is what its called)
268 * @param string $MS_value The value-key to fetch from the config array. If NULL (default) MOD_SETTINGS[$MM_key] will be used. This is useful if you want to force another function than the one defined in MOD_SETTINGS[function]. Call this in init() function of your Script Class: handleExternalFunctionValue('function', $forcedSubModKey)
269 * @see getExternalItemConfig(), init()
270 */
271 public function handleExternalFunctionValue($MM_key = 'function', $MS_value = null)
272 {
273 if ($MS_value === null) {
274 $MS_value = $this->MOD_SETTINGS[$MM_key];
275 }
276 $this->extClassConf = $this->getExternalItemConfig($this->MCONF['name'], $MM_key, $MS_value);
277 }
278
279 /**
280 * Returns configuration values from the global variable $TBE_MODULES_EXT for the module given.
281 * For example if the module is named "web_info" and the "function" key ($menuKey) of MOD_SETTINGS is "stat" ($value) then you will have the values of $TBE_MODULES_EXT['webinfo']['MOD_MENU']['function']['stat'] returned.
282 *
283 * @param string $modName Module name
284 * @param string $menuKey Menu key, eg. "function" for the function menu. See $this->MOD_MENU
285 * @param string $value Optionally the value-key to fetch from the array that would otherwise have been returned if this value was not set. Look source...
286 * @return mixed The value from the TBE_MODULES_EXT array.
287 * @see handleExternalFunctionValue()
288 */
289 public function getExternalItemConfig($modName, $menuKey, $value = '')
290 {
291 if (isset($GLOBALS['TBE_MODULES_EXT'][$modName])) {
292 return (string)$value !== '' ? $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey][$value] : $GLOBALS['TBE_MODULES_EXT'][$modName]['MOD_MENU'][$menuKey];
293 }
294 return null;
295 }
296
297 /**
298 * Creates an instance of the class found in $this->extClassConf['name'] in $this->extObj if any (this should hold three keys, "name", "path" and "title" if a "Function menu module" tries to connect...)
299 * This value in extClassConf might be set by an extension (in an ext_tables/ext_localconf file) which thus "connects" to a module.
300 * The array $this->extClassConf is set in handleExternalFunctionValue() based on the value of MOD_SETTINGS[function]
301 * If an instance is created it is initiated with $this passed as value and $this->extClassConf as second argument. Further the $this->MOD_SETTING is cleaned up again after calling the init function.
302 *
303 * @see handleExternalFunctionValue(), \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::insertModuleFunction(), $extObj
304 */
305 public function checkExtObj()
306 {
307 if (is_array($this->extClassConf) && $this->extClassConf['name']) {
308 $this->extObj = GeneralUtility::makeInstance($this->extClassConf['name']);
309 $this->extObj->init($this, $this->extClassConf);
310 // Re-write:
311 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->MCONF['name'], $this->modMenu_type, $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
312 }
313 }
314
315 /**
316 * Calls the checkExtObj function in sub module if present.
317 */
318 public function checkSubExtObj()
319 {
320 if (is_object($this->extObj)) {
321 $this->extObj->checkExtObj();
322 }
323 }
324
325 /**
326 * Calls the 'header' function inside the "Function menu module" if present.
327 * A header function might be needed to add JavaScript or other stuff in the head. This can't be done in the main function because the head is already written.
328 */
329 public function extObjHeader()
330 {
331 if (is_callable([$this->extObj, 'head'])) {
332 $this->extObj->head();
333 }
334 }
335
336 /**
337 * Calls the 'main' function inside the "Function menu module" if present
338 */
339 public function extObjContent()
340 {
341 if ($this->extObj === null) {
342 $flashMessage = GeneralUtility::makeInstance(
343 FlashMessage::class,
344 $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:no_modules_registered'),
345 $this->getLanguageService()->getLL('title'),
346 FlashMessage::ERROR
347 );
348 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */
349 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
350 /** @var \TYPO3\CMS\Core\Messaging\FlashMessageQueue $defaultFlashMessageQueue */
351 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
352 $defaultFlashMessageQueue->enqueue($flashMessage);
353 } else {
354 $this->extObj->pObj = $this;
355 if (is_callable([$this->extObj, 'main'])) {
356 $this->content .= $this->extObj->main();
357 }
358 }
359 }
360
361 /**
362 * Return the content of the 'main' function inside the "Function menu module" if present
363 *
364 * @return string
365 */
366 public function getExtObjContent()
367 {
368 $savedContent = $this->content;
369 $this->content = '';
370 $this->extObjContent();
371 $newContent = $this->content;
372 $this->content = $savedContent;
373 return $newContent;
374 }
375
376 /**
377 * Returns the Language Service
378 * @return LanguageService
379 */
380 protected function getLanguageService()
381 {
382 return $GLOBALS['LANG'];
383 }
384
385 /**
386 * Returns the Backend User
387 * @return BackendUserAuthentication
388 */
389 protected function getBackendUser()
390 {
391 return $GLOBALS['BE_USER'];
392 }
393
394 /**
395 * @return PageRenderer
396 */
397 protected function getPageRenderer()
398 {
399 if ($this->pageRenderer === null) {
400 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
401 }
402
403 return $this->pageRenderer;
404 }
405 }