connectholland/env-var-loader-bundle
Installation
composer require connectholland/env-var-loader-bundle
The package auto-registers via Symfony Flex, so no manual AppKernel updates are needed.
Enable Loaders
Edit config/packages/env_var_loader.yaml:
env_var_loader:
loaders:
etcd: # or vault, consul, etc.
enabled: true
# Minimal required config (see below for full options)
host: "localhost"
port: 2379
First Use Case
Inject the EnvVarLoaderInterface and load variables:
use ConnectHolland\EnvVarLoaderBundle\Loader\EnvVarLoaderInterface;
class MyService {
public function __construct(private EnvVarLoaderInterface $loader) {}
public function getConfig() {
$vars = $this->loader->load(['DB_HOST', 'REDIS_PORT']);
return [
'database' => [
'host' => $vars['DB_HOST'] ?? 'localhost',
'port' => $vars['REDIS_PORT'] ?? 6379,
],
];
}
}
Where to Look First
config/packages/env_var_loader.yaml (generated by Flex).src/Loader/ for available loaders (e.g., EtcdLoader, VaultLoader).env_var_loader.load for custom logic.Loader Chaining
Enable multiple loaders in config (e.g., etcd + vault). Variables are loaded in order, with later loaders overriding earlier ones.
loaders:
etcd:
enabled: true
prefix: "app/"
vault:
enabled: true
path: "secret/data/app"
Fallback Strategy
Use load() with a default array to handle missing vars:
$vars = $this->loader->load(['API_KEY'], ['API_KEY' => 'default_123']);
Dynamic Loading Load variables conditionally based on environment:
$loader = $this->loader->getLoader('vault');
if ($loader->isAvailable()) {
$vars = $loader->load(['VAULT_VAR']);
}
Integration with Symfony
EnvVarLoaderInterface or specific loaders (e.g., EtcdLoader)..env by loading .env first, then remote sources:
$this->loader->load(['APP_DEBUG'], [], 'env'); // Load from .env first
$this->loader->load(['APP_DEBUG']); // Override with remote vars
Custom Loaders
Extend AbstractLoader to create a new loader (e.g., for AWS SSM):
use ConnectHolland\EnvVarLoaderBundle\Loader\AbstractLoader;
class SsmLoader extends AbstractLoader {
public function load(array $variables): array {
// AWS SSM logic here
return $variables;
}
}
Register it in config/packages/env_var_loader.yaml:
loaders:
ssm:
enabled: true
class: App\Loader\SsmLoader
Loader Order Matters
etcd before vault).priority in config:
loaders:
vault:
enabled: true
priority: 100 # Higher priority = loaded later
Caching Issues
vault) may not cache by default. Use Symfony’s cache system:
env_var_loader:
cache: true
cache_pool: cache.app
php bin/console cache:clear
Variable Naming Conflicts
.env and remote vars (e.g., DB_PASSWORD in both .env and vault).etcd:
prefix: "app/"
Loader Availability
isAvailable() before loading:
if (!$this->loader->getLoader('vault')->isAvailable()) {
throw new \RuntimeException('Vault loader unavailable');
}
Symfony 6+ Compatibility
composer require symfony/flex:"^1.0" --dev
Enable Verbose Logging
Add to config/packages/monolog.yaml:
handlers:
env_var_loader:
type: stream
path: "%kernel.logs_dir%/env_var_loader.log"
level: debug
Check Loader Responses
Use debug:container to inspect loaded variables:
php bin/console debug:container ConnectHolland\EnvVarLoaderBundle\Loader\EnvVarLoaderInterface
Validate Config Run:
php bin/console config:validate env_var_loader
Event Listeners
Listen to env_var_loader.load to modify variables:
use Symfony\Component\EventDispatcher\GenericEvent;
$dispatcher->addListener('env_var_loader.load', function (GenericEvent $event) {
$variables = $event->getArgument('variables');
$variables['CUSTOM_VAR'] = 'overridden';
$event->setArgument('variables', $variables);
});
Custom Variable Parsers
Extend ParserInterface to handle non-standard formats (e.g., JSON blobs):
use ConnectHolland\EnvVarLoaderBundle\Parser\ParserInterface;
class JsonParser implements ParserInterface {
public function parse(string $value): mixed {
return json_decode($value, true);
}
}
Register in config:
env_var_loader:
parsers:
json: App\Parser\JsonParser
Loader-Specific Config
Some loaders support additional options (e.g., vault for token auth):
vault:
enabled: true
token: "%env(VAULT_TOKEN)%"
path: "secret/data"
How can I help you explore Laravel packages today?