Symfony 4 - Service removed or inlined though it is public
Asked Answered
M

5

32

I'm trying to migrate a SF 3.3 app to SF 4 with its new directory structure and everything.

I'm struggling on this exception:

The "simplethings_entityaudit.reader" 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.

(This service comes from an external bundle located in /vendor).

Nevertheless, when I bin/console debug:container simplethings_entityaudit.reader you'll see the service exists and is public:

Information for Service "simplethings_entityaudit.reader"
=========================================================

 ----------------- -------------------------------------- 
  Option            Value                                 
 ----------------- -------------------------------------- 
  Service ID        simplethings_entityaudit.reader       
  Class             SimpleThings\EntityAudit\AuditReader  
  Tags              -                                     
  Public            yes                                   
  Synthetic         no                                    
  Lazy              no                                    
  Shared            yes                                   
  Abstract          no                                    
  Autowired         no                                    
  Autoconfigured    no                                    
  Factory Service   simplethings_entityaudit.manager      
  Factory Method    createAuditReader                     
 ----------------- -------------------------------------- 

This service is currently called in one of my own with $this->container->get('simplethings_entityaudit.reader').

I also tried to inject SimpleThings\EntityAudit\AuditReader into my service constructor, but here's what I get:

Argument "$auditReader" of method "__construct()" references class "SimpleThings\EntityAudit\AuditReader" but no such service exists. It cannot be auto-registered because it is from a different root namespace.

When I add this into my services.yaml it works, but I shouldn't need to do this:

SimpleThings\EntityAudit\AuditReader:
    alias: simplethings_entityaudit.reader

Any ideas?

Morea answered 24/1, 2018 at 14:38 Comment(2)
That's ok with the alias, what you can do when external bundle doesn't provide alias for compatibility with Symfony 4. If this is your bundle, add alias inside it.Ultranationalism
as it´s not clearly visible from the answer: add property public:true as sibling to aliasGuendolen
C
23

In my case, the error appears in a unit test.

I had a single service, which could not be loaded in tests (Symfony 4.2) while all other services in my project worked well.

I've cleared the cache, but it didn't help. Then I created a simple controller with a route and injected the service as method parameter. Afterwards the service worked in my test as well.

Conclusion: If you have a unit test and want to test your service, you must also provide a controller where the service is injected, otherwise it is not available in the test service container. An explicit service configuration might also help.

Catamnesis answered 25/3, 2019 at 12:47 Comment(3)
This is at least partially incorrect. Adding the controller probably just marked the service as used, so it wasn't pruned during container dumping.Overstuff
Indeed the service must be used somewhere first: in a Controller, in a Command... from another Service etc...Departmentalize
indeed, a more direct and declarative way to solve this is to add your service to services.yml with public:trueCressler
C
10

In our case we made a services_test.yml along with .env.test with APP_ENV set to test

then in this services_test.yml we placed

services:
    _defaults:
        public: true

so by default all services are public

don't forget to source your .env and .env.test I often have to do that we I restart my VM

Caresa answered 18/12, 2020 at 11:2 Comment(1)
It is also possible to set the default visibility in the usual services.yaml or set the visibility of single services as needed.Shanna
D
9

In Symfony 4.0, any service that does not specify its visibility is private, https://github.com/symfony/symfony/pull/24238.

As far as I can see, the service you mention does not specify the visibility: https://github.com/simplethings/EntityAuditBundle/blob/1.0/src/SimpleThings/EntityAudit/Resources/config/auditable.xml#L23-L26, so this is probably the reason for your exception.

If simplethings_entityaudit.reader service cannot be autowired (and this is probably because it uses a factory service), you can inject it into your own service by referencing it with @simplethings_entityaudit.reader notation as per this: https://symfony.com/doc/current/service_container.html#services-manually-wire-args, something like this:

services:
    My\Service:
        arguments:
            $auditReader: @simplethings_entityaudit.reader
Dwell answered 24/1, 2018 at 15:42 Comment(5)
Hello Edi, I know that indeed, but for whatever reason the service is marked as public when doing debug:container. When you say "this is probably because it uses a factory service", where is this behavior documented? Never heard of that. Thank you, BenMorea
Oh, I assumed that the output of debug:container command was from Symfony 3.3. On Symfony 4.0, I'm not sure why it should show up as public in the output. As for autowiring and factory service, I don't know if it's documented anywhere, it was an educated guess, because it seems like a valid reason why it couldn't be autowired, since autowiring system wouldn't know how to construct the service. One other potential reason could be that for that service, autowiring simply isn't turned on (since it's not configured in its config file), but these are just guesses.Becerra
It was actually a bug that was fixed in latest Symfony 4.0.x version.Morea
Yes, as you suggest and the docs you posted, one of the options is setting the service visibility using public: trueZee
I just add this doc because it is helpfull in this case : symfony.com/doc/current/service_container/…Cleres
I
7

I had the same issue in my unit KernelTestCase.

The problem arises when you are trying to load a service using the container that is not referenced anywhere in the application. To fix it just include the service in your controllers or in another service that is always registered in the app or manually register it in services.yaml.

// Doesnt work in test case when not registered somewhere else
static::getContainer()->get(MyService::class);

But if we reference it somewhere we can then use container in test to get it:

class MyController {

  public function __construct(protected MyService $myService) {}

}


class AnotherTestCase extends KernelTestCase {

  public function setUp() {
    // Now works because service is used in controller and therefore present in compiled container.
    $myService = static::getContainer()->get(MyService::class);
  }
}

Icarus answered 26/10, 2022 at 14:4 Comment(0)
M
1

I had the same issue, the dependency injection and adding as service didn't work for me. Then I found the alias was setting on PHP code and adding ->setPublic(true) there fixed my issue.

Reference URL which helped me: https://symfony.com/doc/current/service_container/alias_private.html

use Symfony\Component\DependencyInjection\ContainerBuilder;

//...
public function load(ContainerBuilder $container)
{
    $container->setAlias('simplethings_entityaudit.reader', 'SimpleThings\EntityAudit\AuditReader')
              ->setPublic(true);
}
//...
Mariken answered 21/10, 2021 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.