diff --git a/typo3/sysext/backend/Classes/Configuration/BackendUserConfiguration.php b/typo3/sysext/backend/Classes/Configuration/BackendUserConfiguration.php new file mode 100644 index 0000000000000000000000000000000000000000..df797f9a6f37937659cf27aab01f008b0737af56 --- /dev/null +++ b/typo3/sysext/backend/Classes/Configuration/BackendUserConfiguration.php @@ -0,0 +1,182 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Backend\Configuration; + +/* + * 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\Authentication\BackendUserAuthentication; +use TYPO3\CMS\Core\Utility\ArrayUtility; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +/** + * Convenience wrapper for backend user configuration + * + * @internal + */ +class BackendUserConfiguration +{ + /** + * @var BackendUserAuthentication + */ + protected $backendUser; + + /** + * @param BackendUserAuthentication|null $backendUser + */ + public function __construct(BackendUserAuthentication $backendUser = null) + { + $this->backendUser = $backendUser ?: $GLOBALS['BE_USER']; + } + + /** + * Returns a specific user setting + * + * @param string $key Identifier, allows also dotted notation for subarrays + * @return mixed Value associated + */ + public function get(string $key) + { + return (strpos($key, '.') !== false) ? $this->getFromDottedNotation($key) : $this->backendUser->uc[$key]; + } + + /** + * Get all user settings + * + * @return mixed all values, usually a multi-dimensional array + */ + public function getAll() + { + return $this->backendUser->uc; + } + + /** + * Sets user settings by key/value pair + * + * @param string $key + * @param mixed $value + */ + public function set(string $key, $value): void + { + if (strpos($key, '.') !== false) { + $this->setFromDottedNotation($key, $value); + } else { + $this->backendUser->uc[$key] = $value; + } + + $this->backendUser->writeUC($this->backendUser->uc); + } + + /** + * Adds an value to an Comma-separated list + * stored in $key of user settings + * + * @param string $key + * @param mixed $value + */ + public function addToList(string $key, $value): void + { + $list = $this->get($key); + + if (!isset($list)) { + $list = $value; + } elseif (!GeneralUtility::inList($list, $value)) { + $list .= ',' . $value; + } + + $this->set($key, $list); + } + + /** + * Removes an value from an Comma-separated list + * stored $key of user settings + * + * @param string $key + * @param mixed $value + */ + public function removeFromList(string $key, $value): void + { + $list = $this->get($key); + + if (GeneralUtility::inList($list, $value)) { + $list = GeneralUtility::trimExplode(',', $list, true); + $list = ArrayUtility::removeArrayEntryByValue($list, $value); + $this->set($key, implode(',', $list)); + } + } + + /** + * Resets the user settings to the default + */ + public function clear(): void + { + $this->backendUser->resetUC(); + } + + /** + * Unsets a key in user settings + * + * @param string $key + */ + public function unsetOption(string $key): void + { + if (isset($this->backendUser->uc[$key])) { + unset($this->backendUser->uc[$key]); + $this->backendUser->writeUC($this->backendUser->uc); + } + } + + /** + * Computes the subarray from dotted notation + * + * @param $key string Dotted notation of subkeys like moduleData.module1.general.checked + * @return mixed value of the settings + */ + protected function getFromDottedNotation(string $key) + { + $subkeys = GeneralUtility::trimExplode('.', $key); + $configuration = $this->backendUser->uc; + + foreach ($subkeys as $subkey) { + if (isset($configuration[$subkey])) { + $configuration = &$configuration[$subkey]; + } else { + $configuration = []; + break; + } + } + + return $configuration; + } + + /** + * Sets the value of a key written in dotted notation + * + * @param string $key + * @param mixed $value + */ + protected function setFromDottedNotation(string $key, $value): void + { + $subkeys = GeneralUtility::trimExplode('.', $key, true); + $lastKey = $subkeys[count($subkeys) - 1]; + $configuration = &$this->backendUser->uc; + + foreach ($subkeys as $subkey) { + if ($subkey === $lastKey) { + $configuration[$subkey] = $value; + } else { + $configuration = &$configuration[$subkey]; + } + } + } +} diff --git a/typo3/sysext/backend/Classes/Controller/Page/TreeController.php b/typo3/sysext/backend/Classes/Controller/Page/TreeController.php index a6db720a6e53636c24b8b0623488ed0d613e52ac..b36d1704f3d94314ab4c2672e55d8672d282b5c2 100644 --- a/typo3/sysext/backend/Classes/Controller/Page/TreeController.php +++ b/typo3/sysext/backend/Classes/Controller/Page/TreeController.php @@ -17,7 +17,7 @@ namespace TYPO3\CMS\Backend\Controller\Page; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use TYPO3\CMS\Backend\Controller\UserSettingsController; +use TYPO3\CMS\Backend\Configuration\BackendUserConfiguration; use TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; @@ -178,8 +178,8 @@ class TreeController $this->addIdAsPrefix = (bool)$this->getBackendUser()->getTSConfigVal('options.pageTree.showPageIdWithTitle'); $this->addDomainName = (bool)$this->getBackendUser()->getTSConfigVal('options.pageTree.showDomainNameWithTitle'); $this->showMountPathAboveMounts = (bool)$this->getBackendUser()->getTSConfigVal('options.pageTree.showPathAboveMounts'); - $userSettingsController = GeneralUtility::makeInstance(UserSettingsController::class); - $this->expandedState = $userSettingsController->process('get', 'BackendComponents.States.Pagetree'); + $backendUserConfiguration = GeneralUtility::makeInstance(BackendUserConfiguration::class); + $this->expandedState = $backendUserConfiguration->get('BackendComponents.States.Pagetree'); if (is_object($this->expandedState->stateHash)) { $this->expandedState = (array)$this->expandedState->stateHash; } else { diff --git a/typo3/sysext/backend/Classes/Controller/UserSettingsController.php b/typo3/sysext/backend/Classes/Controller/UserSettingsController.php index 3f603f2abbb3a11756cbfa29087fca4d195f57ba..c37dafec8e0d928858b90d86aa262b28d32cb63e 100644 --- a/typo3/sysext/backend/Classes/Controller/UserSettingsController.php +++ b/typo3/sysext/backend/Classes/Controller/UserSettingsController.php @@ -17,8 +17,8 @@ namespace TYPO3\CMS\Backend\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Configuration\BackendUserConfiguration; use TYPO3\CMS\Core\Http\JsonResponse; -use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -27,6 +27,19 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; */ class UserSettingsController { + /** + * @var BackendUserConfiguration + */ + protected $backendUserConfiguration; + + /** + * Initializes the backendUserConfiguration + */ + public function __construct() + { + $this->backendUserConfiguration = GeneralUtility::makeInstance(BackendUserConfiguration::class); + } + /** * Processes all AJAX calls and returns a JSON for the data * @@ -39,9 +52,9 @@ class UserSettingsController $action = $request->getParsedBody()['action'] ?? $request->getQueryParams()['action']; $key = $request->getParsedBody()['key'] ?? $request->getQueryParams()['key']; $value = $request->getParsedBody()['value'] ?? $request->getQueryParams()['value']; + $data = $this->process($action, $key, $value); - $content = $this->process($action, $key, $value); - return (new JsonResponse())->setPayload($content); + return (new JsonResponse())->setPayload($data); } /** @@ -56,29 +69,29 @@ class UserSettingsController { switch ($action) { case 'get': - $content = $this->get($key); + $content = $this->backendUserConfiguration->get($key); break; case 'getAll': - $content = $this->getAll(); + $content = $this->backendUserConfiguration->getAll(); break; case 'set': - $this->set($key, $value); - $content = $this->getAll(); + $this->backendUserConfiguration->set($key, $value); + $content = $this->backendUserConfiguration->getAll(); break; case 'addToList': - $this->addToList($key, $value); - $content = $this->getAll(); + $this->backendUserConfiguration->addToList($key, $value); + $content = $this->backendUserConfiguration->getAll(); break; case 'removeFromList': - $this->removeFromList($key, $value); - $content = $this->getAll(); + $this->backendUserConfiguration->removeFromList($key, $value); + $content = $this->backendUserConfiguration->getAll(); break; case 'unset': - $this->unsetOption($key); - $content = $this->getAll(); + $this->backendUserConfiguration->unsetOption($key); + $content = $this->backendUserConfiguration->getAll(); break; case 'clear': - $this->clear(); + $this->backendUserConfiguration->clear(); $content = ['result' => true]; break; default: @@ -87,152 +100,4 @@ class UserSettingsController return $content; } - - /** - * Returns a specific user setting - * - * @param string $key Identifier, allows also dotted notation for subarrays - * @return mixed Value associated - */ - protected function get($key) - { - return (strpos($key, '.') !== false) ? $this->getFromDottedNotation($key) : $this->getBackendUser()->uc[$key]; - } - - /** - * Get all user settings - * - * @return mixed all values, usually a multi-dimensional array - */ - protected function getAll() - { - return $this->getBackendUser()->uc; - } - - /** - * Sets user settings by key/value pair - * - * @param string $key - * @param mixed $value - */ - protected function set($key, $value) - { - $beUser = $this->getBackendUser(); - if (strpos($key, '.') !== false) { - $this->setFromDottedNotation($key, $value); - } else { - $beUser->uc[$key] = $value; - } - $beUser->writeUC($beUser->uc); - } - - /** - * Adds an value to an Comma-separated list - * stored $key of user settings - * - * @param string $key - * @param mixed $value - */ - protected function addToList($key, $value) - { - $list = $this->get($key); - if (!isset($list)) { - $list = $value; - } else { - if (!GeneralUtility::inList($list, $value)) { - $list .= ',' . $value; - } - } - $this->set($key, $list); - } - - /** - * Removes an value from an Comma-separated list - * stored $key of user settings - * - * @param string $key - * @param mixed $value - */ - protected function removeFromList($key, $value) - { - $list = $this->get($key); - if (GeneralUtility::inList($list, $value)) { - $list = GeneralUtility::trimExplode(',', $list, true); - $list = ArrayUtility::removeArrayEntryByValue($list, $value); - $this->set($key, implode(',', $list)); - } - } - - /** - * Resets the user settings to the default - */ - protected function clear() - { - $this->getBackendUser()->resetUC(); - } - - /** - * Unsets a key in user settings - * - * @param string $key - */ - protected function unsetOption($key) - { - $beUser = $this->getBackendUser(); - if (isset($beUser->uc[$key])) { - unset($beUser->uc[$key]); - $beUser->writeUC($beUser->uc); - } - } - - /** - * Computes the subarray from dotted notation - * - * @param $key string Dotted notation of subkeys like moduleData.module1.general.checked - * @return mixed value of the settings - */ - protected function getFromDottedNotation($key) - { - $subkeys = GeneralUtility::trimExplode('.', $key); - $array = $this->getBackendUser()->uc; - foreach ($subkeys as $subkey) { - if (isset($array[$subkey])) { - $array = &$array[$subkey]; - } else { - $array = []; - break; - } - } - return $array; - } - - /** - * Sets the value of a key written in dotted notation - * - * @param string $key - * @param mixed $value - */ - protected function setFromDottedNotation($key, $value) - { - $subkeys = GeneralUtility::trimExplode('.', $key, true); - $lastKey = $subkeys[count($subkeys) - 1]; - $array = &$this->getBackendUser()->uc; - foreach ($subkeys as $subkey) { - if ($subkey === $lastKey) { - $array[$subkey] = $value; - } else { - $array = &$array[$subkey]; - } - } - } - - /** - * Returns the current BE user. - * - * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication - */ - protected function getBackendUser() - { - return $GLOBALS['BE_USER']; - } } diff --git a/typo3/sysext/backend/Tests/Unit/Configuration/BackendUserConfigurationTest.php b/typo3/sysext/backend/Tests/Unit/Configuration/BackendUserConfigurationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5dc55aecedb581faba20ed1138a9b05d927df5bb --- /dev/null +++ b/typo3/sysext/backend/Tests/Unit/Configuration/BackendUserConfigurationTest.php @@ -0,0 +1,201 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Backend\Tests\Unit\Configuration; + +/* + * 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\Configuration\BackendUserConfiguration; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; +use TYPO3\TestingFramework\Core\Unit\UnitTestCase; + +/** + * Testcase for TYPO3\CMS\Backend\Configuration\BackendUserConfiguration + */ +class BackendUserConfigurationTest extends UnitTestCase +{ + /** + * @var BackendUserConfiguration + */ + protected $backendUserConfiguration; + + /** + * @var BackendUserAuthentication|\Prophecy\Prophecy\ObjectProphecy + */ + protected $backendUser; + + /** + * Set up this testcase + */ + protected function setUp() + { + /** @var BackendUserAuthentication|\Prophecy\Prophecy\ObjectProphecy */ + $this->backendUser = $this->prophesize(BackendUserAuthentication::class); + $this->backendUserConfiguration = new BackendUserConfiguration($this->backendUser->reveal()); + } + + /** + * @test + */ + public function getsConfiguration() + { + $this->backendUser->reveal()->uc = [ + 'key' => 'A', + 'nested' => [ + 'key' => 'B', + ], + ]; + + $this->assertEquals('A', $this->backendUserConfiguration->get('key')); + $this->assertEquals('B', $this->backendUserConfiguration->get('nested.key')); + } + + /** + * @test + */ + public function getsAllConfiguration() + { + $configuration = [ + 'foo' => 'A', + 'bar' => 'B', + ]; + $this->backendUser->reveal()->uc = $configuration; + + $this->assertEquals($configuration, $this->backendUserConfiguration->getAll()); + } + + /** + * @test + */ + public function setsConfiguration() + { + $this->backendUser->reveal()->uc = [ + 'foo' => 'A', + ]; + + $this->backendUserConfiguration->set('foo', 'X'); + $this->backendUserConfiguration->set('bar', 'Y'); + $this->backendUserConfiguration->set('nested.bar', 'Z'); + + $expected = [ + 'foo' => 'X', + 'bar' => 'Y', + 'nested' => [ + 'bar' => 'Z', + ], + ]; + + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + } + + /** + * @test + */ + public function addsToListConfigurationOption() + { + $this->backendUser->reveal()->uc = [ + 'foo' => 'A', + 'nested' => [ + 'foo' => '', + ], + ]; + + $this->backendUserConfiguration->addToList('foo', 'X'); + $this->backendUserConfiguration->addToList('nested.foo', 'X'); + $this->backendUserConfiguration->addToList('nested.foo', 'Z'); + $this->backendUserConfiguration->addToList('nested.foo', 'Z'); + + $expected = [ + 'foo' => 'A,X', + 'nested' => [ + 'foo' => '', + ], + ]; + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + $expected = [ + 'foo' => 'A,X', + 'nested' => [ + 'foo' => ',X', + ], + ]; + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + $expected = [ + 'foo' => 'A,X', + 'nested' => [ + 'foo' => ',X,Z', + ], + ]; + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + } + + /** + * @test + */ + public function removesFromListConfigurationOption() + { + $this->backendUser->reveal()->uc = [ + 'foo' => 'A,B', + 'nested' => [ + 'foo' => 'A,B,C', + ], + ]; + + $this->backendUserConfiguration->removeFromList('foo', 'B'); + $this->backendUserConfiguration->removeFromList('nested.foo', 'B'); + $this->backendUserConfiguration->removeFromList('nested.foo', 'B'); + + $expected = [ + 'foo' => 'A', + 'nested' => [ + 'foo' => 'A,B,C', + ], + ]; + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + $expected = [ + 'foo' => 'A', + 'nested' => [ + 'foo' => 'A,C', + ], + ]; + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + } + + /** + * @test + */ + public function clearsConfiguration() + { + $this->backendUserConfiguration->clear(); + + $this->backendUser->resetUC()->shouldHaveBeenCalled(); + } + + /** + * @test + */ + public function unsetsConfigurationOption() + { + $this->backendUser->reveal()->uc = [ + 'foo' => 'A', + 'bar' => 'B', + ]; + + $this->backendUserConfiguration->unsetOption('foo'); + $this->backendUserConfiguration->unsetOption('foo'); + + $expected = [ + 'bar' => 'B', + ]; + $this->backendUser->writeUC($expected)->shouldHaveBeenCalled(); + } +}