@afup

@florianm__

  • Un itinéraire 🗺️
  • Des hôtels 💤
  • Du carburant ⛽
  • De la nourriture 🍗

De quoi va t'on avoir besoin ?

@afup

@florianm__

✨ Une application ✨

Florian Merle

@florianm__
Florian-Merle
AKAWAKA

@afup

@florianm__

✨ Road Trip Planner ✨

  • Découvrir ce que cache l'injection de dépendances 🔗

    • Conteneur,
    • Services,

    • Paramètres,

    • Tags,

    • Etc.

  • Pour le défi technique 🏋️

@afup

@florianm__

PSR-11

namespace Psr\Container;

/**
 * Describes the interface of a container that exposes methods to read its entries.
 */
interface ContainerInterface
{
    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return mixed Entry.
     */
    public function get($id);

    /**
     * Returns true if the container can return an entry for the given identifier.
     * Returns false otherwise.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return bool
     */
    public function has($id);
}

@afup

@florianm__

🏛️ SOLID 🏛️

@afup

@florianm__

  • Single responsibility principle
  • Open/closed principle
  • Liskov substitution principle
  • Interface segregation principle
  • Dependency inversion principle

Construire notre conteneur

@afup

@florianm__

ContainerBuilder.php 👷

config.yaml 🔧

Container.php 📦

::buildcontainer(): Container

Implemente PSR-11

@afup

@florianm__

ContainerBuilder

final class ContainerBuilder
{
    public function buildContainer(): Container
    {
        $config = \yaml_parse_file('config.yaml');

        return new Container(
            config: $config,
            serviceIds: $this->resolveServiceIds($config),
        );
    }

    /** @param string[] $config */
    private function resolveServiceIds(array $config): array
    {
        $serviceConfigList = $config['services'] ?? [];

        return array_keys($serviceConfigList);
    }
}
services:
    App\SmsSender: ~
    App\Mailer: ~

	app.weather_listener:
    	class: App\Listener\Weather
        parameters:
        	notifier: '@App\Mailer'
  • App\SmsSender
  • App\Mailer
  • app.weather_listener

@afup

@florianm__

final class Container implements ContainerInterface
{    
    public function get(string $id): mixed
    {
        if (false === $this->has($id)) {
            throw new NotFoundException();
        }

        if (false === array_key_exists($id, $this->services)) {
            $this->services[$id] =  $this->buildInstance($id);
        }

        return $this->services[$id];
    }
}

Container

public function has(string $id): bool
{
	return in_array($id, $this->serviceIds);
}

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed
    
    private function buildInstance(string $id): mixed
    {
        $serviceConfig = $this->config['services'][$id] ?? [];

        $reflector = new \ReflectionClass($serviceConfig['class'] ?? $id);
        if (!$reflector->isInstantiable()) {
            throw new ContainerException("Service $id is not instantiable");
        }

        $constructor = $reflector->getConstructor();
        if (null === $constructor || empty($constructor->getParameters())) {
            $instance = $reflector->newInstance();
        } else {
            $parameters = $this->resolveDependencies($constructor->getParameters(), $serviceConfig);
            $instance = $reflector->newInstanceArgs($parameters);
        }

        return $instance;

    }
}
services:
    App\Mailer: ~

	App\Listener\Weather:
        parameters:
        	notifier: '@App\Mailer'

Container

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed

    // private function buildInstance(string $id): mixed
    
    private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    {
        $dependencies = [];
        foreach ($constructorParameterList as $constructorParameter) {
            $dependencies[] = $this->resolveDependency($constructorParameter, $serviceConfig);
        }

        return $dependencies;
    }
}

Container

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed

    // private function buildInstance(string $id): mixed
    
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()];
        
        // To-do: services, parameters, etc.

        return $value;
    }
}

Container

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed

    // private function buildInstance(string $id): mixed
    
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()];
        
        // service
        if (str_starts_with($value, '@')) {
            return $this->get(substr($value, 1));
        }
        
        return $value;
    }
}

