The Spiral framework exposes all the underlying configuration of its components using config objects. The core purpose of config objects is to separate the bootload and runtime phase and provide an easily accessible source of the configuration.
While configuration can change during the bootload process, at runtime all the values are frozen and forbidden for modification.
All of the configuration values can be accessed via Spiral\Config\ConfiguratorInterface
in the form of an array.
To demonstrate that we can create config file app/config/app.php
:
<?php
declare(strict_types=1);
return [
'values' => [123]
];
Note
You can usejson
format as well, or extendConfiguratorInterface
to add custom config readers.
To access the configuration values in your service or controller:
use App\Config\AppConfig;
use Spiral\Config\ConfiguratorInterface;
// ...
public function index(ConfiguratorInterface $configurator)
{
dump($configurator->getConfig(AppConfig::CONFIG));
}
Note
You can check if configuration exists using methodexists
.
It is not very convenient to read the configuration in the form of arrays. The framework provides the OOP abstraction to
read your values. We can create this class manually or automatically generate it via spiral/scaffolder
:
php app.php create:config app -r
Note
Use option-r
to reverse engineer the configuration structure.
The resulted config class located in app/src/config/AppConfig.php
:
namespace App\Config;
use Spiral\Core\InjectableConfig;
class AppConfig extends InjectableConfig
{
public const CONFIG = 'app';
protected $config = [
'values' => []
];
/**
* @return array|int[]
*/
public function getValues(): array
{
return $this->config['values'];
}
}
The base class Spiral\Core\InjectableConfig
allows you to request this object immediately in your code without any
IoC container configuration. The constant CONFIG
contains the name of the configuration file.
use App\Config\AppConfig;
// ...
public function index(AppConfig $appConfig)
{
\dump($appConfig->getValues());
}
Note
The config object provides read-only API, changing values at runtime is not possible to prevent unwanted side-effect in long-running applications.
Every Spiral component provides the config object you can use in your application.
In many cases, the default configuration might be enough for most of the applications. Use custom bootloader to define default configuration values to avoid the need to create unnecessary files. Environment variables can be used as default values.
namespace App\Bootloader;
use App\Config\AppConfig;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Boot\EnvironmentInterface;
use Spiral\Config\ConfiguratorInterface;
class AppBootloader extends Bootloader
{
public function boot(ConfiguratorInterface $configurator, EnvironmentInterface $env): void
{
$configurator->setDefaults(AppConfig::CONFIG, [
'values' => [432],
'other' => $env->get('VALUE_FROM_ENV', 'default')
]);
}
}
The file app/config/app.php
will overwrite default configuration values. Remove this file to use the default
configuration.
Note
The overwrite is done on the first level keys of configuration array.
Some components will expose auto-configuration API to change its settings during the application bootload time. Usually, such API is available through the component bootloader.
Note
For exampleHttpBootloader
->addMiddleware
.
We can provide our auto-configuration API in our Bootloader. Use ConfiguratorInterface
->modify
for this purpose.
Our Bootloader will be declared as Singleton to speed up processing a bit.
namespace App\Bootloader;
use App\Config\AppConfig;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Config\ConfiguratorInterface;
use Spiral\Config\Patch\Append;
use Spiral\Core\Container\SingletonInterface;
class AppBootloader extends Bootloader implements SingletonInterface
{
private ConfiguratorInterface $configurator;
public function __construct(ConfiguratorInterface $configurator)
{
$this->configurator = $configurator;
}
public function boot(): void
{
$this->configurator->setDefaults(AppConfig::CONFIG, [
'values' => [432]
]);
}
public function addValue(int $value): void
{
// append new value to the values section of app config
$this->configurator->modify(AppConfig::CONFIG, new Append('values', null, $value));
}
}
Now, we can modify configuration via strict API from another bootloader:
namespace App\Bootloader;
use Spiral\Boot\Bootloader\Bootloader;
class ValueBootloader extends Bootloader
{
public function boot(AppBootloader $app): void
{
$app->addValue(800);
}
}
Note
Make sure to locate the Bootloader after theAppBootloader
or useDEPENDENCIES
constant.
The framework provides a security mechanism to make sure that you are not changing config values after the config object is requested by any of the components (a.k.a. config is frozen).
To demonstrate it, inject AppConfig
to ValueBootloader
:
namespace App\Bootloader;
use App\Config\AppConfig;
use Spiral\Boot\Bootloader\Bootloader;
class ValueBootloader extends Bootloader
{
public function boot(AppBootloader $app, AppConfig $appConfig): void
{
// forbidden
$app->addValue(800);
}
}
You will receive an exception Spiral\Config\Exception\ConfigDeliveredException
: Unable to patch config app
,
config object has already been delivered.