Skip to content

Commit e5d1abc

Browse files
Merge pull request #14111 from nextcloud/jtr/dev-appconfig-ch-edits
docs(dev/AppConfig): re-organize, expand, update, and improve clarity
2 parents d72519a + ef3b238 commit e5d1abc

1 file changed

Lines changed: 215 additions & 79 deletions

File tree

developer_manual/digging_deeper/config/appconfig.rst

Lines changed: 215 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,36 @@ AppConfig
66

77
.. versionadded:: 29
88

9-
Since v29, Nextcloud includes a new API to manage your app configuration.
9+
Nextcloud includes an AppConfig API to manage app configuration values.
10+
11+
Concept overview
12+
----------------
13+
14+
Nextcloud provides an API to store and access app configuration values.
15+
In addition to simple read/write operations, ``IAppConfig`` supports:
16+
17+
- typed values,
18+
- lazy loading,
19+
- sensitive values,
20+
- key and value discovery helpers.
21+
22+
.. _appconfig_concepts:
23+
24+
.. note::
25+
See `Lexicon Concepts`_ to learn more about **Lexicon**, a way to define configuration keys and avoid conflicts in your code.
26+
27+
.. _Lexicon Concepts: https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/config/lexicon.html#concept-overview
28+
1029

1130
AppFramework
1231
------------
1332

14-
The AppConfig API is also available in the AppFramework, allowing you to use it in your app.
15-
All of the methods are available in the ``OCP\AppFramework\Services\IAppConfig`` interface.
16-
Any of the methods below will automatically be scoped to your app, meaning you can omit the app id.
17-
33+
The AppConfig API is also available in AppFramework through
34+
``OCP\AppFramework\Services\IAppConfig``.
35+
36+
All methods from that interface are scoped to your app automatically, so you do not
37+
need to pass an app ID explicitly.
38+
1839
.. code-block:: php
1940
2041
<?php
@@ -27,159 +48,274 @@ Any of the methods below will automatically be scoped to your app, meaning you c
2748
private IAppConfig $appConfig,
2849
) {}
2950
30-
public function getSomeConfig(): string {
31-
return $this->appConfig->getAppValueString('mykey', 'default');
51+
public function hasConfig(): bool {
52+
return $this->appConfig->hasAppKey('mykey');
3253
}
3354
}
3455
35-
Concept overview
36-
----------------
56+
Use ``\OCP\IAppConfig`` when you need to read or write configuration for arbitrary app IDs.
57+
Use ``OCP\AppFramework\Services\IAppConfig`` for app-scoped operations in your own app.
3758

38-
Nextcloud includes an API to store and access your app configuration values.
39-
On top of storing and accessing your configuration values, ``IAppConfig`` comes with different concepts:
4059

41-
.. _appconfig_concepts:
60+
Typed config values
61+
^^^^^^^^^^^^^^^^^^^
62+
63+
To improve safety and stability, config values are type-enforced.
64+
65+
A type is set when the key is created in the database and cannot be changed later.
4266

67+
A key’s type is defined by the setter you use when the key is first created
68+
(for example, ``setValueString()`` creates a string key, ``setValueInt()`` an int key).
69+
70+
.. code-block:: php
71+
72+
$appConfig->setValueInt('myapp', 'retry_count', 3); // key type: int
73+
$appConfig->setValueString('myapp', 'display_name', 'A'); // key type: string
4374
4475
.. note::
45-
See `Lexicon Concepts`_ to learn more about **Lexicon**, a way to fully define your configuration keys and avoid conflict when using it in your code.
76+
- Values stored before Nextcloud 29 are treated as ``mixed``.
77+
- It is not possible to manually create new ``mixed`` values.
78+
- Values that are not ``mixed`` must be retrieved using the matching typed getter.
4679

47-
.. _Lexicon Concepts: https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/config/lexicon.html#concept-overview
80+
.. note::
81+
Migration urgency differs between reads and writes:
4882

83+
- Read paths should usually be migrated early to typed getters when adopting
84+
``IAppConfig``, so runtime behavior is explicit and type-safe.
85+
- Write-side normalization of legacy values can often be incremental and done
86+
when touching related code paths, especially if:
4987

88+
- you want stricter typing guarantees,
89+
- you are already refactoring,
90+
- the key is causing ambiguity/bugs
5091

51-
Typed Config Values
52-
^^^^^^^^^^^^^^^^^^^
92+
For new keys, always use typed setters and typed getters.
5393

54-
To ensure better stability of your code, config values are typed enforced.
55-
Type is set only once, at creation in database, and cannot be changed.
94+
**A safe write-side migration pattern is:**
5695