Container

services:
    App\Mailer: ~

	App\Listener\Weather:
        parameters:
        	notifier: '@App\Mailer'
class Mailer implements NotifierInterface
{
}

class WeatherListener
{
	public function __construct(private NotifierInterface $notifier) {}
}

Tout configurer à la main ?

@afup

@florianm__

Tout configurer à la main ?

Autowiring

@florianm__

@afup

services:
    App\Controller\RoutePlannerController:
    	parameters:
        	- '@App\Provider\WeatherProvider'
        	- '@App\PointOfInterestFinder'
        	- '@App\Repository\RouteRepository'

	App\Provider\WeatherProvider:
    	parameters:
        	apiKey: '%weather_provider.api_key%'
    
    App\PointOfInterestFinder: ~

    App\Repository\RouteRepository:
        parameters:
        	entityManager: '@App\EntityManager'

    App\EntityManager: ~
$ tree src/
src/
├── Controller
│   ├── RoutePlannerController.php
├── Provider
│   ├── WeatherProvider.php
├── Repository
│   ├── RouteRepository.php
├── EntityManager.php
├── PointOfInterestFinder.php
└── Kernel.php

3 directories, 6 files

Container

  • App\Controller\RoutePlannerController
  • App\Provider\WeatherProvider
  • App\PointOfInterestFinder
  • App\Repository\RouteRepository
  • App\EntityManager

Services

@afup

@florianm__

services:
    App\Controller\RoutePlannerController:
    	parameters:
        	- '@App\Provider\WeatherProvider'
        	- '@App\PointOfInterestFinder'
        	- '@App\Repository\RouteRepository'

	App\Provider\WeatherProvider:
    	parameters:
        	apiKey: '%weather_provider.api_key%'
    
    App\PointOfInterestFinder: ~

    App\Repository\RouteRepository:
        parameters:
        	entityManager: '@App\EntityManager'

    App\EntityManager: ~
autowiring:
    App\:
        resource: '../src/'
        exclude:
            - '../src/Command/'
            - '../src/Entity/'
            - '../src/Kernel.php'

services:
	App\Provider\WeatherProvider:
    	parameters:
        	apiKey: '%weather_provider.api_key%'

@afup

@florianm__

@afup

@florianm__

Choses à faire

  1. Trouver les services à "autowire"

  2. Autowire les dépendances

@afup

@florianm__

get(): mixed

🔎 

buildInstance(): mixed

👷

resolveDependencies(): array

resolveDependency(): mixed

📦

Étapes pour "get" un service

has(id) ?

@afup

@florianm__

final class ContainerBuilder
{
    public function buildContainer(): Container
    {
        $config = \yaml_parse_file('config.yaml');

        return new Container(
            config: $config,
            serviceIds: $this->resolveServiceIds($config),
        );
    }

    /**
     * @param string[] $config
     */
    private function resolveServiceIds(array $config): array
    {        
        return array_keys($config['services']);
    }
}

1- Trouver les services à "autowire"

@afup

@florianm__

final class ContainerBuilder
{
    public function buildContainer(): Container
    {
        $config = \yaml_parse_file('config.yaml');

        return new Container(
            config: $config,
            serviceIds: $this->resolveServiceIds($config),
        );
    }

    /**
     * @param string[] $config
     */
    private function resolveServiceIds(array $config): array
    {
        $ids = [
            ...array_keys($config['services']),
            ...ContainerBuilderHelper::findAutowirableServiceIds($config),
        ];

        return array_unique($ids);
    }
}

1- Trouver les services à "autowire"

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed
    // private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()] ?? null;
        
        // service
        if (str_starts_with($value, '@')) {
            return $this->get(substr($value, 1));
        }

        return $value;
    }
}

2- Autowire les dépendances

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed
    // private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()] ?? null;
     
     	if (null === $value) {
		    try {
        		return $this->get($constructorParameter->getType()->__toString());
    		} catch(NotFoundExceptionInterface) {
        		throw new ContainerException('Cannot autowire parameter');
    		}
		}
        
        // service
        if (str_starts_with($value, '@')) {
            return $this->get(substr($value, 1));
        }

        return $value;
    }
}

