This document summarizes an presentation about dependency injection in Symfony 3.3 or greater. It discusses the service container and how it is used to instantiate services and inject their dependencies. It covers how to configure services and their dependencies, including using autowiring to simplify configuration. It also discusses autoconfiguring services as forms or commands. Finally, it presents options like _defaults and grouped declarations that can reduce configuration size.
1. Présentation par Vlad RIABCHENKO
Injection de dépendances dans Symfony >= 3.3
28
Nov 2017
2. Conteneur de services et
injection de dépendances
D I d a n s S y m f o n y > = 3 . 3
3. C o n t e n e u r d e s s e r v i c e s
D I d a n s S y m f o n y > = 3 . 3
Définitions Objets prêts-à-utiliser
$container->get('mailer');
$container->get('doctrine');
$container->get('app.customer');
app.customer:
class: AppBundleServiceCustomerSerivce
4. I n j e c t i o n d e d é p e n d a n c e s
D I d a n s S y m f o n y > = 3 . 3
But du conteneur de services:
• Garder les services et les fournir par son nom
• Instancier les services seulement à la demande
• Instancier les services en se basant sur leurs définitions
• Instancier les services en les approvisionnant de leur dépendances
app.form.user_type:
class: AppBundleFormUserType
arguments: ["@app.user"]
app.user:
class: AppBundleServiceUserService
arguments: ["@mailer"]
5. I n j e c t i o n d e d é p e n d a n c e s
D I d a n s S y m f o n y > = 3 . 3
app.form.user_type:
class: AppBundleFormUserType
arguments: ["@app.user"]
app.user:
class: AppBundleServiceUserService
arguments: ["@mailer"]
mailer:
class: Swift_Mailer
class UserService
{
public function __construct(Swift_Mailer $mailer)
{ }
}
class UserType
{
public function __construct(UserService $userSerivce)
{}
}
class Swift_Mailer
{ }
7. a u t o wi r e : t r u e
D I d a n s S y m f o n y > = 3 . 3
Autowiring simplifie la configuration de vos services.
Il lit les indications de type (Type-hints) sur le constructeur et passe automatiquement
les services corrects.
class UserType
{
/**
* Constructeur
*
* @param UserService $userService
* @param TokenStorageInterface $tokenStorage
* @param UrlGeneratorInterface $router
*/
public function __construct(
UserService $userService,
TokenStorageInterface $tokenStorage,
UrlGeneratorInterface $router
) { }
}
#services.yml
app.form.user_type:
class: AppBundleFormUserType
arguments:
- "@app.user"
- "@security.token_storage"
- "@router"
#services.yml
app.form.user_type:
class: AppBundleFormUserType
autowire: true
8. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
Il est possible de lister les services qui peuvent être autowired pour savoir quelle
classe/interfase il faut spécifier dans les paramètres de constructeur.
# php bin/console debug:container --types
------------------------------------------------------------------------------------ --------------------------------------------------------
Service ID Class name
------------------------------------------------------------------------------------ --------------------------------------------------------
AppBundleFormUserType AppBundleFormUserType
AppBundleServiceUserServiceA AppBundleServiceUserServiceA
AppBundleServiceUserServiceB AppBundleServiceUserServiceB
AppBundleServiceUserServiceInterface alias for "AppBundleServiceUserServiceA"
DoctrineCommonAnnotationsReader alias for "annotations.cached_reader"
DoctrineCommonPersistenceManagerRegistry alias for "doctrine"
DoctrineCommonPersistenceObjectManager alias for "doctrine.orm.default_entity_manager"
DoctrineDBALConnection alias for "doctrine.dbal.default_connection"
DoctrineDBALDriverConnection alias for "doctrine.dbal.default_connection"
DoctrineORMEntityManagerInterface alias for "doctrine.orm.default_entity_manager"
PsrCacheCacheItemPoolInterface alias for "cache.app"
PsrContainerContainerInterface alias for "service_container"
PsrLogLoggerInterface alias for "monolog.logger"
SessionHandlerInterface alias for "session.handler.native_file"
Swift_Mailer alias for "swiftmailer.mailer.default"
Swift_Spool alias for "swiftmailer.mailer.default.spool.memory"
9. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
class UserType
{
/**
* Constructeur
*
* @param UserServiceInterface $userService
*/
public function __construct(
UserServiceInterface $userService
) { }
}
Indications de type par interfaces.
(1/1) AutowiringFailedException
Cannot autowire service "app.form.user_type": argument "$userService" of
method "AppBundleFormUserType::__construct()" references interface
"AppBundleServiceUserServiceInterface" but no such service exists.
10. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
Nom de service = FQCN (fully qualified class name)
#services.yml
app.form.user_type:
class: AppBundleFormUserType
autowire: true
app.user.a:
class: AppBundleServiceUserServiceA
autowire: true
app.user.b:
class: AppBundleServiceUserServiceB
#services.yml
AppBundleFormUserType:
autowire: true
AppBundleServiceUserServiceA:
autowire: true
AppBundleServiceUserServiceB: ~
$this->get('app.form.user_type'); $this->get(UserType::class);
11. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
#services.yml
AppBundleFormUserType:
autowire: true
AppBundleServiceUserServiceA:
autowire: true
AppBundleServiceUserServiceB: ~
AppBundleServiceUserServiceInterface:
alias: "@AppBundleServiceUserServiceA"
AppBundleServiceUserServiceInterface: "@AppBundleServiceUserServiceA"
Alias est la solution pour l’indications de type par interfaces.
13. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
(1/1) AutowiringFailedException
Cannot autowire service "AppBundleFormUserType": argument "$minOrder" of method "__construct()" must have a type-
hint or be given a value explicitly.
class UserType
{
/**
* Constructeur
*
* @param UserServiceInterface $userService
* @param float $minOrder
* @param int $defaultCity
*/
public function __construct(
UserServiceInterface $userService,
$minOrder,
$defaultCity
) { }
}
#services.yml
parameters:
min_order: 50.5
default_city: Paris
services:
AppBundleFormUserType:
autowire: true
14. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
class UserType
{
/**
* Constructeur
*
* @param UserServiceInterface $userService
* @param float $minOrder
* @param int $defaultCity
*/
public function __construct(
UserServiceInterface $userService,
$minOrder,
$defaultCity
) { }
}
#services.yml
parameters:
min_order: 50.5
default_city: Paris
services:
AppBundleFormUserType:
autowire: true
arguments:
$defaultCity: "%default_city%"
$minOrder: "%min_order%"
15. D I d a n s S y m f o n y > = 3 . 3
a u t o wi r e : t r u e
#services.yml
parameters:
min_order: 50.5
default_city: Paris
services:
AppBundleFormUserType:
autowire: true
arguments:
$userService: "@AppBundleServiceUserServiceB"
$defaultCity: "%default_city%"
$minOrder: "%min_order%"
AppBundleServiceUserServiceA:
autowire: true
AppBundleServiceUserServiceB: ~
AppBundleServiceUserServiceInterface: "@AppBundleServiceUserServiceA"
Notion $arg permet spécifier une valeur ou un service souhaité
17. D I d a n s S y m f o n y > = 3 . 3
a u t o c o n f i g u r e : t r u e
Option autoconfigure enregistre automatiquement vos services en tant que
commandes, event subscribers, types de formulaire etc.
#services.yml
AppBundleFormUserType:
autowire: true
autoconfigure: true
AppBundleEventListenerUserEventSubscriber:
autoconfigure: true
#services.yml
AppBundleFormUserType:
autowire: true
tags: [{name: form.type}]
AppBundleEventListenerUserEventSubscriber:
tags: [{name: kernel.event_subscriber}] class UserEventSubscriber
implements EventSubscriberInterface
{
// implementation
}
class UserType extends AbstractType
{
// implementation
}
18. D I d a n s S y m f o n y > = 3 . 3
a u t o c o n f i g u r e : t r u e
Autoconfigure se base sur l’instance de service en utilisant operateur instanceof.
Instance tag
FormTypeInterface tags: [form.type]
EventSubscriberInterface tags: [kernel.event_subscriber]
Twig_ExtensionInterface tags: [twig.extension]
SymfonyComponentConsoleCommandCommand tags: [console.command]
… …
19. D I d a n s S y m f o n y > = 3 . 3
a u t o c o n f i g u r e : t r u e
Autoconfigure fonctionne à l’aide de clé _instanceof.
#services.yml
services:
_instanceof:
AppBundleDomainLoaderInterface:
public: true
tags: ['app.domain_loader']
Tous les services implémentant ce LoaderInterface seront publics et dotés de
‘app.domain_loader’ tag si la clé autoconfigure est activée pour eux.
21. D I d a n s S y m f o n y > = 3 . 3
_ d e f a u l t s
Clé _defaults permet de spécifier la configuration commune pour les services définis
dans un fichier.
#services.yml
services:
# default configuration for services in *this* file
_defaults:
autowire: true
autoconfigure: true
public: false
AppBundleFormUserType: ~
AppBundleServiceUserServiceA: ~
AppBundleServiceUserServiceB: ~
AppBundleServiceUserServiceInterface: "@AppBundleServiceUserServiceA"
23. D I d a n s S y m f o n y > = 3 . 3
D é c l a r a t i o n g r o u p é e
Déclaration groupée permet de réduire beaucoup la taille de configuration.
#services.yml
services:
# default configuration for services in *this* file
_defaults:
autowire: true
autoconfigure: true
public: true
# makes classes in src/AppBundle available to be used as services
# this creates a service per class whose id is the fully-qualified class name
AppBundle:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository,Tests}'
AppBundleServiceUserServiceInterface: "@AppBundleServiceUserServiceA"
25. D I d a n s S y m f o n y > = 3 . 3
Ta g c o n t r o l l e r. s e r v i c e _ a r g u m e n t s
Les contrôleurs sont dotés de controller.service_arguments tag pour faire fonctionner
l’autowiring lors d’appelle d’une action.
#services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
AppBundle:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository,Tests}'
# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
AppBundleController:
resource: '../../src/AppBundle/Controller'
public: true
tags: ['controller.service_arguments']
26. D I d a n s S y m f o n y > = 3 . 3
Ta g c o n t r o l l e r. s e r v i c e _ a r g u m e n t s
class DefaultController extends Controller
{
/**
* /**
* @Route("/", name="homepage")
*
* @param Request $request
* @param EntityManagerInterface $em
* @param UserServiceInterface $userService
* @param LoggerInterface $logger
*/
public function indexAction(
Request $request,
EntityManagerInterface $em,
UserServiceInterface $userService,
LoggerInterface $logger
) { }
}
27. R ETR OU VEZ W EBN ET
Merci
pour votre attention