Skip to content

Commit 67bd5fb

Browse files
authored
Merge b971015 into 1969871
2 parents 1969871 + b971015 commit 67bd5fb

File tree

12 files changed

+1286
-8
lines changed

12 files changed

+1286
-8
lines changed

docs/configuration.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Configuration
2+
3+
To make changes to the config file, you need to have your own copy in `app/Config/Settings.php`. The easiest way to do it is by using the publish command.
4+
5+
When you run:
6+
7+
php spark settings:publish
8+
9+
You will get your copy ready for modifications.
10+
11+
---
12+
13+
## Handlers
14+
15+
An array of handler aliases to use for storing and retrieving settings. Handlers are checked in order, with the first handler that has a value returning it.
16+
17+
**Type:** `array`
18+
19+
**Default:** `['database']`
20+
21+
**Available handlers:** `database`, `file`, `array`
22+
23+
Example:
24+
25+
```php
26+
public $handlers = ['database'];
27+
```
28+
### Multiple handlers
29+
30+
When multiple handlers are configured, they are checked in the order specified in $handlers. The first handler that has a value for the requested setting will return it.
31+
32+
Example with fallback:
33+
34+
```php
35+
public $handlers = ['file', 'database'];
36+
```
37+
This configuration will:
38+
39+
1. Check the file handler first
40+
2. If not found, check the database handler
41+
3. If not found in any handler, return the default value from the config file
42+
43+
### Writeable Handlers
44+
45+
Only handlers marked as `writeable => true` will be used when calling `set()`, `forget()`, or `flush()` methods.
46+
47+
## DatabaseHandler
48+
49+
This handler stores settings in a database table and is production-ready for high-traffic applications.
50+
51+
**Available options:**
52+
53+
* `class` - The handler class. Default: `DatabaseHandler::class`
54+
* `table` - The database table name for storing settings. Default: `'settings'`
55+
* `group` - The database connection group to use. Default: `null` (uses default connection)
56+
* `writeable` - Whether this handler supports write operations. Default: `true`
57+
58+
Example:
59+
60+
```php
61+
public $database = [
62+
'class' => DatabaseHandler::class,
63+
'table' => 'settings',
64+
'group' => null,
65+
'writeable' => true,
66+
];
67+
```
68+
69+
!!! note
70+
You need to run migrations to create the settings table: `php spark migrate -n CodeIgniter\\Settings`
71+
72+
---
73+
74+
## FileHandler
75+
76+
This handler stores settings as PHP files and is optimized for production use with built-in race condition protection.
77+
78+
**Available options:**
79+
80+
* `class` - The handler class. Default: `FileHandler::class`
81+
* `path` - The directory path where settings files are stored. Default: `WRITEPATH . 'settings'`
82+
* `writeable` - Whether this handler supports write operations. Default: `true`
83+
84+
Example:
85+
86+
```php
87+
public $file = [
88+
'class' => FileHandler::class,
89+
'path' => WRITEPATH . 'settings',
90+
'writeable' => true,
91+
];
92+
```
93+
94+
!!! note
95+
The `FileHandler` automatically creates the directory if it doesn't exist and checks write permissions on instantiation.
96+
97+
---
98+
99+
## ArrayHandler
100+
101+
This handler stores settings in memory only and is primarily useful for testing or as a parent class for other handlers.
102+
103+
**Available options:**
104+
105+
* `class` - The handler class. Default: `ArrayHandler::class`
106+
* `writeable` - Whether this handler supports write operations. Default: `true`
107+
108+
Example:
109+
110+
```php
111+
public $array = [
112+
'class' => ArrayHandler::class,
113+
'writeable' => true,
114+
];
115+
```
116+
117+
!!! note
118+
`ArrayHandler` does not persist data between requests. It's mainly used for testing or extended by other handlers.

docs/limitations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
The following are known limitations of the library:
44

5-
1. You can currently only store a single setting at a time. While the `DatabaseHandler` uses a local cache to
6-
keep performance as high as possible for reads, writes must be done one at a time.
5+
1. You can currently only store a single setting at a time. While the `DatabaseHandler` and `FileHandler`
6+
uses a local cache to keep performance as high as possible for reads, writes must be done one at a time.
77
2. You can only access the first level within a property directly. In most config classes this is a non-issue,
88
since the properties are simple values. Some config files, like the `database` file, contain properties that
99
are arrays.

mkdocs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extra:
5353
site_url: https://settings.codeigniter.com/
5454
repo_url: https://github.com/codeigniter4/settings
5555
edit_uri: edit/develop/docs/
56-
copyright: Copyright © 2023 CodeIgniter Foundation.
56+
copyright: Copyright © 2025 CodeIgniter Foundation.
5757

5858
markdown_extensions:
5959
- admonition
@@ -73,5 +73,6 @@ extra_javascript:
7373
nav:
7474
- Home: index.md
7575
- Installation: installation.md
76+
- Configuration: configuration.md
7677
- Basic usage: basic-usage.md
7778
- Limitations: limitations.md

src/Commands/ClearSettings.php

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,61 @@
77

