草庐IT

php - 发送响应后 Symfony 运行代码

coder 2024-01-01 原文

我看了一下this other question .我正在寻找一种方法来做那个问题的 OP 想要的,那就是 continue processing php after sending http response , 但在 Symfony2 中。

我实现了一个在每次内核终止后触发的事件。到目前为止一切顺利,但我想要的是在某些特定的 Controller 操作中,例如在发送表单之后,而不是在每次请求时都在某些终止后触发。那是因为我想在某些时候做一些繁重的任务,不希望最终用户等待页面加载。

知道我该怎么做吗?

<?php


namespace MedAppBundle\Event;

use JMS\DiExtraBundle\Annotation\InjectParams;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\Tag;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use JMS\DiExtraBundle\Annotation\Inject;
/**
 * Class MedicListener
 * @package MedAppBundle\EventListener
 * @Service("medapp_test.listener")
 * @Tag(name="kernel.event_subscriber")
 */
class TestListener implements EventSubscriberInterface
{
    private $container;

    private $logger;

    /**
     * Constructor.
     *
     * @param ContainerInterface $container A ContainerInterface instance
     * @param LoggerInterface $logger A LoggerInterface instance
     * @InjectParams({
     *     "container" = @Inject("service_container"),
     *     "logger" = @Inject("logger")
     * })
     */
    public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
    {
        $this->container = $container;
        $this->logger = $logger;
    }

    public function onTerminate()
    {
      $this->logger->notice('fired');
    }

    public static function getSubscribedEvents()
    {
        $listeners = array(KernelEvents::TERMINATE => 'onTerminate');

        if (class_exists('Symfony\Component\Console\ConsoleEvents')) {
            $listeners[ConsoleEvents::TERMINATE] = 'onTerminate';
        }

        return $listeners;
    }
}

到目前为止,我已将事件订阅到 kernel.terminate 事件,但显然这会在每次请求时触发它。我使它类似于 Swiftmailer 的 EmailSenderListener

感觉有点奇怪,内核必须每次都监听这个事件,即使它没有被触发。我宁愿只在需要时触发它,但不确定该怎么做。

最佳答案

在 onTerminate 回调中你得到一个 PostResponseEvent 的实例作为第一个参数。您可以从该对象获取请求和响应。 然后您应该能够决定是否要运行实际的终止代码。

您还可以将自定义数据存储在请求的属性包中。请参阅此链接:Symfony and HTTP Fundamentals

The Request class also has a public attributes property, which holds special data related to how the application works internally. For the Symfony Framework, the attributes holds the values returned by the matched route, like _controller, id (if you have an {id} wildcard), and even the name of the matched route (_route). The attributes property exists entirely to be a place where you can prepare and store context-specific information about the request.

您的代码可能如下所示:

// ...

class TestListener implements EventSubscriberInterface
{
    // ...

    public function onTerminate(PostResponseEvent $event)
    {
        $request = $event->getRequest();
        if ($request->attributes->get('_route') == 'some_route_name') {
            // do stuff
        }
    }

    // ...
}

编辑:

kernel.terminate 事件设计为在发送响应后运行。但是 symfony 文档是这样说的(摘自 here ):

Internally, the HttpKernel makes use of the fastcgi_finish_request PHP function. This means that at the moment, only the PHP FPM server API is able to send a response to the client while the server's PHP process still performs some tasks. With all other server APIs, listeners to kernel.terminate are still executed, but the response is not sent to the client until they are all completed.

编辑 2:

使用 here 中的解决方案,您可以直接编辑 web/app.php 文件以将其添加到那里(但这是某种“hacking core”imo,尽管它比以下内容更容易使用)。或者你可以这样做:

  1. 向具有高优先级的 kernel.request 事件添加监听器并启动输出缓冲 (ob_start)。
  2. 向 kernel.response 添加监听器并将 header 值添加到响应。
  3. 将另一个具有最高优先级的监听器添加到 kernel.terminate 并执行刷新(ob_flush、flush)。
  4. 在 kernel.terminate 优先级较低的单独监听器中运行代码

我没有尝试过,但它应该确实有效。

关于php - 发送响应后 Symfony 运行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35219537/

有关php - 发送响应后 Symfony 运行代码的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  5. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  6. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  7. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  8. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  9. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  10. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

随机推荐