Syllz
Syllz

Reputation: 340

Symfony: Explicit define Container in Service

After updating I have this deprecation:

Since symfony/dependency-injection 5.1: The "Symfony\Component\DependencyInjection\ContainerInterface" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it. It is being referenced by the "App\Service\ImportService" service.

Here is my ImportService:

<?php

namespace App\Service;

use Symfony\Component\DependencyInjection\ContainerInterface;

class ImportService
{
    private $doctrine;
    private $em;

    public function __construct(ContainerInterface $container)
    {
        $this->doctrine = $container->get('doctrine'); //needed for database queries
        $this->em = $this->doctrine->getManager(); //needed for database queries
    }

    /** more methods here **/

}

So how exactly do I make it explicit? I googled a bit and I think that I have to add it to my services.yml file somehow. But I am unsure how + do I have to do it for every Service class?

Upvotes: 12

Views: 12675

Answers (4)

Cerad
Cerad

Reputation: 48865

I just created a new 5.1 app and did not get the deprecation. Symfony is really discouraging the injection of the global container. So I am not surprised it is being deprecated.

To fix the message, all you need to do is to explicitly define the ContainerInterface alias:

# services.yml or yaml 
services:
    Symfony\Component\DependencyInjection\ContainerInterface: '@service_container'

That should do the trick. However, since you appear to be moving to 5.1 then you should start refactoring your code and only inject what a particular class needs. It is not mandatory but will save you from problems down the line:

class ImportService
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em
    }

Upvotes: 21

TheKeymaster
TheKeymaster

Reputation: 897

As already apposed by the original answer, the correct way is to only inject the services you really need.

But in case you are extending on already existing code and the existing code changes with a new update and you want to allow backwards-compatibility, it is sometimes easier and more effective to use the ContainerInterface instead.

As some developers also prefer XML over YAML, here are both solutions:

services.yml (if you use yaml)

services:
    Symfony\Component\DependencyInjection\ContainerInterface: '@service_container'

services.xml (if you use XML)

<?xml version="1.0" ?>
<container
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
>
    <services>
        <service
            id="Symfony\Component\DependencyInjection\ContainerInterface"
            alias="service_container"
        />
    </services>
</container>

Upvotes: 1

Tomas Votruba
Tomas Votruba

Reputation: 24280

While other answers with injecting container will work as a quick solution, it's contra the point of this deprecation - to remove all container use from PHP code.

AFAIK Symfony, this will be more and more strict in the future, so you'll have to come back to the code and refactor it anyway.

Refactor to Dependency Injection

If you want to make your code future proof, refactor to constructor injection:

<?php

namespace App\Service;

use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;

final class ImportService
{
    private Connection $connection;

    private EntityManagerInterface $entityManager;

    public function __construct(
        Connection $connection,
        EntityManagerInterface $entityManager
    ) {
        $this->connection = $connection;
        $this->entityManager = $entityManager;
    }

    /** more methods here **/
}

Upvotes: 6

Kargpfen
Kargpfen

Reputation: 316

You must define the '@service_container' argument in your service.yaml.

# services.yml or yaml 
services:
  Symfony\Component\DependencyInjection\ContainerInterface: '@service_container'
  
  Namespace\ImportService:
    arguments:
      - '@service_container'

Then you can use the ContainerInterface as constructor parameter.

Upvotes: 4

Related Questions