You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
4.6 KiB
PHP
179 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace CodeIgniter\Settings;
|
|
|
|
use CodeIgniter\Settings\Config\Settings as SettingsConfig;
|
|
use CodeIgniter\Settings\Handlers\BaseHandler;
|
|
use InvalidArgumentException;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* Allows developers a single location to store and
|
|
* retrieve settings that were original set in config files
|
|
* in the core application or any third-party module.
|
|
*/
|
|
class Settings
|
|
{
|
|
/**
|
|
* An array of handlers for getting/setting the values.
|
|
*
|
|
* @var BaseHandler[]
|
|
*/
|
|
private array $handlers = [];
|
|
|
|
/**
|
|
* An array of the config options for each handler.
|
|
*
|
|
* @var array<string,array<string,mixed>>
|
|
*/
|
|
private ?array $options = null;
|
|
|
|
/**
|
|
* Grabs instances of our handlers.
|
|
*/
|
|
public function __construct(SettingsConfig $config)
|
|
{
|
|
foreach ($config->handlers as $handler) {
|
|
$class = $config->{$handler}['class'] ?? null;
|
|
|
|
if ($class === null) {
|
|
continue;
|
|
}
|
|
|
|
$this->handlers[$handler] = new $class();
|
|
$this->options[$handler] = $config->{$handler};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve a value from any handler
|
|
* or from a config file matching the name
|
|
* file.arg.optionalArg
|
|
*/
|
|
public function get(string $key, ?string $context = null)
|
|
{
|
|
[$class, $property, $config] = $this->prepareClassAndProperty($key);
|
|
|
|
// Check each of our handlers
|
|
foreach ($this->handlers as $handler) {
|
|
if ($handler->has($class, $property, $context)) {
|
|
return $handler->get($class, $property, $context);
|
|
}
|
|
}
|
|
|
|
// If no contextual value was found then fall back to general
|
|
if ($context !== null) {
|
|
return $this->get($key);
|
|
}
|
|
|
|
return $config->{$property} ?? null;
|
|
}
|
|
|
|
/**
|
|
* Save a value to the writable handler for later retrieval.
|
|
*
|
|
* @param mixed $value
|
|
*
|
|
* @return void
|
|
*/
|
|
public function set(string $key, $value = null, ?string $context = null)
|
|
{
|
|
[$class, $property] = $this->prepareClassAndProperty($key);
|
|
|
|
foreach ($this->getWriteHandlers() as $handler) {
|
|
$handler->set($class, $property, $value, $context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes a setting from the persistent storage,
|
|
* effectively returning the value to the default value
|
|
* found in the config file, if any.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function forget(string $key, ?string $context = null)
|
|
{
|
|
[$class, $property] = $this->prepareClassAndProperty($key);
|
|
|
|
foreach ($this->getWriteHandlers() as $handler) {
|
|
$handler->forget($class, $property, $context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all settings from the persistent storage,
|
|
* Useful during testing. Use with caution.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function flush()
|
|
{
|
|
foreach ($this->getWriteHandlers() as $handler) {
|
|
$handler->flush();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the handler that is set to store values.
|
|
*
|
|
* @return BaseHandler[]
|
|
*
|
|
* @throws RuntimeException
|
|
*/
|
|
private function getWriteHandlers()
|
|
{
|
|
$handlers = [];
|
|
|
|
foreach ($this->options as $handler => $options) {
|
|
if (! empty($options['writeable'])) {
|
|
$handlers[] = $this->handlers[$handler];
|
|
}
|
|
}
|
|
|
|
if ($handlers === []) {
|
|
throw new RuntimeException('Unable to find a Settings handler that can store values.');
|
|
}
|
|
|
|
return $handlers;
|
|
}
|
|
|
|
/**
|
|
* Analyzes the given key and breaks it into the class.field parts.
|
|
*
|
|
* @return string[]
|
|
*
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
private function parseDotSyntax(string $key): array
|
|
{
|
|
// Parse the field name for class.field
|
|
$parts = explode('.', $key);
|
|
|
|
if (count($parts) === 1) {
|
|
throw new InvalidArgumentException('$key must contain both the class and field name, i.e. Foo.bar');
|
|
}
|
|
|
|
return $parts;
|
|
}
|
|
|
|
/**
|
|
* Given a key in class.property syntax, will split the values
|
|
* and determine the fully qualified class name, if possible.
|
|
*/
|
|
private function prepareClassAndProperty(string $key): array
|
|
{
|
|
[$class, $property] = $this->parseDotSyntax($key);
|
|
|
|
$config = config($class);
|
|
|
|
// Use a fully qualified class name if the
|
|
// config file was found.
|
|
if ($config !== null) {
|
|
$class = get_class($config);
|
|
}
|
|
|
|
return [$class, $property, $config];
|
|
}
|
|
}
|