88
class ClearSettings extends BaseCommand
99
{
10-
protected $group = 'Housekeeping';
10+
protected $group = 'Settings';
1111
protected $name = 'settings:clear';
12-
protected $description = 'Clears all settings from the database.';
12+
protected $description = 'Clears all settings from persistent storage.';
1313

1414
public function run(array $params)
1515
{
16-
if (CLI::prompt('This will delete all settings from the database. Are you sure you want to continue?', ['y', 'n'], 'required') !== 'y') {
16+
$config = config('Settings');
17+
$handlers = $this->getHandlerNames($config);
18+
19+
if ($handlers === null) {
20+
CLI::write('No handlers available to clear in the config file.');
21+
22+
return;
23+
}
24+
25+
if (CLI::prompt('This will delete all settings from ' . $handlers . '. Are you sure you want to continue?', ['y', 'n'], 'required') !== 'y') {
1726
return;
1827
}
1928

2029
service('settings')->flush();
2130

22-
CLI::write('Settings cleared from the database.', 'green');
31+
CLI::write('Settings cleared from ' . $handlers . '.', 'green');
32+
}
33+
34+
/**
35+
* Gets a human-readable list of handler names.
36+
*
37+
* @param mixed $config
38+
*/
39+
private function getHandlerNames($config): ?string
40+
{
41+
if ($config->handlers === []) {
42+
return null;
43+
}
44+
45+
$handlerNames = [];
46+
47+
foreach ($config->handlers as $handler) {
48+
// Get writeable handlers only (those that can be flushed)
49+
if (isset($config->{$handler}['writeable']) && $config->{$handler}['writeable'] === true) {
50+
$handlerNames[] = $handler;
51+
}
52+
}
53+
54+
if ($handlerNames === []) {
55+
return null;
56+
}
57+
58+
if (count($handlerNames) === 1) {
59+
return $handlerNames[0] . ' handler';
60+
}
61+
62+
// Multiple handlers: "database and file"
63+
$last = array_pop($handlerNames);
64+
65+
return implode(', ', $handlerNames) . ' and ' . $last . ' handlers';
2366
}
2467
}

src/Commands/PublishSettings.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter Queue.
7+
*
8+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace CodeIgniter\Settings\Commands;
15+
16+
use CodeIgniter\CLI\BaseCommand;
17+
use CodeIgniter\CLI\CLI;
18+
use CodeIgniter\Publisher\Publisher;
19+
use Throwable;
20+
21+
class PublishSettings extends BaseCommand
22+
{
23+
protected $group = 'Settings';
24+
protected $name = 'settings:publish';
25+
protected $description = 'Publish Settings config file into the current application.';
26+
27+
public function run(array $params): void
28+
{
29+
$source = service('autoloader')->getNamespace('CodeIgniter\\Settings')[0];
30+
31+
$publisher = new Publisher($source, APPPATH);
32+
33+
try {
34+
$publisher->addPaths([
35+
'Config/Settings.php',
36+
])->merge(false);
37+
} catch (Throwable $e) {
38+
$this->showError($e);
39+
40+
return;
41+
}
42+
43+
foreach ($publisher->getPublished() as $file) {
44+
$contents = file_get_contents($file);
45+
$contents = str_replace('namespace CodeIgniter\\Settings\\Config', 'namespace Config', $contents);
46+
$contents = str_replace('use CodeIgniter\\Config\\BaseConfig', 'use CodeIgniter\\Settings\\Config\\Settings as BaseSettings', $contents);
47+
$contents = str_replace('class Settings extends BaseConfig', 'class Settings extends BaseSettings', $contents);
48+
file_put_contents($file, $contents);
49+
}
50+
51+
CLI::write(CLI::color(' Published! ', 'green') . 'You can customize the configuration by editing the "app/Config/Settings.php" file.');
52+
}
53+
}

src/Config/Settings.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use CodeIgniter\Config\BaseConfig;
66
use CodeIgniter\Settings\Handlers\ArrayHandler;
77
use CodeIgniter\Settings\Handlers\DatabaseHandler;
8+
use CodeIgniter\Settings\Handlers\FileHandler;
89

910
class Settings extends BaseConfig
1011
{
@@ -34,4 +35,13 @@ class Settings extends BaseConfig
3435
'group' => null,
3536
'writeable' => true,
3637
];
38+
39+
/**
40+
* File handler settings.
41+
*/
42+
public $file = [
43+
'class' => FileHandler::class,
44+
'path' => WRITEPATH . 'settings',
45+
'writeable' => true,
46+
];
3747
}

src/Handlers/ArrayHandler.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,18 @@ protected function forgetStored(string $class, string $property, ?string $contex
115115
unset($this->contexts[$context][$class][$property]);
116116
}
117117
}
118+
119+
/**
120+
* Retrieves all stored properties for a specific class and context.
121+
*
122+
* @return array<string,array> Format: ['property' => ['value', 'type']]
123+
*/
124+
protected function getAllStored(string $class, ?string $context): array
125+
{
126+
if ($context === null) {
127+
return $this->general[$class] ?? [];
128+
}
129+
130+
return $this->contexts[$context][$class] ?? [];
131+
}
118132
}

0 commit comments

Comments
 (0)