57-
.. note::
58-
- Value stored before Nextcloud 29 are automatically typed as `mixed`. However, it is not possible to manually set a value as `mixed`.
59-
- Value not set as `mixed` must be retrieved using the corresponding method.
96+
#. Read the existing legacy value.
97+
#. Validate/convert it in your app code.
98+
#. Write it back using the appropriate typed setter (for example ``setValueInt()``,
99+
``setValueString()``, ``setValueBool()``, ...).
100+
#. Afterwards, always use the matching typed getter.
101+
102+
103+
Sensitive values
104+
^^^^^^^^^^^^^^^^
60105

61-
Values Sensitivity
62-
^^^^^^^^^^^^^^^^^^
106+
When storing a new config value, you can mark it as sensitive.
63107

64-
When storing a new config value, it can be set as `sensitive`.
65-
Configuration values set as `sensitive` are hidden from system reports and stored encrypted in the database.
108+
Sensitive values are hidden from filtered listings/reports and are handled as protected
109+
values in AppConfig storage.
66110

67111
.. code-block:: php
68112
69-
setValueString(
113+
$appConfig->setValueString(
70114
'myapp',
71115
'mykey',
72116
'myvalue',
73117
sensitive: true
74118
);
75119
76120
.. note::
77-
Once set as `sensitive`, it can only be reverted using ``updateSensitive()``
121+
Once set as sensitive, this can be changed later using ``updateSensitive()``.
78122

79123

80-
Lazy Loading
124+
Lazy loading
81125
^^^^^^^^^^^^
82126

83-
To lighten the loading of all apps configuration at load, you have the possibility to set config values as `lazy`.
84-
All `lazy` configuration values are loaded from the database once one is read.
127+
To reduce memory and startup overhead, config values can be marked as lazy.
128+
129+
Non-lazy values are loaded first. Lazy values are loaded only when needed. When one lazy
130+
value is requested, lazy values are loaded together.
85131

86132
.. code-block:: php
87133
88-
setValueString(
134+
$appConfig->setValueString(
89135
'myapp',
90136
'mykey',
91137
'myvalue',
92138
lazy: true
93139
);
94140
95-
.. note::
96-
- Flag as `lazy` as much 'large block of text' entries (json, key pairs, ...) as possible,
97-
- flag as `lazy` entries that are needed on quiet endpoints,
98-
- do **not** flag as `lazy` part of code that might be called during the global loading of the instance and its apps.
99-
100-
101-
Retrieving the configuration value will require to specify the fact that it is stored as `lazy`.
141+
Retrieving a lazy value requires using the lazy read mode:
102142

103143
.. code-block:: php
104144
105-
getValueString(
145+
$appConfig->getValueString(
106146
'myapp',
107147
'mykey',
108148
'default',
109149
lazy: true
110150
);
111151
152+
Reading behavior with ``lazy`` parameter
153+
""""""""""""""""""""""""""""""""""""""""
154+
155+
When reading values, the ``lazy`` argument controls which storage bucket is queried.
156+
157+
+----------------------+----------------------+----------------------------------------------+
158+
| Stored key mode | Read with ``lazy`` | Result |
159+
+======================+======================+==============================================+
160+
| non-lazy | ``false`` | stored value |
161+
+----------------------+----------------------+----------------------------------------------+
162+
| non-lazy | ``true`` | stored value |
163+
+----------------------+----------------------+----------------------------------------------+
164+
| lazy | ``false`` | default value (lazy key is not searched) |
165+
+----------------------+----------------------+----------------------------------------------+
166+
| lazy | ``true`` | stored value |
167+
+----------------------+----------------------+----------------------------------------------+
168+
169+
.. warning::
170+
If a key may be lazy, read it with ``lazy: true`` to avoid silently getting defaults.
171+
112172
.. note::
113-
- Requesting with ``1azy: false`` will returns the default value if configuration value is stored as `lazy`.
114-
- Requesting with ``lazy: true`` will returns the correct value even if configuration value is stored as `non-lazy (as there is a huge probability that the `non-lazy` value are already loaded)
173+
Some API methods explicitly ignore lazy filtering and may load all values.
174+
Check each method description for warnings.
175+
176+
Choosing what should be lazy
177+
""""""""""""""""""""""""""""
178+
179+
Good candidates for ``lazy: true``:
180+
181+
- Large values (for example JSON blobs, long text, large key/value maps).
182+
- Values used only in specific flows (admin pages, background jobs, setup/migration tools).
183+
- Values read infrequently or only after explicit user actions.
184+
185+
Usually keep as non-lazy (``lazy: false``):
186+
187+
- Small, frequently accessed values used on most requests.
188+
- Values needed during app bootstrap, registration, capability wiring, or other early lifecycle code paths.
189+
- Values used in hot paths (middleware, common service constructors, request-critical checks).
190+
191+
Practical rule:
192+
193+
- If a value is needed on most requests, keep it non-lazy.
194+
- If it is large and only needed occasionally, make it lazy.
115195

116196
Consuming the AppConfig API
117197
---------------------------
118198

119-
To consume the API, you first need to :ref:`inject<dependency-injection>` ``\OCP\IAppConfig``
199+
You can inject either interface, depending on your use case:
200+
201+
- ``\OCP\IAppConfig`` (global API): use when you need to access configuration
202+
for one or more app IDs explicitly.
203+
- ``\OCP\AppFramework\Services\IAppConfig`` (AppFramework app-scoped API):
204+
use inside your app when you want methods scoped automatically to your app ID.
205+
206+
See :ref:`dependency-injection` for injection details.
207+
208+
.. important::
209+
Unless explicitly stated otherwise, examples in this page use the global
210+
interface ``\OCP\IAppConfig`` (app ID passed explicitly).
211+
212+
If you inject ``\OCP\AppFramework\Services\IAppConfig``, methods are app-scoped
213+
and you do not pass the app ID.
120214

121215

122216
Storing a config value
123217
^^^^^^^^^^^^^^^^^^^^^^
124218

125-
API provide multiple methods to store a config value, based on its type.
126-
The global behavior for each of those methods is to call them using:
219+
The API provides typed methods to store configuration values.
220+
221+
Common arguments are:
222+
223+
- app ID (``string``),
224+
- config key (``string``),
225+
- config value (typed),
226+
- lazy flag (``bool``),
227+
- sensitive flag (``bool``, where supported).
228+
229+
The return value is ``true`` if a database update was required.
127230

128-
- app id (string),
129-
- config key (string),
130-
- config value,
131-
- lazy flag (boolean),
132-
- sensitivity flag (boolean)
231+
- ``setValueString(string $app, string $key, string $value, bool $lazy = false, bool $sensitive = false)``
232+
- ``setValueInt(string $app, string $key, int $value, bool $lazy = false, bool $sensitive = false)``
233+
- ``setValueFloat(string $app, string $key, float $value, bool $lazy = false, bool $sensitive = false)``
234+
- ``setValueBool(string $app, string $key, bool $value, bool $lazy = false)``
235+
- ``setValueArray(string $app, string $key, array $value, bool $lazy = false, bool $sensitive = false)``
133236

134-
The returned boolean will be true if an update of the database were needed.
237+
AppFramework equivalents (app-scoped, no ``$app`` argument):
135238

136-
* ``setValueString(string $app, string $key, string $value, bool $lazy, bool $sensitive)``
137-
* ``setValueInt(string $app, string $key, int $value, bool $lazy, bool $sensitive)``
138-
* ``setValueFloat(string $app, string $key, float $value, bool $lazy, bool $sensitive)``
139-
* ``setValueBool(string $app, string $key, bool $value, bool $lazy)``
140-
* ``setValueArray(string $app, string $key, array $value, bool $lazy, bool $sensitive)``
239+
.. code-block:: php
240+
241+
$appConfig->setAppValueString('mykey', 'myvalue', lazy: true);
242+
$appConfig->setAppValueInt('retry_count', 3);
243+
$appConfig->setAppValueArray('options', ['a' => true], sensitive: true);
141244
142245
143246
Retrieving a config value
144247
^^^^^^^^^^^^^^^^^^^^^^^^^
145248

146-
Configuration values are to be retrieved using one of the return typed method from the list:
249+
Configuration values can be retrieved using typed getters:
147250

148-
* ``getValueString(string $app, string $key, string $default, bool $lazy)``
149-
* ``getValueInt(string $app, string $key, int $default, bool $lazy)``
150-
* ``getValueFloat(string $app, string $key, float $default, bool $lazy)``
151-
* ``getValueBool(string $app, string $key, bool $default, bool $lazy)``
152-
* ``getValueArray(string $app, string $key, array $default, bool $lazy)``
251+
- ``getValueString(string $app, string $key, string $default = '', bool $lazy = false)``
252+
- ``getValueInt(string $app, string $key, int $default = 0, bool $lazy = false)``
253+
- ``getValueFloat(string $app, string $key, float $default = 0.0, bool $lazy = false)``
254+
- ``getValueBool(string $app, string $key, bool $default = false, bool $lazy = false)``
255+
- ``getValueArray(string $app, string $key, array $default = [], bool $lazy = false)``
256+
257+
AppFramework equivalents (app-scoped, no ``$app`` argument):
258+
259+
.. code-block:: php
260+
261+
$name = $appConfig->getAppValueString('display_name', 'default');
262+
$count = $appConfig->getAppValueInt('retry_count', 0);
263+
$enabled = $appConfig->getAppValueBool('enabled', false, lazy: true);
153264
154265
155266
Managing config keys
156267
^^^^^^^^^^^^^^^^^^^^
157268

158-
* ``getApps()`` returns list of ids of apps with stored configuration values
159-
* ``getKeys(string $app)`` returns list of stored configuration keys for an app by its id
160-
* ``hasKey(string $app, string $key, ?bool $lazy)`` returns TRUE if key can be found
161-
* ``isSensitive(string $app, string $key, ?bool $lazy)`` returns TRUE if value is set as `sensitive`
162-
* ``isLazy(string $app, string $key)`` returns TRUE if value is set as `lazy`
163-
* ``updateSensitive(string $app, string $key, bool $sensitive)`` update `sensitive` status of a configuration value
164-
* ``updateLazy(string $app, string $key, bool $lazy)`` update `lazy` status of a configuration value
165-
* ``getValueType(string $app, string $key)`` returns bitflag defining the type of a configuration value
166-
* ``deleteKey(string $app, string $key)`` delete a config key and its value
167-
* ``deleteApp(string $app)`` delete all config keys from an app (using app id)
269+
- ``getApps()`` returns app IDs that have stored configuration values.
270+
- ``getKeys(string $app)`` returns stored keys for an app.
271+
- ``searchKeys(string $app, string $prefix = '', bool $lazy = false)`` returns keys for an app matching a prefix.
272+
- ``hasKey(string $app, string $key, ?bool $lazy = false)`` returns ``true`` if the key exists.
273+
- ``isSensitive(string $app, string $key, ?bool $lazy = false)`` returns ``true`` if the value is sensitive.
274+
- ``isLazy(string $app, string $key)`` returns ``true`` if the value is lazy.
275+
- ``updateSensitive(string $app, string $key, bool $sensitive)`` updates sensitive status.
276+
- ``updateLazy(string $app, string $key, bool $lazy)`` updates lazy status.
277+
- ``getValueType(string $app, string $key)`` returns the type bitflag for a value.
278+
- ``deleteKey(string $app, string $key)`` deletes one key and its value.
279+
- ``deleteApp(string $app)`` deletes all keys for one app.
280+
281+
AppFramework equivalents include:
282+
283+
- ``getAppKeys()``
284+
- ``hasAppKey(string $key, ?bool $lazy = false)``
285+
- ``isSensitive(string $key, ?bool $lazy = false)``
286+
- ``isLazy(string $key)``
168287

169288
.. note::
170-
Some method allows ``$lazy`` to be ``null``, meaning that the search will be extended to all configuration values, `lazy` or not.
289+
Methods with ``?bool $lazy`` can use ``null`` to search both lazy and non-lazy values.
290+
171291

172292
Miscellaneous
173293
^^^^^^^^^^^^^
174294

175-
API also provide extra tools for broaded uses
295+
The API also provides additional helpers:
296+
297+
- ``getAllValues(string $app, string $prefix = '', bool $filtered = false)``
298+
returns stored values for an app. If ``$filtered`` is ``true``, sensitive values are hidden.
299+
- ``searchValues(string $key, bool $lazy = false)``
300+
searches apps/values containing the specified key.
301+
- ``getDetails(string $app, string $key)``
302+
returns metadata/details about a key.
303+
- ``convertTypeToInt(string $type)``
304+
converts a human-readable type to a type bitflag.
305+
- ``convertTypeToString(int $type)``
306+
converts a type bitflag to a human-readable type.
307+
- ``clearCache(bool $reload = false)``
308+
clears internal cache.
176309

177-
* ``getAllValues(string $app, string $prefix, bool $filtered)`` returns all stored configuration values. ``$filtered`` can be set to TRUE to hide _sensitive_ values in the returned array
178-
* ``searchValues(string $key, bool $lazy)`` search for apps and values that have a stored value for the specified configuration key.
179-
* ``getDetails(string $app, string $key)`` get all details about a configuration key.
180-
* ``convertTypeToInt(string $type)`` convert human readable string to the bitflag defining the type of a value
181-
* ``convertTypeToString(int $type)`` convert bitflag defining the type of a value to human readable string
182-
* ``clearCache(bool $reload)`` clear internal cache
310+
AppFramework helper equivalent:
183311

312+
- ``getAllAppValues(string $key = '', bool $filtered = false)``
313+
314+
315+
Constants and flags
316+
^^^^^^^^^^^^^^^^^^^
184317

318+
``\OCP\IAppConfig`` exposes value-type constants and flags, including:
185319

320+
- ``FLAG_SENSITIVE`` (since 31),
321+
- ``FLAG_INTERNAL`` (since 33; marks values as internal and eligible to be hidden from listings).

0 commit comments

Comments
 (0)