ZF-4134: Zend_Controller_Action_Helper_Json->sendJson() blocks front's dispatchLoopShutdown()

Description

h3.Details


/**
 * Simplify AJAX context switching based on requested format
 */
class Zend_Controller_Action_Helper_Json extends Zend_Controller_Action_Helper_Abstract
{
    // Suppress exit when sendJson() called
    public $suppressExit = false;

    // Encode JSON response and immediately send
    public function sendJson($data, $keepLayouts = false)
    {
        $data = $this->encodeJson($data, $keepLayouts);
        $response = $this->getResponse();
        $response->setBody($data);

        if (!$this->suppressExit) {
            $response->sendResponse();
            exit;
        }

        return $data;
    }
...

Everything's ok here only if we assume that no controller plugin adds http headers to Zend_Controller_Response. Otherwise, we get lack of expected headers inserted by FC's plugins.

For example, one of this affected plugin is Zend_Wildfire_Channel_HttpHeaders (extends Zend_Controller_Plugin_Abstract) which inserts firephp-related headers with its flush() method initially triggered by "_plugins->dispatchLoopShutdown()" in front controller.

h3.Test case Zend_Registry::get('log') returns Zend_Logger object with firebug writer.

h4.Works


Zend_Registry::get('log')->info('Test debug msg...'); // WILL send firebug headers

h4.Doesn't work


Zend_Registry::get('log')->info('Test debug msg...'); // Will NOT send firebug headers
$this->_helper->Json($data);

h3. Temporary Workaround for Zend_Wildfire_Channel_HttpHeaders


$json = $this->getHelper('Json');
$json->suppressExit = true;
$json->sendJson($foo);
Zend_Wildfire_Channel_HttpHeaders::getInstance()->flush();
$json->getResponse()->sendResponse();
exit;

Comments

For Zend_Wildfire_Channel_HttpHeaders, the problem could be solved by registering a listener/plugin on Zend_Controller_Response that gets notified when sendResponse() or more specifically sendHeaders() is called. This would work for any other plugins that need to send headers as well.

See ZF-4181 for another reason for needing a listener for sendHeaders() for the Response object.

Also reported here: ZF-4202

Marked as won't fix for the following reasons:

  1. The helper explicitly notes that it's purpose it to immediately send the response when called sendJson().
  2. I can see two possible solutions for deferring the immediate sending using the sendJson() and direct() methods to return the JSON without calling sendResponse().

It appears that the issue is not a bug but a disagreement over the nature/API of the helper. Such disagreements do not constitute a valid issue.