Installation:
composer require symplify/set-config-resolver
Ensure symfony/console and symfony/dependency-injection are also installed (required dependencies).
Basic CLI Integration:
In your Laravel Artisan command or CLI entry point (e.g., app/Console/Kernel.php or a custom bin/console script):
use Symfony\Component\Console\Input\ArgvInput;
use Symplify\SetConfigResolver\SetAwareConfigResolver;
use YourApp\Config\YourSetProvider; // Implement SetProviderInterface
$setProvider = new YourSetProvider();
$configResolver = new SetAwareConfigResolver($setProvider);
// Resolve from CLI --config flag or fallback to a default config file
$inputConfig = $configResolver->resolveFromInputWithFallback(
new ArgvInput(),
['config/default.php']
);
if ($inputConfig !== null) {
config($inputConfig); // Merge into Laravel's config
}
First Use Case:
Create a config file (e.g., config/my-tool.php) with a simple array:
return [
'my_tool' => [
'option1' => 'value1',
'option2' => 'value2',
],
];
Run your CLI tool with:
php artisan my:tool --config=config/my-tool.php
Or use a --set flag if your YourSetProvider supports it:
php artisan my:tool --set=my-set
CLI-Driven Configuration:
resolveFromInputWithFallback() to handle --config flags with fallback files.$config = $configResolver->resolveFromInputWithFallback(
$input, // Symfony\Component\Console\Input\InputInterface
['config/fallback.php']
);
Parameter-Based Sets:
parameters > sets within PHP config files:
$parameterSetsConfigs = $configResolver->resolveFromParameterSetsFromConfigFiles($configs);
$mergedConfigs = array_merge($configs, $parameterSetsConfigs);
Service Provider Integration:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('config.resolver', function () {
return new SetAwareConfigResolver(new YourSetProvider());
});
}
Artisan Command Integration:
Illuminate\Console\Command and resolve configs in handle():
use Illuminate\Support\Facades\App;
protected function handle()
{
$config = App::make('config.resolver')->resolveFromInputWithFallback(
$this->input,
['config/default.php']
);
config($config);
// Proceed with logic...
}
Config Merging:
$resolved = $configResolver->resolve(...);
config()->set($resolved); // Overwrites existing keys
// OR
config()->merge($resolved); // Recursively merges
Development Workflow:
--config flags to override local development settings:
php artisan my:tool --config=config/dev.php
config/ and commit them to version control.CI/CD Workflow:
php artisan my:tool --config=config/ci.php
resolveFromParameterSetsFromConfigFiles to dynamically include sets based on pipeline stages.Plugin/System Architecture:
SetProviderInterface to register plugin-specific configs:
class PluginSetProvider implements SetProviderInterface
{
public function getSets(): array
{
return [
'plugin-set' => ['plugin' => ['option' => 'value']],
];
}
}
Laravel Config Precedence:
config() behavior if needed:
config(['my_tool' => array_merge(config('my_tool', []), $resolved)]);
Symfony Console Compatibility:
Symfony\Component\Console\Input\ArgvInput for CLI entry points or Symfony\Component\Console\Input\ArrayInput for testing:
$input = new ArrayInput(['--config' => 'path/to/config.php']);
Testing:
SetAwareConfigResolver in PHPUnit tests:
$mockResolver = $this->createMock(SetAwareConfigResolver::class);
$mockResolver->method('resolveFromInputWithFallback')
->willReturn(['test' => 'value']);
$this->app->instance('config.resolver', $mockResolver);
Performance:
$cacheKey = 'my_tool_config_' . md5(filemtime('config/default.php'));
$config = Cache::remember($cacheKey, now()->addHours(1), function () use ($configResolver) {
return $configResolver->resolve(...);
});
Config Overwrite vs. Merge:
config() overwrites existing keys by default, while Symfony’s ParameterBag may behave differently. Explicitly use config()->merge() for recursive merging:
// Bad: Overwrites all existing keys
config($resolved);
// Good: Recursively merges
config()->merge($resolved);
Null Handling:
resolveFromInputWithFallback() returns null if no config is found. Always check for null:
$config = $configResolver->resolve(...);
if ($config === null) {
$config = config('defaults.my_tool', []); // Fallback to defaults
}
Symfony DI Container:
ParameterBag for config storage. Laravel’s config() uses a different structure. Bridge the gap with an adapter:
class LaravelConfigAdapter
{
public function __construct(private SetAwareConfigResolver $resolver)
{
}
public function resolve(array $fallbacks): array
{
$symfonyConfig = $this->resolver->resolve(...);
return is_array($symfonyConfig) ? $symfonyConfig : [];
}
}
CLI Argument Parsing:
ArgvInput, which may not handle Laravel’s Artisan-specific flags (e.g., --help). Test thoroughly with your CLI tool’s flags.Archived Package Risk:
Config File Format:
$yamlConfig = yaml_parse_file('config/config.yaml');
$configResolver->resolve([$yamlConfig]);
Config Resolution Issues:
$configResolver = new SetAwareConfigResolver($setProvider, true); // Enable debug
Symplify\SetConfigResolver\Exception\ConfigFileNotFoundException if files are missing.Precedence Conflicts:
dd(config()->all()) to inspect the merged config state after resolution. Look for unexpected overwrites.Set Provider Errors:
resolveFromParameterSetsFromConfigFiles fails, verify:
SetProviderInterface implementation is correct.parameters > sets arrays:
return [
'parameters' => [
'sets' => ['set1', 'set2'],
],
];
Custom Set Providers:
SetProviderInterface implementations:
class DynamicSetProvider implements SetProviderInterface
{
public function getSets(): array
{
return [
'dynamic-set' => [
'value' => env('DYNAMIC_VALUE', 'default'),
],
];
}
}
Environment-Aware Configs:
env()How can I help you explore Laravel packages today?