From 1ddcb9a7de037c709f5f97a9ff980fd1d04d378d Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Fri, 14 Nov 2014 11:32:46 +0100
Subject: [PATCH] [TASK] ToolbarItem registration and position

Toolbar items are now registered with its class name in array
$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'].

The ToolbarItem interface adds a position method to determine
the order of items.

Resolves: #62959
Releases: master
Change-Id: Ie18d4b2148093f28c1f5387907912d8591797582
Reviewed-on: http://review.typo3.org/34149
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
Reviewed-by: Felix Kopp <felix-source@phorax.com>
Tested-by: Felix Kopp <felix-source@phorax.com>
---
 .../ToolbarItems}/ClearCacheToolbarItem.php   |  14 +-
 .../ToolbarItems}/LiveSearchToolbarItem.php   |  15 +-
 .../ToolbarItems}/ShortcutToolbarItem.php     |  12 +-
 .../Backend/ToolbarItems/UserToolbarItem.php  | 147 ++++++++++++++++++
 .../Classes/Controller/BackendController.php  | 137 ++++------------
 .../Toolbar/ToolbarItemHookInterface.php      |  50 ------
 .../Classes/Toolbar/ToolbarItemInterface.php  |  11 ++
 typo3/sysext/backend/ext_localconf.php        |   5 +
 .../Migrations/Code/ClassAliasMap.php         |   1 -
 .../Migrations/Code/LegacyClassesForIde.php   |   2 -
 .../Configuration/DefaultConfiguration.php    |   1 +
 .../ToolbarItems/OpendocsToolbarItem.php}     |  15 +-
 .../Migrations/Code/ClassAliasMap.php         |   4 +-
 .../Resources/PHP/RegisterToolbarItem.php     |   7 -
 typo3/sysext/opendocs/ext_localconf.php       |   5 +-
 .../ToolbarItems/ActionToolbarItem.php}       |  14 +-
 .../Resources/PHP/RegisterToolbarItem.php     |   4 -
 typo3/sysext/sys_action/ext_localconf.php     |   4 +-
 .../WorkspaceSelectorToolbarItem.php          |  11 +-
 .../Resources/PHP/RegisterToolbarItem.php     |   4 -
 typo3/sysext/workspaces/ext_localconf.php     |   4 +-
 21 files changed, 274 insertions(+), 193 deletions(-)
 rename typo3/sysext/backend/Classes/{Toolbar => Backend/ToolbarItems}/ClearCacheToolbarItem.php (96%)
 rename typo3/sysext/backend/Classes/{Toolbar => Backend/ToolbarItems}/LiveSearchToolbarItem.php (91%)
 rename typo3/sysext/backend/Classes/{Toolbar => Backend/ToolbarItems}/ShortcutToolbarItem.php (99%)
 create mode 100644 typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
 delete mode 100644 typo3/sysext/backend/Classes/Toolbar/ToolbarItemHookInterface.php
 rename typo3/sysext/opendocs/Classes/{Controller/OpendocsController.php => Backend/ToolbarItems/OpendocsToolbarItem.php} (97%)
 delete mode 100644 typo3/sysext/opendocs/Resources/PHP/RegisterToolbarItem.php
 rename typo3/sysext/sys_action/Classes/{ActionToolbarMenu.php => Backend/ToolbarItems/ActionToolbarItem.php} (94%)
 delete mode 100644 typo3/sysext/sys_action/Resources/PHP/RegisterToolbarItem.php
 rename typo3/sysext/workspaces/Classes/{ExtDirect => Backend/ToolbarItems}/WorkspaceSelectorToolbarItem.php (97%)
 delete mode 100644 typo3/sysext/workspaces/Resources/PHP/RegisterToolbarItem.php