2- Autowire les dépendances

services:
    App\Controller\RoutePlannerController:
    	parameters:
        	- '@App\Provider\WeatherProvider'
        	- '@App\PointOfInterestFinder'
        	- '@App\Repository\RouteRepository'

	App\Provider\WeatherProvider:
    	parameters:
        	apiKey: '%weather_provider.api_key%'
    
    App\PointOfInterestFinder: ~

    App\Repository\RouteRepository:
        parameters:
        	entityManager: '@App\EntityManager'

    App\EntityManager: ~
autowiring:
    App\:
        resource: '../src/'
        exclude:
            - '../src/Command/'
            - '../src/Entity/'
            - '../src/Kernel.php'

services:
	App\Provider\WeatherProvider:
    	parameters:
        	apiKey: '%weather_provider.api_key%'

@afup

@florianm__

Recherche de points d'intérêt

📍

@afup

@florianm__

final class PointOfInterestHandler
{
    public function __construct(
        private HotelHandler $hotelHandler,
        private FuelHandler $fuelHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Hotel) {
            return $this->hotelHandler->handle($pointOfInterest);
        }

        if ($pointOfInterest instanceof Fuel) {
            return $this->fuelHandler->handle($pointOfInterest);
        }

        throw new \LogicException("No handler found");
    }
}

@afup

@florianm__

final class PointOfInterestHandler
{
    public function __construct(
        private HotelHandler $hotelHandler,
        private FuelHandler $fuelHandler,
        private FoodHandler $foodHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Hotel) {
            return $this->hotelHandler->handle($pointOfInterest);
        }

        if ($pointOfInterest instanceof Fuel) {
            return $this->fuelHandler->handle($pointOfInterest);
        }

        if ($pointOfInterest instanceof Food) {
            return $this->foodHandler->handle($pointOfInterest);
        }

        throw new \LogicException("No handler found");
    }
}

@afup

@florianm__

Chaine de responsabilités

⛓️

@afup

@florianm__

final class PointOfInterestHandler
{
    /** @param iterable<HandlerInterface> $handlers */
    public function __construct(
        private iterable $handlers,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        foreach ($this->handlers as $handler) {
            if ($handler->can($pointOfInterest)) {
                return $handler->handle($pointOfInterest);
            }
        }

        throw new \LogicException("No handler found");
    }
}

@afup

@florianm__

interface HandlerInterface
{
    public function can(PointOfInterest $pointOfInterest): bool;

    public function handle(PointOfInterest $pointOfInterest): mixed;
}

@afup

@florianm__

services:
    App\PointOfInterestHandler:
        parameters:
            handlers: '!tagged_iterator point_of_interest_handler'

    App\HotelHandler:
        tags:
            - { name: 'point_of_interest_handler' }

    App\FuelHandler:
        tags:
            - { name: 'point_of_interest_handler' }

    App\FoodHandler:
        tags:
            - { name: 'point_of_interest_handler' }

🚩

🚩

🚩

🪣

🚩

🚩

🚩

@afup

@florianm__

get(): mixed

🔎 

buildInstance(): mixed

👷

resolveDependencies(): array

resolveDependency(): mixed

📦

Étapes pour "get" un service

@afup

@florianm__

final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed
    // private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()];
        
        // service
        if (str_starts_with($value, '@')) {
            return $this->get(substr($value, 1));
        }

        return $value;
    }
}
services:
    App\PointOfInterestHandler:
        parameters:
            handlers: '!tagged_iterator point_of_interest_handler'

@afup

@florianm__

