diff --git a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php index 27ce48088206da76684ad4261308334d095d5a1a..6eff2ab2144df6494680e7dde6e30f57bb46709f 100644 --- a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php +++ b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php @@ -23,10 +23,10 @@ use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Beuser\Domain\Model\BackendUser; use TYPO3\CMS\Beuser\Domain\Model\Demand; +use TYPO3\CMS\Beuser\Domain\Model\ModuleData; use TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository; use TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository; use TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository; -use TYPO3\CMS\Beuser\Service\ModuleDataStorageService; use TYPO3\CMS\Beuser\Service\UserInformationService; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Context\Context; @@ -38,7 +38,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Http\ForwardResponse; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException; -use TYPO3\CMS\Extbase\Mvc\RequestInterface; use TYPO3\CMS\Extbase\Mvc\View\ViewInterface; use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; @@ -54,44 +53,18 @@ class BackendUserController extends ActionController */ const RECENT_USERS_LIMIT = 3; - /** - * @var \TYPO3\CMS\Beuser\Domain\Model\ModuleData - */ - protected $moduleData; - - /** - * @var ModuleDataStorageService - */ - protected $moduleDataStorageService; - - /** - * @var BackendUserRepository - */ - protected $backendUserRepository; - - /** - * @var BackendUserGroupRepository - */ - protected $backendUserGroupRepository; - - /** - * @var BackendUserSessionRepository - */ - protected $backendUserSessionRepository; - - /** - * @var UserInformationService - */ - protected $userInformationService; + protected ?ModuleData $moduleData = null; + protected BackendUserRepository $backendUserRepository; + protected BackendUserGroupRepository $backendUserGroupRepository; + protected BackendUserSessionRepository $backendUserSessionRepository; + protected UserInformationService $userInformationService; public function __construct( - ModuleDataStorageService $moduleDataStorageService, BackendUserRepository $backendUserRepository, BackendUserGroupRepository $backendUserGroupRepository, BackendUserSessionRepository $backendUserSessionRepository, UserInformationService $userInformationService ) { - $this->moduleDataStorageService = $moduleDataStorageService; $this->backendUserRepository = $backendUserRepository; $this->backendUserGroupRepository = $backendUserGroupRepository; $this->backendUserSessionRepository = $backendUserSessionRepository; @@ -99,31 +72,21 @@ class BackendUserController extends ActionController } /** - * Load and persist module data - * - * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request - * @return ResponseInterface - * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException + * Init module state. + * This isn't done within __construct() since the controller + * object is only created once in extbase when multiple actions are called in + * one call. When those change module state, the second action would see old state. */ - public function processRequest(RequestInterface $request): ResponseInterface + public function initializeAction(): void { - $this->moduleData = $this->moduleDataStorageService->loadModuleData(); - // We "finally" persist the module data. - try { - $response = parent::processRequest($request); - $this->moduleDataStorageService->persistModuleData($this->moduleData); - return $response; - } catch (StopActionException $e) { - $this->moduleDataStorageService->persistModuleData($this->moduleData); - throw $e; - } + $this->moduleData = ModuleData::fromUc((array)($this->getBackendUser()->getModuleData('tx_beuser'))); } /** * Assign default variables to view * @param ViewInterface $view */ - protected function initializeView(ViewInterface $view) + protected function initializeView(ViewInterface $view): void { $view->assignMultiple([ 'shortcutLabel' => 'backendUsers', @@ -139,16 +102,18 @@ class BackendUserController extends ActionController * Displays all BackendUsers * - Switch session to different user * - * @param \TYPO3\CMS\Beuser\Domain\Model\Demand $demand + * @param Demand|null $demand * @param int $currentPage * @param string $operation + * @return ResponseInterface */ public function indexAction(Demand $demand = null, int $currentPage = 1, string $operation = ''): ResponseInterface { + $backendUser = $this->getBackendUser(); + if ($operation === 'reset-filters') { // Reset the module data demand object - $this->moduleData->setDemand(GeneralUtility::makeInstance(Demand::class)); - $this->moduleDataStorageService->persistModuleData($this->moduleData); + $this->moduleData->setDemand(new Demand()); $demand = null; } if ($demand === null) { @@ -156,6 +121,8 @@ class BackendUserController extends ActionController } else { $this->moduleData->setDemand($demand); } + $backendUser->pushModuleData('tx_beuser', $this->moduleData->forUc()); + // Switch user until logout $switchUser = (int)GeneralUtility::_GP('SwitchUser'); if ($switchUser > 0) { @@ -175,7 +142,7 @@ class BackendUserController extends ActionController 'totalAmountOfBackendUsers' => $backendUsers->count(), 'backendUserGroups' => array_merge([''], $this->backendUserGroupRepository->findAll()->toArray()), 'compareUserUidList' => array_combine($compareUserList, $compareUserList), - 'currentUserUid' => $this->getBackendUserAuthentication()->user['uid'], + 'currentUserUid' => $backendUser->user['uid'], 'compareUserList' => !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '', ]); @@ -196,7 +163,7 @@ class BackendUserController extends ActionController ]; } - $currentSessionId = $this->backendUserSessionRepository->getPersistedSessionIdentifier($this->getBackendUserAuthentication()); + $currentSessionId = $this->backendUserSessionRepository->getPersistedSessionIdentifier($this->getBackendUser()); $this->view->assignMultiple([ 'shortcutLabel' => 'onlineUsers', @@ -207,9 +174,6 @@ class BackendUserController extends ActionController return $this->htmlResponse($this->view->render()); } - /** - * @param int $uid - */ public function showAction(int $uid = 0): ResponseInterface { $data = $this->userInformationService->getUserInformation($uid); @@ -287,7 +251,7 @@ class BackendUserController extends ActionController public function addToCompareListAction($uid) { $this->moduleData->attachUidCompareUser($uid); - $this->moduleDataStorageService->persistModuleData($this->moduleData); + $this->getBackendUser()->pushModuleData('tx_beuser', $this->moduleData->forUc()); return new ForwardResponse('index'); } @@ -300,7 +264,7 @@ class BackendUserController extends ActionController public function removeFromCompareListAction($uid, int $redirectToCompare = 0) { $this->moduleData->detachUidCompareUser($uid); - $this->moduleDataStorageService->persistModuleData($this->moduleData); + $this->getBackendUser()->pushModuleData('tx_beuser', $this->moduleData->forUc()); if ($redirectToCompare) { $this->redirect('compare'); } else { @@ -310,13 +274,12 @@ class BackendUserController extends ActionController /** * Removes all backend users from the compare list + * @throws StopActionException */ public function removeAllFromCompareListAction(): void { - foreach ($this->moduleData->getCompareUserList() as $user) { - $this->moduleData->detachUidCompareUser($user); - } - $this->moduleDataStorageService->persistModuleData($this->moduleData); + $this->moduleData->resetCompareUserList(); + $this->getBackendUser()->pushModuleData('tx_beuser', $this->moduleData->forUc()); $this->redirect('index'); } @@ -324,7 +287,7 @@ class BackendUserController extends ActionController * Terminate BackendUser session and logout corresponding client * Redirects to onlineAction with message * - * @param \TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser + * @param BackendUser $backendUser * @param string $sessionId */ protected function terminateBackendUserSessionAction(BackendUser $backendUser, $sessionId) @@ -344,33 +307,34 @@ class BackendUserController extends ActionController */ protected function switchUser($switchUser) { + $backendUser = $this->getBackendUser(); $targetUser = BackendUtility::getRecord('be_users', $switchUser); - if (is_array($targetUser) && $this->getBackendUserAuthentication()->isAdmin()) { + if (is_array($targetUser) && $backendUser->isAdmin()) { // Set backend user listing module as starting module for switchback - $this->getBackendUserAuthentication()->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser'; - $this->getBackendUserAuthentication()->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']); - $this->getBackendUserAuthentication()->writeUC(); + $backendUser->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser'; + $backendUser->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']); + $backendUser->writeUC(); // User switch written to log - $this->getBackendUserAuthentication()->writelog( + $backendUser->writelog( 255, 2, 0, 1, 'User %s switched to user %s (be_users:%s)', [ - $this->getBackendUserAuthentication()->user['username'], + $backendUser->user['username'], $targetUser['username'], $targetUser['uid'], ] ); - $this->backendUserSessionRepository->switchToUser($this->getBackendUserAuthentication(), (int)$targetUser['uid']); + $this->backendUserSessionRepository->switchToUser($backendUser, (int)$targetUser['uid']); $event = new SwitchUserEvent( - $this->getBackendUserAuthentication()->getSession()->getIdentifier(), + $backendUser->getSession()->getIdentifier(), $targetUser, - (array)$this->getBackendUserAuthentication()->user + (array)$backendUser->user ); $this->eventDispatcher->dispatch($event); @@ -391,7 +355,7 @@ class BackendUserController extends ActionController protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array { $latestUserUids = []; - $backendUser = $this->getBackendUserAuthentication(); + $backendUser = $this->getBackendUser(); if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) { $latestUserUids = $backendUser->uc['recentSwitchedToUsers']; @@ -412,7 +376,7 @@ class BackendUserController extends ActionController /** * @return BackendUserAuthentication */ - protected function getBackendUserAuthentication(): BackendUserAuthentication + protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } diff --git a/typo3/sysext/beuser/Classes/Domain/Model/Demand.php b/typo3/sysext/beuser/Classes/Domain/Model/Demand.php index ee0756b8a6086f801892209eea1e55d8dd346b44..80a391b5cbcc182dae645776610623bcaaa59a65 100644 --- a/typo3/sysext/beuser/Classes/Domain/Model/Demand.php +++ b/typo3/sysext/beuser/Classes/Domain/Model/Demand.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /* * This file is part of the TYPO3 CMS project. * @@ -15,143 +17,97 @@ namespace TYPO3\CMS\Beuser\Domain\Model; -use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; - /** * Demand filter for listings * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API. */ -class Demand extends AbstractEntity +class Demand { - /** - * @var int - */ - const ALL = 0; - /** - * @var int - */ - const USERTYPE_ADMINONLY = 1; - /** - * @var int - */ - const USERTYPE_USERONLY = 2; - /** - * @var int - */ - const STATUS_ACTIVE = 1; - /** - * @var int - */ - const STATUS_INACTIVE = 2; - /** - * @var int - */ - const LOGIN_SOME = 1; - /** - * @var int - */ - const LOGIN_NONE = 2; - /** - * @var string - */ - protected $userName = ''; - - /** - * @var int - */ - protected $userType = self::ALL; - - /** - * @var int - */ - protected $status = self::ALL; - - /** - * @var int - */ - protected $logins = 0; - - /** - * @var int - */ - protected $backendUserGroup = 0; - - /** - * @param string $userName - */ - public function setUserName($userName) + public const ALL = 0; + + public const USERTYPE_ADMINONLY = 1; + public const USERTYPE_USERONLY = 2; + + public const STATUS_ACTIVE = 1; + public const STATUS_INACTIVE = 2; + + public const LOGIN_SOME = 1; + public const LOGIN_NONE = 2; + + protected string $userName = ''; + protected int $userType = self::ALL; + protected int $status = self::ALL; + protected int $logins = 0; + protected int $backendUserGroup = 0; + + public static function fromUc(array $uc): self + { + $demand = new self(); + $demand->userName = (string)($uc['userName'] ?? ''); + $demand->userType = (int)($uc['userType'] ?? 0); + $demand->status = (int)($uc['status'] ?? 0); + $demand->logins = (int)($uc['logins'] ?? 0); + $demand->backendUserGroup = (int)($uc['backendUserGroup'] ?? 0); + return $demand; + } + + public function forUc(): array + { + return [ + 'userName' => $this->getUserName(), + 'userType' => $this->getUserType(), + 'status' => $this->getStatus(), + 'logins' => $this->getLogins(), + 'backendUserGroup' => $this->getBackendUserGroup(), + ]; + } + + public function setUserName(string $userName): void { $this->userName = $userName; } - /** - * @return string - */ - public function getUserName() + public function getUserName(): string { return $this->userName; } - /** - * @param int $userType - */ - public function setUserType($userType) + public function setUserType(int $userType): void { $this->userType = $userType; } - /** - * @return int - */ - public function getUserType() + public function getUserType(): int { return $this->userType; } - /** - * @param int $status - */ - public function setStatus($status) + public function setStatus(int $status): void { $this->status = $status; } - /** - * @return int - */ - public function getStatus() + public function getStatus(): int { return $this->status; } - /** - * @param int $logins - */ - public function setLogins($logins) + public function setLogins(int $logins): void { $this->logins = $logins; } - /** - * @return int - */ - public function getLogins() + public function getLogins(): int { return $this->logins; } - /** - * @param int $backendUserGroup - */ - public function setBackendUserGroup($backendUserGroup) + public function setBackendUserGroup(int $backendUserGroup): void { $this->backendUserGroup = $backendUserGroup; } - /** - * @return int - */ - public function getBackendUserGroup() + public function getBackendUserGroup(): int { return $this->backendUserGroup; } diff --git a/typo3/sysext/beuser/Classes/Domain/Model/ModuleData.php b/typo3/sysext/beuser/Classes/Domain/Model/ModuleData.php index ebfd6db8e29fc8576b14e3a114a217c7d61a2215..724b46b3491ddc6bff7fe409a05305ad3251d25a 100644 --- a/typo3/sysext/beuser/Classes/Domain/Model/ModuleData.php +++ b/typo3/sysext/beuser/Classes/Domain/Model/ModuleData.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /* * This file is part of the TYPO3 CMS project. * @@ -21,57 +23,65 @@ namespace TYPO3\CMS\Beuser\Domain\Model; */ class ModuleData { - /** - * @var \TYPO3\CMS\Beuser\Domain\Model\Demand - */ - protected $demand; + protected Demand $demand; + protected array $compareUserList = []; - /** - * @var array - */ - protected $compareUserList = []; + public function __construct() + { + $this->demand = new Demand(); + } - /** - * @param \TYPO3\CMS\Beuser\Domain\Model\Demand $demand - */ - public function injectDemand(Demand $demand) + public static function fromUc(array $uc): self { - $this->demand = $demand; + $moduleData = new self(); + $moduleData->compareUserList = (array)($uc['compareUserList'] ?? []); + $moduleData->demand = Demand::fromUc($uc['demand'] ?? []); + return $moduleData; } - /** - * @return \TYPO3\CMS\Beuser\Domain\Model\Demand - */ - public function getDemand() + public function forUc(): array + { + return [ + 'compareUserList' => $this->compareUserList, + 'demand' => $this->demand->forUc(), + ]; + } + + public function getDemand(): Demand { return $this->demand; } - /** - * @param \TYPO3\CMS\Beuser\Domain\Model\Demand $demand - */ - public function setDemand(Demand $demand) + public function setDemand(Demand $demand): void { $this->demand = $demand; } + protected function setCompareUserList(array $compareUserList): void + { + $this->compareUserList = $compareUserList; + } + /** - * Returns the compare list as array of user uis - * - * @return array + * Returns the compare list as array of user uids */ - public function getCompareUserList() + public function getCompareUserList(): array { return array_keys($this->compareUserList); } + public function resetCompareUserList(): void + { + $this->compareUserList = []; + } + /** * Adds one backend user (by uid) to the compare user list * Cannot be ObjectStorage, must be array * * @param int $uid */ - public function attachUidCompareUser($uid) + public function attachUidCompareUser(int $uid): void { $this->compareUserList[$uid] = true; } @@ -81,7 +91,7 @@ class ModuleData * * @param int $uid */ - public function detachUidCompareUser($uid) + public function detachUidCompareUser(int $uid): void { unset($this->compareUserList[$uid]); } diff --git a/typo3/sysext/beuser/Classes/Service/ModuleDataStorageService.php b/typo3/sysext/beuser/Classes/Service/ModuleDataStorageService.php deleted file mode 100644 index 3463a3d1288a5b83f56760bcf8c7470ec114a967..0000000000000000000000000000000000000000 --- a/typo3/sysext/beuser/Classes/Service/ModuleDataStorageService.php +++ /dev/null @@ -1,75 +0,0 @@ -<?php - -/* - * 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! - */ - -namespace TYPO3\CMS\Beuser\Service; - -use TYPO3\CMS\Beuser\Domain\Model\Demand; -use TYPO3\CMS\Beuser\Domain\Model\ModuleData; -use TYPO3\CMS\Core\SingletonInterface; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; - -/** - * Module data storage service. - * Used to store and retrieve module state (eg. checkboxes, selections). - * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API. - */ -class ModuleDataStorageService implements SingletonInterface -{ - /** - * @var string - */ - const KEY = 'tx_beuser'; - - /** - * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface - */ - protected $objectManager; - - /** - * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) - { - $this->objectManager = $objectManager; - } - - /** - * Loads module data for user settings or returns a fresh object if module data is invalid or unset - * - * @return \TYPO3\CMS\Beuser\Domain\Model\ModuleData - */ - public function loadModuleData() - { - $moduleData = $GLOBALS['BE_USER']->getModuleData(self::KEY) ?? ''; - if ($moduleData !== '') { - $moduleData = @unserialize($moduleData, ['allowed_classes' => [ModuleData::class, Demand::class]]); - if ($moduleData instanceof ModuleData) { - return $moduleData; - } - } - - return $this->objectManager->get(ModuleData::class); - } - - /** - * Persists serialized module data to user settings - * - * @param \TYPO3\CMS\Beuser\Domain\Model\ModuleData $moduleData - */ - public function persistModuleData(ModuleData $moduleData) - { - $GLOBALS['BE_USER']->pushModuleData(self::KEY, serialize($moduleData)); - } -} diff --git a/typo3/sysext/beuser/Resources/Private/Layouts/Default.html b/typo3/sysext/beuser/Resources/Private/Layouts/Default.html index 19ae9915619c440c43cff2a3ffb0f9ac1ffcb3e9..75a06cfe25c9f69a8c85bcb063e00700d93656f4 100644 --- a/typo3/sysext/beuser/Resources/Private/Layouts/Default.html +++ b/typo3/sysext/beuser/Resources/Private/Layouts/Default.html @@ -14,6 +14,9 @@ <be:moduleLayout.menu identifier="BackendUserModuleMenu"> <be:moduleLayout.menuItem label="{f:translate(id: 'backendUsers')}" uri="{f:uri.action(controller: 'BackendUser', action: 'index')}"/> + <f:if condition="{shortcutLabel} == 'compareUsers'"> + <be:moduleLayout.menuItem label="{f:translate(id: 'compareBackendUsers')}" uri="{f:uri.action(controller: 'BackendUser', action: 'compare')}"/> + </f:if> <be:moduleLayout.menuItem label="{f:translate(id: 'backendUserGroupsMenu')}" uri="{f:uri.action(controller: 'BackendUserGroup', action: 'index')}"/> <f:if condition="{shortcutLabel} == 'compareBackendUsersGroups'"> <be:moduleLayout.menuItem label="{f:translate(id: 'compareBackendUsersGroups')}" uri="{f:uri.action(controller: 'BackendUserGroup', action: 'compare')}"/> diff --git a/typo3/sysext/beuser/Tests/Unit/Service/ModuleDataStorageServiceTest.php b/typo3/sysext/beuser/Tests/Unit/Service/ModuleDataStorageServiceTest.php deleted file mode 100644 index e599eeefd84b00e4d9c8d239d36ba680e123fc3f..0000000000000000000000000000000000000000 --- a/typo3/sysext/beuser/Tests/Unit/Service/ModuleDataStorageServiceTest.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php - -/* - * 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! - */ - -namespace TYPO3\CMS\Beuser\Tests\Unit\Service; - -use TYPO3\CMS\Beuser\Domain\Model\ModuleData; -use TYPO3\CMS\Beuser\Service\ModuleDataStorageService; -use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; -use TYPO3\CMS\Extbase\Object\ObjectManager; -use TYPO3\TestingFramework\Core\Unit\UnitTestCase; - -/** - * Test case - */ -class ModuleDataStorageServiceTest extends UnitTestCase -{ - /** - * @test - */ - public function loadModuleDataReturnsModuleDataObjectForEmptyModuleData() - { - // Simulate empty module data - $GLOBALS['BE_USER'] = $this->createMock(BackendUserAuthentication::class); - $GLOBALS['BE_USER']->uc = []; - $GLOBALS['BE_USER']->uc['moduleData'] = []; - - $subject = new ModuleDataStorageService(); - $objectManagerMock = $this->createMock(ObjectManager::class); - $moduleDataMock = $this->createMock(ModuleData::class); - $objectManagerMock - ->expects(self::once()) - ->method('get') - ->with(ModuleData::class) - ->willReturn($moduleDataMock); - $subject->injectObjectManager($objectManagerMock); - - self::assertSame($moduleDataMock, $subject->loadModuleData()); - } -}