aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@users.noreply.github.com>2024-11-06 08:54:40 +0100
committerGitHub <noreply@github.com>2024-11-06 08:54:40 +0100
commit8fab143aa486904f7a17c4f1c2f6364cd43bf9d9 (patch)
tree91381cb6382ea0d1b006ba00c9e4b7d7b418bb97
parent01ad23aaaa3e18fa30fb6bef85e8bd2cc3c3e054 (diff)
parentbcfb02f5d79796cae2fe45b9b64926eae51680a1 (diff)
downloadnextcloud-server-8fab143aa486904f7a17c4f1c2f6364cd43bf9d9.tar.gz
nextcloud-server-8fab143aa486904f7a17c4f1c2f6364cd43bf9d9.zip
Merge pull request #48721 from nextcloud/feat/allow-getter-setter-decl-fors
-rw-r--r--apps/files/composer/composer/autoload_classmap.php4
-rw-r--r--apps/files/composer/composer/autoload_static.php4
-rw-r--r--apps/files/lib/AppInfo/Application.php12
-rw-r--r--apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php39
-rw-r--r--apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php40
-rw-r--r--apps/files/lib/Settings/DeclarativeAdminSettings.php (renamed from apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php)36
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/Settings/DeclarativeManager.php53
-rw-r--r--lib/public/Settings/DeclarativeSettingsTypes.php6
-rw-r--r--lib/public/Settings/IDeclarativeSettingsFormWithHandlers.php31
-rw-r--r--tests/lib/Settings/DeclarativeManagerTest.php76
12 files changed, 183 insertions, 120 deletions
diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php
index 4be3f54c006..e9e45bbd84a 100644
--- a/apps/files/composer/composer/autoload_classmap.php
+++ b/apps/files/composer/composer/autoload_classmap.php
@@ -58,9 +58,6 @@ return array(
'OCA\\Files\\Event\\LoadSidebar' => $baseDir . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => $baseDir . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php',
- 'OCA\\Files\\Listener\\DeclarativeSettingsGetValueEventListener' => $baseDir . '/../lib/Listener/DeclarativeSettingsGetValueEventListener.php',
- 'OCA\\Files\\Listener\\DeclarativeSettingsRegisterFormEventListener' => $baseDir . '/../lib/Listener/DeclarativeSettingsRegisterFormEventListener.php',
- 'OCA\\Files\\Listener\\DeclarativeSettingsSetValueEventListener' => $baseDir . '/../lib/Listener/DeclarativeSettingsSetValueEventListener.php',
'OCA\\Files\\Listener\\LoadSearchPluginsListener' => $baseDir . '/../lib/Listener/LoadSearchPluginsListener.php',
'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files\\Listener\\RenderReferenceEventListener' => $baseDir . '/../lib/Listener/RenderReferenceEventListener.php',
@@ -79,5 +76,6 @@ return array(
'OCA\\Files\\Service\\TagService' => $baseDir . '/../lib/Service/TagService.php',
'OCA\\Files\\Service\\UserConfig' => $baseDir . '/../lib/Service/UserConfig.php',
'OCA\\Files\\Service\\ViewConfig' => $baseDir . '/../lib/Service/ViewConfig.php',
+ 'OCA\\Files\\Settings\\DeclarativeAdminSettings' => $baseDir . '/../lib/Settings/DeclarativeAdminSettings.php',
'OCA\\Files\\Settings\\PersonalSettings' => $baseDir . '/../lib/Settings/PersonalSettings.php',
);
diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php
index 292768fc64f..59695e60fc7 100644
--- a/apps/files/composer/composer/autoload_static.php
+++ b/apps/files/composer/composer/autoload_static.php
@@ -73,9 +73,6 @@ class ComposerStaticInitFiles
'OCA\\Files\\Event\\LoadSidebar' => __DIR__ . '/..' . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => __DIR__ . '/..' . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
- 'OCA\\Files\\Listener\\DeclarativeSettingsGetValueEventListener' => __DIR__ . '/..' . '/../lib/Listener/DeclarativeSettingsGetValueEventListener.php',
- 'OCA\\Files\\Listener\\DeclarativeSettingsRegisterFormEventListener' => __DIR__ . '/..' . '/../lib/Listener/DeclarativeSettingsRegisterFormEventListener.php',
- 'OCA\\Files\\Listener\\DeclarativeSettingsSetValueEventListener' => __DIR__ . '/..' . '/../lib/Listener/DeclarativeSettingsSetValueEventListener.php',
'OCA\\Files\\Listener\\LoadSearchPluginsListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSearchPluginsListener.php',
'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files\\Listener\\RenderReferenceEventListener' => __DIR__ . '/..' . '/../lib/Listener/RenderReferenceEventListener.php',
@@ -94,6 +91,7 @@ class ComposerStaticInitFiles
'OCA\\Files\\Service\\TagService' => __DIR__ . '/..' . '/../lib/Service/TagService.php',
'OCA\\Files\\Service\\UserConfig' => __DIR__ . '/..' . '/../lib/Service/UserConfig.php',
'OCA\\Files\\Service\\ViewConfig' => __DIR__ . '/..' . '/../lib/Service/ViewConfig.php',
+ 'OCA\\Files\\Settings\\DeclarativeAdminSettings' => __DIR__ . '/..' . '/../lib/Settings/DeclarativeAdminSettings.php',
'OCA\\Files\\Settings\\PersonalSettings' => __DIR__ . '/..' . '/../lib/Settings/PersonalSettings.php',
);
diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php
index 3d2d0527072..d50a8d14f5a 100644
--- a/apps/files/lib/AppInfo/Application.php
+++ b/apps/files/lib/AppInfo/Application.php
@@ -16,9 +16,6 @@ use OCA\Files\Controller\ApiController;
use OCA\Files\DirectEditingCapabilities;
use OCA\Files\Event\LoadSearchPlugins;
use OCA\Files\Event\LoadSidebar;
-use OCA\Files\Listener\DeclarativeSettingsGetValueEventListener;
-use OCA\Files\Listener\DeclarativeSettingsRegisterFormEventListener;
-use OCA\Files\Listener\DeclarativeSettingsSetValueEventListener;
use OCA\Files\Listener\LoadSearchPluginsListener;
use OCA\Files\Listener\LoadSidebarListener;
use OCA\Files\Listener\RenderReferenceEventListener;
@@ -28,6 +25,7 @@ use OCA\Files\Search\FilesSearchProvider;
use OCA\Files\Service\TagService;
use OCA\Files\Service\UserConfig;
use OCA\Files\Service\ViewConfig;
+use OCA\Files\Settings\DeclarativeAdminSettings;
use OCP\Activity\IManager as IActivityManager;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
@@ -49,9 +47,6 @@ use OCP\IRequest;
use OCP\IServerContainer;
use OCP\ITagManager;
use OCP\IUserSession;
-use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
-use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
-use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
use OCP\Share\IManager as IShareManager;
use OCP\Util;
use Psr\Container\ContainerInterface;
@@ -111,6 +106,8 @@ class Application extends App implements IBootstrap {
$context->registerCapability(Capabilities::class);
$context->registerCapability(DirectEditingCapabilities::class);
+ $context->registerDeclarativeSettings(DeclarativeAdminSettings::class);
+
$context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class);
$context->registerEventListener(RenderReferenceEvent::class, RenderReferenceEventListener::class);
$context->registerEventListener(BeforeNodeRenamedEvent::class, SyncLivePhotosListener::class);
@@ -119,9 +116,6 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(BeforeNodeCopiedEvent::class, SyncLivePhotosListener::class);
$context->registerEventListener(NodeCopiedEvent::class, SyncLivePhotosListener::class);
$context->registerEventListener(LoadSearchPlugins::class, LoadSearchPluginsListener::class);
- $context->registerEventListener(DeclarativeSettingsRegisterFormEvent::class, DeclarativeSettingsRegisterFormEventListener::class);
- $context->registerEventListener(DeclarativeSettingsGetValueEvent::class, DeclarativeSettingsGetValueEventListener::class);
- $context->registerEventListener(DeclarativeSettingsSetValueEvent::class, DeclarativeSettingsSetValueEventListener::class);
$context->registerSearchProvider(FilesSearchProvider::class);
diff --git a/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php b/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php
deleted file mode 100644
index b1d0ee3a395..00000000000
--- a/apps/files/lib/Listener/DeclarativeSettingsGetValueEventListener.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-declare(strict_types=1);
-/**
- * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace OCA\Files\Listener;
-
-use OCA\Files\AppInfo\Application;
-use OCA\Files\Service\SettingsService;
-use OCP\EventDispatcher\Event;
-use OCP\EventDispatcher\IEventListener;
-use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
-
-/** @template-implements IEventListener<DeclarativeSettingsGetValueEvent> */
-class DeclarativeSettingsGetValueEventListener implements IEventListener {
-
- public function __construct(
- private SettingsService $service,
- ) {
- }
-
- public function handle(Event $event): void {
- if (!($event instanceof DeclarativeSettingsGetValueEvent)) {
- return;
- }
-
- if ($event->getApp() !== Application::APP_ID) {
- return;
- }
-
- $event->setValue(
- match($event->getFieldId()) {
- 'windows_support' => $this->service->hasFilesWindowsSupport(),
- }
- );
- }
-}
diff --git a/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php b/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php
deleted file mode 100644
index a3be2b9141e..00000000000
--- a/apps/files/lib/Listener/DeclarativeSettingsSetValueEventListener.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-declare(strict_types=1);
-/**
- * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace OCA\Files\Listener;
-
-use OCA\Files\AppInfo\Application;
-use OCA\Files\Service\SettingsService;
-use OCP\EventDispatcher\Event;
-use OCP\EventDispatcher\IEventListener;
-use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
-
-/** @template-implements IEventListener<DeclarativeSettingsSetValueEvent> */
-class DeclarativeSettingsSetValueEventListener implements IEventListener {
-
- public function __construct(
- private SettingsService $service,
- ) {
- }
-
- public function handle(Event $event): void {
- if (!($event instanceof DeclarativeSettingsSetValueEvent)) {
- return;
- }
-
- if ($event->getApp() !== Application::APP_ID) {
- return;
- }
-
- switch ($event->getFieldId()) {
- case 'windows_support':
- $this->service->setFilesWindowsSupport((bool)$event->getValue());
- $event->stopPropagation();
- break;
- }
- }
-}
diff --git a/apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php b/apps/files/lib/Settings/DeclarativeAdminSettings.php
index 51832e89ecb..e509ad2233b 100644
--- a/apps/files/lib/Listener/DeclarativeSettingsRegisterFormEventListener.php
+++ b/apps/files/lib/Settings/DeclarativeAdminSettings.php
@@ -2,32 +2,42 @@
declare(strict_types=1);
/**
- * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace OCA\Files\Listener;
+namespace OCA\Files\Settings;
-use OCA\Files\AppInfo\Application;
-use OCP\EventDispatcher\Event;
-use OCP\EventDispatcher\IEventListener;
+use OCA\Files\Service\SettingsService;
use OCP\IL10N;
+use OCP\IUser;
use OCP\Settings\DeclarativeSettingsTypes;
-use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
+use OCP\Settings\IDeclarativeSettingsFormWithHandlers;
-/** @template-implements IEventListener<DeclarativeSettingsRegisterFormEvent> */
-class DeclarativeSettingsRegisterFormEventListener implements IEventListener {
+class DeclarativeAdminSettings implements IDeclarativeSettingsFormWithHandlers {
public function __construct(
private IL10N $l,
+ private SettingsService $service,
) {
}
- public function handle(Event $event): void {
- if (!($event instanceof DeclarativeSettingsRegisterFormEvent)) {
- return;
+ public function getValue(string $fieldId, IUser $user): mixed {
+ return match($fieldId) {
+ 'windows_support' => $this->service->hasFilesWindowsSupport(),
+ default => throw new \InvalidArgumentException('Unexpected field id ' . $fieldId),
+ };
+ }
+
+ public function setValue(string $fieldId, mixed $value, IUser $user): void {
+ switch ($fieldId) {
+ case 'windows_support':
+ $this->service->setFilesWindowsSupport((bool)$value);
+ break;
}
+ }
- $event->registerSchema(Application::APP_ID, [
+ public function getSchema(): array {
+ return [
'id' => 'files-filename-support',
'priority' => 10,
'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN,
@@ -45,6 +55,6 @@ class DeclarativeSettingsRegisterFormEventListener implements IEventListener {
'default' => false,
],
],
- ]);
+ ];
}
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index ef9af33414f..7265edfe95f 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -698,6 +698,7 @@ return array(
'OCP\\Settings\\Events\\DeclarativeSettingsSetValueEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php',
'OCP\\Settings\\IDeclarativeManager' => $baseDir . '/lib/public/Settings/IDeclarativeManager.php',
'OCP\\Settings\\IDeclarativeSettingsForm' => $baseDir . '/lib/public/Settings/IDeclarativeSettingsForm.php',
+ 'OCP\\Settings\\IDeclarativeSettingsFormWithHandlers' => $baseDir . '/lib/public/Settings/IDeclarativeSettingsFormWithHandlers.php',
'OCP\\Settings\\IDelegatedSettings' => $baseDir . '/lib/public/Settings/IDelegatedSettings.php',
'OCP\\Settings\\IIconSection' => $baseDir . '/lib/public/Settings/IIconSection.php',
'OCP\\Settings\\IManager' => $baseDir . '/lib/public/Settings/IManager.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 99f8afb61f1..4bac34425ac 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -731,6 +731,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Settings\\Events\\DeclarativeSettingsSetValueEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php',
'OCP\\Settings\\IDeclarativeManager' => __DIR__ . '/../../..' . '/lib/public/Settings/IDeclarativeManager.php',
'OCP\\Settings\\IDeclarativeSettingsForm' => __DIR__ . '/../../..' . '/lib/public/Settings/IDeclarativeSettingsForm.php',
+ 'OCP\\Settings\\IDeclarativeSettingsFormWithHandlers' => __DIR__ . '/../../..' . '/lib/public/Settings/IDeclarativeSettingsFormWithHandlers.php',
'OCP\\Settings\\IDelegatedSettings' => __DIR__ . '/../../..' . '/lib/public/Settings/IDelegatedSettings.php',
'OCP\\Settings\\IIconSection' => __DIR__ . '/../../..' . '/lib/public/Settings/IIconSection.php',
'OCP\\Settings\\IManager' => __DIR__ . '/../../..' . '/lib/public/Settings/IManager.php',
diff --git a/lib/private/Settings/DeclarativeManager.php b/lib/private/Settings/DeclarativeManager.php
index d8c25c9a5c7..dea0c678f20 100644
--- a/lib/private/Settings/DeclarativeManager.php
+++ b/lib/private/Settings/DeclarativeManager.php
@@ -22,6 +22,7 @@ use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
use OCP\Settings\IDeclarativeManager;
use OCP\Settings\IDeclarativeSettingsForm;
+use OCP\Settings\IDeclarativeSettingsFormWithHandlers;
use Psr\Log\LoggerInterface;
/**
@@ -32,6 +33,15 @@ use Psr\Log\LoggerInterface;
* @psalm-import-type DeclarativeSettingsFormSchemaWithoutValues from IDeclarativeSettingsForm
*/
class DeclarativeManager implements IDeclarativeManager {
+
+ /** @var array<string, list<IDeclarativeSettingsForm>> */
+ private array $declarativeForms = [];
+
+ /**
+ * @var array<string, list<DeclarativeSettingsFormSchemaWithoutValues>>
+ */
+ private array $appSchemas = [];
+
public function __construct(
private IEventDispatcher $eventDispatcher,
private IGroupManager $groupManager,
@@ -43,11 +53,6 @@ class DeclarativeManager implements IDeclarativeManager {
}
/**
- * @var array<string, list<DeclarativeSettingsFormSchemaWithoutValues>>
- */
- private array $appSchemas = [];
-
- /**
* @inheritdoc
*/
public function registerSchema(string $app, array $schema): void {
@@ -77,11 +82,15 @@ class DeclarativeManager implements IDeclarativeManager {
* @inheritdoc
*/
public function loadSchemas(): void {
- $declarativeSettings = $this->coordinator->getRegistrationContext()->getDeclarativeSettings();
- foreach ($declarativeSettings as $declarativeSetting) {
- /** @var IDeclarativeSettingsForm $declarativeSettingObject */
- $declarativeSettingObject = Server::get($declarativeSetting->getService());
- $this->registerSchema($declarativeSetting->getAppId(), $declarativeSettingObject->getSchema());
+ if (empty($this->declarativeForms)) {
+ $declarativeSettings = $this->coordinator->getRegistrationContext()->getDeclarativeSettings();
+ foreach ($declarativeSettings as $declarativeSetting) {
+ $app = $declarativeSetting->getAppId();
+ /** @var IDeclarativeSettingsForm $declarativeForm */
+ $declarativeForm = Server::get($declarativeSetting->getService());
+ $this->registerSchema($app, $declarativeForm->getSchema());
+ $this->declarativeForms[$app][] = $declarativeForm;
+ }
}
$this->eventDispatcher->dispatchTyped(new DeclarativeSettingsRegisterFormEvent($this));
@@ -224,6 +233,10 @@ class DeclarativeManager implements IDeclarativeManager {
$storageType = $this->getStorageType($app, $fieldId);
switch ($storageType) {
case DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL:
+ $form = $this->getForm($app, $formId);
+ if ($form !== null && $form instanceof IDeclarativeSettingsFormWithHandlers) {
+ return $form->getValue($fieldId, $user);
+ }
$event = new DeclarativeSettingsGetValueEvent($user, $app, $formId, $fieldId);
$this->eventDispatcher->dispatchTyped($event);
return $event->getValue();
@@ -244,6 +257,12 @@ class DeclarativeManager implements IDeclarativeManager {
$storageType = $this->getStorageType($app, $fieldId);
switch ($storageType) {
case DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL:
+ $form = $this->getForm($app, $formId);
+ if ($form !== null && $form instanceof IDeclarativeSettingsFormWithHandlers) {
+ $form->setValue($fieldId, $value, $user);
+ break;
+ }
+ // fall back to event handling
$this->eventDispatcher->dispatchTyped(new DeclarativeSettingsSetValueEvent($user, $app, $formId, $fieldId, $value));
break;
case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL:
@@ -254,6 +273,20 @@ class DeclarativeManager implements IDeclarativeManager {
}
}
+ /**
+ * If a declarative setting was registered as a form and not just a schema
+ * then this will yield the registering form.
+ */
+ private function getForm(string $app, string $formId): ?IDeclarativeSettingsForm {
+ $allForms = $this->declarativeForms[$app] ?? [];
+ foreach ($allForms as $form) {
+ if ($form->getSchema()['id'] === $formId) {
+ return $form;
+ }
+ }
+ return null;
+ }
+
private function getInternalValue(IUser $user, string $app, string $formId, string $fieldId): mixed {
$sectionType = $this->getSectionType($app, $fieldId);
$defaultValue = $this->getDefaultValue($app, $formId, $fieldId);
diff --git a/lib/public/Settings/DeclarativeSettingsTypes.php b/lib/public/Settings/DeclarativeSettingsTypes.php
index 82444af9b82..7edf0cbdd6e 100644
--- a/lib/public/Settings/DeclarativeSettingsTypes.php
+++ b/lib/public/Settings/DeclarativeSettingsTypes.php
@@ -32,8 +32,9 @@ final class DeclarativeSettingsTypes {
/**
* IDeclarativeSettingsForm storage_type which is determines where and how the config value is stored
*
- *
- * For `external` storage_type the app implementing \OCP\Settings\SetDeclarativeSettingsValueEvent and \OCP\Settings\GetDeclarativeSettingsValueEvent events is responsible for storing and retrieving the config value.
+ * For `external` storage_type the app needs to either implement event listeners for \OCP\Settings\SetDeclarativeSettingsValueEvent
+ * and \OCP\Settings\GetDeclarativeSettingsValueEvent or the IDeclarativeSettingsForm also needs to implement
+ * IDeclarativeSettingsFormWithHandlers for storing and retrieving the config value.
*
* @since 29.0.0
*/
@@ -43,7 +44,6 @@ final class DeclarativeSettingsTypes {
* IDeclarativeSettingsForm storage_type which is determines where and how the config value is stored
*
* For `internal` storage_type the config value is stored in default `appconfig` and `preferences` tables.
- * For `external` storage_type the app implementing \OCP\Settings\SetDeclarativeSettingsValueEvent and \OCP\Settings\GetDeclarativeSettingsValueEvent events is responsible for storing and retrieving the config value.
*
* @since 29.0.0
*/
diff --git a/lib/public/Settings/IDeclarativeSettingsFormWithHandlers.php b/lib/public/Settings/IDeclarativeSettingsFormWithHandlers.php
new file mode 100644
index 00000000000..180df73d995
--- /dev/null
+++ b/lib/public/Settings/IDeclarativeSettingsFormWithHandlers.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Settings;
+
+use OCP\IUser;
+
+/**
+ * @since 31.0.0
+ */
+interface IDeclarativeSettingsFormWithHandlers extends IDeclarativeSettingsForm {
+
+ /**
+ * This function is called to get the current value of a specific forms field.
+ * @since 31.0.0
+ */
+ public function getValue(string $fieldId, IUser $user): mixed;
+
+ /**
+ * This function is called when a user updated a form field to persist the setting.
+ * @since 31.0.0
+ */
+ public function setValue(string $fieldId, mixed $value, IUser $user): void;
+
+}
diff --git a/tests/lib/Settings/DeclarativeManagerTest.php b/tests/lib/Settings/DeclarativeManagerTest.php
index f0d97c7ea25..522264acd8c 100644
--- a/tests/lib/Settings/DeclarativeManagerTest.php
+++ b/tests/lib/Settings/DeclarativeManagerTest.php
@@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Test\Settings;
use OC\AppFramework\Bootstrap\Coordinator;
+use OC\AppFramework\Bootstrap\RegistrationContext;
+use OC\AppFramework\Bootstrap\ServiceRegistration;
use OC\Settings\DeclarativeManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IAppConfig;
@@ -19,6 +21,8 @@ use OCP\IUser;
use OCP\Settings\DeclarativeSettingsTypes;
use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
use OCP\Settings\IDeclarativeManager;
+use OCP\Settings\IDeclarativeSettingsForm;
+use OCP\Settings\IDeclarativeSettingsFormWithHandlers;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Test\TestCase;
@@ -52,6 +56,8 @@ class DeclarativeManagerTest extends TestCase {
/** @var IUser|MockObject */
private $adminUser;
+ private IDeclarativeSettingsForm&MockObject $closureForm;
+
public const validSchemaAllFields = [
'id' => 'test_form_1',
'priority' => 10,
@@ -518,4 +524,74 @@ class DeclarativeManagerTest extends TestCase {
$this->expectException(\Exception::class);
$this->declarativeManager->getFormsWithValues($this->user, $schema['section_type'], $schema['section_id']);
}
+
+ /**
+ * Ensure that the `setValue` method is called if the form implements the handler interface.
+ */
+ public function testSetValueWithHandler(): void {
+ $schema = self::validSchemaAllFields;
+ $schema['storage_type'] = DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL;
+
+ $form = $this->createMock(IDeclarativeSettingsFormWithHandlers::class);
+ $form->expects(self::atLeastOnce())
+ ->method('getSchema')
+ ->willReturn($schema);
+ // The setter should be called once!
+ $form->expects(self::once())
+ ->method('setValue')
+ ->with('test_field_2', 'some password', $this->adminUser);
+
+ \OC::$server->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
+
+ $context = $this->createMock(RegistrationContext::class);
+ $context->expects(self::atLeastOnce())
+ ->method('getDeclarativeSettings')
+ ->willReturn([new ServiceRegistration('testing', 'OCA\\Testing\\Settings\\DeclarativeForm')]);
+
+ $this->coordinator->expects(self::atLeastOnce())
+ ->method('getRegistrationContext')
+ ->willReturn($context);
+
+ $this->declarativeManager->loadSchemas();
+
+ $this->eventDispatcher->expects(self::never())
+ ->method('dispatchTyped');
+
+ $this->declarativeManager->setValue($this->adminUser, 'testing', 'test_form_1', 'test_field_2', 'some password');
+ }
+
+ public function testGetValueWithHandler(): void {
+ $schema = self::validSchemaAllFields;
+ $schema['storage_type'] = DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL;
+
+ $form = $this->createMock(IDeclarativeSettingsFormWithHandlers::class);
+ $form->expects(self::atLeastOnce())
+ ->method('getSchema')
+ ->willReturn($schema);
+ // The setter should be called once!
+ $form->expects(self::once())
+ ->method('getValue')
+ ->with('test_field_2', $this->adminUser)
+ ->willReturn('very secret password');
+
+ \OC::$server->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
+
+ $context = $this->createMock(RegistrationContext::class);
+ $context->expects(self::atLeastOnce())
+ ->method('getDeclarativeSettings')
+ ->willReturn([new ServiceRegistration('testing', 'OCA\\Testing\\Settings\\DeclarativeForm')]);
+
+ $this->coordinator->expects(self::atLeastOnce())
+ ->method('getRegistrationContext')
+ ->willReturn($context);
+
+ $this->declarativeManager->loadSchemas();
+
+ $this->eventDispatcher->expects(self::never())
+ ->method('dispatchTyped');
+
+ $password = $this->invokePrivate($this->declarativeManager, 'getValue', [$this->adminUser, 'testing', 'test_form_1', 'test_field_2']);
+ self::assertEquals('very secret password', $password);
+ }
+
}