7d12140fe37fe5c8baa03749160de7934dafc10c
[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\Core\SystemEnvironmentBuilder;
24 use TYPO3\CMS\Core\Database\ConnectionPool;
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\Fluid\View\StandaloneView;
31
32 /**
33 * Render system info toolbar item
34 */
35 class SystemInformationToolbarItem implements ToolbarItemInterface
36 {
37 /**
38 * Number displayed as badge on the dropdown trigger
39 *
40 * @var int
41 */
42 protected $totalCount = 0;
43
44 /**
45 * Holds the highest severity
46 *
47 * @var InformationStatus
48 */
49 protected $highestSeverity;
50
51 /**
52 * The CSS class for the badge
53 *
54 * @var string
55 */
56 protected $severityBadgeClass = '';
57
58 /**
59 * @var array
60 */
61 protected $systemInformation = [];
62
63 /**
64 * @var array
65 */
66 protected $systemMessages = [];
67
68 /**
69 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
70 */
71 protected $signalSlotDispatcher = null;
72
73 /**
74 * @var int
75 */
76 protected $maximumCountInBadge = 99;
77
78 /**
79 * Constructor
80 */
81 public function __construct()
82 {
83 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/SystemInformationMenu');
84 $this->highestSeverity = InformationStatus::cast(InformationStatus::STATUS_INFO);
85 }
86
87 /**
88 * Collect the information for the menu
89 */
90 protected function collectInformation()
91 {
92 $this->getTypo3Version();
93 $this->getWebServer();
94 $this->getPhpVersion();
95 $this->getDatabase();
96 $this->getApplicationContext();
97 $this->getComposerMode();
98 $this->getGitRevision();
99 $this->getOperatingSystem();
100
101 $this->emitGetSystemInformation();
102 $this->emitLoadMessages();
103
104 $this->severityBadgeClass = !$this->highestSeverity->equals(InformationStatus::STATUS_NOTICE) ? 'badge-' . (string)$this->highestSeverity : '';
105 }
106
107 /**
108 * Renders the menu for AJAX calls
109 *
110 * @param ServerRequestInterface $request
111 * @param ResponseInterface $response
112 * @return ResponseInterface
113 */
114 public function renderMenuAction(ServerRequestInterface $request, ResponseInterface $response)
115 {
116 $this->collectInformation();
117 $response->getBody()->write($this->getDropDown());
118 return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
119 }
120
121 /**
122 * Gets the PHP version
123 */
124 protected function getPhpVersion()
125 {
126 $this->systemInformation[] = [
127 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.phpversion',
128 'value' => PHP_VERSION,
129 'iconIdentifier' => 'sysinfo-php-version'
130 ];
131 }
132
133 /**
134 * Get the database info
135 */
136 protected function getDatabase()
137 {
138 foreach (GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionNames() as $connectionName) {
139 $this->systemInformation[] = [
140 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.database',
141 'titleAddition' => $connectionName,
142 'value' => GeneralUtility::makeInstance(ConnectionPool::class)
143 ->getConnectionByName($connectionName)
144 ->getServerVersion(),
145 'iconIdentifier' => 'sysinfo-database'
146 ];
147 }
148 }
149
150 /**
151 * Gets the application context
152 */
153 protected function getApplicationContext()
154 {
155 $applicationContext = GeneralUtility::getApplicationContext();
156 $this->systemInformation[] = [
157 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.applicationcontext',
158 'value' => (string)$applicationContext,
159 'status' => $applicationContext->isProduction() ? InformationStatus::STATUS_OK : InformationStatus::STATUS_WARNING,
160 'iconIdentifier' => 'sysinfo-application-context'
161 ];
162 }
163
164 /**
165 * Adds the information if the Composer mode is enabled or disabled to the displayed system information
166 */
167 protected function getComposerMode()
168 {
169 if (!Bootstrap::usesComposerClassLoading()) {
170 return;
171 }
172
173 $this->systemInformation[] = [
174 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.composerMode',
175 'value' => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.enabled'),
176 'iconIdentifier' => 'sysinfo-composer-mode'
177 ];
178 }
179
180 /**
181 * Gets the current GIT revision and branch
182 */
183 protected function getGitRevision()
184 {
185 if (!StringUtility::endsWith(TYPO3_version, '-dev') || SystemEnvironmentBuilder::isFunctionDisabled('exec')) {
186 return;
187 }
188 // check if git exists
189 CommandUtility::exec('git --version', $_, $returnCode);
190 if ((int)$returnCode !== 0) {
191 // git is not available
192 return;
193 }
194
195 $revision = trim(CommandUtility::exec('git rev-parse --short HEAD'));
196 $branch = trim(CommandUtility::exec('git rev-parse --abbrev-ref HEAD'));
197 if (!empty($revision) && !empty($branch)) {
198 $this->systemInformation[] = [
199 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.gitrevision',
200 'value' => sprintf('%s [%s]', $revision, $branch),
201 'iconIdentifier' => 'sysinfo-git'
202 ];
203 }
204 }
205
206 /**
207 * Gets the system kernel and version
208 */
209 protected function getOperatingSystem()
210 {
211 $kernelName = php_uname('s');
212 switch (strtolower($kernelName)) {
213 case 'linux':
214 $icon = 'linux';
215 break;
216 case 'darwin':
217 $icon = 'apple';
218 break;
219 default:
220 $icon = 'windows';
221 }
222 $this->systemInformation[] = [
223 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.operatingsystem',
224 'value' => $kernelName . ' ' . php_uname('r'),
225 'iconIdentifier' => 'sysinfo-os-' . $icon
226 ];
227 }
228
229 /**
230 * Gets the webserver software
231 */
232 protected function getWebServer()
233 {
234 $this->systemInformation[] = [
235 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.webserver',
236 'value' => $_SERVER['SERVER_SOFTWARE'],
237 'iconIdentifier' => 'sysinfo-webserver'
238 ];
239 }
240
241 /**
242 * Gets the TYPO3 version
243 */
244 protected function getTypo3Version()
245 {
246 $this->systemInformation[] = [
247 'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.typo3-version',
248 'value' => VersionNumberUtility::getCurrentTypo3Version(),
249 'iconIdentifier' => 'sysinfo-typo3-version'
250 ];
251 }
252
253 /**
254 * Emits the "getSystemInformation" signal
255 */
256 protected function emitGetSystemInformation()
257 {
258 $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'getSystemInformation', [$this]);
259 }
260
261 /**
262 * Emits the "loadMessages" signal
263 */
264 protected function emitLoadMessages()
265 {
266 $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'loadMessages', [$this]);
267 }
268
269 /**
270 * Add a system message.
271 * This is a callback method for signal receivers.
272 *
273 * @param string $text The text to be displayed
274 * @param string $status The status of this system message
275 * @param int $count Will be added to the total count
276 * @param string $module The associated module
277 * @param string $params Query string with additional parameters
278 */
279 public function addSystemMessage($text, $status = InformationStatus::STATUS_OK, $count = 0, $module = '', $params = '')
280 {
281 $this->totalCount += (int)$count;
282
283 /** @var InformationStatus $messageSeverity */
284 $messageSeverity = InformationStatus::cast($status);
285 // define the severity for the badge
286 if ($messageSeverity->isGreaterThan($this->highestSeverity)) {
287 $this->highestSeverity = $messageSeverity;
288 }
289
290 $this->systemMessages[] = [
291 'module' => $module,
292 'params' => $params,
293 'count' => (int)$count,
294 'status' => $messageSeverity,
295 'text' => $text
296 ];
297 }
298
299 /**
300 * Add a system information.
301 * This is a callback method for signal receivers.
302 *
303 * @param string $title The title of this system information
304 * @param string $value The associated value
305 * @param string $iconIdentifier The icon identifier
306 * @param string $status The status of this system information
307 */
308 public function addSystemInformation($title, $value, $iconIdentifier, $status = InformationStatus::STATUS_NOTICE)
309 {
310 $this->systemInformation[] = [
311 'title' => $title,
312 'value' => $value,
313 'iconIdentifier' => $iconIdentifier,
314 'status' => $status
315 ];
316 }
317
318 /**
319 * Checks whether the user has access to this toolbar item
320 *
321 * @return bool TRUE if user has access, FALSE if not
322 */
323 public function checkAccess()
324 {
325 return $this->getBackendUserAuthentication()->isAdmin();
326 }
327
328 /**
329 * Render system information dropdown
330 *
331 * @return string Icon HTML
332 */
333 public function getItem()
334 {
335 return $this->getFluidTemplateObject('SystemInformationToolbarItem.html')->render();
336 }
337
338 /**
339 * Render drop down
340 *
341 * @return string Drop down HTML
342 */
343 public function getDropDown()
344 {
345 if (!$this->checkAccess()) {
346 return '';
347 }
348
349 $view = $this->getFluidTemplateObject('SystemInformationDropDown.html');
350 $view->assignMultiple([
351 'environmentToolUrl' => BackendUtility::getModuleUrl('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 \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
414 */
415 protected function getSignalSlotDispatcher()
416 {
417 if (!isset($this->signalSlotDispatcher)) {
418 $this->signalSlotDispatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class)
419 ->get(\TYPO3\CMS\Extbase\SignalSlot\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 }