[FEATURE] Introduce System Information dropdown item 81/37881/16
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Mon, 16 Mar 2015 13:51:52 +0000 (14:51 +0100)
committerJigal van Hemert <jigal.van.hemert@typo3.org>
Wed, 1 Apr 2015 19:12:10 +0000 (21:12 +0200)
This patch introduces a new System Information dropdown item that
contains several system information. By default it displays:
* PHP version
* Database version
* Application context
* git revision (if TYPO3 version has "-dev" suffix)
* Operating system

The item list is extendable by the SystemInformationHookInterface.

Resolves: #65767
Releases: master
Change-Id: I2e7489f53198d44edea9995fe4cce49696a2f888
Reviewed-on: http://review.typo3.org/37881
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Frank N├Ągler <typo3@naegler.net>
Reviewed-by: Jigal van Hemert <jigal.van.hemert@typo3.org>
Tested-by: Jigal van Hemert <jigal.van.hemert@typo3.org>
19 files changed:
typo3/sysext/backend/Classes/Backend/ToolbarItems/AbstractToolbarItem.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Toolbar/Enumeration/InformationStatus.php [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/Language/locallang.xlf
typo3/sysext/backend/Resources/Private/Templates/ToolbarMenu/SystemInformation.html [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js [new file with mode: 0644]
typo3/sysext/backend/ext_localconf.php
typo3/sysext/belog/Classes/Controller/SystemInformationController.php [new file with mode: 0644]
typo3/sysext/belog/Resources/Private/Language/locallang.xlf
typo3/sysext/belog/ext_localconf.php [new file with mode: 0644]
typo3/sysext/core/Classes/Core/SystemEnvironmentBuilder.php
typo3/sysext/core/Classes/Database/DatabaseConnection.php
typo3/sysext/core/Documentation/Changelog/master/Feature-65767-SystemInformationDropdown.rst [new file with mode: 0644]
typo3/sysext/dbal/Classes/Database/DatabaseConnection.php
typo3/sysext/lang/locallang_core.xlf
typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_badges.less [new file with mode: 0644]
typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_topbar.less
typo3/sysext/t3skin/Resources/Private/Styles/t3skin.less
typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css

diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/AbstractToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/AbstractToolbarItem.php
new file mode 100644 (file)
index 0000000..9ddf47e
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+
+/**
+ * Render system info toolbar item
+ */
+abstract class AbstractToolbarItem {
+
+       /**
+        * @var StandaloneView
+        */
+       protected $standaloneView = NULL;
+
+       public function __construct() {
+               $extPath = ExtensionManagementUtility::extPath('backend');
+               /* @var $view StandaloneView */
+               $this->standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
+               $this->standaloneView->setTemplatePathAndFilename($extPath . 'Resources/Private/Templates/ToolbarMenu/' . static::TOOLBAR_MENU_TEMPLATE);
+       }
+
+       /**
+        * @param string $extension Set the extension context (required for shorthand locallang.xlf references)
+        * @return StandaloneView
+        */
+       protected function getStandaloneView($extension = NULL) {
+               if (!empty($extension)) {
+                       $request = $this->standaloneView->getRequest();
+                       $request->setControllerExtensionName($extension);
+               }
+               return $this->standaloneView;
+       }
+}
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php
new file mode 100644 (file)
index 0000000..4d29f0b
--- /dev/null
@@ -0,0 +1,322 @@
+<?php
+namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\Utility\IconUtility;
+use TYPO3\CMS\Core\Utility\CommandUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
+
+/**
+ * Render system info toolbar item
+ */
+class SystemInformationToolbarItem extends AbstractToolbarItem implements ToolbarItemInterface {
+
+       /**
+        * Template file for the dropdown menu
+        */
+       const TOOLBAR_MENU_TEMPLATE = 'SystemInformation.html';
+
+       /**
+        * Number displayed as badge on the dropdown trigger
+        *
+        * @var int
+        */
+       protected $totalCount = 0;
+
+       /**
+        * Holds the highest severity
+        *
+        * @var string
+        */
+       protected $highestSeverity = '';
+
+       /**
+        * @var array
+        */
+       protected $systemInformation = array();
+
+       /**
+        * @var array
+        */
+       protected $systemMessages = array();
+
+       /**
+        * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+        */
+       protected $signalSlotDispatcher = NULL;
+
+       /**
+        * Constructor
+        */
+       public function __construct() {
+               if (!$this->checkAccess()) {
+                       return;
+               }
+
+               parent::__construct();
+
+               $pageRenderer = $this->getPageRenderer();
+               $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/SystemInformationMenu');
+
+               $this->getPhpVersion();
+               $this->getDatabase();
+               $this->getApplicationContext();
+               $this->getGitRevision();
+               $this->getOperatingSystem();
+
+               $this->emitGetSystemInformation();
+               $this->emitLoadMessages();
+       }
+
+       /**
+        * Gets the PHP version
+        */
+       protected function getPhpVersion() {
+               $this->systemInformation[] = array(
+                       'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.phpversion', TRUE),
+                       'value' => PHP_VERSION,
+                       'icon' => '<span class="fa fa-code"></span>'
+               );
+       }
+
+       /**
+        * Get the database info
+        */
+       protected function getDatabase() {
+               $this->systemInformation[] = array(
+                       'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.database', TRUE),
+                       'value' => $this->getDatabaseConnection()->getServerVersion(),
+                       'icon' => '<span class="fa fa-database"></span>'
+               );
+       }
+
+       /**
+        * Gets the application context
+        */
+       protected function getApplicationContext() {
+               $applicationContext = GeneralUtility::getApplicationContext();
+               $this->systemInformation[] = array(
+                       'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.applicationcontext', TRUE),
+                       'value' => (string)$applicationContext,
+                       'status' => $applicationContext->isProduction() ? InformationStatus::STATUS_OK : InformationStatus::STATUS_ERROR,
+                       'icon' => '<span class="fa fa-tasks"></span>'
+               );
+       }
+
+       /**
+        * Gets the current GIT revision and branch
+        */
+       protected function getGitRevision() {
+               if (!StringUtility::endsWith(TYPO3_version, '-dev') || \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::isFunctionDisabled('exec')) {
+                       return '';
+               }
+               // check if git exists
+               CommandUtility::exec('git --version', $_, $returnCode);
+               if ((int)$returnCode !== 0) {
+                       // git is not available
+                       return '';
+               }
+
+               $revision = trim(CommandUtility::exec('git rev-parse --short HEAD'));
+               $branch = trim(CommandUtility::exec('git rev-parse --abbrev-ref HEAD'));
+               if (!empty($revision) && !empty($branch)) {
+                       $this->systemInformation[] = array(
+                               'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.gitrevision', TRUE),
+                               'value' => sprintf('%s [%s]', $revision, $branch),
+                               'icon' => '<span class="fa fa-git"></span>'
+                       );
+               }
+       }
+
+       /**
+        * Gets the system kernel and version
+        */
+       protected function getOperatingSystem() {
+               $kernelName = php_uname('s');
+               switch (strtolower($kernelName)) {
+                       case 'linux':
+                               $icon = 'linux';
+                               break;
+                       case 'darwin':
+                               $icon = 'apple';
+                               break;
+                       default:
+                               $icon = 'windows';
+               }
+               $this->systemInformation[] = array(
+                       'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.operatingsystem', TRUE),
+                       'value' => $kernelName . ' ' . php_uname('r'),
+                       'icon' => '<span class="fa fa-' . htmlspecialchars($icon) . '"></span>'
+               );
+       }
+
+       /**
+        * Emits the "getSystemInformation" signal
+        */
+       protected function emitGetSystemInformation() {
+               list($systemInformation) = $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'getSystemInformation', array(array()));
+               if (!empty($systemInformation)) {
+                       $this->systemInformation[] = $systemInformation;
+               }
+       }
+
+       /**
+        * Emits the "loadMessages" signal
+        */
+       protected function emitLoadMessages() {
+               list($message) = $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'loadMessages', array(array()));
+               if (empty($message)) {
+                       return;
+               }
+
+               // increase counter
+               if (isset($message['count'])) {
+                       $this->totalCount += (int)$message['count'];
+               }
+
+               // define the severity for the badge
+               if (InformationStatus::mapStatusToInt($message['status']) > InformationStatus::mapStatusToInt($this->highestSeverity)) {
+                       $this->highestSeverity = $message['status'];
+               }
+
+               $this->systemMessages[] = $message;
+       }
+
+       /**
+        * Checks whether the user has access to this toolbar item
+        *
+        * @return bool TRUE if user has access, FALSE if not
+        */
+       public function checkAccess() {
+               return $this->getBackendUserAuthentication()->isAdmin();
+       }
+
+       /**
+        * Render system information dropdown
+        *
+        * @return string Icon HTML
+        */
+       public function getItem() {
+               $title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo', TRUE);
+               $item = IconUtility::getSpriteIcon('actions-system-list-open', array('title' => $title));
+
+               if ($this->totalCount > 0) {
+                       $severityBadge = $this->highestSeverity !== InformationStatus::STATUS_DEFAULT ? 'badge-' . $this->highestSeverity : '';
+                       $item .= '<span id="t3js-systeminformation-counter" class="badge ' . $severityBadge . '">' . $this->totalCount . '</span>';
+               }
+               return $item;
+       }
+
+       /**
+        * Render drop down
+        *
+        * @return string Drop down HTML
+        */
+       public function getDropDown() {
+               if (!$this->checkAccess()) {
+                       return '';
+               }
+
+               $this->getStandaloneView('backend')->assignMultiple(array(
+                       'installToolUrl' => BackendUtility::getModuleUrl('system_InstallInstall'),
+                       'messages' => $this->systemMessages,
+                       'systemInformation' => $this->systemInformation
+               ));
+               return $this->getStandaloneView()->render();
+       }
+
+       /**
+        * No additional attributes needed.
+        *
+        * @return array
+        */
+       public function getAdditionalAttributes() {
+               return array();
+       }
+
+       /**
+        * This item has a drop down
+        *
+        * @return bool
+        */
+       public function hasDropDown() {
+               return TRUE;
+       }
+
+       /**
+        * Position relative to others
+        *
+        * @return int
+        */
+       public function getIndex() {
+               return 75;
+       }
+
+       /**
+        * Returns the current BE user.
+        *
+        * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+        */
+       protected function getBackendUserAuthentication() {
+               return $GLOBALS['BE_USER'];
+       }
+
+       /**
+        * Returns DatabaseConnection
+        *
+        * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+
+       /**
+        * Returns current PageRenderer
+        *
+        * @return \TYPO3\CMS\Core\Page\PageRenderer
+        */
+       protected function getPageRenderer() {
+               /** @var \TYPO3\CMS\Backend\Template\DocumentTemplate $documentTemplate */
+               $documentTemplate = $GLOBALS['TBE_TEMPLATE'];
+               return $documentTemplate->getPageRenderer();
+       }
+
+       /**
+        * Returns LanguageService
+        *
+        * @return \TYPO3\CMS\Lang\LanguageService
+        */
+       protected function getLanguageService() {
+               return $GLOBALS['LANG'];
+       }
+
+       /**
+        * Get the SignalSlot dispatcher
+        *
+        * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+        */
+       protected function getSignalSlotDispatcher() {
+               if (!isset($this->signalSlotDispatcher)) {
+                       $this->signalSlotDispatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class)
+                               ->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+               }
+               return $this->signalSlotDispatcher;
+       }
+
+}
diff --git a/typo3/sysext/backend/Classes/Toolbar/Enumeration/InformationStatus.php b/typo3/sysext/backend/Classes/Toolbar/Enumeration/InformationStatus.php
new file mode 100644 (file)
index 0000000..2243cb8
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+namespace TYPO3\CMS\Backend\Toolbar\Enumeration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * This class holds the severities of the SystemInformation toolbar menu
+ */
+class InformationStatus extends \TYPO3\CMS\Core\Type\Enumeration {
+
+       /**
+        * @var string
+        */
+       const STATUS_DEFAULT = '';
+
+       /**
+        * @var string
+        */
+       const STATUS_OK = 'success';
+
+       /**
+        * @var string
+        */
+       const STATUS_WARNING = 'warning';
+
+       /**
+        * @var string
+        */
+       const STATUS_ERROR = 'danger';
+
+       /**
+        * @var int[]
+        */
+       static protected $statusIntegerMap = array(
+               self::STATUS_DEFAULT => -1,
+               self::STATUS_OK => 0,
+               self::STATUS_WARNING => 1,
+               self::STATUS_ERROR => 2
+       );
+
+       /**
+        * Map the status string to an integer
+        *
+        * @param string $status
+        * @return int
+        */
+       static public function mapStatusToInt($status) {
+               if (isset(static::$statusIntegerMap[$status])) {
+                       return static::$statusIntegerMap[$status];
+               }
+               return -1;
+       }
+}
\ No newline at end of file
index 2e02b4f..324ceda 100644 (file)
@@ -9,6 +9,16 @@
                        <trans-unit id="show_references">
                                <source>Show references</source>
                        </trans-unit>