diff --git a/typo3/sysext/backend/Classes/Toolbar/ClearCacheToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php
similarity index 96%
rename from typo3/sysext/backend/Classes/Toolbar/ClearCacheToolbarItem.php
rename to typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php
index fe12f859b2d7..4d5cc32510a1 100644
--- a/typo3/sysext/backend/Classes/Toolbar/ClearCacheToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\Backend\Toolbar;
+namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Toolbar;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 
 /**
  * class to render the menu for the cache clearing actions
@@ -140,7 +141,7 @@ class ClearCacheToolbarItem implements ToolbarItemInterface {
 		$cacheMenu = array();
 		$cacheMenu[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . IconUtility::getSpriteIcon('apps-toolbar-menu-cache', array('title' => $title)) . '</a>';
 		$cacheMenu[] = '<ul class="dropdown-menu" role="menu">';
-		foreach ($this->cacheActions as $actionKey => $cacheAction) {
+		foreach ($this->cacheActions as $cacheAction) {
 			$cacheMenu[] = '<li><a href="' . htmlspecialchars($cacheAction['href'])
 				. '" title="' . htmlspecialchars($cacheAction['description'] ?: $cacheAction['title']) . '">'
 				. $cacheAction['icon'] . ' ' . htmlspecialchars($cacheAction['title']) . '</a></li>';
@@ -206,4 +207,13 @@ class ClearCacheToolbarItem implements ToolbarItemInterface {
 		return $GLOBALS['BE_USER'];
 	}
 
+	/**
+	 * Position relative to others
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 25;
+	}
+
 }
diff --git a/typo3/sysext/backend/Classes/Toolbar/LiveSearchToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php
similarity index 91%
rename from typo3/sysext/backend/Classes/Toolbar/LiveSearchToolbarItem.php
rename to typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php
index c6075b0699c5..90b2f3ed82f9 100644
--- a/typo3/sysext/backend/Classes/Toolbar/LiveSearchToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\Backend\Toolbar;
+namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Backend\Toolbar;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+
 /**
  * Adds backend live search to the toolbar
  *
@@ -91,7 +93,7 @@ class LiveSearchToolbarItem implements ToolbarItemInterface {
 	 * @return string The name of the ID attribute
 	 */
 	public function getIdAttribute() {
-		return 'live-search-menu';
+		return 'livesearch-menu';
 	}
 
 	/**
@@ -112,4 +114,13 @@ class LiveSearchToolbarItem implements ToolbarItemInterface {
 		return FALSE;
 	}
 
+	/**
+	 * Position relative to others, live search should be very right
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 90;
+	}
+
 }
diff --git a/typo3/sysext/backend/Classes/Toolbar/ShortcutToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
similarity index 99%
rename from typo3/sysext/backend/Classes/Toolbar/ShortcutToolbarItem.php
rename to typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
index 13efcdbc6d4e..4cece5a81843 100644
--- a/typo3/sysext/backend/Classes/Toolbar/ShortcutToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\Backend\Toolbar;
+namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -18,6 +18,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 
 /**
  * Class to render the shortcut menu
@@ -742,4 +743,13 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 		return preg_replace('/.*[\\?&]id=([^&]+).*/', '$1', $url);
 	}
 
