darvinstudio/darvin-config-bundle
Installation Add the package via Composer:
composer require darvinstudio/darvin-config-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Darvin\ConfigBundle\DarvinConfigBundle::class => ['all' => true],
];
First Configuration Class
Create a config class (e.g., src/Config/AppConfig.php) implementing ConfigurationInterface or extending AbstractConfiguration:
use Darvin\ConfigBundle\Configuration\AbstractConfiguration;
use Darvin\ConfigBundle\Parameter\ParameterModel;
class AppConfig extends AbstractConfiguration {
public function getModel(): iterable {
yield new ParameterModel('api_key', ParameterModel::TYPE_STRING, '');
}
}
Register the Service
Tag the config class in config/services.yaml:
services:
App\Config\AppConfig:
tags: ['darvin_config.configuration']
Access Config in Controllers
Inject Darvin\ConfigBundle\Configuration\ConfigurationManager and fetch values:
use Darvin\ConfigBundle\Configuration\ConfigurationManager;
class SomeController {
public function __construct(private ConfigurationManager $configManager) {}
public function index() {
$apiKey = $this->configManager->get('AppConfig', 'api_key');
// Use $apiKey...
}
}
Centralized Configuration
Group related settings (e.g., DatabaseConfig, MailConfig) into separate classes, each tagged with darvin_config.configuration. Use the ConfigurationManager to access them uniformly:
$dbHost = $this->configManager->get('DatabaseConfig', 'host');
$mailFrom = $this->configManager->get('MailConfig', 'from_email');
Environment-Specific Overrides
Extend configurations for environments (e.g., AppConfigDev for dev environment) and tag them with darvin_config.configuration. The bundle prioritizes the first matching config class.
Dynamic Configuration Loading Load configurations lazily in services:
public function __construct(private ConfigurationManager $configManager) {}
public function someMethod() {
$this->configManager->get('AppConfig', 'feature_flag', false); // Default fallback
}
Validation and Defaults
Define strict types (e.g., TYPE_ARRAY, TYPE_INTEGER) in ParameterModel to enforce validation. Provide defaults to avoid runtime errors:
yield new ParameterModel('timeout', ParameterModel::TYPE_INTEGER, 30);
Configuration-Driven Features Use configs to toggle features or behaviors:
if ($this->configManager->get('AppConfig', 'enable_logging', false)) {
$logger->info('Feature enabled');
}
Symfony Parameters
Bridge with Symfony’s ParameterBag by extending AbstractConfiguration and overriding load() to merge with parameters.yaml:
public function load(array $config): void {
$this->config['api_key'] = $config['api_key'] ?? '';
}
Cache Warmup
Preload configurations during cache warmup (e.g., in a CacheWarmer service) to avoid runtime overhead:
public function warmUp($cacheDir) {
$this->configManager->getAll(); // Force-load all configs
}
Dependency Injection Bind configurations to services via autowiring or explicit arguments:
services:
App\Service\FeatureService:
arguments:
$configManager: '@darvin_config.configuration_manager'
Service Tagging
Forgetting to tag a configuration class with darvin_config.configuration will make it invisible to ConfigurationManager. Verify tags with:
bin/console debug:container darvin_config.configuration
Type Mismatches
Passing incorrect types (e.g., string to TYPE_INTEGER) will throw exceptions. Use ParameterModel::TYPE_ANY for flexible values or validate manually:
$value = $this->configManager->get('AppConfig', 'timeout');
if (!is_int($value)) {
throw new \RuntimeException('Timeout must be an integer');
}
Circular Dependencies
Avoid circular references between configurations (e.g., ConfigA referencing ConfigB which references ConfigA). Use lazy loading or defaults to break cycles.
Configuration Overrides
Overriding configs in config/packages/darvin_config.yaml may not work as expected. Use environment-specific config classes instead:
# config/packages/darvin_config.yaml
darvin_config:
configs:
- App\Config\AppConfigDev # For dev environment
Performance
Loading all configurations (getAll()) can be slow for large apps. Fetch only what’s needed or cache results:
$this->configManager->get('AppConfig', 'api_key'); // Lazy-load
Dump All Configs Use the debug command to inspect loaded configurations:
bin/console darvin:config:dump
Check for Missing Configs
If get() returns null, verify:
getModel().Custom Parameter Types
Extend ParameterModel to support custom validation or serialization:
class CustomParameterModel extends ParameterModel {
public const TYPE_DATETIME = 'datetime';
public function validate($value) {
if ($this->type === self::TYPE_DATETIME && !is_string($value)) {
throw new \InvalidArgumentException('Datetime must be a string');
}
}
}
Configuration Events Listen for config load events to modify values dynamically:
use Darvin\ConfigBundle\Event\ConfigLoadEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ConfigSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
ConfigLoadEvent::NAME => 'onConfigLoad',
];
}
public function onConfigLoad(ConfigLoadEvent $event) {
$config = $event->getConfig();
if ($config instanceof AppConfig) {
$config['api_key'] = 'overridden_value';
}
}
}
Database-Backed Configs
Store configs in a database and hydrate them in getModel():
public function getModel(): iterable {
$dbConfigs = $this->entityManager->getRepository(ConfigEntity::class)->findAll();
foreach ($dbConfigs as $entity) {
yield new ParameterModel($entity->getKey(), ParameterModel::TYPE_STRING, $entity->getValue());
}
}
Configuration Namespaces Organize configs hierarchically by prefixing keys:
yield new ParameterModel('database.host', ParameterModel::TYPE_STRING, 'localhost');
Access with:
$host = $this->configManager->get('DatabaseConfig', 'database.host');
How can I help you explore Laravel packages today?