Skip to content

Commit 5433069

Browse files
authored
feat: add batch setting operations (codeigniter4#161)
1 parent f0cd3e2 commit 5433069

10 files changed

Lines changed: 936 additions & 52 deletions

docs/basic-usage.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,32 @@ when retrieved.
3030
service('settings')->set('App.siteName', 'My Great Site');
3131
```
3232

33+
You can save multiple values with `setMany()`. This behaves like calling `set()` for each key/value pair,
34+
but allows supported handlers to persist the changes more efficiently.
35+
36+
```php
37+
service('settings')->setMany([
38+
'App.siteName' => 'My Great Site',
39+
'App.siteEmail' => '[email protected]',
40+
]);
41+
```
42+
3343
You can delete a value from the persistent storage with the `forget()` method. Since it is removed from the storage,
3444
it effectively resets itself back to the default value in config file, if any.
3545

3646
```php
3747
service('settings')->forget('App.siteName');
3848
```
3949

50+
You can delete multiple values with `forgetMany()`.
51+
52+
```php
53+
service('settings')->forgetMany([
54+
'App.siteName',
55+
'App.siteEmail',
56+
]);
57+
```
58+
4059
If you ever need to completely remove all settings from their persistent storage, you can use the `flush()` method. This immediately removes all settings from the database and the in-memory cache.
4160

4261
```php
@@ -62,6 +81,16 @@ $context = 'user:' . user_id();
6281
service('settings')->set('App.theme', 'dark', $context);
6382
```
6483

84+
The same context can be applied to a batch of values:
85+
86+
```php
87+
$context = 'user:' . user_id();
88+
service('settings')->setMany([
89+
'App.theme' => 'dark',
90+
'App.locale' => 'en',
91+
], $context);
92+
```
93+
6594
Now when your filter is determining which theme to apply it can check for the current user as the context:
6695

6796
```php
@@ -91,9 +120,17 @@ setting('App.siteName', 'My Great Site');
91120
// Using the service through the helper
92121
$name = setting()->get('App.siteName');
93122
setting()->set('App.siteName', 'My Great Site');
123+
setting()->setMany([
124+
'App.siteName' => 'My Great Site',
125+
'App.siteEmail' => '[email protected]',
126+
]);
94127

95128
// Forgetting a value
96129
setting()->forget('App.siteName');
130+
setting()->forgetMany([
131+
'App.siteName',
132+
'App.siteEmail',
133+
]);
97134
```
98135

99136
!!! Note

docs/configuration.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ Handlers like `database` and `file` support deferred writes. When `deferWrites`
3232
are batched and persisted efficiently at the end of the request during the `post_system` event. This minimizes the number of
3333
database queries or file I/O operations, improving performance for write-heavy operations.
3434

35+
!!! note
36+
This is separate from the explicit `setMany()` and `forgetMany()` APIs. Batch APIs allow callers to group multiple settings
37+
in one method call, while deferred writes decide whether writes are persisted immediately or at the end of the request.
38+
The two features are independent and can be combined.
39+
3540
### Multiple handlers
3641

3742
Example:
@@ -94,6 +99,16 @@ $settings->set('Example.prop3', 'value3');
9499

95100
The deferred approach is especially beneficial when updating existing records or performing many operations in a single request.
96101

102+
For explicit batches, use `setMany()` or `forgetMany()`:
103+
104+
```php
105+
$settings->setMany([
106+
'Example.prop1' => 'value1',
107+
'Example.prop2' => 'value2',
108+
'Example.prop3' => 'value3',
109+
]);
110+
```
111+
97112
---
98113

99114
## FileHandler
@@ -136,6 +151,16 @@ $settings->set('Example.prop3', 'value3');
136151

137152
The deferred approach is especially beneficial when updating multiple properties in the same class.
138153

154+
For explicit batches, use `setMany()` or `forgetMany()`:
155+
156+
```php
157+
$settings->setMany([
158+
'Example.prop1' => 'value1',
159+
'Example.prop2' => 'value2',
160+
'Example.prop3' => 'value3',
161+
]);
162+
```
163+
139164
---
140165

141166
## ArrayHandler

docs/limitations.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ The following are known limitations of the library:
55
1. **Immediate writes (`deferWrites => false`)**: Each setting is written to storage immediately when you call `set()` or `forget()`.
66
The first operation hydrates all settings for that context (1 SELECT query), then each subsequent write performs a separate
77
INSERT or UPDATE. While `DatabaseHandler` and `FileHandler` use an in-memory cache to maintain fast reads, individual write
8-
operations may result in multiple database queries or file writes per request.
8+
operations may result in multiple database queries or file writes per request. When multiple changes are known ahead of time,
9+
use `setMany()` or `forgetMany()` to group them explicitly and allow supported handlers to persist them more efficiently.
910

1011
2. **Deferred writes (`deferWrites => true`)**: All settings are batched and written to storage at the end of the request
1112
(during the `post_system` event). This minimizes the number of database queries and file writes, improving performance.

src/Handlers/BaseHandler.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ public function set(string $class, string $property, $value = null, ?string $con
3535
throw new RuntimeException('Set method not implemented for current Settings handler.');
3636
}
3737

38+
/**
39+
* If the Handler supports saving values, it MAY override this method
40+
* to provide optimized batch functionality.
41+
*
42+
* @param list<array{class: string, property: string, value: mixed}> $settings
43+
*
44+
* @throws RuntimeException
45+
*/
46+
public function setMany(array $settings, ?string $context = null): void
47+
{
48+
foreach ($settings as $setting) {
49+
$this->set($setting['class'], $setting['property'], $setting['value'], $context);
50+
}
51+
}
52+
3853
/**
3954
* If the Handler supports forgetting values, it
4055
* MUST override this method to provide that functionality.
@@ -48,6 +63,21 @@ public function forget(string $class, string $property, ?string $context = null)
4863
throw new RuntimeException('Forget method not implemented for current Settings handler.');
4964
}
5065

66+
/**
67+
* If the Handler supports forgetting values, it MAY override this method
68+
* to provide optimized batch functionality.
69+
*
70+
* @param list<array{class: string, property: string}> $settings
71+
*
72+
* @throws RuntimeException
73+
*/
74+
public function forgetMany(array $settings, ?string $context = null): void
75+
{
76+
foreach ($settings as $setting) {
77+
$this->forget($setting['class'], $setting['property'], $context);
78+
}
79+
}
80+
5181
/**
5282
* All handlers MUST support flushing all values.
5383
*

0 commit comments

Comments
 (0)