+	/**
+	 * Position relative to others, live search should be very right
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 20;
+	}
+
 }
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
new file mode 100644
index 000000000000..ac9c01386b63
--- /dev/null
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
@@ -0,0 +1,147 @@
+<?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\GeneralUtility;
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+
+/**
+ * User toobar item
+ */
+class UserToolbarItem implements ToolbarItemInterface {
+
+	/**
+	 * Constructor
+	 *
+	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
+	 * @throws \UnexpectedValueException
+	 */
+	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
+	}
+
+	/**
+	 * Checks whether the user has access to this toolbar item
+	 *
+	 * @return bool TRUE if user has access, FALSE if not
+	 */
+	public function checkAccess() {
+		return TRUE;
+	}
+
+	/**
+	 * Creates the selector for workspaces
+	 *
+	 * @return string Workspace selector as HTML select
+	 */
+	public function render() {
+		$icon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-user-' . ($GLOBALS['BE_USER']->isAdmin() ? 'admin' : 'backend'));
+
+		$realName = $GLOBALS['BE_USER']->user['realName'];
+		$username = $GLOBALS['BE_USER']->user['username'];
+		$label = $realName ?: $username;
+		$title = $username;
+
+		// Superuser mode
+		if ($GLOBALS['BE_USER']->user['ses_backuserid']) {
+			$title = $GLOBALS['LANG']->getLL('switchtouser') . ': ' . $username;
+			$label = $GLOBALS['LANG']->getLL('switchtousershort') . ' ' . ($realName ? $realName . ' (' . $username . ')' : $username);
+		}
+
+
+		$html = array();
+		$html[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
+		$html[] = $icon . '<span title="' . htmlspecialchars($title) . '">' . htmlspecialchars($label) . ' <span class="caret"></span></span>';
+		$html[] = '</a>';
+
+		$html[] = '<ul class="dropdown-menu" role="menu">';
+
+		/** @var \TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository $backendModuleRepository */
+		$backendModuleRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository::class);
+		/** @var \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $userModuleMenu */
+		$userModuleMenu = $backendModuleRepository->findByModuleName('user');
+		if ($userModuleMenu != FALSE && $userModuleMenu->getChildren()->count() > 0) {
+			foreach ($userModuleMenu->getChildren() as $module) {
+				$moduleIcon = $module->getIcon();
+				$html[] = '
+					<li id="' . $module->getName() . '" class="t3-menuitem-submodule submodule mod-' . $module->getName() . '" data-modulename="' . $module->getName() . '" data-navigationcomponentid="' . $module->getNavigationComponentId() . '" data-navigationframescript="' . $module->getNavigationFrameScript() . '" data-navigationframescriptparameters="' . $module->getNavigationFrameScriptParameters() . '">
+						<a title="' .$module->getDescription() . '" href="' . $module->getLink() . '" class="modlink">
+							<span class="submodule-icon">' . ($moduleIcon['html'] ?: $moduleIcon['html']) . '</span>
+							<span class="submodule-label">' . $module->getTitle() . '</span>
+						</a>
+					</li>';
+			}
+			$html[] = '<li class="divider"></li>';
+		}
+
+		// logout button
+		$buttonLabel = 'LLL:EXT:lang/locallang_core.xlf:' . ($GLOBALS['BE_USER']->user['ses_backuserid'] ? 'buttons.exit' : 'buttons.logout');
+		$html[] = '<li><a href="logout.php" target="_top">' . $GLOBALS['LANG']->sL($buttonLabel, TRUE) . '</a></li>';
+
+		$html[] = '</ul>';
+
+		return implode(LF, $html);
+	}
+
+	/**
+	 * Returns additional attributes for the list item in the toolbar
+	 *
+	 * This should not contain the "class" or "id" attribute.
+	 * Use the methods for setting these attributes
+	 *
+	 * @return string List item HTML attibutes
+	 */
+	public function getAdditionalAttributes() {
+		if ($GLOBALS['BE_USER']->user['ses_backuserid']) {
+			return 'su-user';
+		}
+	}
+
+	/**
+	 * Return attribute id name
+	 *
+	 * @return string The name of the ID attribute
+	 */
+	public function getIdAttribute() {
+		return 'topbar-user-menu';
+	}
+
+	/**
+	 * Returns extra classes
+	 *
+	 * @return array
+	 */
+	public function getExtraClasses() {
+		return array();
+	}
+
+	/**
+	 * Get dropdown
+	 *
+	 * @return bool
+	 */
+	public function getDropdown() {
+		return TRUE;
+	}
+
+	/**
+	 * Position relative to others
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 80;
+	}
+
+}
diff --git a/typo3/sysext/backend/Classes/Controller/BackendController.php b/typo3/sysext/backend/Classes/Controller/BackendController.php
index 6abeeec0bbe7..a1fd5bc4c59e 100644
--- a/typo3/sysext/backend/Classes/Controller/BackendController.php
+++ b/typo3/sysext/backend/Classes/Controller/BackendController.php
@@ -38,7 +38,7 @@ class BackendController {
 	/**
 	 * @var array
 	 */
-	protected $cssFiles;
+	protected $cssFiles = array();
 
 	/**
 	 * @var string
@@ -53,7 +53,7 @@ class BackendController {
 	/**
 	 * @var array
 	 */
-	protected $toolbarItems;
+	protected $toolbarItems = array();
 
 	/**
 	 * @var int Intentionally private as nobody should modify defaults
@@ -143,9 +143,7 @@ class BackendController {
 		$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/UserMenu');
 
 		$this->css = '';
-		$this->cssFiles = array();
-		$this->toolbarItems = array();
-		$this->initializeCoreToolbarItems();
+		$this->initializeToolbarItems();
 		$this->menuWidth = $this->menuWidthDefault;
 		if (isset($GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW']) && (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'] != (int)$this->menuWidth) {
 			$this->menuWidth = (int)$GLOBALS['TBE_STYLES']['dims']['leftMenuFrameW'];
@@ -154,28 +152,38 @@ class BackendController {
 	}
 
 	/**
-	 * Initializes the core toolbar items
+	 * Initialize toolbar item objects
 	 *
+	 * @throws \RuntimeException
 	 * @return void
 	 */
