I read on the Symfony documentation for the ServiceContainer that any services that are not used before compiling the container are removed from the container.
Now, I compile the container on the request if the container isn't cached.
How would I stop unused services from being removed, especially if they're required after the container has been compiled?
I'm aware Drupal does it by essentially re-writing the the container (mostly code taken from the original Symfony container), but although this is an option I'm wondering if there's a more efficient method on doing this? Also, I'm relatively new to Symfony, so any related documentation links would be greatly appreciated.
By default, all unused private Symfony services are removed, simply because they are private and they are not defined to be called from outside.
If the private service is used only once, it will be inlined (and removed from the container).
But the public services are not removed from the container, even if you don't use them, so if you want keep your service in the DI container, make sure that it is public
Related
I'm trying to make vatin-bundle compatible with Symfony 6.
But the tests fail
The "validator" 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.
It seems this is new in Symfony 6
The container in static::getContainer() is actually a special test container. It gives you access to both the public services and the non-removed private services services.
What is the preferred way to make validator available in tests again?
The only way I found is creating my own alias like
services:
myvalidator:
alias: validator
public: true
and use the new alias. Is there a better way?
If the service is removed, then it's no longer accessible no matter what. It's not a matter of visibility, the service is no longer there. So you need to prevent the service from being removed: creating an alias is the best and simplest way to go about it.
This has been confirmed by maintainers here.
You can create the alias only during testing, and still access the original service. (e.g. ->get('validator'). Once the alias is created, the original service is no longer removed.
I don't think this is something really new in Symfony 6, but it's bee a thing since Symfony 4.4. Although it's true that now on Symfony 6, since it's removes previously deprecated behaviour, things could have changed.
I creat a bundle and I would like use best practice with it.
So all my services are private
https://symfony.com/doc/current/service_container/alias_private.html
So unless you specifically need to access a service directly from the
container via $container->get(), the best-practice is to make your
services private. In fact, the default services.yaml configuration
configures all services to be private by default.
And
https://symfony.com/blog/new-in-symfony-3-4-services-are-private-by-default
In Symfony core we've already done that and we made all services and
aliases private, except a few selected ones, that are required at
bootstrap time. In fact, bootstrapping is the last and only legitimate
use case for using the container directly.
So, should we deprecate the possibility to inject the
service_container entirely alongside with ContainerAware*? That's a
possibility that the community might consider when preparing Symfony
5.
I have an Trait or Abstract controller which have to use by App/Controller. The trait can call the private service with autowiring and the probleme is fix BUT
The best practice of Symfony is don't use only autowiring in Bundle:
https://symfony.com/doc/current/service_container/autowiring.html
Public and Reusable Bundles¶
Public bundles should explicitly configure their services and not rely
on autowiring.
So How to inject my private service in my Trait or abstract controller. Or even in the App controller without the user having to configure are services.yml.
I hope I'm clear.
Sorry for my english. I try to improve it ;-)
If you are developing a third party bundle, i.e., a bundle that will be used by other people, then you must define your services manually and also in xml. Those are the best practices.
Now, third party bundles can have public services. The article you are referencing refers to your AppBundle services, that should be private because contain your application/bussiness logic. The reason why they are private by default is because you should be using Constructor Dependency Injection to use them, so things are more easily testable.
Now, in regards to your issue, you should't be creating controllers in third party bundles: it's not good practice. Instead, use the routing to route to a service that will perform the action you need. Api Platform does that, here:
routing.xml
EntryPointAction.php
It's possible to lazy-load a service in Symfony, but:
Is it possible to make it the default way to load services
without having to configure it for all service?
Is there a possibility to annotate a service for lazy-loading?
Regarding the lazy loading. There are multiple ways you can solve this:
For one there is the new Service Locator that was introduced in 3.3. The documentation explicitly says:
Sometimes, a service needs access to several other services without being sure that all of them will actually be used. In those cases, you may want the instantiation of the services to be lazy. However, that's not possible using the explicit dependency injection since services are not all meant to be lazy (see Lazy Services).
The referenced article on Lazy Service describes another way to solve this which requires an additional dependency ocramius/proxy-manager which will then make it possible to mark services as lazy: true in your DI config.
I don't know if I understand the first question correctly, but if you don't want to manually configure dependencies you can rely on the autowiring feature that also received major changes in Symfony 3.3 and 3.4. You can only make the autowring a default per configuration file, but using the PSR-4 autodiscovery can basically autowire your whol src directory if you want to with some manual intervention, e.g. for parameters.
I'm starting to migrate my application to symfony4 but I have the following deprecation notice in one of my third-party bundle ( tbbcmoneybundle . And I would like to know what to change in order to propose a PR
Currently the build is failing because of these errors (complete report here )
The "doctrine.database_create_command" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead: 25x
12x in ConfigTest::setUp from Tbbc\MoneyBundle\Tests\Config
6x in ConsoleTest::setUp from Tbbc\MoneyBundle\Tests\Console
3x in ConsoleTest::testRunRatioList from Tbbc\MoneyBundle\Tests\Console
2x in ConsoleTest::testRunRatioFetch from Tbbc\MoneyBundle\Tests\Console
1x in ConfigTest::testHistoryOfFetchedRatio from Tbbc\MoneyBundle\Tests\Config
1x in ConsoleTest::testRunSaveRatio from Tbbc\MoneyBundle\Tests\Console
I guess it's related to this code
$this->runCommand($this->client,'doctrine:database:create');
$this->runCommand($this->client,'doctrine:schema:update --force');
However I don't see see how to fix this and google seems unhelpful on this one.
The problem looks like it comes from the loss of container awareness (if that's a valid phrase) in Symfony 4, which started in Symfony 3.4. This blog talks about restricting container injection in 3.4 and how it will go away in 4.0.
It looks as though someone has opened a PR to upgrade to Symfony 4, but that is failing. (Looks like you're trying to help that along as well.)
According to this Travis integration test that is failing, the commands which extend "ContainerAwareCommand" are the source of the fail.
Which makes sense. The ContainerAwareCommand attempts to inject the Container, which is set to private in Symfony 4 (and deprecated since 3.4) as outlined in the blog post above. A fix, and I think you want to fix this in a PR to TBBC if I read your question correctly, seems to be to remove the extension of ContainerAwareCommand from those command classes and just inject the services necessary. See the new Symfony 4 doc on commands (and note that ContainerAware is no longer an option as it was in 2.8-ish.)
In short, get rid of the extension to ContainerAwareCommand and inject the services used by those commands. (Might need to do some extra configuration to ensure that the services are public.)
is it possible overwrite/extend Symfony\Component\DependencyInjection\Container::get() method? I want automatic creating service, when it is not contain in container, but class of service exists.
For example:
Name of service is My.MyBundle.Model.FooRepository
Service with this name doesnt exists, but when i call:
$container->get('My.MyBundle.Model.FooRepository');
check class_exists for \My\MyBundle\Model\FooRepository and when its exists, add to container and return it. Dependencies of this new services will be resolve by kutny/autowiring-bundle.
This feature can be extended only for some namespaces or interfaces and in production enviroment can be cached, but for developing will be great helper.
Any idea?
This is not directly answering your question but maybe it's answering your need: if you want to have "auto-wiring" inside your Symfony project, you can use PHP-DI inside Symfony. PHP-DI is an alternative container that can do auto-wiring (which Symfony does not).
Have a look at the Symfony 2 integration documentation to see if it can fit your bill.