aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorprovokateurin <kate@provokateurin.de>2024-09-03 13:43:43 +0200
committerprovokateurin <kate@provokateurin.de>2024-09-13 07:41:17 +0200
commit3d384ce0bdf89752d16ef1fbcda3b8242a10bd89 (patch)
tree1c526557e47441c9a1f632ccf2051957b7cda6c7
parentb6454e7480e9d3aa32d1670b365df0029d89dcd7 (diff)
downloadnextcloud-server-feat/declarative-settings/typed-abstraction.tar.gz
nextcloud-server-feat/declarative-settings/typed-abstraction.zip
-rw-r--r--apps/testing/composer/composer/autoload_classmap.php2
-rw-r--r--apps/testing/composer/composer/autoload_static.php2
-rw-r--r--apps/testing/lib/Controller/PageController.php38
-rw-r--r--apps/testing/lib/Listener/DeleteDeclarativeSettingsValueListener.php35
-rw-r--r--apps/testing/lib/Settings/DeclarativeSettingsFormTyped.php3
-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.php69
-rw-r--r--lib/private/Settings/DeclarativeSettingsOption.php108
-rw-r--r--lib/public/Settings/DeclarativeSettingsOptionInt.php19
-rw-r--r--lib/public/Settings/Events/DeclarativeSettingsDeleteValueEvent.php58
-rw-r--r--lib/public/Settings/IDeclarativeManager.php24
12 files changed, 342 insertions, 18 deletions
diff --git a/apps/testing/composer/composer/autoload_classmap.php b/apps/testing/composer/composer/autoload_classmap.php
index d7b767f63d5..d985f49e617 100644
--- a/apps/testing/composer/composer/autoload_classmap.php
+++ b/apps/testing/composer/composer/autoload_classmap.php
@@ -11,7 +11,9 @@ return array(
'OCA\\Testing\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
'OCA\\Testing\\Controller\\ConfigController' => $baseDir . '/../lib/Controller/ConfigController.php',
'OCA\\Testing\\Controller\\LockingController' => $baseDir . '/../lib/Controller/LockingController.php',
+ 'OCA\\Testing\\Controller\\PageController' => $baseDir . '/../lib/Controller/PageController.php',
'OCA\\Testing\\Controller\\RateLimitTestController' => $baseDir . '/../lib/Controller/RateLimitTestController.php',
+ 'OCA\\Testing\\Listener\\DeleteDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/DeleteDeclarativeSettingsValueListener.php',
'OCA\\Testing\\Listener\\GetDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/GetDeclarativeSettingsValueListener.php',
'OCA\\Testing\\Listener\\RegisterDeclarativeSettingsListener' => $baseDir . '/../lib/Listener/RegisterDeclarativeSettingsListener.php',
'OCA\\Testing\\Listener\\SetDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/SetDeclarativeSettingsValueListener.php',
diff --git a/apps/testing/composer/composer/autoload_static.php b/apps/testing/composer/composer/autoload_static.php
index a147eab93b3..ba18e6ba4f4 100644
--- a/apps/testing/composer/composer/autoload_static.php
+++ b/apps/testing/composer/composer/autoload_static.php
@@ -26,7 +26,9 @@ class ComposerStaticInitTesting
'OCA\\Testing\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
'OCA\\Testing\\Controller\\ConfigController' => __DIR__ . '/..' . '/../lib/Controller/ConfigController.php',
'OCA\\Testing\\Controller\\LockingController' => __DIR__ . '/..' . '/../lib/Controller/LockingController.php',
+ 'OCA\\Testing\\Controller\\PageController' => __DIR__ . '/..' . '/../lib/Controller/PageController.php',
'OCA\\Testing\\Controller\\RateLimitTestController' => __DIR__ . '/..' . '/../lib/Controller/RateLimitTestController.php',
+ 'OCA\\Testing\\Listener\\DeleteDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/DeleteDeclarativeSettingsValueListener.php',
'OCA\\Testing\\Listener\\GetDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/GetDeclarativeSettingsValueListener.php',
'OCA\\Testing\\Listener\\RegisterDeclarativeSettingsListener' => __DIR__ . '/..' . '/../lib/Listener/RegisterDeclarativeSettingsListener.php',
'OCA\\Testing\\Listener\\SetDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/SetDeclarativeSettingsValueListener.php',
diff --git a/apps/testing/lib/Controller/PageController.php b/apps/testing/lib/Controller/PageController.php
new file mode 100644
index 00000000000..fb9e46381a6
--- /dev/null
+++ b/apps/testing/lib/Controller/PageController.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace OCA\Testing\Controller;
+
+use OCA\Testing\Settings\DeclarativeSettingsFormTyped;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\FrontpageRoute;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\IRequest;
+
+class PageController extends Controller {
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private DeclarativeSettingsFormTyped $form,
+ ) {
+ parent::__construct($appName, $request);
+ }
+
+ #[NoAdminRequired]
+ #[NoCSRFRequired]
+ #[FrontpageRoute(verb: 'GET', url: '/declarative-settings-typed')]
+ public function declarativeSettingsTyped(): JSONResponse {
+ $this->form->test->setValue(1);
+ $value1 = $this->form->test->getValue();
+ $this->form->test->setValue(8);
+ $value2 = $this->form->test->getValue();
+ $this->form->test->deleteValue();
+ $value3 = $this->form->test->getValue();
+ return new JSONResponse([
+ 'value1' => $value1,
+ 'value2' => $value2,
+ 'value3' => $value3,
+ ]);
+ }
+}
diff --git a/apps/testing/lib/Listener/DeleteDeclarativeSettingsValueListener.php b/apps/testing/lib/Listener/DeleteDeclarativeSettingsValueListener.php
new file mode 100644
index 00000000000..8fbf8e60025
--- /dev/null
+++ b/apps/testing/lib/Listener/DeleteDeclarativeSettingsValueListener.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Testing\Listener;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IConfig;
+use OCP\Settings\Events\DeclarativeSettingsDeleteValueEvent;
+
+/**
+ * @template-implements IEventListener<DeclarativeSettingsDeleteValueEvent>
+ */
+class DeleteDeclarativeSettingsValueListener implements IEventListener {
+
+ public function __construct(private IConfig $config) {
+ }
+
+ public function handle(Event $event): void {
+ if (!$event instanceof DeclarativeSettingsDeleteValueEvent) {
+ return;
+ }
+
+ if ($event->getApp() !== 'testing') {
+ return;
+ }
+
+ error_log('Testing app wants to delete field ' . $event->getFieldId() . ' for user ' . $event->getUser()->getUID());
+ $this->config->deleteUserValue($event->getUser()->getUID(), $event->getApp(), $event->getFieldId());
+ }
+}
diff --git a/apps/testing/lib/Settings/DeclarativeSettingsFormTyped.php b/apps/testing/lib/Settings/DeclarativeSettingsFormTyped.php
index 1dff17e3684..7aaa1cba33d 100644
--- a/apps/testing/lib/Settings/DeclarativeSettingsFormTyped.php
+++ b/apps/testing/lib/Settings/DeclarativeSettingsFormTyped.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
namespace OCA\Testing\Settings;
+use OCA\Testing\AppInfo\Application;
use OCP\Settings\DeclarativeSettingsForm;
use OCP\Settings\DeclarativeSettingsOptionInt;
use OCP\Settings\DeclarativeSettingsTypes;
@@ -17,6 +18,8 @@ class DeclarativeSettingsFormTyped extends DeclarativeSettingsForm {
public function __construct() {
$this->test = new DeclarativeSettingsOptionInt(
+ appName: Application::APP_ID,
+ form: $this,
id: 'test_ex_app_field_8',
title: 'Multi-selection',
default: 2,
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 36748d2fc83..6911692a7c0 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -692,6 +692,7 @@ return array(
'OCP\\Settings\\DeclarativeSettingsForm' => $baseDir . '/lib/public/Settings/DeclarativeSettingsForm.php',
'OCP\\Settings\\DeclarativeSettingsOptionInt' => $baseDir . '/lib/public/Settings/DeclarativeSettingsOptionInt.php',
'OCP\\Settings\\DeclarativeSettingsTypes' => $baseDir . '/lib/public/Settings/DeclarativeSettingsTypes.php',
+ 'OCP\\Settings\\Events\\DeclarativeSettingsDeleteValueEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsDeleteValueEvent.php',
'OCP\\Settings\\Events\\DeclarativeSettingsGetValueEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php',
'OCP\\Settings\\Events\\DeclarativeSettingsRegisterFormEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php',
'OCP\\Settings\\Events\\DeclarativeSettingsSetValueEvent' => $baseDir . '/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 0c65fae8e19..25cbd6c1632 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -725,6 +725,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Settings\\DeclarativeSettingsForm' => __DIR__ . '/../../..' . '/lib/public/Settings/DeclarativeSettingsForm.php',
'OCP\\Settings\\DeclarativeSettingsOptionInt' => __DIR__ . '/../../..' . '/lib/public/Settings/DeclarativeSettingsOptionInt.php',
'OCP\\Settings\\DeclarativeSettingsTypes' => __DIR__ . '/../../..' . '/lib/public/Settings/DeclarativeSettingsTypes.php',
+ 'OCP\\Settings\\Events\\DeclarativeSettingsDeleteValueEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsDeleteValueEvent.php',
'OCP\\Settings\\Events\\DeclarativeSettingsGetValueEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsGetValueEvent.php',
'OCP\\Settings\\Events\\DeclarativeSettingsRegisterFormEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsRegisterFormEvent.php',
'OCP\\Settings\\Events\\DeclarativeSettingsSetValueEvent' => __DIR__ . '/../../..' . '/lib/public/Settings/Events/DeclarativeSettingsSetValueEvent.php',
diff --git a/lib/private/Settings/DeclarativeManager.php b/lib/private/Settings/DeclarativeManager.php
index 29557187175..89a75b43b66 100644
--- a/lib/private/Settings/DeclarativeManager.php
+++ b/lib/private/Settings/DeclarativeManager.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+
namespace OC\Settings;
use Exception;
@@ -17,6 +18,7 @@ use OCP\IGroupManager;
use OCP\IUser;
use OCP\Server;
use OCP\Settings\DeclarativeSettingsTypes;
+use OCP\Settings\Events\DeclarativeSettingsDeleteValueEvent;
use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
@@ -36,11 +38,11 @@ class DeclarativeManager implements IDeclarativeManager {
public function __construct(
private IEventDispatcher $eventDispatcher,
- private IGroupManager $groupManager,
- private Coordinator $coordinator,
- private IConfig $config,
- private IAppConfig $appConfig,
- private LoggerInterface $logger,
+ private IGroupManager $groupManager,
+ private Coordinator $coordinator,
+ private IConfig $config,
+ private IAppConfig $appConfig,
+ private LoggerInterface $logger,
) {
}
@@ -65,8 +67,8 @@ class DeclarativeManager implements IDeclarativeManager {
}
}
- $fieldIDs = array_map(fn ($field) => $field['id'], $schema['fields']);
- $otherFieldIDs = array_merge(...array_map(fn ($schema) => array_map(fn ($field) => $field['id'], $schema['fields']), $this->appSchemas[$app]));
+ $fieldIDs = array_map(fn($field) => $field['id'], $schema['fields']);
+ $otherFieldIDs = array_merge(...array_map(fn($schema) => array_map(fn($field) => $field['id'], $schema['fields']), $this->appSchemas[$app]));
$intersectionFieldIDs = array_intersect($fieldIDs, $otherFieldIDs);
if (count($intersectionFieldIDs) > 0) {
throw new Exception('Non unique field IDs detected: ' . join(', ', $intersectionFieldIDs));
@@ -220,11 +222,33 @@ class DeclarativeManager implements IDeclarativeManager {
}
/**
+ * @throws Exception
+ * @throws NotAdminException
+ */
+ public function deleteValue(IUser $user, string $app, string $formId, string $fieldId): void {
+ $sectionType = $this->getSectionType($app, $fieldId);
+ $this->assertAuthorized($user, $sectionType);
+
+ $storageType = $this->getStorageType($app, $fieldId);
+ switch ($storageType) {
+ case DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL:
+ $event = new DeclarativeSettingsDeleteValueEvent($user, $app, $formId, $fieldId);
+ $this->eventDispatcher->dispatchTyped($event);
+ break;
+ case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL:
+ $this->deleteInternalValue($user, $app, $fieldId);
+ break;
+ default:
+ throw new Exception('Unknown storage type "' . $storageType . '"');
+ }
+ }
+
+ /**
* @return DeclarativeSettingsValueTypes
* @throws Exception
* @throws NotAdminException
*/
- private function getValue(IUser $user, string $app, string $formId, string $fieldId): mixed {
+ public function getValue(IUser $user, string $app, string $formId, string $fieldId): mixed {
$sectionType = $this->getSectionType($app, $fieldId);
$this->assertAuthorized($user, $sectionType);
@@ -254,7 +278,7 @@ class DeclarativeManager implements IDeclarativeManager {
$this->eventDispatcher->dispatchTyped(new DeclarativeSettingsSetValueEvent($user, $app, $formId, $fieldId, $value));
break;
case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL:
- $this->saveInternalValue($user, $app, $fieldId, $value);
+ $this->setInternalValue($user, $app, $fieldId, $value);
break;
default:
throw new Exception('Unknown storage type "' . $storageType . '"');
@@ -274,11 +298,11 @@ class DeclarativeManager implements IDeclarativeManager {
}
}
- private function saveInternalValue(IUser $user, string $app, string $fieldId, mixed $value): void {
+ private function setInternalValue(IUser $user, string $app, string $fieldId, mixed $value): void {
$sectionType = $this->getSectionType($app, $fieldId);
switch ($sectionType) {
case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN:
- $this->appConfig->setValueString($app, $fieldId, $value);
+ $this->config->setAppValue($app, $fieldId, $value);
break;
case DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL:
$this->config->setUserValue($user->getUID(), $app, $fieldId, $value);
@@ -288,16 +312,25 @@ class DeclarativeManager implements IDeclarativeManager {
}
}
+ private function deleteInternalValue(IUser $user, string $app, string $fieldId): void {
+ $sectionType = $this->getSectionType($app, $fieldId);
+ switch ($sectionType) {
+ case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN:
+ $this->appConfig->deleteKey($app, $fieldId);
+ break;
+ case DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL:
+ $this->config->deleteUserValue($user->getUID(), $app, $fieldId);
+ break;
+ default:
+ throw new Exception('Unknown section type "' . $sectionType . '"');
+ }
+ }
+
private function getDefaultValue(string $app, string $fieldId): mixed {
foreach ($this->appSchemas[$app] as $schema) {
foreach ($schema['fields'] as $field) {
- if ($field['id'] === $fieldId) {
- if (isset($field['default'])) {
- if (is_array($field['default'])) {
- return json_encode($field['default']);
- }
- return $field['default'];
- }
+ if ($field['id'] === $fieldId && isset($field['default'])) {
+ return $field['default'];
}
}
}
diff --git a/lib/private/Settings/DeclarativeSettingsOption.php b/lib/private/Settings/DeclarativeSettingsOption.php
new file mode 100644
index 00000000000..e7982924d64
--- /dev/null
+++ b/lib/private/Settings/DeclarativeSettingsOption.php
@@ -0,0 +1,108 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Settings;
+
+use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
+use OCP\Common\Exception\NotFoundException;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Server;
+use OCP\Settings\DeclarativeSettingsForm;
+use OCP\Settings\IDeclarativeManager;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
+
+class DeclarativeSettingsOption {
+ private ?IUser $user = null;
+ private ?IDeclarativeManager $manager = null;
+
+ public function __construct(
+ public string $appName,
+ public DeclarativeSettingsForm $form,
+ public string $id,
+ ) {
+ }
+
+ /**
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ * @throws NotFoundException
+ */
+ private function getUser(): IUser {
+ if ($this->user === null) {
+ $userSession = Server::get(IUserSession::class);
+ $this->user = $userSession->getUser();
+ if ($this->user === null) {
+ throw new NotFoundException('User not found');
+ }
+ }
+
+ return $this->user;
+ }
+
+ /**
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ */
+ private function getDeclarativeManager(): IDeclarativeManager {
+ if ($this->manager === null) {
+ $this->manager = Server::get(IDeclarativeManager::class);
+ }
+
+ $this->manager->loadSchemas();
+ return $this->manager;
+ }
+
+ /**
+ * @throws NotAdminException
+ * @throws NotFoundExceptionInterface
+ * @throws NotFoundException
+ * @throws ContainerExceptionInterface
+ */
+ public function setValue(mixed $value): void {
+ $this->getDeclarativeManager()->setValue(
+ $this->getUser(),
+ $this->appName,
+ $this->form->getId(),
+ $this->id,
+ $value,
+ );
+ }
+
+ /**
+ * @throws NotAdminException
+ * @throws NotFoundExceptionInterface
+ * @throws NotFoundException
+ * @throws ContainerExceptionInterface
+ */
+ public function getValue(): mixed {
+ return $this->getDeclarativeManager()->getValue(
+ $this->getUser(),
+ $this->appName,
+ $this->form->getId(),
+ $this->id,
+ );
+ }
+
+ /**
+ * @throws NotAdminException
+ * @throws NotFoundExceptionInterface
+ * @throws NotFoundException
+ * @throws ContainerExceptionInterface
+ */
+ public function deleteValue(): void {
+ $this->getDeclarativeManager()->deleteValue(
+ $this->getUser(),
+ $this->appName,
+ $this->form->getId(),
+ $this->id,
+ );
+ }
+}
diff --git a/lib/public/Settings/DeclarativeSettingsOptionInt.php b/lib/public/Settings/DeclarativeSettingsOptionInt.php
index 5e947c8a0fe..dbeef3413e6 100644
--- a/lib/public/Settings/DeclarativeSettingsOptionInt.php
+++ b/lib/public/Settings/DeclarativeSettingsOptionInt.php
@@ -9,15 +9,21 @@ declare(strict_types=1);
namespace OCP\Settings;
+use OC\Settings\DeclarativeSettingsOption;
+
/**
* @psalm-import-type DeclarativeSettingsFormFieldType from IDeclarativeSettingsForm
* @psalm-import-type DeclarativeSettingsFormFieldOptions from IDeclarativeSettingsForm
*/
class DeclarativeSettingsOptionInt implements IDeclarativeSettingsOption {
+ private DeclarativeSettingsOption $internal;
+
/**
* @param DeclarativeSettingsFormFieldOptions $options
*/
public function __construct(
+ public readonly string $appName,
+ public readonly DeclarativeSettingsForm $form,
public readonly string $id,
public readonly string $title,
public readonly int $default,
@@ -26,6 +32,7 @@ class DeclarativeSettingsOptionInt implements IDeclarativeSettingsOption {
public readonly ?string $placeholder = null,
public readonly ?string $label = null,
) {
+ $this->internal = new DeclarativeSettingsOption($this->appName, $this->form, $this->id);
}
public function getId(): string {
@@ -59,4 +66,16 @@ class DeclarativeSettingsOptionInt implements IDeclarativeSettingsOption {
public function getOptions(): mixed {
return $this->options;
}
+
+ public function setValue(int $value): void {
+ $this->internal->setValue($value);
+ }
+
+ public function getValue(): int {
+ return $this->internal->getValue();
+ }
+
+ public function deleteValue(): void {
+ $this->internal->deleteValue();
+ }
}
diff --git a/lib/public/Settings/Events/DeclarativeSettingsDeleteValueEvent.php b/lib/public/Settings/Events/DeclarativeSettingsDeleteValueEvent.php
new file mode 100644
index 00000000000..9a50aae29c5
--- /dev/null
+++ b/lib/public/Settings/Events/DeclarativeSettingsDeleteValueEvent.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Settings\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * @since 31.0.0
+ */
+class DeclarativeSettingsDeleteValueEvent extends Event {
+ /**
+ * @since 31.0.0
+ */
+ public function __construct(
+ private IUser $user,
+ private string $app,
+ private string $formId,
+ private string $fieldId,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @since 31.0.0
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+
+ /**
+ * @since 31.0.0
+ */
+ public function getApp(): string {
+ return $this->app;
+ }
+
+ /**
+ * @since 31.0.0
+ */
+ public function getFormId(): string {
+ return $this->formId;
+ }
+
+ /**
+ * @since 31.0.0
+ */
+ public function getFieldId(): string {
+ return $this->fieldId;
+ }
+}
diff --git a/lib/public/Settings/IDeclarativeManager.php b/lib/public/Settings/IDeclarativeManager.php
index 5c21ee6750b..a87f846a17a 100644
--- a/lib/public/Settings/IDeclarativeManager.php
+++ b/lib/public/Settings/IDeclarativeManager.php
@@ -72,4 +72,28 @@ interface IDeclarativeManager {
* @since 29.0.0
*/
public function setValue(IUser $user, string $app, string $formId, string $fieldId, mixed $value): void;
+
+ /**
+ * Returns the value of the given field ID.
+ *
+ * @param IUser $user Used for storing values in the personal section or for authorization for the admin section.
+ *
+ * @throws Exception
+ * @throws NotAdminException
+ *
+ * @since 31.0.0
+ */
+ public function getValue(IUser $user, string $app, string $formId, string $fieldId): mixed;
+
+ /**
+ * Deletes the value of the given field ID.
+ *
+ * @param IUser $user Used for storing values in the personal section or for authorization for the admin section.
+ *
+ * @throws Exception
+ * @throws NotAdminException
+ *
+ * @since 31.0.0
+ */
+ public function deleteValue(IUser $user, string $app, string $formId, string $fieldId): void;
}