*/ private array $handlers = []; /** * An array of the config options for each handler. * * @var array> */ 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 */ public function set(string $key, $value = null, ?string $context = null): void { [$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. */ public function forget(string $key, ?string $context = null): void { [$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. */ public function flush(): void { foreach ($this->getWriteHandlers() as $handler) { $handler->flush(); } } /** * Returns the handler that is set to store values. * * @return list * * @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 list * * @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. * * @return array{string, string, BaseConfig|null} */ 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 = $config::class; } return [$class, $property, $config]; } }