[TASK] Create own response instance in controller actions
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Backend / ToolbarItems / SystemInformationToolbarItem.php
1 <?php
2 namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
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 Psr\Http\Message\ResponseInterface;
18 use TYPO3\CMS\Backend\Routing\UriBuilder;
19 use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus;
20 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
21 use TYPO3\CMS\Core\Core\Bootstrap;
22 use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
23 use TYPO3\CMS\Core\Database\ConnectionPool;
24 use TYPO3\CMS\Core\Http\HtmlResponse;
25 use TYPO3\CMS\Core\Page\PageRenderer;
26 use TYPO3\CMS\Core\Utility\CommandUtility;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Utility\StringUtility;
29 use TYPO3\CMS\Core\Utility\VersionNumberUtility;
30 use TYPO3\CMS\Extbase\Object\ObjectManager;
31 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
32 use TYPO3\CMS\Fluid\View\StandaloneView;
33
34 /**
35 * Render system info toolbar item
36 */
37 class SystemInformationToolbarItem implements ToolbarItemInterface
38 {
39 /**
40 * Number displayed as badge on the dropdown trigger
41 *
42 * @var int
43 */
44 protected $totalCount = 0;
45
46 /**
47 * Holds the highest severity
48 *
49 * @var InformationStatus
50 */
51 protected $highestSeverity;
52
53 /**
54 * The CSS class for the badge
55 *
56 * @var string
57 */
58 protected $severityBadgeClass = '';
59
60 /**
61 * @var array
62 */
63 protected $systemInformation = [];
64
65 /**
66 * @var array
67 */
68 protected $systemMessages = [];
69
70 /**
71 * @var Dispatcher
72 */
73 protected $signalSlotDispatcher = null;
74
75 /**
76 * @var int
77 */
78 protected $maximumCountInBadge = 99;
79
80 /**
81 * Constructor
82 */
83 public function __construct()
84 {
85 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/SystemInformationMenu');
86 $this->highestSeverity = InformationStatus::cast(InformationStatus::STATUS_INFO);
87 }
88
89 /**
90 * Collect the information for the menu
91 */
92 protected function collectInformation()
93 {
94 $this->getTypo3Version();
95 $this->getWebServer();
96 $this->getPhpVersion();
97 $this->getDatabase();
98 $this->getApplicationContext();
99 $this->getComposerMode();
100 $this->getGitRevision();
101 $this->getOperatingSystem();
102
103 $this->emitGetSystemInformation();
104 $this->emitLoadMessages();
105
106 $this->severityBadgeClass = !$this->highestSeverity->equals(InformationStatus::STATUS_NOTICE) ? 'badge-' . (string)$this->highestSeverity : '';
107 }
108
109 /**
110 * Renders the menu for AJAX calls
111 *
112 * @return ResponseInterface
113 */
114 public function renderMenuAction(): ResponseInterface
115 {
116 $this->collectInformation();
117 return new HtmlResponse($this->getDropDown());
118 }
119
120 /**
121 * Gets the PHP version
122 */
123 protected function getPhpVersion()
124 {
125 $this->systemInformation[] = [
126 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.phpversion',
127 'value' => PHP_VERSION,
128 'iconIdentifier' => 'sysinfo-php-version'
129 ];
130 }
131
132 /**
133 * Get the database info
134 */
135 protected function getDatabase()
136 {
137 foreach (GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionNames() as $connectionName) {
138 $this->systemInformation[] = [
139 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.database',
140 'titleAddition' => $connectionName,
141 'value' => GeneralUtility::makeInstance(ConnectionPool::class)
142 ->getConnectionByName($connectionName)
143 ->getServerVersion(),
144 'iconIdentifier' => 'sysinfo-database'
145 ];
146 }
147 }
148
149 /**
150 * Gets the application context
151 */
152 protected function getApplicationContext()
153 {
154 $applicationContext = GeneralUtility::getApplicationContext();
155 $this->systemInformation[] = [
156 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.applicationcontext',
157 'value' => (string)$applicationContext,
158 'status' => $applicationContext->isProduction() ? InformationStatus::STATUS_OK : InformationStatus::STATUS_WARNING,
159 'iconIdentifier' => 'sysinfo-application-context'
160 ];
161 }
162
163 /**
164 * Adds the information if the Composer mode is enabled or disabled to the displayed system information
165 */
166 protected function getComposerMode()
167 {
168 if (!Bootstrap::usesComposerClassLoading()) {
169 return;
170 }
171
172 $this->systemInformation[] = [
173 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.composerMode',
174 'value' => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.enabled'),
175 'iconIdentifier' => 'sysinfo-composer-mode'
176 ];
177 }
178
179 /**
180 * Gets the current GIT revision and branch
181 */
182 protected function getGitRevision()
183 {
184 if (!StringUtility::endsWith(TYPO3_version, '-dev') || SystemEnvironmentBuilder::isFunctionDisabled('exec')) {
185 return;
186 }
187 // check if git exists
188 CommandUtility::exec('git --version', $_, $returnCode);
189 if ((int)$returnCode !== 0) {
190 // git is not available
191 return;
192 }
193
194 $revision = trim(CommandUtility::exec('git rev-parse --short HEAD'));
195 $branch = trim(CommandUtility::exec('git rev-parse --abbrev-ref HEAD'));
196 if (!empty($revision) && !empty($branch)) {
197 $this->systemInformation[] = [
198 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.gitrevision',
199 'value' => sprintf('%s [%s]', $revision, $branch),
200 'iconIdentifier' => 'sysinfo-git'
201 ];
202 }
203 }
204
205 /**
206 * Gets the system kernel and version
207 */
208 protected function getOperatingSystem()
209 {
210 $kernelName = php_uname('s');
211 switch (strtolower($kernelName)) {
212 case 'linux':
213 $icon = 'linux';
214 break;
215 case 'darwin':
216 $icon = 'apple';
217 break;
218 default:
219 $icon = 'windows';
220 }
221 $this->systemInformation[] = [
222 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.operatingsystem',
223 'value' => $kernelName . ' ' . php_uname('r'),
224 'iconIdentifier' => 'sysinfo-os-' . $icon
225 ];
226 }
227
228 /**
229 * Gets the webserver software
230 */
231 protected function getWebServer()
232 {
233 $this->systemInformation[] = [
234 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.webserver',
235 'value' => $_SERVER['SERVER_SOFTWARE'],
236 'iconIdentifier' => 'sysinfo-webserver'
237 ];
238 }
239
240 /**
241 * Gets the TYPO3 version
242 */
243 protected function getTypo3Version()
244 {
245 $this->systemInformation[] = [
246 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.typo3-version',
247 'value' => VersionNumberUtility::getCurrentTypo3Version(),
248 'iconIdentifier' => 'sysinfo-typo3-version'
249 ];
250 }
251
252 /**
253 * Emits the "getSystemInformation" signal
254 */
255 protected function emitGetSystemInformation()
256 {
257 $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'getSystemInformation', [$this]);
258 }
259
260 /**
261 * Emits the "loadMessages" signal
262 */
263 protected function emitLoadMessages()
264 {
265 $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'loadMessages', [$this]);
266 }
267
268 /**
269 * Add a system message.
270 * This is a callback method for signal receivers.
271 *
272 * @param string $text The text to be displayed
273 * @param string $status The status of this system message
274 * @param int $count Will be added to the total count
275 * @param string $module The associated module
276 * @param string $params Query string with additional parameters
277 */
278 public function addSystemMessage($text, $status = InformationStatus::STATUS_OK, $count = 0, $module = '', $params = '')
279 {
280 $this->totalCount += (int)$count;
281
282 /** @var InformationStatus $messageSeverity */
283 $messageSeverity = InformationStatus::cast($status);
284 // define the severity for the badge
285 if ($messageSeverity->isGreaterThan($this->highestSeverity)) {
286 $this->highestSeverity = $messageSeverity;
287 }
288
289 $this->systemMessages[] = [
290 'module' => $module,
291 'params' => $params,
292 'count' => (int)$count,
293 'status' => $messageSeverity,
294 'text' => $text
295 ];
296 }
297
298 /**
299 * Add a system information.
300 * This is a callback method for signal receivers.
301 *
302 * @param string $title The title of this system information
303 * @param string $value The associated value
304 * @param string $iconIdentifier The icon identifier
305 * @param string $status The status of this system information
306 */
307 public function addSystemInformation($title, $value, $iconIdentifier, $status = InformationStatus::STATUS_NOTICE)
308 {
309 $this->systemInformation[] = [
310 'title' => $title,
311 'value' => $value,
312 'iconIdentifier' => $iconIdentifier,
313 'status' => $status
314 ];
315 }
316
317 /**
318 * Checks whether the user has access to this toolbar item
319 *
320 * @return bool TRUE if user has access, FALSE if not
321 */
322 public function checkAccess()
323 {
324 return $this->getBackendUserAuthentication()->isAdmin();
325 }
326
327 /**
328 * Render system information dropdown
329 *
330 * @return string Icon HTML
331 */
332 public function getItem()
333 {
334 return $this->getFluidTemplateObject('SystemInformationToolbarItem.html')->render();
335 }
336
337 /**
338 * Render drop down
339 *
340 * @return string Drop down HTML
341 */
342 public function getDropDown()
343 {
344 if (!$this->checkAccess()) {
345 return '';
346 }
347
348 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
349 $view = $this->getFluidTemplateObject('SystemInformationDropDown.html');
350 $view->assignMultiple([
351 'environmentToolUrl' => (string)$uriBuilder->buildUriFromRoute('tools_toolsenvironment'),
352 'messages' => $this->systemMessages,
353 'count' => $this->totalCount > $this->maximumCountInBadge ? $this->maximumCountInBadge . '+' : $this->totalCount,
354 'severityBadgeClass' => $this->severityBadgeClass,
355 'systemInformation' => $this->systemInformation
356 ]);
357 return $view->render();
358 }
359
360 /**
361 * No additional attributes needed.
362 *
363 * @return array
364 */
365 public function getAdditionalAttributes()
366 {
367 return [];
368 }
369
370 /**
371 * This item has a drop down
372 *
373 * @return bool
374 */
375 public function hasDropDown()
376 {
377 return true;
378 }
379
380 /**
381 * Position relative to others
382 *
383 * @return int
384 */
385 public function getIndex()
386 {
387 return 75;
388 }
389
390 /**
391 * Returns the current BE user.
392 *
393 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
394 */
395 protected function getBackendUserAuthentication()
396 {
397 return $GLOBALS['BE_USER'];
398 }
399
400 /**
401 * Returns current PageRenderer
402 *
403 * @return PageRenderer
404 */
405 protected function getPageRenderer()
406 {
407 return GeneralUtility::makeInstance(PageRenderer::class);
408 }
409
410 /**
411 * Get the SignalSlot dispatcher
412 *
413 * @return Dispatcher
414 */
415 protected function getSignalSlotDispatcher()
416 {
417 if (!isset($this->signalSlotDispatcher)) {
418 $this->signalSlotDispatcher = GeneralUtility::makeInstance(ObjectManager::class)
419 ->get(Dispatcher::class);
420 }
421 return $this->signalSlotDispatcher;
422 }
423
424 /**
425 * Returns a new standalone view, shorthand function
426 *
427 * @param string $filename Which templateFile should be used.
428 * @return StandaloneView
429 */
430 protected function getFluidTemplateObject(string $filename): StandaloneView
431 {
432 $view = GeneralUtility::makeInstance(StandaloneView::class);
433 $view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
434 $view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
435 $view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
436
437 $view->setTemplate($filename);
438
439 $view->getRequest()->setControllerExtensionName('Backend');
440 return $view;
441 }
442 }