+                       <trans-unit id="systemmessage.header">
+                               <source>Application Information</source>
+                       </trans-unit>
+                       <trans-unit id="systemmessage.intro">
+                               <source><![CDATA[This is a short system overview, for advanced information please head to the <a href="%s">Install Tool</a>.]]></source>
+                       </trans-unit>
+                       <trans-unit id="systemmessage.allgood" xml:space="preserve">
+                               <source>Your system is fully operational.
+Have a nice day.</source>
+                       </trans-unit>
                </body>
        </file>
 </xliff>
diff --git a/typo3/sysext/backend/Resources/Private/Templates/ToolbarMenu/SystemInformation.html b/typo3/sysext/backend/Resources/Private/Templates/ToolbarMenu/SystemInformation.html
new file mode 100644 (file)
index 0000000..c3ef80d
--- /dev/null
@@ -0,0 +1,32 @@
+<ul class="dropdown-list">
+       <li class="dropdown-header"><f:translate key="systemmessage.header" /></li>
+       <li id="systeminformation_installtool" class="dropdown-intro typo3-module-menu-item submodule mod-system_InstallInstall" data-modulename="system_InstallInstall">
+               <f:translate key="systemmessage.intro" arguments="{0: '{installToolUrl}'}" />
+       </li>
+       <li>
+               <dl class="dl-horizontal">
+                       <f:for each="{systemInformation}" as="info">
+                               <dt title="{info.title}"><f:format.raw>{info.icon}</f:format.raw> {info.title}</dt>
+                               <dd><f:if condition="{info.status}">
+                                       <f:then>
+                                               <span class="text-{info.status}">{info.value}</span>
+                                       </f:then>
+                                       <f:else>
+                                               {info.value}
+                                       </f:else>
+                               </f:if></dd>
+                       </f:for>
+               </dl>
+       </li>
+       <li class="divider"></li>
+       <f:if condition="{messages -> f:count()} > 0">
+               <f:then>
+                       <f:for each="{messages}" as="message">
+                               <li><span class="text-{message.status}">{message.text}</span></li>
+                       </f:for>
+               </f:then>
+               <f:else>
+                       <li><span class="text-success"><f:format.nl2br><f:translate key="systemmessage.allgood" /></f:format.nl2br></span></li>
+               </f:else>
+       </f:if>
+</ul>
\ No newline at end of file
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js
new file mode 100644 (file)
index 0000000..fab870d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * System information menu handler
+ */
+define('TYPO3/CMS/Backend/Toolbar/SystemInformationMenu', ['jquery'], function($) {
+
+       var SystemInformationMenu = {
+               elements: {
+                       $counter: $('#t3js-systeminformation-counter')
+               }
+       };
+
+       /**
+        * register event handlers
+        */
+       SystemInformationMenu.initializeEvents = function() {
+               var count = parseInt(SystemInformationMenu.elements.$counter.text());
+               SystemInformationMenu.elements.$counter.toggle(count > 0);
+       };
+
+       /**
+        * initialize and return the Opendocs object
+        */
+       $(document).ready(function() {
+               SystemInformationMenu.initializeEvents();
+       });
+
+       TYPO3.SystemInformationMenu = SystemInformationMenu;
+       return SystemInformationMenu;
+});
index 32879a2..24450b1 100644 (file)
@@ -13,6 +13,7 @@ if (TYPO3_MODE === 'BE') {
        $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = \TYPO3\CMS\Backend\Backend\ToolbarItems\HelpToolbarItem::class;
        $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = \TYPO3\CMS\Backend\Backend\ToolbarItems\LiveSearchToolbarItem::class;
        $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = \TYPO3\CMS\Backend\Backend\ToolbarItems\ShortcutToolbarItem::class;
+       $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = \TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::class;
        $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = \TYPO3\CMS\Backend\Backend\ToolbarItems\UserToolbarItem::class;
 }
 
