Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[Console] Added support for lazy-loaded commands#13946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Refactored the commands to extract the configuration into a separate class. That allows to define the configuration of a command without instantiating the command. The command is then loaded only when being used.
mnapoli commentedMar 17, 2015
The build on 2.7 is currently broken which explains the failing PR, I will rebase when it is fixed. Locally tests are passing. |
unkind commentedMar 18, 2015
Honestly, I don't understand why we can't (re)use existing Anyway, I definitely like to see separate |
mnapoli commentedMar 18, 2015
Yes it's possible but I consider it a cheap workaround rather than a solution. With that you would have to write commands that do not extend the Instead of putting the command out of the
I don't I understand that part sorry? |
unkind commentedMar 18, 2015
Why? Closure can resolve command and execute it: $command =new newCommand(null,$configuration);$command->setCode(function ($input,$output,$configuration) {// Feel free to resolve command instance from DI container$internal =newGreetCommand(null,$configuration);return$internal->run($input,$output);}); You can add this 3rd argument without breaking BC.
I'd like to see a value object, not a mutable one. |
mnapoli commentedMar 18, 2015
@unkind Your example is a workaround. That's also the kind of workaround I have implemented for using inPiwik and we are not using it yet (and not released) because "it's not the Symfony API so people have to learn the Piwik console version (and we have to maintain it)". So yes of course you can always find a way, but here I'm suggesting to improve Symfony Console to have an easy and clean solution available for everyone instead of releasing a "fork" (or rather alternative to symfony/console). |
unkind commentedMar 19, 2015
I don't state it isn't. The only thing I don't like in your one is that AFAIK, Symfony 2.7 is already closed for new features according tohttp://symfony.com/doc/current/contributing/community/releases.html. If it isn't, I can make alternative PR. However, I don't see much sense in these workarounds for 3.0. |
fabpot commentedMar 19, 2015
2.7 will not accept any new features at the end of the month, so we still have time. |
mnapoli commentedMar 19, 2015
@unkind Ah you mean Yes I don't find this perfect too and I'd rather introduce a |
unkind commentedMar 19, 2015
@mnapoli by the way, you should remove |
mickaelandrieu commentedApr 2, 2015
@mnapoli what is the status of this pull request ? |
mnapoli commentedApr 2, 2015
@mickaelandrieu it is waiting for some love :) I.e. waiting for a core team member to tell me:
|
stof commentedApr 18, 2015
I would prefer a way staying closer to the current architecture, as I explained in#13989 (comment) as well |
mnapoli commentedApr 19, 2015
@stof OK I can try a different approach, just to be clear the name and aliases would have to be defined outside the command right? Here is a solution using callbacks as a factory: $callable =function ($commandName) {// return the command instance};$app->addLazyCommand('name', ['aliases'],$callable); Or we could introduce a interface CommandResolver {publicfunctiongetCommand($name);}$app->setCommandResolver($resolver);$app->addLazyCommand('name', ['aliases'],'command-id'); Thoughts before I go with an implementation? |
notrix commentedMay 25, 2015
👍 |
linaori commentedJul 13, 2015
Any update on this? I'm having major issues right now due to a The only way I can fix it is by fetching the soap service from the container at a later stage and this is something I'm hoping to avoid. /ping@mnapoli |
mnapoli commentedJul 18, 2015
On my side I have nothing new to add here, I opened the PR and also offered alternative ideas for implementations so I'm waiting for feedback ;) And since I opened this PR I keep seeing this problem more and more, for example onPiwik as we introduce dependency injection more and more. |
xabbuh commentedJul 20, 2015
@iltar For now, you coulddeclare the SoapClient service lazy, can't you? |
linaori commentedJul 20, 2015
@xabbuh it's an option but I actually wrote my own interfaced wrapper for it, which in turn is a nicer solution than it originally was by calling the SoapClient directly. I don't like introducing lazy services via that package as the generated proxies provide some obstacles. The php SoapClient is just bad by design. |
TomasVotruba commentedNov 16, 2015
What state is this in? |
cedvan commentedDec 16, 2016
👍 |
mnapoli commentedJul 6, 2017
Have a look also at#22734 which seems to be a very good solution (maybe better than this one because simpler). |
nicolas-grekas commentedJul 11, 2017
Closing since a better approach is being worked on. |
TomasVotruba commentedJul 11, 2017
@nicolas-grekas Could you link that one please? |
theofidry commentedJul 11, 2017
@TomasVotruba I think he was referring to#22734 |
TomasVotruba commentedJul 11, 2017
@theofidry I prefer links over guessing. Thanks. |
mnapoli commentedJul 11, 2017
🎉 thanks@chalasr |
This PR was merged into the 3.4 branch.Discussion----------[Console] Add support for command lazy-loading| Q | A| ------------- | ---| Branch? | 3.4| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |#12063#16438#13946#21781| License | MIT| Doc PR | todoThis PR adds command lazy-loading support to the console, based on PSR-11 and DI tags.(#12063 (comment))Commands registered as services which set the `command` attribute on their `console.command` tag are now instantiated when calling `Application::get()` instead of all instantiated at `run()`.__Usage__```yamlapp.command.heavy: tags: - { name: console.command, command: app:heavy }```This way private command services can be inlined (no public aliases, remain really private).With console+PSR11 implem only:```php$application = new Application();$container = new ServiceLocator(['heavy' => function () { return new Heavy(); }]);$application->setCommandLoader(new ContainerCommandLoader($container, ['app:heavy' => 'heavy']);```Implementation is widely inspired from Twig runtime loaders (without the definition/runtime separation which is not needed here).Commits-------7f97519 Add support for command lazy-loading
This PR was merged into the 3.4 branch.Discussion----------[Console] Add support for command lazy-loading| Q | A| ------------- | ---| Branch? | 3.4| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |symfony/symfony#12063symfony/symfony#16438symfony/symfony#13946 #21781| License | MIT| Doc PR | todoThis PR adds command lazy-loading support to the console, based on PSR-11 and DI tags.(symfony/symfony#12063 (comment))Commands registered as services which set the `command` attribute on their `console.command` tag are now instantiated when calling `Application::get()` instead of all instantiated at `run()`.__Usage__```yamlapp.command.heavy: tags: - { name: console.command, command: app:heavy }```This way private command services can be inlined (no public aliases, remain really private).With console+PSR11 implem only:```php$application = new Application();$container = new ServiceLocator(['heavy' => function () { return new Heavy(); }]);$application->setCommandLoader(new ContainerCommandLoader($container, ['app:heavy' => 'heavy']);```Implementation is widely inspired from Twig runtime loaders (without the definition/runtime separation which is not needed here).Commits-------7f97519 Add support for command lazy-loading
This PR adds support for lazy-loaded commands in the Console component (#12063).
I had to refactor the commands to extract the configuration into a separate class. That allows to define the configuration of a command separately from the command itself, which means we don't have to instantiate it. The command is then loaded only when being used. This is particularly useful when writing an application with a dependency injection container.
Backward compatibility is kept (if not it's a bug to fix) as
Commandextend from the newCommandConfigurationclass (i.e. current commandsare their own configuration). I wish they didn't as composition would be better instead of inheritance here, suggestions are welcome. Maybe we can break BC if we are targeting 3.0 and the change is deemed good enough?To define a lazy-loaded command, here is a simple example:
Lazy-loaded commands don't have to define
configure():I hesitated between using closures that return the Command instance, or introducing a
CommandResolver. I went with the simpler solution.As explained in#12063, the current implementation forces to create all the Command instances which has the following problems for example:
The impact and reality of those problems depend a lot of your application obviously. But just like an application shouldn't loadevery controller and their dependencies on each request, the console application shouldn't load every command and their dependencies on each execution if that can be avoided.
I don't believe this change has any impact on the Symfony full-stack framework but maybe it will give you some ideas.