// tagged iterator
if (str_starts_with($value, '!tagged_iterator ')) {
    $tag = substr($value, 17);

    // find service with a specific tag
    $taggedServiceListConfig = ContainerHelper::findTaggedServices(
        $tag,
        $this->config['services']
    );
    
    $taggedServices = [];
    foreach ($taggedServiceListConfig as $id => $taggedServiceConfig) {
        $taggedServices[] = $this->get($id);
    }

    return $taggedServices;
}
final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed
    // private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()];
        
        // service
        if (str_starts_with($value, '@')) {
            return $this->get(substr($value, 1));
        }

        return $value;
    }
}
services:
    App\PointOfInterestHandler:
        parameters:
            handlers: '!tagged_iterator point_of_interest_handler'

Recherche de points d'intérêt

📍

@afup

@florianm__

final class PointOfInterestHandler
{
    public function __construct(
        private HotelHandler $hotelHandler,
        private FuelHandler $fuelHandler,
        private FoodHandler $foodHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Hotel) {
            return $this->hotelHandler->handle($pointOfInterest);
        }

        if ($pointOfInterest instanceof Fuel) {
            return $this->fuelHandler->handle($pointOfInterest);
        }

        if ($pointOfInterest instanceof Food) {
            return $this->foodHandler->handle($pointOfInterest);
        }

        throw new \LogicException("No handler found");
    }
}

@afup

@florianm__

final class HotelHandler implements HandlerInterface
{
    public function __construct(
        private ?HandlerInterface $nextHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Hotel) {
        	// do stuff

        	return 'hotel';
        }
        
        if ($this->nextHandler) {
        	return $this->nextHandler->handle($pointOfInterest);
		}
        
        throw new \LogicException("No handler found");   
    }
}

@afup

@florianm__

final class HotelHandler implements HandlerInterface
{
    public function __construct(
        private ?HandlerInterface $nextHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Hotel) {
        	// do stuff

        	return 'hotel';
        }
        
        if ($this->nextHandler) {
        	return $this->nextHandler->handle($pointOfInterest);
		}
        
        throw new \LogicException("No handler found");   
    }
}

@afup

@florianm__

final class FuelHandler implements HandlerInterface
{
    public function __construct(
        private ?HandlerInterface $nextHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Fuel) {
        	// do stuff

        	return 'fuel';
        }
        
        if ($this->nextHandler) {
        	return $this->nextHandler->handle($pointOfInterest);
		}
        
        throw new \LogicException("No handler found");   
    }
}
final class FoodHandler implements HandlerInterface
{
    public function __construct(
        private ?HandlerInterface $nextHandler,
    ) {
    }

    public function handle(PointOfInterest $pointOfInterest): mixed
    {
        if ($pointOfInterest instanceof Food) {
        	// do stuff

        	return 'food';
        }
        
        if ($this->nextHandler) {
        	return $this->nextHandler->handle($pointOfInterest);
		}
        
        throw new \LogicException("No handler found");   
    }
}

Décoration

@afup

@florianm__

@afup

@florianm__

Configuration

HotelHandler

FuelHandler

FoodHandler

HandlerInterface

@afup

@florianm__

Configuration

services:
    point_of_interest_handler:
        class: App\HotelHandler

    App\FuelHandler:
        decorates: point_of_interest_handler
        parameters:
            nextHandler: '@.inner'

    App\FoodHandler:
        decorates: point_of_interest_handler
        parameters:
            nextHandler: '@.inner'

HotelHandler

FuelHandler

FoodHandler

point_of_interest_handler

@afup

@florianm__

get(): mixed

🔎 

buildInstance(): mixed

👷

resolveDependencies(): array

resolveDependency(): mixed

📦

Étapes pour "get" un service

@afup

@florianm__

final class Container implements ContainerInterface
{    
    public function get(string $id): mixed
    {
        if (false === $this->has($id)) {
            throw new NotFoundException();
        }

        if (false === array_key_exists($id, $this->services)) {
            $this->services[$id] =  $this->buildInstance($id);
        }

        return $this->services[$id];
    }

