Reputation: 915
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?
Upvotes: 32
Views: 46048
Reputation: 785
on Symfony 6 the solution was for me to load container this way:
$this->container = static::getContainer();
$this->redis = $this->container->get('snc_redis.default');
I used to load to bootKernel and then get container:
$this->container = static::bootKernel()->getContainer();
$this->redis = $this->container->get('snc_redis.default');
which gave me the same error: The "snc_redis.default" 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.
If this solution above does not work for you can also set your services public
by creating aliases for it in test env in /config/services_test.yaml
. Ex:
services:
_defaults:
public: true
test.App\Service\MyService
alias: App\Service\MyService
Note prefix test.
so that you won't have conflicts if service is already available.
and then access it in tests:
public function setUp(): void
{
parent::setUp();
$this->container = static::getContainer();
$this->service = $this->getTestService(\App\Service\MyService::class);
}
/**
* typing for autocomplete
* @template T
* @param class-string<T> $serviceId
* @return T
*/
protected function getTestService(string $serviceId)
{
return $this->container->get('test.' . $serviceId);
}
If APP_DEBUG=0 for test env then remember to clear test cache.
In order to clear test cache you can add following line into the /tests/bootstrap.php
which should configured to be used in your phpunit configs.
(new \Symfony\Component\Filesystem\Filesystem())->remove(__DIR__ . '/../var/cache/test');
Upvotes: 0
Reputation: 5071
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);
}
}
Upvotes: 7
Reputation: 2310
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
Upvotes: 9
Reputation: 167
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
Upvotes: 10
Reputation: 1894
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);
}
//...
Upvotes: 1
Reputation: 267
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.
Upvotes: 25