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