Dependency Injection & Configuration Container
The project uses the PSR-11 container to manage dependencies. This document covers both the configuration structure and the DI binding patterns that wire everything together.
Configuration Structure
The configuration is organized by environment in the config/{environment}/ folders. Each environment can have:
- credentials.env - Environment variables (database connections, API keys, JWT secrets, etc.)
- Numbered PHP files - Dependency injection bindings organized by layer:
01-infrastructure.php- Database, Cache, Logging02-security.php- JWT, Authentication, CORS03-api.php- OpenAPI routes, Middleware04-repositories.php- Repository bindings05-services.php- Service bindings06-external.php- External services (Email, etc.)
You must set the APP_ENV environment variable to specify which environment to use.
Example: credentials.env
WEB_SERVER=localhost
DASH_SERVER=localhost
WEB_SCHEMA=http
API_SERVER=localhost
API_SCHEMA=http
DBDRIVER_CONNECTION=mysql://root:mysqlp455w0rd@mysql-container/mydb
EMAIL_CONNECTION=smtp://username:[email protected]
JWT_SECRET=OFbOmC2VxlgQHNrBLa/wyj7/fFkgPnLpckbXMVuIU7Sqb3RTztNx3xzEYaoeA31JUpvBjkD7FRKBFGQ0+fnTig==
CORS_SERVERS=.*
Example: 01-infrastructure.php
<?php
use ByJG\Cache\Psr16\BaseCacheEngine;
use ByJG\Cache\Psr16\NoCacheEngine;
use ByJG\Config\DependencyInjection as DI;
use ByJG\Config\Param;
return [
BaseCacheEngine::class => DI::bind(NoCacheEngine::class)->toSingleton(),
DbDriverInterface::class => DI::bind(Factory::class)
->withFactoryMethod("getDbRelationalInstance", [Param::get('DBDRIVER_CONNECTION')])
->toSingleton(),
];
The configuration is loaded by the byjg/config library.
Getting Configuration Values
Use the Config::get() method:
Config::get('WEB_SERVER');
Environment Hierarchy
The available environments are defined in the config/ConfigBootstrap.php file.
The project has four environments with the following inheritance hierarchy:
Inheritance Rules:
- test inherits from dev
- staging inherits from dev (with caching enabled)
- prod inherits from staging and dev (with caching enabled)
Child environments override parent configurations. For example:
config/dev/credentials.envdefines base database connectionconfig/prod/credentials.envoverrides with production database connectionconfig/prod/01-infrastructure.phpoverrides to use FileSystemCache instead of NoCache
You can modify the environment hierarchy in config/ConfigBootstrap.php:
<?php
use ByJG\Cache\Psr16\FileSystemCacheEngine;
use ByJG\Config\ConfigInitializeInterface;
use ByJG\Config\Definition;
use ByJG\Config\Environment;
return new class implements ConfigInitializeInterface {
public function loadDefinition(?string $env = null): Definition
{
$dev = Environment::create('dev');
$test = Environment::create('test')->inheritFrom($dev);
$staging = Environment::create('staging')->inheritFrom($dev)->withCache(new FileSystemCacheEngine());
$prod = Environment::create('prod')->inheritFrom($staging, $dev)->withCache(new FileSystemCacheEngine());
return (new Definition())
->addEnvironment($dev)
->addEnvironment($test)
->addEnvironment($staging)
->addEnvironment($prod)
->withOSEnvironment([
'TAG_VERSION',
'TAG_COMMIT',
]);
}
};
The Config is automatically initialized when first accessed, thanks to byjg/config's auto-initialization feature.
Dependency Injection Patterns
Dependency Injection (DI) decouples your code from specific implementations, making it easier to swap dependencies based on environment or requirements.
Example: Environment-Specific Cache
You might want caching enabled in production but disabled in development for easier debugging.
Development - config/dev/01-infrastructure.php:
<?php
use ByJG\Cache\Psr16\BaseCacheEngine;
use ByJG\Cache\Psr16\NoCacheEngine;
use ByJG\Config\DependencyInjection as DI;
return [
BaseCacheEngine::class => DI::bind(NoCacheEngine::class)
->toSingleton(),
];
Production - config/prod/01-infrastructure.php:
<?php
use ByJG\Cache\Psr16\BaseCacheEngine;
use ByJG\Cache\Psr16\FileSystemCacheEngine;
use ByJG\Config\DependencyInjection as DI;
return [
BaseCacheEngine::class => DI::bind(FileSystemCacheEngine::class)
->toSingleton(),
];
Usage in Code:
<?php
use ByJG\Config\Config;
use ByJG\Cache\Psr16\BaseCacheEngine;
// Get the cache instance (implementation depends on APP_ENV)
$cache = Config::get(BaseCacheEngine::class);
// Use it the same way regardless of environment
$cache->set('key', 'value', 3600);
$value = $cache->get('key');
The application automatically returns the correct implementation based on the APP_ENV environment variable.
Constructor Injection (withInjectedConstructor)
DummyService::class => DI::bind(DummyService::class)
->withInjectedConstructor()
->toSingleton(),
The container automatically injects dependencies defined in the constructor based on their type hints.
Constructor with Parameters (withConstructorArgs)
JwtWrapper::class => DI::bind(JwtWrapper::class)
->withConstructorArgs([
Param::get('API_SERVER'),
Param::get(JwtKeyInterface::class)
])
->toSingleton(),
Mix environment parameters and other dependencies.
Factory Method (withFactoryMethod)
DbDriverInterface::class => DI::bind(Factory::class)
->withFactoryMethod("getDbRelationalInstance", [
Param::get('DBDRIVER_CONNECTION')
])
->toSingleton(),
Use a factory method instead of a constructor.
Singleton vs Transient (toSingleton)
// Singleton - Same instance every time
MyService::class => DI::bind(MyService::class)->toSingleton(),
// Transient - New instance every time
MyService::class => DI::bind(MyService::class),
Configuration Organization
Dependencies are organized by layer in numbered files:
01-infrastructure.php- Database, Cache, Logging02-security.php- JWT, Authentication, User Management03-api.php- OpenAPI, Routes, Middleware04-repositories.php- Data access layer05-services.php- Business logic layer06-external.php- Email, SMS, external APIs
This organization makes it easy to find and modify related configurations.
Related Documentation
- Configuration Guide - Advanced configuration patterns
- Service Layer - Registering services in the container
- Architecture - How DI fits the overall architecture