diff --git a/typo3/sysext/belog/Classes/Controller/SystemInformationController.php b/typo3/sysext/belog/Classes/Controller/SystemInformationController.php
new file mode 100644 (file)
index 0000000..03f21f4
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+namespace TYPO3\CMS\Belog\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Belog\Domain\Model\Constraint;
+
+/**
+ * Count newest exceptions for the system information menu
+ */
+class SystemInformationController extends AbstractController {
+
+       /**
+        * Modifies the SystemInformation array
+        *
+        * @param array $systemMessages Array of system messages
+        * @return
+        */
+       public function appendMessage() {
+               $constraint = $this->getConstraintFromBeUserData();
+               if ($constraint === NULL) {
+                       $constraint = $this->objectManager->get(Constraint::class);
+               }
+
+               $this->setStartAndEndTimeFromTimeSelector($constraint);
+               // we can't use the extbase repository here as the required TypoScript may not be parsed yet
+               $count = $this->getDatabaseConnection()->exec_SELECTcountRows('error', 'sys_log', 'tstamp >= ' . $constraint->getStartTimestamp() . ' AND tstamp <= ' . $constraint->getEndTimestamp() . ' AND error IN(-1,1,2,3)');
+
+               if ($count > 0) {
+                       return array(
+                               array(
+                                       'count' => $count,
+                                       'status' => \TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus::STATUS_ERROR,
+                                       'text' => sprintf(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('systemmessage.errorsInPeriod', 'belog'), $count)
+                               )
+                       );
+               }
+               return NULL;
+       }
+
+       /**
+        * Get module states (the constraint object) from user data
+        *
+        * @return \TYPO3\CMS\Belog\Domain\Model\Constraint|NULL
+        */
+       protected function getConstraintFromBeUserData() {
+               $serializedConstraint = $GLOBALS['BE_USER']->getModuleData(ToolsController::class);
+               if (!is_string($serializedConstraint) || empty($serializedConstraint)) {
+                       return NULL;
+               }
+               return @unserialize($serializedConstraint);
+       }
+
+       /**
+        * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+        */
+       protected function getDatabaseConnection() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+}
index 7995179..4f86c9b 100644 (file)
                        <trans-unit id="chLog_menuTime">
                                <source>Time</source>
                        </trans-unit>
