-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Console] Add LazyCommandTrait to help writing lazy commands #39726
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
6ccd276
to
dd1dd63
Compare
|
that'd work only for one item in the list of things that need to be configurable... |
dd1dd63
to
ac0a8c3
Compare
well, do we need anything else? Discouraging constructor injection for this feels like the wrong trade off. |
There is no tradeoff here. Constructor injection is not the only way to inject deps. |
The main design flaw of the component is that we have to instantiate the command to get its definition. And I feel like we're wrapping the the command into yet another layer of workarounds here. 😕 |
There are only two alternatives here:
The current design is not flawed to me. It provides just the right amount of DX + maintainability. Providing laziness is the very purpose of |
If this is accepted, I think |
regardless of LazyCommandTrait as a feature (works for me), should we split name+description from the definition? in favor of static props currently extensibility is already broken given aliases are shown in it's a WTF actually :P |
What do you mean? I just had a look at the code and the name looks extensible to me. |
|
That wasn't obvious to me, but now I think that what you mean is that the Could be... I like the current proposal because it gives a simple way to wire commands (no need for the constructor boilerplate, which provides nothing useful). |
Can you elaborate? I don't understand what you mean here... |
@nicolas-grekas given sf/console@v5.2.1 i have class FooBarCommand extends Command
{
// protected static $defaultName = 'foo:bar';
protected function configure()
{
$this
->setName('foo:abc')
->setAliases(['foo:def'])
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
return Command::SUCCESS;
}
} list shows
both foo:abc and foo:def work at this point next uncomment now list shows
but only foo:bar works, whereas i expected the previous output as well. If you remove setName, but keep $defaultName the alias Hence i think if we extract |
If we look at how an HTTP request is matched to a controller, we find a router in between that knows everything we need to know to decide which controller exactly we need to instantiate (or pull from the container). The controller instance does not know which paths it is attached to. It can be a dump callable if we want. I think, we can build something similar to match a CLI call to a command. The command itself is only pulled from the container if we really intend to execute it. |
Oh, OK. That doesn't mean that extensibility is broken. It means it doesn't work the way you thought it works... You can change the name e.g by using a DI tag attribute. The reason is of course that we built for laziness when reading names.
That could work. We could even extend the format of $defaultName to allow listing aliases in the same string, eg For the description, I guess we should do the same: a DI attribute + a default static prop. Up for a PR? |
i like the we have also
does it mean I also like the command_routing.yaml proposal, to define everything in one go. But it separates some concerns of which im not sure it scales well. Eg. for CLI, vendors are allowed to mount commands currently. |
On the other hand, a command must declare it's arguments, because that's its signature. I think having this signature declared in the same place as the implementation is critical. A design based around a command router would be radically different. Enough to warrant experimenting the idea in a separate package, if someone is interested in it. |
nope, as that would damage reusability ( |
fair enough
i figured at this point im indeed wondering if LazyCommandTrait would be sufficient. |
|
i think that + $defaultDescription will do for a lazy in the long run i think we should prefer signature (opt+args) are bound to implementation, so making it immutable as of then only seems reasonable. |
and if It still unpacks all deps at once, whereas using ServiceSubscriberInterface directly allows invoking them on demand. |
I'd prefer not having to teach such an alternative |
So am I. Thanks for the discussion. PR welcome if anyone is up to giving this a try! |
See #39851 for a follow-up PR. |
In #33804, @helhum is wondering about a way to get the description of a command without instantiating its dependencies.
We already have a solution to this: implement
ServiceSubscriberInterface
.In this PR, I'd like to propose adding a new
LazyCommandTrait
to help implementServiceSubscriberInterface
. This trait would allow writing commands like controllers: list services as arguments to get them when the command runs.Here is a dummy command that works with this trait (see how RequestStack is passed):
WDYT?