From 867e2afcb2434d4c0ba25991d14565ad62b46606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 17 Dec 2015 00:23:28 +0100 Subject: [PATCH 1/5] [DependencyInjection] Autowiring doc --- .../dependency_injection/autowiring.rst | 411 ++++++++++++++++++ components/map.rst.inc | 1 + 2 files changed, 412 insertions(+) create mode 100644 components/dependency_injection/autowiring.rst diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst new file mode 100644 index 00000000000..518ea484623 --- /dev/null +++ b/components/dependency_injection/autowiring.rst @@ -0,0 +1,411 @@ +.. index:: + single: DependencyInjection; Autowiring + +Using the Autowiring +==================== + +Autowiring allows to register services in the container with minimal configuration. +It is practical in the field of Rapid Application Development, when designing prototypes +and in early stages of large projects. It makes it easy to bootstrap an app service +graph and eases refactoring. + +Let’s see how it works. To do so we will build a fake API publishing statutes on a Twitter +feed obfuscated with ROT13 (a special case of the Caesar cipher). + +Start by creating a ROT13 transformer class:: + + // src/AppBundle/Rot13Transformer.php + + namespace AppBundle; + + class Rot13Transformer + { + public function transform($value) + { + return str_rot13($value); + } + } + +And now a Twitter client using this transformer:: + + // src/AppBundle/TwitterClient.php + + namespace AppBundle; + + class TwitterClient + { + private $rot13Transformer; + + public function __construct(Rot13Transformer $rot13Transformer) + { + $this->rot13Transformer = $rot13Transformer; + } + + public function tweetInRot13($user, $key, $status) + { + $transformedStatus = $this->rot13Transformer->transform($status); + + // Connect to Twitter and send the encoded status + } + } + + +The Dependency Injection Component is now able to automatically register the dependencies +of this ``TwitterClient`` class. The ``twitter_client`` service definition just +need to be marked as autowired: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + + services: + twitter_client: + class: AppBundle\TwitterClient + autowire: true + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Definition; + + // ... + $definition = new Definition('AppBundle\TwitterClient'); + $definition->setAutowired(true); + + $container->setDefinition('twitter_client', $definition); + +The autowiring subsystem will parse the constructor of the ``TwitterClient`` class +and detects its dependencies that way. Here it will find and fill the need for +an instance of a ``Rot13Transformer``. + +If an existing service definition (and only one – see below) is of the needed type, +it will inject it. Here it’s not the case, but the subsystem is smart enough to +automatically register a private service for the Rot13Transformer class and set +it as first argument of the ``twitter_client`` service. Again, it can work only +if there is one class of the given type. If there are several classes of the same +type, you must fallback to the explicit service definition or register a default +implementation. + +As you can see, the autowiring feature drastically reduces the amount of configuration +required to define a service. No more arguments section! It also makes it easy +to change the dependencies of the ``TwitterClient`` class: just add or remove typehinted +arguments in the constructor and you’re done. There is no need anymore to search +and edit related service definitions. + +Here is a typical controller using the ``twitter_client`` service:: + + // src/AppBundle/Controller/DefaultController.php + + namespace AppBundle\Controller; + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; + + class DefaultController extends Controller + { + /** + * @Route("/tweet") + * @Method("POST") + */ + public function tweetAction(Request $request) + { + $user = $request->request->get('user'); + $key = $request->request->get('key'); + $status = $request->request->get('status'); + + if (!$user || !$key || !$status) { + throw new BadRequestHttpException(); + } + + $this->get('twitter_client')->tweetInRot13($user, $key, $status); + + return new Response('OK'); + } + } + +You can give a try to the API with ``curl``:: + + curl -d "user=kevin&key=ABCD&status=Salut" http://localhost:8000/tweet + +It should return ``OK``. + +Working with Interfaces +----------------------- + +This is nice but when the application grows, it’s recommended to code against abstractions +instead of implementations: it allows to easily replace some dependencies without +modifying the class depending of them. + +To follow this best practice, constructor arguments must be typehinted with interfaces +and not concrete classes. It allows to replace easily the current implementation +if necessary. + +Let’s introduce a ``Rot13TransformerInterface``:: + + // src/AppBundle/Rot13TransformerInterface.php + + namespace AppBundle; + + interface Rot13TransformerInterface + { + public function transform($value); + } + +Then edit ``Rot13Transformer`` to make it implementing the new interface:: + + // ... + + class Rot13Transformer implements Rot13TransformerInterface + + // ... + + +And update ``TwitterClient`` to depend of this new interface:: + + class TwitterClient + { + // ... + + public function __construct(Rot13TransformerInterface $rot13Transformer) + { + // ... + } + + // ... + } + +Finally the service definition must be updated because, obviously, the autowiring +subsystem isn’t able to find itself the interface implementation to register:: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + + services: + rot13_transformer: + class: AppBundle\Rot13Transformer + + twitter_client: + class: AppBundle\TwitterClient + autowire: true + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Definition; + + // ... + $definition1 = new Definition('AppBundle\Rot13Transformer'); + $container->setDefinition('rot13_transformer', $definition1); + + $definition2 = new Definition('AppBundle\TwitterClient'); + $definition2->setAutowired(true); + $container->setDefinition('twitter_client', $definition2); + +The autowiring subsystem detects that the ``rot13_transformer`` service implements +the ``Rot13TransformerInterface`` and injects it automatically. Even when using +interfaces (and you should), building the service graph and refactoring the project +is easier than with standard definitions. + +Dealing with Multiple Implementations of the Same Type +------------------------------------------------------ + +Last but not least, the autowiring feature allows to specify the default implementation +of a given type. Let’s introduce a new implementation of the ``Rot13TransformerInterface`` +returning the result of the ROT13 transformation uppercased:: + + // src/AppBundle/UppercaseRot13Transformer.php + + namespace AppBundle; + + class UppercaseRot13Transformer implements Rot13TransformerInterface + { + private $rot13transformer; + + public function __construct(Rot13TransformerInterface $rot13transformer) + { + $this->rot13transformer = $rot13transformer; + } + + public function transform($value) + { + return strtoupper($this->rot13transformer->transform($value)); + } + } + +This class is intended to decorate the standard ROT13 transformer (or any other +implementation) and return it uppercased. + +We can now refactor the controller to add another endpoint leveraging this new +transformer:: + + // src/AppBundle/Controller/DefaultController.php + + namespace AppBundle\Controller; + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; + + class DefaultController extends Controller + { + /** + * @Route("/tweet") + * @Method("POST") + */ + public function tweetAction(Request $request) + { + return $this->tweet($request, 'twitter_client'); + } + + /** + * @Route("/tweet-uppercase") + * @Method("POST") + */ + public function tweetUppercaseAction(Request $request) + { + return $this->tweet($request, 'uppercase_twitter_client'); + } + + private function tweet(Request $request, $service) + { + $user = $request->request->get('user'); + $key = $request->request->get('key'); + $status = $request->request->get('status'); + + if (!$user || !$key || !$status) { + throw new BadRequestHttpException(); + } + + $this->get($service)->tweetInRot13($user, $key, $status); + + return new Response('OK'); + } + } + +The last step is to update service definitions to register this new implementation +and a Twitter client using it:: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + + services: + rot13_transformer: + class: AppBundle\Rot13Transformer + autowiring_types: AppBundle\Rot13TransformerInterface + + twitter_client: + class: AppBundle\TwitterClient + autowire: true + + uppercase_rot13_transformer: + class: AppBundle\UppercaseRot13Transformer + autowire: true + + uppercase_twitter_client: + class: AppBundle\TwitterClient + arguments: [ @uppercase_rot13_transformer ] + + .. code-block:: xml + + + + + + + + + AppBundle\Rot13TransformerInterface + + + + + + + + + + .. code-block:: php + + use Symfony\Component\DependencyInjection\Reference; + use Symfony\Component\DependencyInjection\Definition; + + // ... + $definition1 = new Definition('AppBundle\Rot13Transformer'); + $definition1->setAutowiringTypes(array('AppBundle\Rot13TransformerInterface')); + $container->setDefinition('rot13_transformer', $definition1); + + $definition2 = new Definition('AppBundle\TwitterClient'); + $definition2->setAutowired(true); + $container->setDefinition('twitter_client', $definition2); + + $definition3 = new Definition('AppBundle\UppercaseRot13Transformer'); + $definition3->setAutowired(true); + $container->setDefinition('uppercase_rot13_transformer', $definition3); + + $definition4 = new Definition('AppBundle\TwitterClient'); + $definition4->addArgument(new Reference('uppercase_rot13_transformer')); + $container->setDefinition('uppercase_twitter_client', $definition4); + +It deserves some explanations. We now have 2 services implementing the ``Rot13TransformerInterface``. +The autowiring subsystem cannot guess the which one to use, this leads to errors +like:: + + [Symfony\Component\DependencyInjection\Exception\RuntimeException] + Unable to autowire argument of type "AppBundle\Rot13TransformerInterface" for the service "twitter_client". + +Fortunately, the ``autowiring_types`` key is here to specify which implementation +to use by default. This key can take a list of types if necessary (using a YAML +array). + +Thanks to this setting, the ``rot13_transformer`` service is automatically injected +as argument of the uppercase_rot13_transformer and twitter_client services. For +the ``uppercase_twitter_client``, we use a standard service definition to inject +the specific ``uppercase_rot13_transformer`` service. + +As for other RAD features such as the FrameworkBundle controller or annotations, +keep in mind to not use autowiring in public bundles nor in large projects with +complex maintenance needs. diff --git a/components/map.rst.inc b/components/map.rst.inc index dfead75f62c..64f2b8c70f2 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -46,6 +46,7 @@ * :doc:`/components/dependency_injection/types` * :doc:`/components/dependency_injection/parameters` * :doc:`/components/dependency_injection/definitions` + * :doc:`/components/dependency_injection/autowiring` * :doc:`/components/dependency_injection/synthetic_services` * :doc:`/components/dependency_injection/compilation` * :doc:`/components/dependency_injection/tags` From cbf7448c797069c831af66a71a8335919d484bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 22 Dec 2015 22:20:20 +0100 Subject: [PATCH 2/5] Merge @theofidry and @WouterJ changes --- .../dependency_injection/autowiring.rst | 64 ++++++++----------- components/dependency_injection/index.rst | 1 + 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst index 518ea484623..11445c70bc4 100644 --- a/components/dependency_injection/autowiring.rst +++ b/components/dependency_injection/autowiring.rst @@ -5,17 +5,16 @@ Using the Autowiring ==================== Autowiring allows to register services in the container with minimal configuration. -It is practical in the field of Rapid Application Development, when designing prototypes -and in early stages of large projects. It makes it easy to bootstrap an app service +It is useful in the field of `Rapid Application Development`_, when designing prototypes +in early stages of large projects. It makes it easy to bootstrap an app service graph and eases refactoring. -Let’s see how it works. To do so we will build a fake API publishing statutes on a Twitter -feed obfuscated with ROT13 (a special case of the Caesar cipher). +Imagine you're building an API to publish statuses on a Twitter feed, obfuscated +with `ROT13`.. (a special case of the Caesar cipher). Start by creating a ROT13 transformer class:: // src/AppBundle/Rot13Transformer.php - namespace AppBundle; class Rot13Transformer @@ -29,7 +28,6 @@ Start by creating a ROT13 transformer class:: And now a Twitter client using this transformer:: // src/AppBundle/TwitterClient.php - namespace AppBundle; class TwitterClient @@ -45,21 +43,19 @@ And now a Twitter client using this transformer:: { $transformedStatus = $this->rot13Transformer->transform($status); - // Connect to Twitter and send the encoded status + // ... connect to Twitter and send the encoded status } } -The Dependency Injection Component is now able to automatically register the dependencies -of this ``TwitterClient`` class. The ``twitter_client`` service definition just -need to be marked as autowired: +The Dependency Injection Component will be able able to automatically register the dependencies +of this ``TwitterClient`` class by marking the ``twitter_client`` service as autowired: .. configuration-block:: .. code-block:: yaml # app/config/services.yml - services: twitter_client: class: AppBundle\TwitterClient @@ -68,7 +64,6 @@ need to be marked as autowired: .. code-block:: xml - setDefinition('twitter_client', $definition); -The autowiring subsystem will parse the constructor of the ``TwitterClient`` class -and detects its dependencies that way. Here it will find and fill the need for -an instance of a ``Rot13Transformer``. - -If an existing service definition (and only one – see below) is of the needed type, -it will inject it. Here it’s not the case, but the subsystem is smart enough to -automatically register a private service for the Rot13Transformer class and set -it as first argument of the ``twitter_client`` service. Again, it can work only -if there is one class of the given type. If there are several classes of the same -type, you must fallback to the explicit service definition or register a default -implementation. +The autowiring subsystem will detect the dependencies of the ``TwitterClient`` +class by parsing its constructor. For instance it will find here an instance of +a ``Rot13Transformer`` as dependency. If an existing service definition (and only +one – see below) is of the required type, this service will be injected. If it +not the case (like in this example), the subsystem is smart enough to automatically +register a private service for the ``Rot13Transformer`` class and set it as first +argument of the `twitter_client``` service. Again, it can work only if there is one +class of the given type. If there are several classes of the same type, you must +use an explicit service definition or register a default implementation. As you can see, the autowiring feature drastically reduces the amount of configuration required to define a service. No more arguments section! It also makes it easy to change the dependencies of the ``TwitterClient`` class: just add or remove typehinted -arguments in the constructor and you’re done. There is no need anymore to search +arguments in the constructor and you are done. There is no need anymore to search and edit related service definitions. Here is a typical controller using the ``twitter_client`` service:: // src/AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; @@ -151,18 +143,17 @@ It should return ``OK``. Working with Interfaces ----------------------- -This is nice but when the application grows, it’s recommended to code against abstractions -instead of implementations: it allows to easily replace some dependencies without +You might also find yourself using abstractions instead of implementations (especially +in grown applications) as it allows to easily replace some dependencies without modifying the class depending of them. To follow this best practice, constructor arguments must be typehinted with interfaces and not concrete classes. It allows to replace easily the current implementation if necessary. -Let’s introduce a ``Rot13TransformerInterface``:: +Let's introduce a ``Rot13TransformerInterface``:: // src/AppBundle/Rot13TransformerInterface.php - namespace AppBundle; interface Rot13TransformerInterface @@ -194,14 +185,13 @@ And update ``TwitterClient`` to depend of this new interface:: } Finally the service definition must be updated because, obviously, the autowiring -subsystem isn’t able to find itself the interface implementation to register:: +subsystem isn't able to find itself the interface implementation to register:: .. configuration-block:: .. code-block:: yaml # app/config/services.yml - services: rot13_transformer: class: AppBundle\Rot13Transformer @@ -213,7 +203,6 @@ subsystem isn’t able to find itself the interface implementation to register:: .. code-block:: xml - - Date: Sun, 17 Jan 2016 19:47:38 +0100 Subject: [PATCH 3/5] Fix @javiereguiluz comments --- .../dependency_injection/autowiring.rst | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst index 11445c70bc4..14ed0b95ba2 100644 --- a/components/dependency_injection/autowiring.rst +++ b/components/dependency_injection/autowiring.rst @@ -1,13 +1,13 @@ .. index:: single: DependencyInjection; Autowiring -Using the Autowiring -==================== +Defining Services Dependencies Automatically +============================================ Autowiring allows to register services in the container with minimal configuration. It is useful in the field of `Rapid Application Development`_, when designing prototypes -in early stages of large projects. It makes it easy to bootstrap an app service -graph and eases refactoring. +in early stages of large projects. It makes it easy to register a service graph +and eases refactoring. Imagine you're building an API to publish statuses on a Twitter feed, obfuscated with `ROT13`.. (a special case of the Caesar cipher). @@ -47,8 +47,7 @@ And now a Twitter client using this transformer:: } } - -The Dependency Injection Component will be able able to automatically register the dependencies +The Dependency Injection Component will be able to automatically register the dependencies of this ``TwitterClient`` class by marking the ``twitter_client`` service as autowired: .. configuration-block:: @@ -87,10 +86,10 @@ of this ``TwitterClient`` class by marking the ``twitter_client`` service as aut The autowiring subsystem will detect the dependencies of the ``TwitterClient`` class by parsing its constructor. For instance it will find here an instance of a ``Rot13Transformer`` as dependency. If an existing service definition (and only -one – see below) is of the required type, this service will be injected. If it +one – see below) is of the required type, this service will be injected. If it's not the case (like in this example), the subsystem is smart enough to automatically register a private service for the ``Rot13Transformer`` class and set it as first -argument of the `twitter_client``` service. Again, it can work only if there is one +argument of the `twitter_client`` service. Again, it can work only if there is one class of the given type. If there are several classes of the same type, you must use an explicit service definition or register a default implementation. @@ -136,7 +135,7 @@ Here is a typical controller using the ``twitter_client`` service:: You can give a try to the API with ``curl``:: - curl -d "user=kevin&key=ABCD&status=Salut" http://localhost:8000/tweet + curl -d "user=kevin&key=ABCD&status=Hello" http://localhost:8000/tweet It should return ``OK``. @@ -376,7 +375,7 @@ and a Twitter client using it:: $container->setDefinition('uppercase_twitter_client', $definition4); It deserves some explanations. We now have 2 services implementing the ``Rot13TransformerInterface``. -The autowiring subsystem cannot guess the which one to use, this leads to errors +The autowiring subsystem cannot guess which one to use, this leads to errors like:: [Symfony\Component\DependencyInjection\Exception\RuntimeException] From 9999cc6a0d9918665b89fb9acb2455a9b2a253bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 31 Jan 2016 15:36:04 +0100 Subject: [PATCH 4/5] Change Rot13TransformerInterface to TransformerInterface --- .../dependency_injection/autowiring.rst | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst index 14ed0b95ba2..1090a3ac747 100644 --- a/components/dependency_injection/autowiring.rst +++ b/components/dependency_injection/autowiring.rst @@ -32,16 +32,16 @@ And now a Twitter client using this transformer:: class TwitterClient { - private $rot13Transformer; + private $transformer; - public function __construct(Rot13Transformer $rot13Transformer) + public function __construct(Rot13Transformer $transformer) { - $this->rot13Transformer = $rot13Transformer; + $this->transformer = $transformer; } - public function tweetInRot13($user, $key, $status) + public function tweet($user, $key, $status) { - $transformedStatus = $this->rot13Transformer->transform($status); + $transformedStatus = $this->transformer->transform($status); // ... connect to Twitter and send the encoded status } @@ -89,7 +89,7 @@ a ``Rot13Transformer`` as dependency. If an existing service definition (and onl one – see below) is of the required type, this service will be injected. If it's not the case (like in this example), the subsystem is smart enough to automatically register a private service for the ``Rot13Transformer`` class and set it as first -argument of the `twitter_client`` service. Again, it can work only if there is one +argument of the ``twitter_client`` service. Again, it can work only if there is one class of the given type. If there are several classes of the same type, you must use an explicit service definition or register a default implementation. @@ -127,7 +127,7 @@ Here is a typical controller using the ``twitter_client`` service:: throw new BadRequestHttpException(); } - $this->get('twitter_client')->tweetInRot13($user, $key, $status); + $this->get('twitter_client')->tweet($user, $key, $status); return new Response('OK'); } @@ -148,14 +148,14 @@ modifying the class depending of them. To follow this best practice, constructor arguments must be typehinted with interfaces and not concrete classes. It allows to replace easily the current implementation -if necessary. +if necessary. It also allows to use other transformers. -Let's introduce a ``Rot13TransformerInterface``:: +Let's introduce a ``TransformerInterface``:: - // src/AppBundle/Rot13TransformerInterface.php + // src/AppBundle/TransformerInterface.php namespace AppBundle; - interface Rot13TransformerInterface + interface TransformerInterface { public function transform($value); } @@ -164,7 +164,7 @@ Then edit ``Rot13Transformer`` to make it implementing the new interface:: // ... - class Rot13Transformer implements Rot13TransformerInterface + class Rot13Transformer implements TransformerInterface // ... @@ -175,7 +175,7 @@ And update ``TwitterClient`` to depend of this new interface:: { // ... - public function __construct(Rot13TransformerInterface $rot13Transformer) + public function __construct(TransformerInterface $transformer) { // ... } @@ -226,7 +226,7 @@ subsystem isn't able to find itself the interface implementation to register:: $container->setDefinition('twitter_client', $definition2); The autowiring subsystem detects that the ``rot13_transformer`` service implements -the ``Rot13TransformerInterface`` and injects it automatically. Even when using +the ``TransformerInterface`` and injects it automatically. Even when using interfaces (and you should), building the service graph and refactoring the project is easier than with standard definitions. @@ -234,29 +234,28 @@ Dealing with Multiple Implementations of the Same Type ------------------------------------------------------ Last but not least, the autowiring feature allows to specify the default implementation -of a given type. Let's introduce a new implementation of the ``Rot13TransformerInterface`` +of a given type. Let's introduce a new implementation of the ``TransformerInterface`` returning the result of the ROT13 transformation uppercased:: // src/AppBundle/UppercaseRot13Transformer.php namespace AppBundle; - class UppercaseRot13Transformer implements Rot13TransformerInterface + class UppercaseTransformer implements TransformerInterface { - private $rot13transformer; + private $transformer; - public function __construct(Rot13TransformerInterface $rot13transformer) + public function __construct(TransformerInterface $transformer) { - $this->rot13transformer = $rot13transformer; + $this->transformer = $transformer; } public function transform($value) { - return strtoupper($this->rot13transformer->transform($value)); + return strtoupper($this->transformer->transform($value)); } } -This class is intended to decorate the standard ROT13 transformer (or any other -implementation) and return it uppercased. +This class is intended to decorate the any transformer and return its value uppercased. We can now refactor the controller to add another endpoint leveraging this new transformer:: @@ -301,7 +300,7 @@ transformer:: throw new BadRequestHttpException(); } - $this->get($service)->tweetInRot13($user, $key, $status); + $this->get($service)->tweet($user, $key, $status); return new Response('OK'); } @@ -318,7 +317,7 @@ and a Twitter client using it:: services: rot13_transformer: class: AppBundle\Rot13Transformer - autowiring_types: AppBundle\Rot13TransformerInterface + autowiring_types: AppBundle\TransformerInterface twitter_client: class: AppBundle\TwitterClient @@ -342,7 +341,7 @@ and a Twitter client using it:: - AppBundle\Rot13TransformerInterface + AppBundle\TransformerInterface @@ -359,7 +358,7 @@ and a Twitter client using it:: // ... $definition1 = new Definition('AppBundle\Rot13Transformer'); - $definition1->setAutowiringTypes(array('AppBundle\Rot13TransformerInterface')); + $definition1->setAutowiringTypes(array('AppBundle\TransformerInterface')); $container->setDefinition('rot13_transformer', $definition1); $definition2 = new Definition('AppBundle\TwitterClient'); @@ -374,12 +373,12 @@ and a Twitter client using it:: $definition4->addArgument(new Reference('uppercase_rot13_transformer')); $container->setDefinition('uppercase_twitter_client', $definition4); -It deserves some explanations. We now have 2 services implementing the ``Rot13TransformerInterface``. +It deserves some explanations. We now have 2 services implementing the ``TransformerInterface``. The autowiring subsystem cannot guess which one to use, this leads to errors like:: [Symfony\Component\DependencyInjection\Exception\RuntimeException] - Unable to autowire argument of type "AppBundle\Rot13TransformerInterface" for the service "twitter_client". + Unable to autowire argument of type "AppBundle\TransformerInterface" for the service "twitter_client". Fortunately, the ``autowiring_types`` key is here to specify which implementation to use by default. This key can take a list of types if necessary (using a YAML From c8bc17f46c6803accdc75a2c57913880fb1630bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 31 Jan 2016 16:46:02 +0100 Subject: [PATCH 5/5] Fix YAML snippets --- components/dependency_injection/autowiring.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/dependency_injection/autowiring.rst b/components/dependency_injection/autowiring.rst index 1090a3ac747..86287d5d5a7 100644 --- a/components/dependency_injection/autowiring.rst +++ b/components/dependency_injection/autowiring.rst @@ -57,7 +57,7 @@ of this ``TwitterClient`` class by marking the ``twitter_client`` service as aut # app/config/services.yml services: twitter_client: - class: AppBundle\TwitterClient + class: 'AppBundle\TwitterClient' autowire: true .. code-block:: xml @@ -193,10 +193,10 @@ subsystem isn't able to find itself the interface implementation to register:: # app/config/services.yml services: rot13_transformer: - class: AppBundle\Rot13Transformer + class: 'AppBundle\Rot13Transformer' twitter_client: - class: AppBundle\TwitterClient + class: 'AppBundle\TwitterClient' autowire: true .. code-block:: xml @@ -316,20 +316,20 @@ and a Twitter client using it:: # app/config/services.yml services: rot13_transformer: - class: AppBundle\Rot13Transformer - autowiring_types: AppBundle\TransformerInterface + class: 'AppBundle\Rot13Transformer' + autowiring_types: 'AppBundle\TransformerInterface' twitter_client: - class: AppBundle\TwitterClient + class: 'AppBundle\TwitterClient' autowire: true uppercase_rot13_transformer: - class: AppBundle\UppercaseRot13Transformer + class: 'AppBundle\UppercaseRot13Transformer' autowire: true uppercase_twitter_client: - class: AppBundle\TwitterClient - arguments: [ @uppercase_rot13_transformer ] + class: 'AppBundle\TwitterClient' + arguments: [ '@uppercase_rot13_transformer' ] .. code-block:: xml