Symfony2.8迁移Symfony5.4:命令不显示及容器访问问题
Symfony2.8 迁移到Symfony5.4:命令自动注册与服务容器访问问题
问题1:命令未自动出现在bin/console列表中
你的命令都位于WORD\*Bundle\Command命名空间下,但当前services.yml仅对App\命名空间开启了自动配置,未覆盖WORD\下的命令类,导致Symfony无法自动识别这些命令,必须手动逐个声明。
解决方案
在services.yml的services节点下添加WORD\命名空间的自动配置规则,让Symfony自动扫描并注册所有命令:
services: # 保留原有App\配置 App\: resource: '../src/' exclude: - '../src/DependencyInjection/' - '../src/Entity/' - '../src/Kernel.php' # 新增WORD命名空间的自动配置 WORD\: resource: './WORD/' exclude: - './WORD/*Bundle/DependencyInjection/' - './WORD/*Bundle/Entity/' - './WORD/*Bundle/Tests/' autowire: true autoconfigure: true _defaults: autowire: true autoconfigure: true
配置后Symfony会自动扫描WORD目录下的所有类,包括各Bundle中的Command类,并自动添加console.command标签,无需手动逐个配置。
问题2:命令中访问服务容器的方式
Symfony5.4已移除ContainerAwareCommand,直接调用$this->getContainer()会失效。不建议直接注入整个服务容器(违背依赖注入原则),推荐构造函数注入所需服务,若需临时过渡可通过实现ContainerAwareInterface访问容器。
方案1:构造函数注入(推荐)
直接在命令构造函数中注入所需服务,替代容器获取方式:
use Symfony\Component\Console\Command\Command; use Psr\Log\LoggerInterface; use WORD\AlertBundle\Manager\AlertEmployeeManager; class AlertExpirationEmailCommand extends Command { private $alertManager; private $logger; // 构造函数注入依赖 public function __construct(AlertEmployeeManager $alertManager, LoggerInterface $logger) { $this->alertManager = $alertManager; $this->logger = $logger; parent::__construct(); } protected function configure() { $this->setName('word:manager:expiration_email') ->setDescription('Alert email : Send an email x days before the expiration.') ->addOption('days', 'd', InputOption::VALUE_REQUIRED, 'How many days before the expiration', 1); } protected function execute(InputInterface $input, OutputInterface $output): int { $days = intval($input->getOption('days')); if ($days > 0) { try { // 直接使用注入的服务 $this->alertManager->sendExpirationEmail($days); } catch (\Exception $e) { $this->logger->error(sprintf( 'aemCommand: an error occurred in file "%s" (L%d): "%s"', $e->getFile(), $e->getLine(), $e->getMessage() )); } } return Command::SUCCESS; } }
该方式符合Symfony依赖注入最佳实践,代码更清晰且便于测试。
方案2:实现ContainerAwareInterface(临时过渡)
若需快速迁移、减少代码修改,可让命令类实现ContainerAwareInterface:
use Symfony\Component\Console\Command\Command; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; class AlertExpirationEmailCommand extends Command implements ContainerAwareInterface { private $container; public function setContainer(ContainerInterface $container = null) { $this->container = $container; } // 可继续使用$this->container->get('service_id')获取服务 private function getManager() { return $this->container->get('word.manager.alert_employee'); } }
注意:此为临时过渡方案,长期建议改用构造函数注入。
内容的提问来源于stack exchange,提问作者oracle972
相关产品推荐
相关产品推荐

