skrz / autowiring-bundle

Autowiring + automatic service discovery for Symfony DI container
MIT License
8 stars 6 forks source link

Skrz\Bundle\AutowiringBundle

Build Status Quality Score Code Coverage Downloads this Month Latest stable

Annotation-based autowiring for Symfony 4 dependency injection container

Installation

Add as Composer dependency:

$ composer require skrz/autowiring-bundle

Then add SkrzAutowiringBundle to Symfony Kernel:

use Skrz\Bundle\AutowiringBundle\SkrzAutowiringBundle;

class AppKernel
{

    public function registerBundles()
    {
        return [
            ...
            new SkrzAutowiringBundle()
            ...
        ];
    }

}

Usage

Annotate your application components using @Component annotation and its subclasses, or so called "stereotypes". Predefined stereotypes are @Controller, @Repository, and @Service, e.g.:

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;

/**
 * @Controller
 */
class HomepageController
{
    ...
}

Create your own application stereotypes by subclassing @Component.

Constructor dependency injection

// services.yml
services:
  Example\HomepageController: ~
namespace Example;

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;

/**
 * @Controller
 */
class HomepageController
{

    /**
     * @var SomeService
     */
    private $someService;

    public function __construct(SomeService $someService)
    {
        $this->someService = $someService;
    }

    ...

}

SomeService is automatically injected into HomepageController instance during creation in container.

Note that constructor is ALWAYS autowired if there is not enough arguments specified in services.yml. If you really do not want the constructor to be autowired, add the service to ignored_services configuration directive.

Note: if you need to specify some of the constructor arguments and autowire other constructor aurguments, you need to configure your service the following way:

// services.yml
services:
  Example\HomepageController:
    arguments: 
      someParameter: %kernel.whatever%
namespace Example;

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;

/**
 * @Controller
 */
class HomepageController
{

    /**
     * @var SomeService
     */
    private $someService;

    /**
     * @var string
     */
    private $someParameter;

    public function __construct(SomeService $someService, $someParameter)
    {
        $this->someService = $someService;
        $this->someParameter = $someParameter;
    }

    ...

}

The $someService argument is autowired and the $someParameter argument is injected depending on the configuration.

Method dependency injection

// services.yml

services:
  Example\HomepageController: ~
namespace Example;

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;
use Skrz\Bundle\AutowiringBundle\Annotation\Autowired;

/**
 * @Controller
 */
class HomepageController
{

    /**
     * @var SomeService
     */
    private $someService;

    /**
     * @param SomeService $someService
     * @return void
     *
     * @Autowired
     */
    public function setSomeService(SomeService $someService)
    {
        $this->someService = $someService;
    }

    ...

}

Property dependency injection

// services.yml

services:
  Example\HomepageController: ~
namespace Example;

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;
use Skrz\Bundle\AutowiringBundle\Annotation\Autowired;

/**
 * @Controller
 */
class HomepageController
{

    /**
     * @var SomeService
     *
     * @Autowired
     */
    public $someService;

    ...

}

Note: using property dependency injection is quite addictive.

Property parameter injection

You can also inject container parameters using @Value annotation.

// services.yml

services:
  Example\HomepageController: ~
namespace Example;

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;
use Skrz\Bundle\AutowiringBundle\Annotation\Value;

/**
 * @Controller
 */
class HomepageController
{

    /**
     * @var string
     *
     * @Value("%kernel.root_dir%")
     */
    public $rootDir;

    ...

}

Pro-Tip: inject always scalar values, do not inject arrays. When you inject scalar values, their presence in container is validated during container compilation.

Autoscan

Autoscan was a feature of version 1.x of SkrzAutowiringBundle. However, since Symfony 4.0, container supports this feature natively. Therefore, it was removed from the bundle and you should use resource key to import directories of services.

// services.yml

services:
  Example\:
    resource: "../path/to/controllers/*Controller.php"
namespace Example;

use Skrz\Bundle\AutowiringBundle\Annotation\Controller;
use Skrz\Bundle\AutowiringBundle\Annotation\Autowired;

/**
 * @Controller
 */
class HomepageController
{

    /**
     * @var SomeService
     *
     * @Autowired
     */
    public $someService;

    ...

}

Configuration

# container extension key is "autowiring"
autowiring:

  # these service IDs won't be processed by autowiring
  ignored_services:
    # either specify exact service IDs
    - kernel
    - http_kernel

    # or use regular expressions (they must start with "/")
    - /^debug\./
    - /^file/

  # match interfaces to exact services
  preferred_services:
    Psr\Log\LoggerInterface: logger
    Monolog\Logger: logger
    Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface: session.storage.native

  # if you create your own stereotypes, you must add then here
  fast_annotation_checks: [ @Task, @Widget ]

License

The MIT license. See LICENSE file.