	// private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    // private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
}
services:
    point_of_interest_handler:
        class: App\HotelHandler

    App\FuelHandler:
        decorates: point_of_interest_handler
        parameters:
            nextHandler: '@.inner'

    App\FoodHandler:
        decorates: point_of_interest_handler
        parameters:
            nextHandler: '@.inner'

@afup

@florianm__

final class Container implements ContainerInterface
{    
    public function get(string $id): mixed
    {
        if (false === $this->has($id)) {
            throw new NotFoundException();
        }

        if (false === array_key_exists($id, $this->services)) {
            $this->services[$id] =  $this->buildInstance(
                ContainerHelper::getMainId($id, $this->serviceIds, $this->config),
            );
        }

        return $this->services[$id];
    }

	// private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    // private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
}

@afup

@florianm__

// decoration
if (str_starts_with($value, '@.inner')) {
	$stack = ContainerHelper::getDecorationStack($id, $this->serviceIds, $this->config);
	$currentPosition = array_search($id, array_keys($stack));

	return $this->buildInstance(array_keys($stack)[$currentPosition - 1]);
}
final class Container implements ContainerInterface
{    
    // public function get(string $id): mixed
    // private function buildInstance(string $id): mixed
    // private function resolveDependencies(array $constructorParameterList, array $serviceConfig): array
    
    private function resolveDependency(ReflectionParameter $constructorParameter, array $serviceConfig): mixed
    {
        $value = $serviceConfig['parameters'][$constructorParameter->getName()];
        
        // service
        if (str_starts_with($value, '@')) {
            return $this->get(substr($value, 1));
        }

        return $value;
    }
}
  • point_of_interest_handler
  • App\FuelHandler
  • App\FoodHandler

Récupérer la météo

🌞

@afup

@florianm__

composer require cmfcmf/openweathermap-php-api

@afup

@florianm__

@afup

@florianm__

<?php

use Cmfcmf\OpenWeatherMap;
use Cmfcmf\OpenWeatherMap\Exception as OWMException;
use Http\Factory\Guzzle\RequestFactory;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;

$httpRequestFactory = new RequestFactory();
$httpClient = GuzzleAdapter::createWithConfig([]);

$owm = new OpenWeatherMap('YOUR-API-KEY', $httpClient, $httpRequestFactory);

$weather = $owm->getWeather('Berne', 'metric', 'ch');
echo $weather->temperature;

Factory

@afup

@florianm__

services:
    weather.client:
        factory: ['@App\Weather\ClientFactory', 'create']

@afup

@florianm__

get(): mixed

🔎 

buildInstance(): mixed

👷

resolveDependencies(): array

resolveDependency(): mixed

📦

Étapes pour "get" un service

@afup

@florianm__

services:
    weather.client:
        factory: ['@App\Weather\ClientFactory', 'create']
final class Container implements ContainerInterface
{
	// ...

	private function buildInstance(string $id): mixed
    {
        $serviceConfig = $this->config['services'][$id] ?? [];

        $reflector = new \ReflectionClass($serviceConfig['class'] ?? $id);
        if (!$reflector->isInstantiable()) {
            throw new ContainerException("Service $id is not instantiable");
        }

        $constructor = $reflector->getConstructor();
        if (null === $constructor || empty($constructor->getParameters())) {
            $instance = $reflector->newInstance();
        } else {
            $parameters = $this->resolveDependencies($constructor->getParameters(), $serviceConfig);
            $instance = $reflector->newInstanceArgs($parameters);
        }

        return $instance;
    }
}

@afup

@florianm__

final class Container implements ContainerInterface
{
	// ...

	private function buildInstance(string $id): mixed
    {
        $serviceConfig = $this->config['services'][$id] ?? [];

        $factoryConfig = $serviceConfig['factory'] ?? null;
        if ($factoryConfig !== null) {
            $factoryServiceId = substr($factoryConfig[0], 1);
            $factoryMethod = $factoryConfig[1];
            
            return $this->get($factoryServiceId)->$factoryMethod();
        }

        $reflector = new \ReflectionClass($serviceConfig['class'] ?? $id);
        if (!$reflector->isInstantiable()) {
            throw new ContainerException("Service $id is not instantiable");
        }

        $constructor = $reflector->getConstructor();
        if (null === $constructor || empty($constructor->getParameters())) {
            $instance = $reflector->newInstance();
        } else {
            $parameters = $this->resolveDependencies($constructor->getParameters(), $serviceConfig);
            $instance = $reflector->newInstanceArgs($parameters);
        }

        return $instance;
    }
}
services:
    weather.client:
        factory: ['@App\Weather\ClientFactory', 'create']

