I am trying to implement a custom Symfony bundle and inside my service I need to pass the global symfony logger that I defined in my Symfony App and it is an instance of Psr\Log\LoggerInterface. The problem is that when I am configuring my services with the ContainerBuilder the logger service is not yet initialised.
In my bundle service I am passing the Logger like this:
public function __construct(LoggerInterface $logger, $argument1, $argument2);
The two arguments are being delivered from the packages/my_custom_bundle_config.yaml file. However I can't pass the App's Logger as a parameter even in the above config file.
Any help or any comments will be much appreciated.
Thank you.
There are three things you need to do:
Create a compiler pass. You can search for them in the documentation. Basically, they allow you to modify the container just before it is compiled, when all definitions and aliases have been registered.
Is really good practice in your configuration class to define a service id for the logger, in case your users want to use a different implementation. In your extension class, you should pass that reference as an argument.
Usually all bundles that rely on psr interfaces register an alias of it to a default implementation. They are usually called logger.default or something similar. You can search in monolog bundle extension class for the definitions they use or use the interface, that will have an alias.
Related
I have a service defined in services.yaml that has a calls entry since I don't want to specify my dependencies in it's constructor so I use setters.
Now I am trying to point the security.firewalls.main.guard.authenticators.0 configuration entry to it, but if I try to reference it like this: '#App\Service\Authentication\Guard' I get The service "security.authentication.provider.guard.main" has a dependency on a non-existent service "#App\Service\Authentication\Guard".
If I specify just the name of the class as per Symfony's docs: App\Service\Authentication\Guard then there's no exception and the guard works, however the calls section of my definition is completely ignored and thus my setters don't work.
My best guess would be that the security module uses it's own service locator that's somehow disconnected and ignores definitions in services.yaml, which is probably why you won't find examples of the above config entry using simple service names rather than canonical class names.
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
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.
I am having a hard time understanding Symfony2 services. I have read lots of stuff everywhere (including some here in SO) but none seems to fully explain it.
Suppose I have a bundle A and a separated bundle B. I want B functionality available to the A bundle. I want to inject B in the service container so A will be able to use it.
Which bundle should have a Services directory? Which one should have a configuration file? Both if needed? And where the Extension goes? Why?
Bundle B will require an Extension in order to load it's services.xml file.
Bundle B will require an entry in it's services.xml file to define the service.
Bundle B will have the Services directory containing your service class which exposes the desired functionality.
Bundle A does not require anything special. It will be able to use the container to access the service exposed by Bundle B. Just needs to know the service id.
It's confusing until you make a few services.
Read these two questions and my answers to them first:
Symfony2 conceptual issue: general bundles vs. specific ones,
Should everything really be a bundle in Symfony 2?
Assuming you're talking about app specific bundles, I suggest having one bundle only and keep services out it. Then, you could register your services in several ways:
Directly in the config.yml,
Creating an extension class in your AppBundle, or
Via annotations from JMSDiExtraBundle — this is what I prefer personally.
I have a problem of not being able to access configuration and path information outside controller context. I am in a Assetic Filter class that has no methods to help me, and I need to know the kernel path along with some configuration. How do I do the Symfony 1 sfContext::getInstance() call in Symfony 2?
If you are writing an assetic filter you are writing a service. In the service definition you can pass parameters from the DIC. For example you can pass the AppKernel absolute path writing:
<argument>%kernel.root_dir%</argument>
If you want to have a semantic configuration for your filter (and for any service in general) it would reside in a DIC extension. By default "MyNamespaceMyBundle" will register the "MyNamespaceMyExtension" extension class inside the DependencyInjection subpackage and this extension will handle configuration from the "my_namespace_my" top level configuration key creating services or setting DIC parameters.
Moreover you would want to have a Configuration class that handles validation, normalization and merging of your configuration. Sadly all of this is more or less not documented anywhere, so best way to achieve your goal is to look at some other bundle (e.g. I learned very much reading FOSUserBundle).
You don't. You must use depency injection somehow. See here why it might have been removed.