1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the TYPO3 CMS project. |
5
|
|
|
* |
6
|
|
|
* It is free software; you can redistribute it and/or modify it under |
7
|
|
|
* the terms of the GNU General Public License, either version 2 |
8
|
|
|
* of the License, or any later version. |
9
|
|
|
* |
10
|
|
|
* For the full copyright and license information, please read the |
11
|
|
|
* LICENSE.txt file that was distributed with this source code. |
12
|
|
|
* |
13
|
|
|
* The TYPO3 project - inspiring people to share! |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
namespace TYPO3\CMS\Recycler\Controller; |
17
|
|
|
|
18
|
|
|
use Psr\Http\Message\ResponseInterface; |
19
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
20
|
|
|
use TYPO3\CMS\Backend\Template\Components\ButtonBar; |
21
|
|
|
use TYPO3\CMS\Backend\Template\ModuleTemplate; |
22
|
|
|
use TYPO3\CMS\Backend\Utility\BackendUtility; |
23
|
|
|
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; |
24
|
|
|
use TYPO3\CMS\Core\Http\HtmlResponse; |
25
|
|
|
use TYPO3\CMS\Core\Http\NormalizedParams; |
26
|
|
|
use TYPO3\CMS\Core\Imaging\Icon; |
27
|
|
|
use TYPO3\CMS\Core\Localization\LanguageService; |
28
|
|
|
use TYPO3\CMS\Core\Type\Bitmask\Permission; |
29
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
30
|
|
|
use TYPO3\CMS\Core\Utility\MathUtility; |
31
|
|
|
use TYPO3\CMS\Fluid\View\StandaloneView; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Backend Module for the 'recycler' extension. |
35
|
|
|
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API. |
36
|
|
|
*/ |
37
|
|
|
class RecyclerModuleController |
38
|
|
|
{ |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var array |
42
|
|
|
*/ |
43
|
|
|
protected $pageRecord = []; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var bool |
47
|
|
|
*/ |
48
|
|
|
protected $isAccessibleForCurrentUser = false; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var bool |
52
|
|
|
*/ |
53
|
|
|
protected $allowDelete = false; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var int |
57
|
|
|
*/ |
58
|
|
|
protected $recordsPageLimit = 50; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var int |
62
|
|
|
*/ |
63
|
|
|
protected $id; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var StandaloneView |
67
|
|
|
*/ |
68
|
|
|
protected $view; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var ModuleTemplate |
72
|
|
|
*/ |
73
|
|
|
protected $moduleTemplate; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Injects the request object for the current request, and renders correct action |
77
|
|
|
* |
78
|
|
|
* @param ServerRequestInterface $request the current request |
79
|
|
|
* @return ResponseInterface the response with the content |
80
|
|
|
*/ |
81
|
|
|
public function handleRequest(ServerRequestInterface $request): ResponseInterface |
82
|
|
|
{ |
83
|
|
|
$this->id = (int)($request->getQueryParams()['id'] ?? $request->getParsedBody()['id'] ?? 0); |
84
|
|
|
$backendUser = $this->getBackendUser(); |
85
|
|
|
$this->pageRecord = BackendUtility::readPageAccess($this->id, $backendUser->getPagePermsClause(Permission::PAGE_SHOW)); |
|
|
|
|
86
|
|
|
$this->isAccessibleForCurrentUser = $this->id && is_array($this->pageRecord) || !$this->id && $this->getBackendUser()->isAdmin(); |
|
|
|
|
87
|
|
|
$this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class); |
88
|
|
|
|
89
|
|
|
// don't access in workspace |
90
|
|
|
if ($backendUser->workspace !== 0) { |
91
|
|
|
$this->isAccessibleForCurrentUser = false; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
// read configuration |
95
|
|
|
if ($backendUser->isAdmin()) { |
96
|
|
|
$this->allowDelete = true; |
97
|
|
|
} else { |
98
|
|
|
$this->allowDelete = (bool)($backendUser->getTSConfig()['mod.']['recycler.']['allowDelete'] ?? false); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
$this->recordsPageLimit = MathUtility::forceIntegerInRange( |
102
|
|
|
(int)($backendUser->getTSConfig()['mod.']['recycler.']['recordsPageLimit'] ?? 25), |
103
|
|
|
1 |
104
|
|
|
); |
105
|
|
|
|
106
|
|
|
$action = 'index'; |
107
|
|
|
$this->initializeView($action); |
108
|
|
|
|
109
|
|
|
$result = call_user_func_array([$this, $action . 'Action'], [$request]); |
110
|
|
|
if ($result instanceof ResponseInterface) { |
111
|
|
|
return $result; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
$this->registerDocheaderButtons($request->getQueryParams()['route']); |
115
|
|
|
|
116
|
|
|
$this->moduleTemplate->setContent($this->view->render()); |
117
|
|
|
return new HtmlResponse($this->moduleTemplate->renderContent()); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @param string $templateName |
122
|
|
|
*/ |
123
|
|
|
protected function initializeView(string $templateName) |
124
|
|
|
{ |
125
|
|
|
$this->view = GeneralUtility::makeInstance(StandaloneView::class); |
126
|
|
|
$this->view->setTemplate($templateName); |
127
|
|
|
$this->view->setTemplateRootPaths(['EXT:recycler/Resources/Private/Templates/RecyclerModule']); |
128
|
|
|
$this->view->setPartialRootPaths(['EXT:recycler/Resources/Private/Partials']); |
129
|
|
|
$this->view->setLayoutRootPaths(['EXT:recycler/Resources/Private/Layouts']); |
130
|
|
|
$this->view->getRequest()->setControllerExtensionName('Recycler'); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Renders the content of the module. |
135
|
|
|
* |
136
|
|
|
* @param ServerRequestInterface $request |
137
|
|
|
*/ |
138
|
|
|
public function indexAction(ServerRequestInterface $request) |
139
|
|
|
{ |
140
|
|
|
$this->moduleTemplate->getPageRenderer()->addInlineSettingArray('Recycler', $this->getJavaScriptConfiguration($request->getAttribute('normalizedParams'))); |
141
|
|
|
$this->moduleTemplate->getPageRenderer()->addInlineLanguageLabelFile('EXT:recycler/Resources/Private/Language/locallang.xlf'); |
142
|
|
|
if ($this->isAccessibleForCurrentUser) { |
143
|
|
|
$this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageRecord); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
$this->view->assign('allowDelete', $this->allowDelete); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Registers the Icons into the docheader |
151
|
|
|
* |
152
|
|
|
* @param string $route |
153
|
|
|
* @throws \InvalidArgumentException |
154
|
|
|
*/ |
155
|
|
|
protected function registerDocheaderButtons(string $route) |
156
|
|
|
{ |
157
|
|
|
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar(); |
158
|
|
|
|
159
|
|
|
$shortcutButton = $buttonBar->makeShortcutButton() |
160
|
|
|
->setModuleName('web_RecyclerRecycler') |
161
|
|
|
->setDisplayName($this->getShortcutTitle()) |
162
|
|
|
->setArguments([ |
163
|
|
|
'route' => $route, |
164
|
|
|
'id' => (int)$this->id |
165
|
|
|
]); |
166
|
|
|
$buttonBar->addButton($shortcutButton); |
167
|
|
|
|
168
|
|
|
$reloadButton = $buttonBar->makeLinkButton() |
169
|
|
|
->setHref('#') |
170
|
|
|
->setDataAttributes(['action' => 'reload']) |
171
|
|
|
->setTitle($this->getLanguageService()->sL('LLL:EXT:recycler/Resources/Private/Language/locallang.xlf:button.reload')) |
172
|
|
|
->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-refresh', Icon::SIZE_SMALL)); |
173
|
|
|
$buttonBar->addButton($reloadButton, ButtonBar::BUTTON_POSITION_RIGHT); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Gets the JavaScript configuration. |
178
|
|
|
* |
179
|
|
|
* @param NormalizedParams $normalizedParams |
180
|
|
|
* @return array The JavaScript configuration |
181
|
|
|
*/ |
182
|
|
|
protected function getJavaScriptConfiguration(NormalizedParams $normalizedParams): array |
183
|
|
|
{ |
184
|
|
|
return [ |
185
|
|
|
'pagingSize' => $this->recordsPageLimit, |
186
|
|
|
'showDepthMenu' => true, |
187
|
|
|
'startUid' => $this->id, |
188
|
|
|
'isSSL' => $normalizedParams->isHttps(), |
189
|
|
|
'deleteDisable' => !$this->allowDelete, |
190
|
|
|
'depthSelection' => $this->getDataFromSession('depthSelection', '0'), |
191
|
|
|
'tableSelection' => $this->getDataFromSession('tableSelection', ''), |
192
|
|
|
'States' => $this->getBackendUser()->uc['moduleData']['web_recycler']['States'] |
193
|
|
|
]; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Gets data from the session of the current backend user. |
198
|
|
|
* |
199
|
|
|
* @param string $identifier The identifier to be used to get the data |
200
|
|
|
* @param string $default The default date to be used if nothing was found in the session |
201
|
|
|
* @return string The accordant data in the session of the current backend user |
202
|
|
|
*/ |
203
|
|
|
protected function getDataFromSession($identifier, $default = null) |
204
|
|
|
{ |
205
|
|
|
$sessionData = &$this->getBackendUser()->uc['tx_recycler']; |
206
|
|
|
if (isset($sessionData[$identifier]) && $sessionData[$identifier]) { |
207
|
|
|
$data = $sessionData[$identifier]; |
208
|
|
|
} else { |
209
|
|
|
$data = $default; |
210
|
|
|
} |
211
|
|
|
return $data; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Returns the shortcut title for the current page |
216
|
|
|
* |
217
|
|
|
* @return string |
218
|
|
|
*/ |
219
|
|
|
protected function getShortcutTitle(): string |
220
|
|
|
{ |
221
|
|
|
return sprintf( |
222
|
|
|
'%s: %s [%d]', |
223
|
|
|
$this->getLanguageService()->sL('LLL:EXT:recycler/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'), |
224
|
|
|
BackendUtility::getRecordTitle('pages', $this->pageRecord), |
225
|
|
|
$this->id |
226
|
|
|
); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Returns the current BE user. |
231
|
|
|
* |
232
|
|
|
* @return BackendUserAuthentication |
233
|
|
|
*/ |
234
|
|
|
protected function getBackendUser(): BackendUserAuthentication |
235
|
|
|
{ |
236
|
|
|
return $GLOBALS['BE_USER']; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* Returns an instance of LanguageService |
241
|
|
|
* |
242
|
|
|
* @return LanguageService |
243
|
|
|
*/ |
244
|
|
|
protected function getLanguageService(): LanguageService |
245
|
|
|
{ |
246
|
|
|
return $GLOBALS['LANG']; |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.