Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,39 @@ it effectively resets itself back to the default value in config file, if any.
service('setting')->forget('App.siteName')
```

### Contextual Settings

In addition to the default behavior describe above, `Settings` can can be used to define "contextual settings".
A context may be anything you want, but common examples are a runtime environment or an authenticated user.
In order to use a context you pass it as an additional parameter to the `get()`/`set()`/`forget()` methods; if
a context setting is requested and does not exist then the general value will be used.

Contexts may be any unique string you choose, but a recommended format for supplying some consistency is to
give them a category and identifier, like `environment:production` or `group:42`.

An example... Say your App config includes the name of a theme to use to enhance your display. By default
your config file specifies `App.theme = 'default'`. When a user changes their theme, you do not want this to
change the theme for all visitors to the site, so you need to provide the user as the *context* for the change:

```php
$context = 'user:' . user_id();
service('setting')->set('App.theme', 'dark', $context);
```

Now when your filter is determining which theme to apply it can check for the current user as the context:

```php
$context = 'user:' . user_id();
$theme = service('setting')->get('App.theme', $context);

// or using the helper
setting()->get('App.theme', $context);
```

Contexts are a cascading check, so if a context does not match a value it will fall back on general,
i.e. `service('setting')->get('App.theme')`. Return value priority is as follows:
"Setting with a context > Setting without context > Config value > null".

### Using the Helper

The helper provides a shortcut to the using the service. It must first be loaded using the `helper()` method
Expand All @@ -100,6 +133,8 @@ setting()->set('App.siteName', 'My Great Site');
setting()->forget('App.siteName');
```

> Note: Due to the shorthand nature of the helper function it cannot access contextual settings.

## Known Limitations

The following are known limitations of the library:
Expand Down
6 changes: 6 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Upgrade Guide

## Version 1 to 2
***

* Due to the addition of contexts the `BaseHandler` abstract class was changed. Update any handlers that extend this class to include the new and changed methods.
25 changes: 25 additions & 0 deletions src/Database/Migrations/2021-11-14-143905_AddContextColumn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Sparks\Settings\Database\Migrations;

use CodeIgniter\Database\Migration;

class AddContextColumn extends Migration
{
public function up()
{
$this->forge->addColumn(config('Settings')->database['table'], [
'context' => [
'type' => 'varchar',
'constraint' => 255,
'null' => true,
'after' => 'type',
],
]);
}

public function down()
{
$this->forge->dropColumn(config('Settings')->database['table'], 'context');
}
}
29 changes: 26 additions & 3 deletions src/Handlers/BaseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@

namespace Sparks\Settings\Handlers;

use RuntimeException;

abstract class BaseHandler
{
/**
* Checks whether this handler has a value set.
*/
abstract public function has(string $class, string $property, ?string $context = null): bool;

/**
* Returns a single value from the handler, if stored.
*
* @return mixed
*/
abstract public function get(string $class, string $property);
abstract public function get(string $class, string $property, ?string $context = null);

/**
* If the Handler supports saving values, it
Expand All @@ -18,11 +25,27 @@ abstract public function get(string $class, string $property);
*
* @param mixed $value
*
* @throws RuntimeException
*
* @return mixed
*/
public function set(string $class, string $property, $value = null, ?string $context = null)
{
throw new RuntimeException('Set method not implemented for current Settings handler.');
}

/**
* If the Handler supports forgetting values, it
* MUST override this method to provide that functionality.
* Not all Handlers will support writing values.
*
* @throws RuntimeException
*
* @return mixed
*/
public function set(string $class, string $property, $value = null)
public function forget(string $class, string $property, ?string $context = null)
{
throw new \RuntimeException('Set method not implemented for current Settings handler.');
throw new RuntimeException('Forget method not implemented for current Settings handler.');
}

/**
Expand Down
Loading