【问题标题】:Symfony Console: Event not FiringSymfony 控制台:事件未触发
【发布时间】:2017-12-15 17:37:45
【问题描述】:

按照these instructions,我已经使用以下命令安装了 Symfony 3.4。

composer.phar create-project symfony/framework-standard-edition my_project_name_3_4

然后,在 these other instructions 之后,我向股票控制台应用程序添加了一个事件调度程序,以及一个事件侦听器

#File: my_project_name_3_4/bin/console
/* ... other code ... */

$application = new Application($kernel);

//START: my new code

//create dispatcher and add to application
use Symfony\Component\EventDispatcher\EventDispatcher;
$dispatcher = new EventDispatcher();
$application->setDispatcher($dispatcher);

//add my event to dispatcher
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\ConsoleEvents;

$dispatcher->addListener(ConsoleEvents::COMMAND, function (ConsoleCommandEvent $event) {
    exit("\n\nHey, Symfony called my event!  Let's crash this party! \n\n");
});

//END:   my new code
$application->run($input);

但是,当我运行 Symfony 控制台命令时,

php bin/console help

我的事件没有触发。当 Symfony 调用我的 ConsoleEvents::COMMAND 监听器时,我希望上面的代码会停止。

我已经做了一些调试,似乎从调度程序调用$application->run删除我的事件?!在我进入进行适量调试的兔子洞之前,我想检查一下是否有什么明显的我做错了,是否有已知的科学来解决这个问题。我应该以不同的方式将事件添加到现有的 Symfony 控制台应用程序吗?

【问题讨论】:

  • 试试:$dispatcher = $kernel->getContainer()->get('event_dispatcher');
  • @Cerad 我们没有在$kernel->boot() 之前准备好容器,因此无法按原样工作,因此在您的代码之前添加$kernel->boot(),它应该可以工作。
  • 在获取容器之前调用 $kernel->boot()。似乎工作。内核保护自己不被多次引导。
  • 这是 FrameworkBundle:Application:doRun 方法,它将您的调度程序替换为容器的调度程序。我想如果你真的想要你也可以覆盖它。
  • 感谢两者——而不是创建调度程序,进行早期内核启动,然后从应用程序容器$kernel->boot(); $dispatcher = $kernel->getContainer()->get('event_dispatcher'); 获取调度程序,并使用该调度程序代替先前实例化的调度程序似乎有工作。不过,让这个问题悬而未决,因为早期手动启动感觉有点脏,而且似乎应该有更好的方法来做到这一点。很高兴对正式输入的答案进行投票,如果没有更好的结果,则将其标记为最佳。

标签: php symfony symfony-console


【解决方案1】:

我想我应该更仔细地阅读这个问题。一直到最后。我有点专注于如何修改 bin/console。

在任何情况下(双关语),您都可以像 add any event listener 一样添加命令侦听器。

namespace AppBundle;

use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class MySubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        // return the subscribed events, their methods and priorities
        return array(
            ConsoleEvents::COMMAND => array(
                array('onCommand', 0),
            )
        );
    }
    public function onCommand(ConsoleCommandEvent $event)
    {
        echo "onCommand\n";
    }
}

并且由于默认的自动装配和自动配置,您甚至不必在 services.yml 中添加任何内容。它只是工作。

==============================

原答案

我认为您可能将控制台组件与控制台框架文档混为一谈。

首先通过编辑框架安装的 bin/console 文件来回答您的问题:

# bin/console
use Symfony\Bundle\FrameworkBundle\Console\Application as FrameworkApplication;
$kernel = new AppKernel($env, $debug);
$kernel->boot();

$application = new FrameworkApplication($kernel);

$dispatcher = $kernel->getContainer()->get('event_dispatcher');

$dispatcher->addListener(\Symfony\Component\Console\ConsoleEvents::COMMAND,
    function (\Symfony\Component\Console\Event\ConsoleCommandEvent $event) {
    exit("\n\nHey, Symfony called my event!  Let's crash this party! \n\n");
});
$application->run($input);

这是基于使用框架应用程序类的完全有效的代码。

但是,您问题中的第二个链接指向基于组件应用程序类的控制台组件文档。

use Symfony\Component\Console\Application as ComponentApplication;

ComponentApplication 类不了解内核或容器。它几乎是独立的,并提供了一种通过 ComponentApplication::setDispatcher 注入事件调度程序的方法。如果您使用 ComponentApplication 类,您在问题中尝试的代码将可以正常工作,但您必须注册自己的命令。

FrameworkApplication 从内核中拉取容器,然后从中拉取事件分派器并将其传递给 setDispatcher。它还使用内核来注册命令。类中的任何内容实际上都依赖于未引导的内核。内核类本身可以防止被多次引导。

所以在调用 FrameworkApplication::run() 之前启动内核并访问容器就可以了。

我猜如果你真的想以一种“不脏”的方式来做这件事,那么只需扩展 Application 类并在 doRun 方法中添加你的监听器。

【讨论】:

  • 您早先的帮助,并为您透视@Cerad。稍微重构一下:我是从(可能过于理想化)的角度来看的,捆绑的 Symfony 控制台应用程序除了是一个有用的工具之外,也是使用 symfony 控制台组件的最佳实践的参考应用程序构建一个应用程序,我的期望是该组件的代码示例可以在控制台应用程序中运行。
  • 关于启动内核是否“脏”:虽然这个解决方案有效,并且是一个很好的解决方案(我可能会采用),但它确实迫使我(客户端程序员刚刚想要添加一个事件)到 1. 注意引导内核,以及 2. 如果 symfony 控制台应用程序进行了假设其内核引导程序的更改,请承担责任。一个“干净”的解决方案可以让我添加我的侦听器,而无需了解应用程序如何完成其​​工作。
  • 基于框架的应用程序控制台与基于组件的应用程序控制台不同。 bin/console 根本不是为开发人员修改而设计的。如果您出于某种原因需要它以不同的方式工作,请克隆它并进行相应的调整。
  • 我想我终于明白这个问题了。更新了答案。
  • 感谢您花时间解析我的“我不是全职 Symfony 开发人员”的问题。不胜感激!
猜你喜欢
  • 2010-10-15
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多