@afup

@florianm__

class ClientFactory
{
	public function __construct(private string $apiKey) {}

	pulbic function create(): OpenWeatherMap
    {
		return new OpenWeatherMap(
        	$this->apiKey,
            GuzzleAdapter::createWithConfig([]),
            new RequestFactory(),
        );
    }
}
services:
    weather.client:
        factory: ['@App\Weather\ClientFactory', 'create']

Integration avec Symfony

@afup

@florianm__

@afup

@florianm__

CustomContainer

  • App\Controller\RoutePlannerController      
  • App\Provider\WeatherProvider
  • App\PointOfInterestFinder

Services

Container

  • kernel                                             
  • event_dispatcher
  • request_stack
  • router.default

Services

@afup

@florianm__

CustomContainer

  • App\Controller\RoutePlannerController      
  • App\Provider\WeatherProvider
  • App\PointOfInterestFinder

Services

Container

  • kernel                                             
  • event_dispatcher
  • request_stack
  • router.default
  • App\Controller\RoutePlannerController
  • App\Provider\WeatherProvider
  • App\PointOfInterestFinder

Services

@afup

@florianm__

class Kernel extends BaseKernel
{
    use MicroKernelTrait;
}

@afup

@florianm__

use App\DependencyInjection\Container as CustomContainer;
use App\DependencyInjection\ContainerBuilder as CustomContainerBuilder;

class Kernel extends BaseKernel
{
    use MicroKernelTrait;
    private CustomContainer $customContainer;

    public function boot(): void
    {
        $containerBuilder = new CustomContainerBuilder();
        $this->customContainer = $containerBuilder->buildContainer();

        parent::boot();
    }
}

@afup

@florianm__

class Kernel extends BaseKernel
{
    use MicroKernelTrait;
    private CustomContainer $customContainer;

    // public function boot(): void
    
    protected function initializeContainer(): void
    {
        parent::initializeContainer();

        foreach ($this->customContainer->getIds() as $id) {
            $this->container->set($id, $this->customContainer->get($id));
        }
    }
}

@afup

@florianm__

class Kernel extends BaseKernel
{
    use MicroKernelTrait;
    private CustomContainer $customContainer;

    // public function boot(): void
    // protected function initializeContainer(): void
    
    protected function build(ContainerBuilder $container): void
    {
        $container->addCompilerPass(
        	new RegisterCustomServicesCompilerPass($this->customContainer)
        );
    }
}
class RegisterCustomServicesCompilerPass implements CompilerPassInterface
{
	public function __construct(
    	private readonly CustomContainer $customContainer
    ) {
    }

	public function process(ContainerBuilder $container): void
    {
    	foreach ($this->customContainer->getIds() as $id) {
        	$service = $this->customContainer->get($id);
            
            $definition = new Definition(get_class($service));
            $definition->setSynthetic(true);

			$container->setDefinition($id, $definition);
        }
    }
}

Démo'

@afup

@florianm__

🎬

Services

Paramètres

Tags

Compiler pass

Référence circulaire

Alias

Configurator

Factory

Lazy Services

Immutable-setter Injection

Service Closures

Decoration

Service locator

Non Shared Services

Synthetic services

Parent Services

@afup

@florianm__

Autowiring

  • SOLID 💪

  • Différents environnements 🎭

  • Optimisation 🚀

  • Configuration facilitée👌

@afup

@florianm__

Merci 🙏

[AFUP Day Lyon 2024] DI

By Florian David Merle