Symfony: How to call private services in Bundle Controller - php

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

Related

How to use my own service definition for a security firewall guard in Symfony 4.2?

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.

Symfony 4 Custom Bundle use Logger Interface

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.

What is the advantage of using a service in symfony

I have a question, why symfony use a service instead of "use" directly into a controller.
I have a class named DisplayManager and I declare this class as a service.
Why not use DisplayManager directly into a controller using "use DisplayManager"
Thanks
The advantage of thinking about "services" is that you begin to think about separating each piece of functionality in your application into a series of services. Since each service does just one job, you can easily access each service and use its functionality wherever you need it. Each service can also be more easily tested and configured since it's separated from the other functionality in your application. This idea is called service-oriented architecture and is not unique to Symfony or even PHP. Structuring your application around a set of independent service classes is a well-known and trusted object-oriented best-practice. These skills are key to being a good developer in almost any language.
http://symfony.com/doc/current/service_container.html
Questions that suggest define your class as service:
My class is used in several places in my application?
My class has many dependencies?
There is a good example for these topics here:
http://symfony.com/doc/current/service_container.html#what-is-a-service-container
Performance Advantage:
The service has a default condition that allows to the related class instantiate it only once.
Imagine a class with 5 dependencies (and these as well with their dependencies) and has been used in 20 parts of our system, what if we do not define this class as a service?
However define your class as a service is not required, this will always depend on the architecture of your system and the mission to be fulfilled its class, in addition to the dependencies you have.
Controllers are made only to take requests (http) and produce a response (http). No more. Never.
Services are totally independent classes that you can use everywhere. Moreover, with services, you can take advantage of DependencyInjection.
Services are more testable.
Services (like controllers and whatever) must have only a responsibility.
And so on ...

Global logging service

I have written my own logging class that I defined as a service and placed inside the AppBundle\Services namespace. I can access it easily inside the controller when I want to log something, but what about accessing it from other services?
I'd have to pass the logging service as a dependency injection, but what if I have more than 100 services defined (services, modules, event listeners etc. etc.), each of them having their own dependencies? It would create a mess.
I've been also thinking about extending some core service that defines the logging service, but then again - all my services, modules, event listeners, would have to extend one core class.
What's the best approach to solve this?
May be a good approach would be to rethink responsibilities in order to avoid the creation of too many services.
About the fact of consumming service itself, I think there are no problem to reuse as much as you need along the application lifecycle. In fact, symfony will handle the instantiation and you will be only consumming it as a service.
Another approach will be to create base classes for all your core objects, let these base classes to handle log services and final classes will log in a implicit way. This will not save service calls but almost will leave you to handle it manually.
If you think you will use your log feature in several projects then I recommend you to move to vendors folder and use it as external module, synchronised via composer to your github account. It will be like your own 3rd party product.
If you are not a symfony friend then you can break the law and create your own singleton pattern available by autoloading, but I think you should take advantage of the powerfull symfony service structure.

Symfony2 service structure

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.

Categories