PHP code example of purpleharmonie / dependency-injection
1. Go to this page and download the library: Download purpleharmonie/dependency-injection library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
purpleharmonie / dependency-injection example snippets
//services.php
return function ($containerConfigurator) {
$services = $containerConfigurator->services();
//define harmony service with argument
$services->set('harmony', Harmony::class)
->addArgument(new Reference('adapter'))
->addArgument(new Reference('sql_builder'))
->addArgument(new Reference('schema'))
->addArgument(new Reference('executor'))
//->addArgument('%harmonyConfig%')
->addMethodCall('initialize', [/*pass array of arguments*/]) //[@service,'%DB_ENV%', %PARAMETER%]
->asGlobal(true)
->asShared(true);
// Define a service using an inline factory
$services->set('database_connection', function ($container) {
$host = $container->getParameter('db.host');
$port = $container->getParameter('db.port');
$username = $container->getParameter('db.username');
$password = $container->getParameter('db.password');
$database = $container->getParameter('db.database');
return new DatabaseConnection($host, $port, $username, $password, $database);
})
->asGlobal(true)
->asShared(true);
// Define a service using an inline factory with dependencies
$services->set('user_repository', function ($container) {
$dbConnection = $container->get('database_connection');
return new UserRepository($dbConnection);
})
->asGlobal(false)
->asShared(true);
// You can also use arrow functions (PHP 7.4+) for more concise definitions
$services->set('logger', fn($container) => new Logger($container->getParameter('log_file')))
->asGlobal(true) //available within and outiside the container
->asShared(true); //either a shared instance or new instance per request
//Defining factory with classes .
$services->set('platform', PlatformFactory::class)
->factory([PlatformFactory::class, 'create']) // Factory class name and method that returns the service
//->addArgument('$DB_CONNECTION$')
->implements(DatabasePlatform::class) // handles the interface
->asGlobal(false)
->asShared(true)
->autowire();
$services->set('some_service', SomeService::class)
->asGlobal(false)->lazy()
->asShared(true)
->addMethodCall('doSomething',[]) // since the method is defined with arguments passed. it will be autorired. cos of autowire set on this service
->addTag(['example'])
->autowire(); //will use parameter type hinting to resolve the class
//with automatically autowire class and specified method using annotations.
$services->set('userManager', UserManager::class)
->asGlobal(true)
->asShared(true)
->addMethodCall('createUser',[])
->annotwire();
//arguments setting in bulk @service , env param %HOST% or passed param %parameter%
$services->set('xpressive', Xpressive::class)
->asGlobal(false)
->asShared(true)
->autowire();
->arguments(['@platform','@adapter','@executor']);
};
//event dispatcher boot
$eventDispatcher->addListener('kernel.pre_boot', function() {
echo "Kernel is about to boot!\n";
});
$eventDispatcher->addListener('kernel.post_boot', function() {
echo "Kernel has finished booting!\n";
});
$kernel->addExtension(new DatabaseExtension());
namespace Purple\Core\EventsExamples;
use Purple\Core\Services\Container;
use Purple\Core\Services\Interface\KernelExtensionInterface;
// Example implementation
class DatabaseExtension implements KernelExtensionInterface
{
public function load(Container $container): void
{
$container->set('database', function(Container $c) {
return new DatabaseConnection(
$c->getParameter('db_host'),
$c->getParameter('db_name'),
$c->getParameter('db_user'),
$c->getParameter('db_pass')
);
});
}
}
//the extension interface that extensions must implement
namespace Purple\Core\Services\Interface;
use Purple\Core\Services\Container;
interface KernelExtensionInterface
{
public function load(Container $container): void;
}
// Load environment variables
$kernel->loadEnv(__DIR__ . '/../.env');
//either one or both
// Load service configurations from a file (e.g., YAML)
$kernel->loadConfigurationFromFile(__DIR__ . '/../config/services.yaml');
// Define services in PHP
$kernel->loadConfigurationFromFile(__DIR__ . '/../public/service.php');
// Assuming we have a Container instance
$container = new Container(/* ... */);
// Using bindIf()
$container->bindIf('logger', function(Container $c) {
return new FileLogger($c->getParameter('log_file'));
});
// This won't overwrite the existing 'logger' binding
$container->bindIf('logger', function(Container $c) {
return new ConsoleLogger();
});
// Using callable()
$container->callable('mailer', function(Container $c) {
$transport = $c->get('mailer.transport');
$logger = $c->get('logger');
return new Mailer($transport, $logger);
});
// Later in the code, you can get these services
$logger = $container->get('logger'); // This will be a FileLogger
//original use
$services->set('mailer', Mailer::class);
// Define the decorator
$services->set('decorMailer', LoggingDecorator::class)
->addArgument(new Reference('mailer'))
->decorate('mailer');
//or alternatively
$services->set('decorMailer', LoggingDecorator::class)
->addArgument(new Reference('mailer'));
// Using setAlias
$container->setAlias('app.database', DatabaseConnection::class);
// Binding interfaces to concrete implementations
$container->set('interfaceservicename', ConcreteUserRepositoryInterface::class);
$container->set('concreteclassforinterfaceservicename', ConcreteUserRepository::class);
$container->setAlias('interfaceservicename', 'concreteclassforinterfaceservicename');
// Quick alias chaining
$services->set('mailer', Mailer::class)->alias('public_mailer_service');
// Using aliases in service definitions
$container->set('another_service', AnotherService::class)
->addArgument(new Reference('app.user_repository'));
// Retrieving services using aliases
$dbConnection = $container->get('app.database');
$userRepo = $container->get(UserRepositoryInterface::class);
$mailer = $container->get('public_mailer_service');
// In your configuration
$container = new Container();
$configurator = new ContainerConfigurator($container);
// Add global middleware
$configurator->addGlobalMiddleware(new LoggingMiddleware());
$configurator->addGlobalMiddleware(new ProfilingMiddleware());
// Configure a service with specific middleware
$configurator->set('user_service', UserService::class)
->addServiceMiddleware(new ValidationMiddleware());
// Usage
$userService = $container->get('user_service');
// This will log creation, validate the service, and profile creation time
namespace Purple\Core\Services\Interface;
use Closure;
interface MiddlewareInterface
{
public function process($service, string $id, Closure $next);
}
// Usage example outside service files or index
$container = new Container();
$container->annotationDiscovery([
'namespace' => [
'App\\Core\\Db\\Example' => [
'resource' => '../core/Db/Example/*',
'exclude' => ['../core/Db/Example/{DependencyInjection,Entity,Migrations,Tests}']
]
]
]);
// example of annotation classes with contructor and method inject
namespace Purple\Core;
use Purple\Core\FileLogger;
use Purple\Core\Mailer;
use Purple\Core\SomeService;
#[Service(name: "userManager")]
class UserManager {
private FileLogger $logger;
public function __construct(#[Inject("@logger")] FileLogger $logger, $basic ="ghost") {
$this->logger = $logger;
}
public function createUser(#[Inject("@mailer")] Mailer $mailer,#[Inject("@some_service")] SomeService $some_service): bool {
echo "anot method is called ";
return false;
}
}
//example with property inject
class UserManager {
#[Inject("@logger")]
private FileLogger $logger;
#[Inject("@mailer")]
private Mailer $mailer;
public function __construct(#[Inject("@database")] Database $db) {
$this->db = $db;
}
// ... other methods ...
}
//services.php
return function ($containerConfigurator) {
$configPath = __DIR__ . '/../config/database.php';
$services = $containerConfigurator->services();
$middleware = $containerConfigurator->middlewares();
$defaults = $containerConfigurator->defaults();
//takes a string either hints to type hints autowire for all services by default or use annots for annotations
//$defaults->wireType("annots");
//when its set to true, the container will use annotations along with wiretype
//$defaults->setAnnotwire("annots");
//when its set to true, the continue will use parameter hints for autowring along with wiretype
//$defaults->setAutowire("annots");
//by defaults all service have asGlobal false hence private, only alias makes them public or asGlobal method
//by configuring this to true all methods become public by default
//$defaults->setAsGlobal("annots");
$services->parameters('db.host', 'localhost');
$services->parameters('db.port', 3306);
$services->parameters('db.username', 'root');
$services->parameters('db.password', 'secret');
$services->parameters('db.database', 'my_database');
$services->parameters('db.charset', 'utf8');
$services->parameters('db.options', []);
$services->parameters('migrations_dir', '/path/to/migrations');
$services->parameters('migrations_table', 'migrations');
$services->parameters('column', 'default_column');
$services->parameters('config.database_path', $configPath);
$services->parameters('harmonyConfig', [
'setting1' => 'value1',
'setting2' => 'value2',
// Other configuration parameters...
]);
//internal autodirectory scanning and add to services definitions
$containerConfigurator->discovery([
'Purple\Core\Db\Example\\' => [
'resource' => '../core/Db/Example/*',
'exclude' => ['../core/Db/Example/{DependencyInjection,Entity,Migrations,Tests}']
]
]);
// Add middleware
// Add global middleware
$middleware->addGlobalMiddleware(new LoggingMiddlewares());
//for example use to be deleted
$services->parameters('session_data', "dfgfhgfgghjkhjkh");
//defining event dispatcher
$services->set('event_dispatcher', EventDispatcher::class) ->asGlobal(false)
->asShared(true);
//define harmony service
$services->set('harmony', Harmony::class)
->addArgument(new Reference('adapter'))
->addArgument(new Reference('sql_builder'))
->addArgument(new Reference('schema'))
->addArgument(new Reference('executor'))
//->addArgument('%harmonyConfig%')
->addMethodCall('initialize', [])
->asGlobal(true)
->asShared(true);
//defining adapter through factory
// Define a service that uses a factory method to create an instance
$services->set('adapter', AdapterFactory::class)
->factory([AdapterFactory::class, 'create'])
->asGlobal(false)
->asShared(true)
//->addArgument('$DB_CONNECTION$')
//->addArgument('$DB_DATABASE$')
//->addArgument('$DB_HOST$')
//->addArgument('$DB_USERNAME$')
//->addArgument('$DB_PASSWORD$')
//->addArgument('$DB_CHARSET$')
->implements(DatabaseAdapterInterface::class)
->autowire()
->asGlobal(false)
->asShared(true);
//defining service sqlbuilder
$services->set('sql_builder', QueryBuilderFactory::class)
->factory([QueryBuilderFactory::class, 'create'])
//->addArgument(new Reference('adapter'))
//->addArgument(new Reference('executor'))
->autowire()
->asGlobal(false)
->asShared(true);
//defining platform
$services->set('platform', PlatformFactory::class)
->factory([PlatformFactory::class, 'create'])
//->addArgument('$DB_CONNECTION$')
->implements(DatabasePlatform::class)
->asGlobal(false)
->asShared(true)
->autowire();
// defining schema service
$services->set('schema', Schema::class)
->addArgument(new Reference('adapter'))
->addArgument(new Reference('sql_builder'))
->addArgument(new Reference('event_dispatcher'))
->asGlobal(false)
->asShared(true);
//defining executor
$services->set('executor', QueryExecutor::class)
->addArgument(new Reference('adapter'))
->addArgument(new Reference('event_dispatcher'))
->asGlobal(true)
->asShared(true);
//defining migration manager
$services->set('migration_manager', MigrationManager::class)
->addArgument(new Reference('harmony'))
->addArgument('%migrations_dir%')
->addArgument('%migrations_table%')
->asGlobal(false)
->asShared(true);
//defining xpressive fluent query builder
$services->set('xpressive', Xpressive::class)
->asGlobal(false)
->asShared(true)
->autowire();
//->arguments(['@platform','@adapter','@executor']);
//example use
$services->set('mailer', Mailer::class)
->asGlobal(false)
->asShared(true);
// Define the decorator
$services->set('decorMailer', LoggingDecorator::class)
->addArgument(new Reference('mailer'))
->decorate('mailer');
$services->set('database', DbaseConnection::class) ->asGlobal(false)
->asShared(true)->setAlias('database')->addTag(['example']);
$services->set('logger', FileLogger::class)
->addArgument(new Reference('mailer'))
->asGlobal(true)
->asShared(true)
->lazy()
->addServiceMiddleware(new LoggingMiddlewares());
$services->set('some_service', SomeService::class)->asGlobal(false)->lazy()
->asShared(true)->addMethodCall('doSomething',[]) ->addTag(['example']) ->autowire();
$services->set('userManager', UserManager::class)
->asGlobal(true)
->asShared(true)
->addMethodCall('createUser',[])
->annotwire();
// Finalize and detect circular dependencies
$containerConfigurator->finalize();
};
//index.php
// Define the cache configuration
$cacheType = 'memory'; // or 'file', or 'memory' or 'redis'
$cacheConfig = [
'redis' => [
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
],
'maxSize' => 1000,
'evictionPolicy' => 'LRU'
];
// Create the cache instance using the factory
$cache = CacheFactory::createCache($cacheType, $cacheConfig);
// Initialize the DI container with the log path using monolog
$logFilePath = __DIR__ . '/../bootstrap/logs/container.log';
// Initialize the DI container with the log path using monolog
$logFilePath = __DIR__ . '/../bootstrap/logs/container.log';
$configDir = __DIR__ . '/../config';
$resourceDir = __DIR__ . '/../resources';
$eventDispatcher = new EventDispatcher();
// Create the kernel
$kernel = new Kernel('prod', false, $logFilePath, $cache, $configDir, $resourceDir, $eventDispatcher );
// Load environment variables
$kernel->loadEnv(__DIR__ . '/../.env');
// Load service configurations from a file (e.g., YAML)
$kernel->loadConfigurationFromFile(__DIR__ . '/../config/services.yaml');
// Define services in PHP
$kernel->loadConfigurationFromFile(__DIR__ . '/../public/service.php');
//event dispatcher boot
$eventDispatcher->addListener('kernel.pre_boot', function() {
echo "Kernel is about to boot!\n";
});
$eventDispatcher->addListener('kernel.post_boot', function() {
echo "Kernel has finished booting!\n";
});
//$kernel->addExtension(new DatabaseExtension());
//auto discovery of services feature outside the yaml and php file
$kernel->autoDiscoverServices('../core/Db/Example', 'Purple\Core\Db\Example');
// Add any compiler passes
$kernel->addCompilerPass(new CustomCompilerPass('exampletag','examplemethod'));
// Boot the kernel and get the container
$kernel->boot();
$container = $kernel->getContainer();
$container->annotationDiscovery([
'namespace' => [
'Purple\\Core\\AnnotEx' => [
'resource' => __DIR__.'/../core/AnnotEx',
'exclude' => []
]
]
]);
//get service by tag
$databaseServices = $container->getByTag('example');
//get all services with a tag name
$databaseServices = $container->findTaggedServiceIds('purple.core.db.example.autowired');
// Retrieve and use services as usual
$harmony = $container->get('harmony');
$schema = $container->get('schema');
//example compiler pass
namespace Purple\Core\Services\CompilerPass;
use Purple\Core\Services\Container;
use Purple\Core\Services\Interface\CompilerPassInterface;
use Purple\Core\Services\ContainerConfigurator;
use Purple\Core\Services\Kernel\PassConfig;
use Purple\Core\Services\Reference;
class CustomCompilerPass implements CompilerPassInterface
{
private $tagName;
private $methodName;
public function __construct(string $tagName, string $methodName)
{
$this->tagName = $tagName;
$this->methodName = $methodName;
}
/**
* Modify the container here before it is dumped to PHP code.
*/
public function process(ContainerConfigurator $containerConfigurator): void
{
// Example: Tag all services with a specific interface
$taggedServices = $containerConfigurator->findTaggedServiceIds('example');
//print_r( $taggedServices);
foreach ($taggedServices as $id => $tags) {
// Set the currentservice
$containerConfigurator->setCurrentService($tags);
echo $tags;
// Add a method call to each tagged service
$containerConfigurator->addMethodCall('setTester', [new Reference('logger')]);
// You can also modify other aspects of the service definition here
}
}
/**
* Get the priority of this compiler pass.
*
* @return int The priority (higher values mean earlier execution)
*/
public function getPriority(): int
{
// This compiler pass will run earlier than default priority passes
return 10;
}
/**
* Get the type of this compiler pass.
*
* @return string One of the TYPE_* constants in Symfony\Component\DependencyInjection\Compiler\PassConfig
*/
public function getType(): string
{
// This pass runs before optimization, allowing it to modify service definitions
return PassConfig::TYPE_BEFORE_OPTIMIZATION;
}
}