[BUGFIX] iconIdentifier for custom system information panel items
[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 */
278 public function addSystemMessage($text, $status = InformationStatus::STATUS_OK, $count = 0, $module = '')
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 'count' => (int)$count,
292 'status' => $messageSeverity,
293 'text' => $text
294 ];
295 }
296
297 /**
298 * Add a system information.
299 * This is a callback method for signal receivers.
300 *
301 * @param string $title The title of this system information
302 * @param string $value The associated value
303 * @param string $iconIdentifier The icon identifier
304 * @param string $status The status of this system information
305 */
306 public function addSystemInformation($title, $value, $iconIdentifier, $status = InformationStatus::STATUS_NOTICE)
307 {
308 $this->systemInformation[] = [
309 'title' => $title,
310 'value' => $value,
311 'iconIdentifier' => $iconIdentifier,
312 'status' => $status
313 ];
314 }
315
316 /**
317 * Checks whether the user has access to this toolbar item
318 *
319 * @return bool TRUE if user has access, FALSE if not
320 */
321 public function checkAccess()
322 {
323 return $this->getBackendUserAuthentication()->isAdmin();
324 }
325
326 /**
327 * Render system information dropdown
328 *
329 * @return string Icon HTML
330 */
331 public function getItem()
332 {
333 return $this->getFluidTemplateObject('SystemInformationToolbarItem.html')->render();
334 }
335
336 /**
337 * Render drop down
338 *
339 * @return string Drop down HTML
340 */
341 public function getDropDown()
342 {
343 if (!$this->checkAccess()) {
344 return '';
345 }
346
347 $view = $this->getFluidTemplateObject('SystemInformationDropDown.html');
348 $view->assignMultiple([
349 'installToolUrl' => BackendUtility::getModuleUrl('system_extinstall'),
350 'messages' => $this->systemMessages,
351 'count' => $this->totalCount > $this->maximumCountInBadge ? $this->maximumCountInBadge . '+' : $this->totalCount,
352 'severityBadgeClass' => $this->severityBadgeClass,
353 'systemInformation' => $this->systemInformation
354 ]);
355 return $view->render();
356 }
357
358 /**
359 * No additional attributes needed.
360 *
361 * @return array
362 */
363 public function getAdditionalAttributes()
364 {
365 return [];
366 }
367
368 /**
369 * This item has a drop down
370 *
371 * @return bool
372 */
373 public function hasDropDown()
374 {
375 return true;
376 }
377
378 /**
379 * Position relative to others
380 *
381 * @return int
382 */
383 public function getIndex()
384 {
385 return 75;
386 }
387
388 /**
389 * Returns the current BE user.
390 *
391 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
392 */
393 protected function getBackendUserAuthentication()
394 {
395 return $GLOBALS['BE_USER'];
396 }
397
398 /**
399 * Returns current PageRenderer
400 *
401 * @return PageRenderer
402 */
403 protected function getPageRenderer()
404 {
405 return GeneralUtility::makeInstance(PageRenderer::class);
406 }
407
408 /**
409 * Get the SignalSlot dispatcher
410 *
411 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
412 */
413 protected function getSignalSlotDispatcher()
414 {
415 if (!isset($this->signalSlotDispatcher)) {
416 $this->signalSlotDispatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class)
417 ->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
418 }
419 return $this->signalSlotDispatcher;
420 }
421
422 /**
423 * Returns a new standalone view, shorthand function
424 *
425 * @param string $filename Which templateFile should be used.
426 * @return StandaloneView
427 */
428 protected function getFluidTemplateObject(string $filename): StandaloneView
429 {
430 $view = GeneralUtility::makeInstance(StandaloneView::class);
431 $view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
432 $view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
433 $view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
434
435 $view->setTemplate($filename);
436
437 $view->getRequest()->setControllerExtensionName('Backend');
438 return $view;
439 }
440 }