Search code examples
symfonysymfony4symfony-4.3

Public service is handled as private


I have a library used by two Symfony apps, this library defines a set of services that I want to be public (I want to be able to retrieve them directly through the container. When I try to access one service I have this:

The "Library\Service\DerivedServices\OneSpecificImplementation" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.

The problem is that said service is declared public.

Basically there is:

  • a Library\Service\BaseService class that has two setters for the common dependencies (doctrine and a logger in this snippet);
  • several derived class (in the Library\Service\DerivedServices namespace), each defines a new service (with its own constructor to handle DI directly).

So here are my services definitions:

# Base: inject common dependencies
Library\Service\BaseService:
  abstract: true
  calls:
    - [setDoctrine, ['@doctrine.orm.entity_manager']]
    - [setLogger, ['@Library\Service\Logger']]

# These services are public to be retrieved directly by the container interface
Library\Service\DerivedServices\:
  resource: '../vendor/company/library/src/Library/Service/DerivedServices'
  public: true
  autowire: true
  autoconfigure: false
  parent: Library\Service\BaseService

Then, the Symfony application retrieves one derived service like:

$this->get('Library\Service\DerivedServices\OneSpecificImplementation');

These didn't make any difference:

  • I have changed the order of the service definitions
  • Both apps run Symfony 4.3.3

I think this is something trivial configuration-wise, but I can't pinpoint it (and after 2 hours trying to debug why the framework compiles my service as private, I thought that someone probably had this and could probably help me).


Solution

  • It turns out the order of declaration of the services matter a lot. As I thought so, the problem was configuration-wise.

    I had:

    Library\Service\BaseService:
      ...
    
    Library\Service\DerivedServices\:
      ...
    
    Library\Service\:
      resource: '../vendor/company/library/src/Library/Service'
    

    The last instruction redeclared all services as private (by default).
    I changed this to:

    Library\Service\:
      resource: '../vendor/company/library/src/Library/Service'
    
    Library\Service\BaseService:
      ...
    
    Library\Service\DerivedServices\:
      ...
    

    This declared all the services private first, then redeclared them with the new declaration: use of parent + public.