+                       <trans-unit id="systemmessage.errorsInPeriod">
+                               <source>We have found %1$d errors. Please check your administration log.</source>
+                       </trans-unit>
                </body>
        </file>
 </xliff>
diff --git a/typo3/sysext/belog/ext_localconf.php b/typo3/sysext/belog/ext_localconf.php
new file mode 100644 (file)
index 0000000..c6b54d3
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+defined('TYPO3_MODE') or die();
+
+if (TYPO3_MODE === 'BE' && !(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL)) {
+       $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+       $signalSlotDispatcher->connect(
+               \TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::class,
+               'loadMessages',
+               \TYPO3\CMS\Belog\Controller\SystemInformationController::class,
+               'appendMessage'
+       );
+}
\ No newline at end of file
index 0b4f347..12b9538 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Core;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
 /**
  * Class to encapsulate base setup of bootstrap.
  *
@@ -51,6 +53,13 @@ class SystemEnvironmentBuilder {
        );
 
        /**
+        * An array of disabled methods
+        *
+        * @var string[]
+        */
+       static protected $disabledFunctions = NULL;
+
+       /**
         * Run base setup.
         * This entry method is used in all scopes (FE, BE, eid, ajax, ...)
         *
@@ -194,8 +203,8 @@ class SystemEnvironmentBuilder {
         */
        static protected function handleMagicQuotesGpc() {
                if (!get_magic_quotes_gpc()) {
-                       \TYPO3\CMS\Core\Utility\GeneralUtility::addSlashesOnArray($_GET);
-                       \TYPO3\CMS\Core\Utility\GeneralUtility::addSlashesOnArray($_POST);
+                       GeneralUtility::addSlashesOnArray($_GET);
+                       GeneralUtility::addSlashesOnArray($_POST);
                        $GLOBALS['HTTP_GET_VARS'] = $_GET;
                        $GLOBALS['HTTP_POST_VARS'] = $_POST;
                }
@@ -210,7 +219,7 @@ class SystemEnvironmentBuilder {
                // Unset variable(s) in global scope (security issue #13959)
                unset($GLOBALS['error']);
                // Set up base information about browser/user-agent
-               $GLOBALS['CLIENT'] = \TYPO3\CMS\Core\Utility\GeneralUtility::clientInfo();
+               $GLOBALS['CLIENT'] = GeneralUtility::clientInfo();
                $GLOBALS['TYPO3_MISC'] = array();
                $GLOBALS['T3_VAR'] = array();
                $GLOBALS['T3_SERVICES'] = array();
@@ -224,7 +233,7 @@ class SystemEnvironmentBuilder {
         */
        static protected function initializeGlobalTimeTrackingVariables() {
                // Set PARSETIME_START to the system time in milliseconds.
-               $GLOBALS['PARSETIME_START'] = \TYPO3\CMS\Core\Utility\GeneralUtility::milliseconds();
+               $GLOBALS['PARSETIME_START'] = GeneralUtility::milliseconds();
                // Microtime of (nearly) script start
                $GLOBALS['TYPO3_MISC']['microtime_start'] = microtime(TRUE);
                // EXEC_TIME is set so that the rest of the script has a common value for the script execution time
@@ -458,4 +467,20 @@ class SystemEnvironmentBuilder {
                die($message);
        }
 
+       /**
+        * Check if the given function is disabled in the system
+        *
+        * @param string $function
+        * @return bool
+        */
+       static public function isFunctionDisabled($function) {
+               if (static::$disabledFunctions === NULL) {
+                       static::$disabledFunctions = GeneralUtility::trimExplode(',', ini_get('disable_functions'));
+               }
+               if (!empty(static::$disabledFunctions)) {
+                       return in_array($function, static::$disabledFunctions, TRUE);
+               }
+
+               return FALSE;
+       }
 }
index fcc139b..8de1bdc 100644 (file)
@@ -1703,6 +1703,15 @@ class DatabaseConnection {
                $this->link = $handle;
        }
 
+       /**
+        * Get the MySQL server version
+        *
+        * @return string
+        */
+       public function getServerVersion() {
+               return $this->link->server_info;
+       }
+
        /******************************
         *
         * Debugging
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-65767-SystemInformationDropdown.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-65767-SystemInformationDropdown.rst
new file mode 100644 (file)
index 0000000..aa7b14b
--- /dev/null
@@ -0,0 +1,93 @@
+=============================================
+Feature: #65767 - System Information Dropdown
+=============================================
+
+Description
+===========
+
+A new, extendable dropdown menu item is introduced that contains several information about
+the system TYPO3 is installed on.
+
+
+Impact
+======
+
+In a default installation. the new dropdown item will be placed between the "help" and the "user"
+dropdown items and is accessible by administrators only.
+
+Items
+^^^^^
+
+It is possible to add own system information items by creating a slot. The slot must be registered in
+the extension's ext_localconf.php
+
+.. code-block:: php
+
+       $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+       $signalSlotDispatcher->connect(
+               \TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::class,
+               'getSystemInformation',
+               \Vendor\Extension\SystemInformation\Item::class,
+               'getItem'
+       );
+
+This requires the class `Item` and it's method `getItem()` in EXT:extension\Classes\SystemInformation\Item.php:
+
+.. code-block:: php
+       class Item {
+               public function getItem() {
+                       return array(array(
+                               'title' => 'The title shown on hover',
+                               'value' => 'Description shown in the list',
+                               'status' => SystemInformationHookInterface::STATUS_OK,
+                               'count' => 4,
+                               'icon' => \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('extensions-example-information-icon')
+                       ));
+               }
+       }
+
+Due to the SignalSlot internals, the data array must be encapsulated with another array! If there is no data to return, return `NULL`.
+
+The icon `extensions-example-information-icon` must be registered in ext_localconf.php:
+
+.. code-block:: php
+       \TYPO3\CMS\Backend\Sprite\SpriteManager::addSingleIcons(
+               array(
+                       'information-icon' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'Resources/Public/Images/Icons/information-icon.png'
+               ),
+               $_EXTKEY
+       );
+
+"extensions-" is a hardcoded prefix, combined with `$_EXTKEY` (e.g. "example") creates the prefix "extensions-example-" to
+be used with every icon being registered. Since the first parameter of `SpriteManager::addSingleIcons()` is an array, multiple icons
+can be registered at once.
+
+
+Messages
+^^^^^^^^
+
+Messages are shown at the bottom og the dropdown. An extension can provide it's own slot to fill the messages:
+
+.. code-block:: php
+
+       $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+       $signalSlotDispatcher->connect(
+               \TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::class,
+               'loadMessages',
+               \Vendor\Extension\SystemInformation\Message::class,
+               'getMessage'
+       );
+
+This requires the class `Message` and it's method `getMessage()` in EXT:extension\Classes\SystemInformation\Message.php:
+
+.. code-block:: php
+       class Message {
+               public function getMessage() {
+                       return array(array(
+                               'status' => SystemInformationHookInterface::STATUS_OK,
+                               'text' => 'Something went somewhere terribly wrong. Take a look at the reports module.'
+                       ));
+               }
+       }
+
+Due to the SignalSlot internals, the data array must be encapsulated with another array! If there is no data to return, return `NULL`.
\ No newline at end of file
index 52ffd68..b14aa32 100644 (file)
@@ -3165,6 +3165,28 @@ class DatabaseConnection extends \TYPO3\CMS\Core\Database\DatabaseConnection {
                return strpos($this->handlerCfg[$this->lastHandlerKey]['config']['driver'], $driver) !== FALSE;
        }
 
+       /**
+        * Get the SQL server version
+        *
+        * @return string
+        */
+       public function getServerVersion() {
+               $result = '';
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               $result = $this->handlerInstance[$this->lastHandlerKey]['link']->server_info;
+                               break;
+                       case 'adodb':
+                       case 'userdefined':
+                               if (is_object($this->handlerInstance[$this->lastHandlerKey])) {
+                                       $serverInfo = $this->handlerInstance[$this->lastHandlerKey]->ServerInfo();
+                                       $result = $serverInfo['version'];
+                               }
+                               break;
+               }
+               return $result;
+       }
+
        /************************************
         *
         * Table/Field mapping
index bde88f8..44d1261 100644 (file)
@@ -1063,6 +1063,24 @@ Would you like to save now in order to refresh the display?</source>
                        <trans-unit id="toolbarItems.workspace">
                                <source>Workspace</source>
                        </trans-unit>
+                       <trans-unit id="toolbarItems.sysinfo">
+                               <source>System Information</source>
+                       </trans-unit>
+                       <trans-unit id="toolbarItems.sysinfo.phpversion">
+                               <source>PHP Version</source>
+                       </trans-unit>
+                       <trans-unit id="toolbarItems.sysinfo.database">
+                               <source>Database</source>
+                       </trans-unit>
+                       <trans-unit id="toolbarItems.sysinfo.applicationcontext">
+                               <source>Application Context</source>
+                       </trans-unit>
+                       <trans-unit id="toolbarItems.sysinfo.gitrevision">
+                               <source>GIT Revision</source>
+                       </trans-unit>
+                       <trans-unit id="toolbarItems.sysinfo.operatingsystem">
+                               <source>Operating System</source>
+                       </trans-unit>
                        <trans-unit id="tabs.closeAll">
                                <source>Close All Tabs</source>
                        </trans-unit>
diff --git a/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_badges.less b/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_badges.less
new file mode 100644 (file)
index 0000000..e8af826
--- /dev/null
@@ -0,0 +1,15 @@
+//
+// Badges
+//
+
+.badge-success {
+       .bg-variant(@brand-success);
+}
+
+.badge-warning {
+       .bg-variant(@brand-warning);
+}
+
+.badge-danger {
+       .bg-variant(@brand-danger);
+}
\ No newline at end of file
index 6a24d5d..b957e57 100644 (file)
                        margin-right: -@topbar-dropdown-padding;
                        padding: (@topbar-dropdown-padding / 2) @topbar-dropdown-padding;
                }
+               .dropdown-intro {
+                       color: darken(@topbar-color, 20%);
+                       margin-left: -@topbar-dropdown-padding;
+                       margin-right: -@topbar-dropdown-padding;
+                       padding: (@topbar-dropdown-padding / 2) @topbar-dropdown-padding;
+               }
+               .dl-horizontal {
+                       dt {
+                               width: 140px;
+                               text-align: left;
+                               font-weight: normal;
+                       }
+                       dd {
+                               margin-left: 150px;
+                               width: 170px;
+                       }
+               }
        }
        .dropdown-list-link {
                max-width: 300px;
                        color: @topbar-dropdown-link-hover-color;
                        background-color: @topbar-dropdown-link-hover-bg;
                }
+               .badge {
+                       background-color: @brand-danger;
+                       color: @btn-danger-color;
+               }
        }
        .dropdown-list-link-edit,
        .dropdown-list-link-delete,
index 2798a33..1116108 100644 (file)
 @import "TYPO3/_element_tree.less";
 @import "TYPO3/_element_pagination.less";
 @import "TYPO3/_element_label.less";
+@import "TYPO3/_element_badges.less";
 @import "TYPO3/_element_buttons.less";
 @import "TYPO3/_fonts.less";
 @import "TYPO3/_icons.less";
index bfe0765..3aa620b 100644 (file)
@@ -9920,6 +9920,24 @@ table#typo3-tree tr:hover {
 .label-block {
   display: block;
 }
+.badge-success {
+  background-color: #1eb941;
+}
+a.badge-success:hover {
+  background-color: #178d32;
+}
+.badge-warning {
+  background-color: #f07814;
+}
+a.badge-warning:hover {
+  background-color: #c4600d;
+}
+.badge-danger {
+  background-color: #c83c3c;
+}
+a.badge-danger:hover {
+  background-color: #a32e2e;
+}
 .btn .t3-icon {
   margin: 0;
 }
@@ -11192,6 +11210,21 @@ iframe {
   margin-right: -16px;
   padding: 8px 16px;
 }
+.typo3-topbar-navigation-items .dropdown-list .dropdown-intro {
+  color: #aaaaaa;
+  margin-left: -16px;
+  margin-right: -16px;
+  padding: 8px 16px;
+}
+.typo3-topbar-navigation-items .dropdown-list .dl-horizontal dt {
+  width: 140px;
+  text-align: left;
+  font-weight: normal;
+}
+.typo3-topbar-navigation-items .dropdown-list .dl-horizontal dd {
+  margin-left: 150px;
+  width: 170px;
+}
 .typo3-topbar-navigation-items .dropdown-list-link {
   max-width: 300px;
   overflow: hidden;
@@ -11209,6 +11242,10 @@ iframe {
   color: #ffffff;
   background-color: #333333;
 }
+.typo3-topbar-navigation-items .dropdown-list-link .badge {
+  background-color: #c83c3c;
+  color: #ffffff;
+}
 .typo3-topbar-navigation-items .dropdown-list-link-edit,
 .typo3-topbar-navigation-items .dropdown-list-link-delete,
 .typo3-topbar-navigation-items .dropdown-list-link-close {