Read More
Read More
Menu Close

    Autowiring in Symfony

    In this blog we are going to learn about Autowiring in Symfony.

    In modern programming uses of dependency injection (DI) is very common.

    What is DI (Dependency Injection) ?

    Usually, Classes require instances of other classes for their internal uses. So an object receives its required object.

    • These required classes are called dependencies.
    • The code which passes the dependency to the receiving object is called dependency injector.
    • DI is used to make the classes completely loosely coupled.

    Lets see how class declare dependencies objects in the __construct method :

    Start your headless eCommerce
    now.
    Read More
    // Motor class requires Engine object dependency through constructor
    Class Motor {
      private $engine;
      public function __construct(Engine $engine) {
        $this->engine = $engine;
        
        //....
      }
    
      //.....
    }

    In the above example, to pass Engine object dependency, we have to pass the object while creating the Motor class object. read dependency injection here

    So above is a general idea of dependency injection. We have to create and pass object to the other objects manually.

    Autowiring is one step ahead of dependency injection.

    What is Autowiring ?

    Autowiring is process in which container create and inject object dependencies automatically.

    So you need not to pass dependencies manually. Receiving object will get the needed dependency automatically.

    Note:

    • Symfony uses PHP-DI. It works alongside Symfony’s container.
    • PHP-DI uses PHP’s reflection to detect what parameters a constructor needs.
    • PHP-DI provides an easy and clean integration with Symfony that does not replace the original container: all bundles and existing code still work the same. reference: https://php-di.org/doc/autowiring.html

    How autowiring works in Symfony ?

    Using Autowiring, you can manage services in the container with minimal configuration.
    In autowiring, type-hints in your constructor or other methods are read and the correct services are passed automatically to each method.

    What is Service Container ?

    We create Services in Symfony for creating reusable codes/methods. There are many useful objects in symfony application like “Mailer” object to send emails and many more.

    In Symfony, all the services live inside a very special object which is called the Service Container.
    Service container centralises all the services.

    Lets understand the Autowiring process in Symfony with an example.

    Lets create a service in the application at ../src/Service/CouponCodeGenerator.php

    // src/Service/CouponCodeGenerator.php
    
    namespace App\Service;
    
    class CouponCodeGenerator
    {
        public function generateRandomCode($length = 8)
        {
            $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
            $randomNumber = '';
            for ($i = 0; $i < $length; ++$i) {
                $randomNumber = $randomNumber.$characters[mt_rand(0, Tools::strlen($characters) - 1)];
            }
    
            return $randomNumber;
        }
    }

    Now we can use this service in our controller in the application at ../src/Controller/CouponController.php

    // src/Controller/CouponController.php
    
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    
    // get the service namespace to include the CouponCodeGenerator service
    use App\Service\CouponCodeGenerator;
    
    class CouponController extends AbstractController
    {
      /**
       * @Route("/coupon/new")
       */
      public function new(CouponCodeGenerator $codeGenerator): Response
      {
          $couponCode = $codeGenerator->generateRandomCode();
          
          // Use this $couponCode as per your requirements
          // ...
      
          return new Response('Return your content');
      }
    }

    In the above controller, in new(..) method CouponCodeGenerator service is a dependency object. We are using this dependency in the method.

    We need not to worry passing this dependency to the controller. Service Container will take care of it automatically.

    In services.yml file Autowiring is by default enabled for all the services

    # config/services.yaml
    services:
        # default configuration for services in *this* file
        _defaults:
            autowire: true      # Automatically injects dependencies in your services.
            autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
    
        # makes classes in src/ available to be used as services
        # this creates a service per class whose id is the fully-qualified class name
        App\:
            resource: '../src/*'
            exclude: '../src/{DependencyInjection,Entity,Tests,Kernel.php}'

    In the above services configuration file, you can see autowire and autoconfigure options are enabled. So these options must be enabled for service for autowiring.

    Important Note:

    If controller extends AbstractController the you have not to do any things for autowiring to work in your controller. in this case, controllers automatically registered as services. And you can use dependency injection like services.

    But if controller does not extend the AbstractController then you have to register your controller as a service.

    # config/services.yaml
    
    #....
    
    App\Controller\:
       resource: '../src/Controller/'
       tags: ['controller.service_arguments']
    
    #....

    controller.service_arguments tag can be applied to controller services. through this tagged services will be public and available to inject services in method arguments.

    Your routing config also need to reference the service properly, so that Symfony knows to use it.
    To refer to controller method, Use syntax the service_id::method_name. If the service id is the Class name of controller(recommended) then the syntax will be as if the controller was not a service

    ex. App\Controller\CouponController::new

    How to know available services for autowiring?

    So in symfony you can see all the Services available through below symfony console command.

    php bin/console debug:autowiring

    If you want to see availability of any specific Services then use symfony console command.
    Below command to check CouponCodeGenerator service.

    php bin/console debug:autowiring CouponCodeGenerator

    So this is how symfony use Service Containers for autowiring. Its a great feature of the symfony framework.

    Hope this blog will help you understanding autowiring concept.

    Thanks for reading. Happy coding. 🙂

    References:
    https://symfony.com/doc/current/service_container.html
    https://en.wikipedia.org/wiki/Dependency_injection

    . . .
    Discuss on Helpdesk

    Leave a Comment

    Your email address will not be published. Required fields are marked*


    Be the first to comment.

    Back to Top