I'm writing a 3-rd party bundle (let's call it Bundle1), which needs to use another 3rd-party bundle (Bundle2). I've declared the dependency in Bundle1's composer.json, so Bundle2 is successfully downloaded.
But in my AppKernel.php, i've only declared Bundle1 :
$bundles = [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
[...]
new MyCompany\Bundle1(),
];
As far as i know, It would not be correct to declare Bundle2 here. So obviously, I can't access any service provided by Bundle2 in my application. That's ok, as far as my application is concerned, but I need Bundle1 to use thoses services in its own inner classes.
How can I pass them to Bundle1, and how can I use them ? Should I declare them in Bundle1's services.yml and point them to Bundle2's classes ? I guess that would be a duplication with Bundle2's own services ? I can't think of any other way to do that.
What would be the correct way to achieve this ? Many thanks in advance.
I'm running Symfony 3.2.4 by the way.
Related
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.
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
I would like to know if there's a way to create a reusable bundle that depends on a public bundle in my case, OneupFlysystemBundle ?
By adding OneupFlysystemBundle to my bundle's composer.json I can see that it's downloaded and present in the vendor folder.
I want to only include my own bundle in the AppKernel (which has a dependency on OneupFlysystemBundle)
Beside these solutions I ended using the non-bundle (library) version of OneupFlysystem as a dependency of my bundle and rewrite it as facade
Probably the best way is to use Symfony Flex. Which allows you to use recipes. An alternative would be to use symfony-bundle-dependencies
Before using Symfony2, I used to have a common lib with a lot of simple but useful functions (for instance, a function which takes "Azè_rtï" in argument and returns "aze-rti").
So, well, I created a Bundle: CommonLibsBundle.
But.. I have only one or two php files. It does not make sense to me to use a controller / view / model in this kind of situation.
What should I do? May I erase all folders in my new bundle (Controller, DependencyInjection, Resources, Tests... + CommonLibsBundle.php) and just put my lib.php in it?
Many thanks,
Bliss
Unless you need to tap into the Symfony framework itself - for configuration or to define services, it doesn't need to be a bundle - it's just a library. Give it a reasonable namespace, and call as required as you would any other component or library.
Even if you wanted to add Symfony-specific services that you could call, there is something to be said to still have an external simple library - usable anywhere, which then is wrapped by a very thin bundle which would only add the Symfony-specific (or Laravel, or ZF, or whatever) services and configuration as required.
This question already has an answer here:
How to use DependencyInjection from symfony in stand alone application with commands?
(1 answer)
Closed last year.
A Symfony novice here. After reading some of the Symfony documentation and some answers here at SO, I am now almost completely confused.
I am trying to use the console application component and create a small db-aware console application.
Many people state that in order to use Symfony's DI features it would be enough to inherit my command class not from Symfony\Component\Console\Command\Command but from ContainerAwareCommand.
However when I try this I get a Method Not Found error on an application::getKernel() call.
I have a feeling that DI features are in fact not available in a console application based on the console component. Is there another kind of Symfony console application, for example, based on the full-blown framework?
I very much like the simple framework provided by the console component Symfony\Component\Console\Application. But the question is then - what to do for dependency injection and DBAL? All examples that I find seem to refer to the full Symfony framework and get me just all the more stuck.
Just a quick update on my progress if anybody stumbles upon the same problems.
I incorporated into my project the PHP-DI dependency injection framework, which seems to be working fairly well with no configuration (so far) - it figures out quite a lot by reflection, actually.
The same way, Doctrine\DBAL is included as a standalone library (I opted against the O/RM part of it, as it is really a tiny project and I'm on a much firmer ground with SQL than anything else) and the connection is simply returned by a connection provider which is injected wherever needed by the DI.
One thing I couldn't figure out is how to have the command classes instantiated by the DI library without my help, so I actually had to inject the container itself into my overridden application class and override the getDefaultCommands() where I then pull the instances out of the container manually. Not ideal but will have to do for now.
If your command extends ContainerAwareCommand
...
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
...
class MyCommand extends ContainerAwareCommand
{
The DI container is available with the getContainer() method. (like in a standard controller), ex:
$this->validator = $this->getContainer()->get('validator');
I don't know if your question is still relevant, but I have an answer as I stumbled across the same problem here.
You just have to create the kernel yourself and give it to the \Symfony\Bundle\FrameworkBundle\Console\Application that extends the basic \Symfony\Component\Console\Application.
<?php
// CronRun.php
require __DIR__.'/../../../../vendor/autoload.php';
require_once __DIR__.'/../../../../app/AppKernel.php';
$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
$application->add(new \KingdomHall\TaskBundle\Command\CronCommand());
$input = new \Symfony\Component\Console\Input\StringInput('k:c:r');
$application->run($input);
You could use a solution I just pushed it to packagist.org. Includes full working symfony/dependency-injection. You're welcome to give it a shot. use composer to create your own project composer create-project coral-media/crune project_dir or just clone the repository.
https://packagist.org/packages/coral-media/crune
You only need to install DBAL dependencies (I don't suggest ORM if you don't really need it). Configure connection parameters in .env and just define a service to handle connection. That service can be injected in your Commands using public setMyService($myService) method with #required annotation. Also you could create a Connection class and bind is as parameter in your command constructor.The crune boilerplate also supports autowire and autoconfiguring features.