symfony/config
Symfony Config component helps you find, load, merge, autofill, and validate configuration from sources like YAML, XML, INI, or databases. Provides structured handling of config values for reusable, consistent application setups.
## Getting Started
### Minimal Setup in Laravel
1. **Installation**:
```bash
composer require symfony/config
Laravel already uses this package under the hood for configuration management (e.g., config/, bootstrap/app.php).
First Use Case:
Define a custom configuration structure for a package or service. For example, create a config/my-package.php file:
return [
'enabled' => env('MY_PACKAGE_ENABLED', false),
'timeout' => env('MY_PACKAGE_TIMEOUT', 30),
'services' => [
'api' => [
'url' => env('MY_PACKAGE_API_URL', 'https://api.example.com'),
],
],
];
Load Configuration:
Use Laravel’s built-in config() helper or access it directly via the Config facade:
$config = config('my-package.enabled'); // Returns `false` or the env value
Validation:
Leverage Symfony’s Definition and NodeBuilder to validate config files programmatically:
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class MyPackageConfig implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('my_package');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()
->booleanNode('enabled')->defaultFalse()->end()
->integerNode('timeout')
->min(5)
->max(120)
->defaultValue(30)
->end()
->arrayNode('services')
->addDefaultsIfNotSet()
->children()
->arrayNode('api')
->children()
->scalarNode('url')->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
Register this in a service provider’s boot() method:
$this->app->make('config')->set(MyPackageConfig::class, 'my-package');
ConfigurationInterface to enforce strict config schemas. Example:
$config = $this->app['config'];
$config->shouldValidate(MyPackageConfig::class, 'my-package');
ConfigurationInterface for your package.shouldValidate()..env files using placeholders:
# config/my-package.yaml
services:
api:
url: '%env(MY_PACKAGE_API_URL)%'
env() helper in PHP config files for dynamic values:
return [
'timeout' => env('MY_PACKAGE_TIMEOUT', 30),
];
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\DelegatingLoader;
$loader = new DelegatingLoader([
new YamlFileLoader($this->app['path.config'].'/my-package'),
new PhpFileLoader($this->app['path.config']),
]);
$config = $loader->load('my-package');
ConfigRepository to support custom loaders.// In a service provider
$this->publishes([
__DIR__.'/../config/my-package.php' => config_path('my-package.php'),
], 'config');
config/ during installation.NodeBuilder.use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
$rootNode->children()
->enumNode('status')
->values(['active', 'inactive', 'pending'])
->end()
->arrayNode('roles')
->prototype('scalar')->end()
->end();
Deprecated Features:
$this->loadFromExtension()). Use YAML or PHP arrays instead.defaultValue() and isRequired() in NodeBuilder (throws InvalidArgumentException).Case Sensitivity:
snake_case) for consistency.Circular References:
include statements. Use absolute paths or avoid circular includes.Environment Placeholders:
%env(MY_VAR)% must be resolved before validation. Use ParameterBag or Laravel’s env() helper to pre-process values.Array Merging Quirks:
->ignoreExtraKeys(false) or ->normalizeKeys(false) in ArrayNodeDefinition.Enable Debug Mode:
Symfony’s DefinitionErrorException provides detailed validation errors. Enable Laravel’s debug mode (APP_DEBUG=true) for stack traces.
Inspect Config Tree: Dump the config tree to debug structure:
$configTree = (new MyPackageConfig())->getConfigTreeBuilder()->buildTree();
var_dump($configTree->getRootNode()->getSchema());
Validate Without Throwing:
Use validate() with a ValidationExceptionHandler to catch errors gracefully:
try {
$config->validate(MyPackageConfig::class, 'my-package');
} catch (\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException $e) {
report($e);
}
Custom Resource Loaders:
Extend FileLocator or LoaderInterface to load config from databases, APIs, or S3:
class ApiConfigLoader implements LoaderInterface
{
public function load($resource, $type = null)
{
$data = $this->fetchFromApi($resource);
return $data;
}
public function supports($resource, $type = null) { /* ... */ }
}
Dynamic Node Factories:
Create reusable NodeDefinition factories for common patterns (e.g., API endpoints):
class ApiEndpointNodeDefinition extends ArrayNodeDefinition
{
public function __construct(string $name)
{
$this->addDefaultsIfNotSet()
->children()
->scalarNode('url')->isRequired()->end()
->integerNode('timeout')->defaultValue(30)->end()
->end();
}
}
Override Default Config:
Use Laravel’s mergeConfigFrom to override package defaults:
$this->mergeConfigFrom(__DIR__.'/config/my-package.php', 'my-package');
Cache Config Validation: Cache the compiled config tree to avoid re-parsing on every request:
$cache = new \Symfony\Component\Cache\Simple\FilesystemCache(sys_get_temp_dir());
$configTree = $cache->get('my_package_config_tree', function() {
return (new MyPackageConfig())->getConfigTreeBuilder()->buildTree();
});
Lazy-Load Config:
Load config only when needed (e.g., in a service provider’s register()):
$this->app->singleton('my-package.config', function() {
return $this->app['config']->get('my-package');
});
Avoid Redundant Merging:
Use ->beforeNormalization() or ->beforeValidation() in NodeBuilder to pre-process values and reduce merging overhead.
```markdown
### **Laravel-Specific Quirks**
1. **Service Container Integration**:
Bind config validators to the container for reuse:
```php
$this->app->bind(MyPackageConfig::class, function() {
return new MyPackageConfig();
});
validate() helper:
use Symfony
How can I help you explore Laravel packages today?