-	protected function initializeCoreToolbarItems() {
-		$coreToolbarItems = array(
-			'shortcuts' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem',
-			'clearCacheActions' => 'TYPO3\\CMS\\Backend\\Toolbar\\ClearCacheToolbarItem',
-			'liveSearch' => 'TYPO3\\CMS\\Backend\\Toolbar\\LiveSearchToolbarItem'
-		);
-		foreach ($coreToolbarItems as $toolbarItemName => $toolbarItemClassName) {
-			$toolbarItem = GeneralUtility::makeInstance($toolbarItemClassName, $this);
-			// @TODO: Should throw as soon as "loading by convention" is implemented
-			if (!$toolbarItem instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
-				continue;
+	protected function initializeToolbarItems() {
+		$toolbarItemInstances = array();
+		$classNameRegistry = $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'];
+		foreach ($classNameRegistry as $className) {
+			$toolbarItemInstance = GeneralUtility::makeInstance($className, $this);
+			if (!$toolbarItemInstance instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
+				throw new \RuntimeException(
+					'class ' . $className . ' is registered as toolbar item but does not implement'
+						. '\TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface',
+					1415958218
+				);
 			}
-			if ($toolbarItem->checkAccess()) {
-				$this->toolbarItems[$toolbarItemName] = $toolbarItem;
-			} else {
-				unset($toolbarItem);
+			$index = (int)$toolbarItemInstance->getIndex();
+			if ($index < 0 || $index > 100) {
+				throw new \RuntimeException(
+					'getIndex() must return an integer between 0 and 100',
+					1415968498
+				);
+			}
+			while(array_key_exists($index, $toolbarItemInstances)) {
+				$index++;
 			}
+			// Find next free position in
+			$toolbarItemInstances[$index] = $toolbarItemInstance;
 		}
+		ksort($toolbarItemInstances);
+		$this->toolbarItems = $toolbarItemInstances;
 	}
 
 	/**
@@ -311,15 +319,8 @@ class BackendController {
 	 * @return string top toolbar elements as HTML
 	 */
 	protected function renderToolbar() {
-		// Move search to last position
-		if (array_key_exists('liveSearch', $this->toolbarItems)) {
-			$search = $this->toolbarItems['liveSearch'];
-			unset($this->toolbarItems['liveSearch']);
-		}
-
 		$toolbar = '';
-
-		foreach ($this->toolbarItems as $key => $toolbarItem) {
+		foreach ($this->toolbarItems as $toolbarItem) {
 			$menu = $toolbarItem->render();
 			if ($menu) {
 				// @TODO: Should throw as soon as "loading by convention" is implemented
@@ -337,64 +338,9 @@ class BackendController {
 				}
 			}
 		}
-
-		$toolbar .= $this->renderUserToolbar();
-
-		if ($search) {
-			$toolbar .= '<li ' . $search->getAdditionalAttributes() . ' role="menu">' . $search->render() . '</li>';
-		}
 		return $toolbar;
 	}
 
-	/**
-	 * Gets the label of the BE user currently logged in
-	 *
-	 * @return string Html code snippet displaying the currently logged in user
-	 */
-	protected function renderUserToolbar() {
-		$css = 'dropdown';
-		$icon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-user-' . ($GLOBALS['BE_USER']->isAdmin() ? 'admin' : 'backend'));
-		$realName = $GLOBALS['BE_USER']->user['realName'];
-		$username = $GLOBALS['BE_USER']->user['username'];
-		$label = $realName ?: $username;
-		$title = $username;
-
-		// Superuser mode
-		if ($GLOBALS['BE_USER']->user['ses_backuserid']) {
-			$css .= ' su-user';
-			$title = $GLOBALS['LANG']->getLL('switchtouser') . ': ' . $username;
-			$label = $GLOBALS['LANG']->getLL('switchtousershort') . ' ' . ($realName ? $realName . ' (' . $username . ')' : $username);
-		}
-
-		$toolbar = '<ul class="dropdown-menu" role="menu">';
-
-		/** @var \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $userModuleMenu */
-		$userModuleMenu = $this->backendModuleRepository->findByModuleName('user');
-		if ($userModuleMenu != FALSE && $userModuleMenu->getChildren()->count() > 0) {
-			foreach ($userModuleMenu->getChildren() as $key => $module) {
-				$moduleIcon = $module->getIcon();
-				$toolbar .= '
-					<li id="' . $module->getName() . '" class="t3-menuitem-submodule submodule mod-' . $module->getName() . '" data-modulename="' . $module->getName() . '" data-navigationcomponentid="' . $module->getNavigationComponentId() . '" data-navigationframescript="' . $module->getNavigationFrameScript() . '" data-navigationframescriptparameters="' . $module->getNavigationFrameScriptParameters() . '">
-						<a title="' .$module->getDescription() . '" href="' . $module->getLink() . '" class="modlink">
-							<span class="submodule-icon">' . ($moduleIcon['html'] ?: $moduleIcon['html']) . '</span>
-							<span class="submodule-label">' . $module->getTitle() . '</span>
-						</a>
-					</li>';
-			}
-			$toolbar .= '<li class="divider"></li>';
-		}
-
-		$toolbar .= '<li>' . $this->renderLogoutButton() . '</li>';
-		$toolbar .= '</ul>';
-
-		return '<li id="topbar-user-menu" class="' . $css . '" role="menu">' .
-			'<a href="#" class="dropdown-toggle" data-toggle="dropdown">' .
-			$icon . '<span title="' . htmlspecialchars($title) . '">' . htmlspecialchars($label) . ' <span class="caret"></span></span>' .
-			'</a>' .
-			$toolbar .
-		'</li>';
-	}
-
 	/**
 	 * Returns the file name  to the LLL JavaScript, containing the localized labels,
 	 * which can be used in JavaScript code.
@@ -749,18 +695,10 @@ class BackendController {
 	 * @param string $toolbarItemClassName Toolbar item class name, f.e. tx_toolbarExtension_coolItem
 	 * @return void
 	 * @throws \UnexpectedValueException
+	 * @deprecated since CMS 7, will be removed with CMS 8. Toolbar items are registered in $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'] now.
 	 */
 	public function addToolbarItem($toolbarItemName, $toolbarItemClassName) {
-		$toolbarItem = GeneralUtility::makeInstance($toolbarItemClassName, $this);
-		if (!$toolbarItem instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
-			// @TODO: Should throw as soon as "loading by convention" is implemented
-			return;
-		}
-		if ($toolbarItem->checkAccess()) {
-			$this->toolbarItems[$toolbarItemName] = $toolbarItem;
-		} else {
-			unset($toolbarItem);
-		}
+		GeneralUtility::logDeprecatedFunction();
 	}
 
 	/**
@@ -784,17 +722,6 @@ class BackendController {
 		}
 	}
 
-	/**
-	 * Renders the logout button form
-	 *
-	 * @return string Html code snippet displaying the logout button
-	 */
-	protected function renderLogoutButton() {
-		// show logout or "exit" (from switch user mode) label
-		$buttonLabel = 'LLL:EXT:lang/locallang_core.xlf:' . ($GLOBALS['BE_USER']->user['ses_backuserid'] ? 'buttons.exit' : 'buttons.logout');
-		return '<a href="logout.php" target="_top">' . $GLOBALS['LANG']->sL($buttonLabel, TRUE) . '</a>';
-	}
-
 	/**
 	 * loads all modules from the repository
 	 * and renders it with a template
diff --git a/typo3/sysext/backend/Classes/Toolbar/ToolbarItemHookInterface.php b/typo3/sysext/backend/Classes/Toolbar/ToolbarItemHookInterface.php
deleted file mode 100644
index f3ba84d7e9db..000000000000
--- a/typo3/sysext/backend/Classes/Toolbar/ToolbarItemHookInterface.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Toolbar;
-
-/**
- * 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!
- */
-/**
- * Interface for classes which extend the backend by adding items to the top toolbar
- *
- * @author Ingo Renner <ingo@typo3.org>
- */
-interface ToolbarItemHookInterface {
-	/**
-	 * Constructor that receives a back reference to the backend
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
-	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL);
-
-	/**
-	 * Checks whether the user has access to this toolbar item
-	 *
-	 * @return bool TRUE if user has access, FALSE if not
-	 */
-	public function checkAccess();
-
-	/**
-	 * Renders the toolbar item
-	 *
-	 * @return string The toolbar item rendered as HTML string
-	 */
-	public function render();
-
-	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * @return string List item HTML attibutes
-	 */
-	public function getAdditionalAttributes();
-
-}
diff --git a/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php b/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php
index cfb9084829ac..79198e32b904 100644
--- a/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php
+++ b/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php
@@ -74,4 +74,15 @@ interface ToolbarItemInterface {
 	 */
 	public function getAdditionalAttributes();
 
+	/**
+	 * Returns an integer between 0 and 100 to determine
+	 * the position of this item relative to others
+	 *
+	 * By default, extensions should return 50 to be sorted between main core
+	 * items and other items that should be on the very right.
+	 *
+	 * @return integer 0 .. 100
+	 */
+	public function getIndex();
+
 }
diff --git a/typo3/sysext/backend/ext_localconf.php b/typo3/sysext/backend/ext_localconf.php
index d9c5781ba735..db8bc28aba5d 100644
--- a/typo3/sysext/backend/ext_localconf.php
+++ b/typo3/sysext/backend/ext_localconf.php
@@ -8,6 +8,11 @@ if (TYPO3_MODE === 'BE') {
 		'TYPO3\\CMS\\Backend\\Security\\CategoryPermissionsAspect',
 		'addUserPermissionsToCategoryTreeData'
 	);
+
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ClearCacheToolbarItem';
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\LiveSearchToolbarItem';
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem';
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\UserToolbarItem';
 }
 
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default'] = 'TYPO3\\CMS\\Core\\FrontendEditing\\FrontendEditingController';
diff --git a/typo3/sysext/compatibility6/Migrations/Code/ClassAliasMap.php b/typo3/sysext/compatibility6/Migrations/Code/ClassAliasMap.php
index d9a1b8f64c0c..eb834777fa6d 100644
--- a/typo3/sysext/compatibility6/Migrations/Code/ClassAliasMap.php
+++ b/typo3/sysext/compatibility6/Migrations/Code/ClassAliasMap.php
@@ -89,7 +89,6 @@ return array(
 	'ClearCacheMenu' => 'TYPO3\\CMS\\Backend\\Toolbar\\ClearCacheToolbarItem',
 	'LiveSearch' => 'TYPO3\\CMS\\Backend\\Toolbar\\LiveSearchToolbarItem',
 	'ShortcutMenu' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem',
-	'backend_toolbarItem' => 'TYPO3\\CMS\\Backend\\Toolbar\\ToolbarItemHookInterface',
 	't3lib_tree_ExtDirect_AbstractExtJsTree' => 'TYPO3\\CMS\\Backend\\Tree\\AbstractExtJsTree',
 	't3lib_tree_AbstractTree' => 'TYPO3\\CMS\\Backend\\Tree\\AbstractTree',
 	't3lib_tree_AbstractDataProvider' => 'TYPO3\\CMS\\Backend\\Tree\\AbstractTreeDataProvider',
diff --git a/typo3/sysext/compatibility6/Migrations/Code/LegacyClassesForIde.php b/typo3/sysext/compatibility6/Migrations/Code/LegacyClassesForIde.php
index afb116f1ba87..f20b7900386d 100644
--- a/typo3/sysext/compatibility6/Migrations/Code/LegacyClassesForIde.php
+++ b/typo3/sysext/compatibility6/Migrations/Code/LegacyClassesForIde.php
@@ -179,8 +179,6 @@ class LiveSearch extends \TYPO3\CMS\Backend\Toolbar\LiveSearchToolbarItem {}
 
 class ShortcutMenu extends \TYPO3\CMS\Backend\Toolbar\ShortcutToolbarItem {}
 
-interface backend_toolbarItem extends \TYPO3\CMS\Backend\Toolbar\ToolbarItemHookInterface {}
-
 abstract class t3lib_tree_ExtDirect_AbstractExtJsTree extends \TYPO3\CMS\Backend\Tree\AbstractExtJsTree {}
 
 abstract class t3lib_tree_AbstractTree extends \TYPO3\CMS\Backend\Tree\AbstractTree {}
diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php
index ce3b05835b90..9e9754297fe4 100644
--- a/typo3/sysext/core/Configuration/DefaultConfiguration.php
+++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php
@@ -702,6 +702,7 @@ return array(
 				'csrfTokenCheck' => TRUE
 			),
 		),
+		'toolbarItems' => array(), // Array: Registered toolbar items classes
 		'HTTP' => array(
 			'Response' => array(
 				'Headers' => array('clickJackingProtection' => 'X-Frame-Options: SAMEORIGIN')
diff --git a/typo3/sysext/opendocs/Classes/Controller/OpendocsController.php b/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
similarity index 97%
rename from typo3/sysext/opendocs/Classes/Controller/OpendocsController.php
rename to typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
index 699d166db372..478b3c6a5aea 100644
--- a/typo3/sysext/opendocs/Classes/Controller/OpendocsController.php
+++ b/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\Opendocs\Controller;
+namespace TYPO3\CMS\Opendocs\Backend\ToolbarItems;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -14,13 +14,15 @@ namespace TYPO3\CMS\Opendocs\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+
 /**
  * Adding a list of all open documents of a user to the backend.php
  *
  * @author Benjamin Mack <benni@typo3.org>
  * @author Ingo Renner <ingo@typo3.org>
  */
-class OpendocsController implements \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface {
+class OpendocsToolbarItem implements ToolbarItemInterface {
 
 	/**
 	 * @var \TYPO3\CMS\Backend\Controller\BackendController
@@ -297,4 +299,13 @@ class OpendocsController implements \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterf
 		$ajaxObj->addContent('opendocsMenu', $menuContent);
 	}
 
+	/**
+	 * Position relative to others
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 30;
+	}
+
 }
diff --git a/typo3/sysext/opendocs/Migrations/Code/ClassAliasMap.php b/typo3/sysext/opendocs/Migrations/Code/ClassAliasMap.php
index 6b592c2263cc..4648715879f6 100644
--- a/typo3/sysext/opendocs/Migrations/Code/ClassAliasMap.php
+++ b/typo3/sysext/opendocs/Migrations/Code/ClassAliasMap.php
@@ -1,4 +1,6 @@
 <?php
 return array(
-	'tx_opendocs' => 'TYPO3\\CMS\\Opendocs\\Controller\\OpendocsController',
+	'tx_opendocs' => 'TYPO3\\CMS\\Opendocs\\Backend\\ToolbarItems\\OpendocsToolbarItem',
+	// @TODO: Migrate old class name usages to the new one
+	'TYPO3\\CMS\\Opendocs\\Controller\\OpendocsController' => 'TYPO3\\CMS\\Opendocs\\Backend\\ToolbarItems\\OpendocsToolbarItem',
 );
diff --git a/typo3/sysext/opendocs/Resources/PHP/RegisterToolbarItem.php b/typo3/sysext/opendocs/Resources/PHP/RegisterToolbarItem.php
deleted file mode 100644
index 8fb35677aa52..000000000000
--- a/typo3/sysext/opendocs/Resources/PHP/RegisterToolbarItem.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-defined('TYPO3_MODE') or die();
-
-if (TYPO3_MODE === 'BE') {
-	// Now register the class as toolbar item
-	$GLOBALS['TYPO3backend']->addToolbarItem('opendocs', 'TYPO3\\CMS\\Opendocs\\Controller\\OpendocsController');
-}
diff --git a/typo3/sysext/opendocs/ext_localconf.php b/typo3/sysext/opendocs/ext_localconf.php
index c77a87baf399..864cc8273154 100644
--- a/typo3/sysext/opendocs/ext_localconf.php
+++ b/typo3/sysext/opendocs/ext_localconf.php
@@ -1,7 +1,4 @@
 <?php
-defined('TYPO3_MODE') or die();
-
 if (TYPO3_MODE === 'BE') {
-	// Register toolbar item
-	$GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('opendocs'). 'Resources/PHP/RegisterToolbarItem.php';
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Opendocs\\Backend\\ToolbarItems\\OpendocsToolbarItem';
 }
\ No newline at end of file
diff --git a/typo3/sysext/sys_action/Classes/ActionToolbarMenu.php b/typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php
similarity index 94%
rename from typo3/sysext/sys_action/Classes/ActionToolbarMenu.php
rename to typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php
index 04615bf77aaa..eefbe0b432d3 100644
--- a/typo3/sysext/sys_action/Classes/ActionToolbarMenu.php
+++ b/typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\SysAction;
+namespace TYPO3\CMS\SysAction\Backend\ToolbarItems;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -15,13 +15,14 @@ namespace TYPO3\CMS\SysAction;
  */
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 
 /**
  * Adds action links to the backend's toolbar
  *
  * @author Steffen Kamper <info@sk-typo3.de>
  */
-class ActionToolbarMenu implements \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface {
+class ActionToolbarItem implements ToolbarItemInterface {
 
 	/**
 	 * @var \TYPO3\CMS\Backend\Controller\BackendController
@@ -163,4 +164,13 @@ class ActionToolbarMenu implements \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterfa
 		return TRUE;
 	}
 
+	/**
+	 * Position relative to others
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 35;
+	}
+
 }
diff --git a/typo3/sysext/sys_action/Resources/PHP/RegisterToolbarItem.php b/typo3/sysext/sys_action/Resources/PHP/RegisterToolbarItem.php
deleted file mode 100644
index 9b8a30c47e8a..000000000000
--- a/typo3/sysext/sys_action/Resources/PHP/RegisterToolbarItem.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-defined('TYPO3_MODE') or die();
-
-$GLOBALS['TYPO3backend']->addToolbarItem('sys_action', 'TYPO3\\CMS\\SysAction\\ActionToolbarMenu');
\ No newline at end of file
diff --git a/typo3/sysext/sys_action/ext_localconf.php b/typo3/sysext/sys_action/ext_localconf.php
index dce51f3c96e7..b2828cce0b86 100644
--- a/typo3/sysext/sys_action/ext_localconf.php
+++ b/typo3/sysext/sys_action/ext_localconf.php
@@ -1,6 +1,4 @@
 <?php
-defined('TYPO3_MODE') or die();
-
 if (TYPO3_MODE === 'BE') {
-	$GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('sys_action') . 'Resources/PHP/RegisterToolbarItem.php';
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\SysAction\\Backend\\ToolbarItems\\ActionToolbarItem';
 }
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Classes/ExtDirect/WorkspaceSelectorToolbarItem.php b/typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php
similarity index 97%
rename from typo3/sysext/workspaces/Classes/ExtDirect/WorkspaceSelectorToolbarItem.php
rename to typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php
index c55932f02687..877f95eb27db 100644
--- a/typo3/sysext/workspaces/Classes/ExtDirect/WorkspaceSelectorToolbarItem.php
+++ b/typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\Workspaces\ExtDirect;
+namespace TYPO3\CMS\Workspaces\Backend\ToolbarItems;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -156,4 +156,13 @@ class WorkspaceSelectorToolbarItem implements \TYPO3\CMS\Backend\Toolbar\Toolbar
 		return TRUE;
 	}
 
+	/**
+	 * Position relative to others
+	 *
+	 * @return int
+	 */
+	public function getIndex() {
+		return 40;
+	}
+
 }
diff --git a/typo3/sysext/workspaces/Resources/PHP/RegisterToolbarItem.php b/typo3/sysext/workspaces/Resources/PHP/RegisterToolbarItem.php
deleted file mode 100644
index cc8634547d16..000000000000
--- a/typo3/sysext/workspaces/Resources/PHP/RegisterToolbarItem.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-defined('TYPO3_MODE') or die();
-
-$GLOBALS['TYPO3backend']->addToolbarItem('workSpaceSelector', 'TYPO3\\CMS\\Workspaces\\ExtDirect\\WorkspaceSelectorToolbarItem');
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/ext_localconf.php b/typo3/sysext/workspaces/ext_localconf.php
index 7e8a6d2c9252..61166e1edb3c 100644
--- a/typo3/sysext/workspaces/ext_localconf.php
+++ b/typo3/sysext/workspaces/ext_localconf.php
@@ -28,9 +28,9 @@ if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations
 }
 
 if (TYPO3_MODE === 'BE') {
-	$GLOBALS['TYPO3_CONF_VARS']['typo3/backend.php']['additionalBackendItems'][] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Resources/PHP/RegisterToolbarItem.php';
-
 	// If publishing/swapping dependent parent-child references, consider all parents and children
 	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addUserTSConfig('options.workspaces.considerReferences = 1');
 	$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/tree/pagetree/class.t3lib_tree_pagetree_dataprovider.php']['postProcessCollections'][] = 'TYPO3\\CMS\\Workspaces\\ExtDirect\\PagetreeCollectionsProcessor';
+
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Workspaces\\Backend\\ToolbarItems\\WorkspaceSelectorToolbarItem';
 }
-- 
GitLab