Kdyby\Console: Dependecy Injection? Why? Or why not?
- Honza Kuchař
- Member | 1662
Hi! I would like to ask, why or why not it is possible or not
possible recommended to use DI in Console commands?
This example from documentation contains magic reference to Models\NewsletterSender. (you are not able to figure out required dependencies from class header)
namespace App\Console;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SendNewslettersCommand extends Command
{
protected function configure()
{
$this->setName('app:newsletter')
->setDescription('Sends the newsletter');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$newsletterSender = $this->getHelper('container')->getByType('Models\NewsletterSender');
try {
$newsletterSender->sendNewsletters();
$output->writeLn('Newsletter sended');
return 0; // zero return code means everything is ok
} catch (\Nette\Mail\SmtpException $e) {
$output->writeLn('<error>' . $e->getMessage() . '</error>');
return 1; // non-zero return code means error
}
}
}
Why something like this is not supported not the best
practice?
namespace App\Console;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SendNewslettersCommand extends Command
{
/** @var Models\NewsletterSender */
private $sender;
public function __construct(Models\NewsletterSender $sender) {
$this->sender = $sender;
}
protected function configure()
{
$this->setName('app:newsletter')
->setDescription('Sends the newsletter');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$newsletterSender = $this->sender;
try {
$newsletterSender->sendNewsletters();
$output->writeLn('Newsletter sended');
return 0; // zero return code means everything is ok
} catch (\Nette\Mail\SmtpException $e) {
$output->writeLn('<error>' . $e->getMessage() . '</error>');
return 1; // non-zero return code means error
}
}
}
Using DI in Console commands has
- Upsides:
- more clear dependencies
- Downsides:
- even when you want to print help, you need to instantiate all dependencies
- this can be solved by using inject*() methods, which can be injected before
execute() method (too much magic?)
- not that big issue; printing help is not business critical use-case :)
- or using factories/accessors for complex classes
- this can be solved by using inject*() methods, which can be injected before
execute() method (too much magic?)
- even when you want to print help, you need to instantiate all dependencies
cc @FilipProcházka @Aurielle
- Tomáš Votruba
- Moderator | 1114
What happens when you use constructor? I use it this way with no obstacles.
- David Matějka
- Moderator | 6445
this can be solved by using inject*() methods, which can be injected before execute() method (too much magic?)
https://github.com/…lication.php#L183 ;)
@TomášVotruba
even when you want to print help, you need to instantiate all dependencies
- Honza Kuchař
- Member | 1662
Tomáš Votruba wrote:
What happens when you use constructor? I use it this way with no obstacles.
Thanks for response! I wansn't clear enough. I was asking for best practices and why this example is in documentation. (updated question)
- Tomáš Votruba
- Moderator | 1114
@HonzaMarek I'd only say profile. It depends on you application. If you have over 1000 commands, your app might perform slower with ctor injection. If you have 5 commands, it probably won't matter. There is no “best practice” in these matters.
That's why I wrote “I use it with no obstacles”.