The best way for JSON response.

As we seen in manual: http://docs.phalconphp.com/en/latest/reference/views.html#control-rendering-levels the good way is a prevent view rendering.

But question is how to flush JSON data from action method with proper headers in right way?

$this->view->setRenderLevel(\Phalcon\Mvc\View::LEVEL_NO_RENDER);
// ...
return json_encode([]);
// -or-
echo json_encode([]);
// -or-
$this->response->setContentType('application/json', 'UTF-8');
$this->response->setContent(json_encode([]));
#$this->response->send();
// -or- ???


85.3k

This is the short way to do that:

<?php

class FeedController extends Phalcon\Mvc\Controller
{

    public function getAction()
    {
       $this->view->disable();
        echo json_encode([1, 2, 3]);
    }

}

Or a more structured way:

<?php

class FeedController extends Phalcon\Mvc\Controller
{

    public function getAction()
    {
       $this->view->disable();

        //Create a response instance
        $response = new \Phalcon\Http\Response();

        //Set the content of the response
        $response->setContent(json_encode([1, 2, 3]));

        //Return the response
        return $response;
    }

}

I think the second solution is a more applicable. Thanks!

$response = new \Phalcon\Http\Request();
->
$response = new \Phalcon\Http\Response();


87
edited Apr '14

For some big apps you can use custom Abstract Controller and Events Menager

abstract class MyController extends Phalcon\Mvc\Controller {
  protected $_isJsonResponse = false;

  // Call this func to set json response enabled
  public function setJsonResponse() {
    $this->view->disable();

    $this->_isJsonResponse = true;
    $this->response->setContentType('application/json', 'UTF-8');
  }

  // After route executed event
  public function afterExecuteRoute(\Phalcon\Mvc\Dispatcher $dispatcher) {
    if ($this->_isJsonResponse) {
      $data = $dispatcher->getReturnedValue();
      if (is_array($data)) {
        $data = json_encode($data);
      }

      $this->response->setContent($data);
    }
  }
}

Then in your controller:

class AjaxController extends MyController {
   public function checkAction() {
      $this->setJsonResponse();
      return array('success' => true);
   }
}


1.9k
edited Apr '14

Which is the proper way? I'm currently using: (and works fine actually)

$this->response->setJsonContent(array('status' => 'ERROR', 'messages' => $errors));
$this->response->send();

Or it should be:

$this->response->setJsonContent(array('status' => 'ERROR', 'messages' => $errors));
return $this->response;

What's the difference intenally? Should i add $this->view->disable(); for either?

Neither of the ways from @Phalcon are working out as expected for me. The content is display twice on the page (the controller is also called twice).

This is the output I am getting:

[1,2,3][1,2,3]

Is this a bug or am I doing something wrong (wrong settings for example)?

Thanks in advance.

The solution given from lexx-a worked for me, the only thing that I changed was that in the afterExecuteRoute method I needed to add the following return:

return $this->response->send();

edited Aug '14

Base on lexx-d answer, this is my baseController - For complex apps with mix of pure and Ajax calls. No need to change controller and action logic to return params! Just send Ajax call and all decisions will be made:

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\View;

class ControllerBase extends Controller
{
    // After route executed event
    public function afterExecuteRoute(\Phalcon\Mvc\Dispatcher $dispatcher) {
        if($this->request->isAjax() == true) {
            $this->view->disableLevel(array(
                View::LEVEL_ACTION_VIEW => true,
                View::LEVEL_LAYOUT => true,
                View::LEVEL_MAIN_LAYOUT => true,
                View::LEVEL_AFTER_TEMPLATE => true,
                View::LEVEL_BEFORE_TEMPLATE => true
            ));

            $this->response->setContentType('application/json', 'UTF-8');
            $data = $this->view->getParamsToView();

            /*
             * Or for returnish action lovers:
             *   ->  $data = $dispatcher->getReturnedValue();
             */

            /* Set global params if is not set in controller/action */
            if (is_array($data)) {
                $data['success'] = isset($data['success']) ?: true;
                $data['message'] = isset($data['message']) ?: '';
                $data = json_encode($data);
            }

            $this->response->setContent($data);
        }

        return $this->response->send();
    }
}

Then this is controller Use case: PostsController

class PostsController extends ControllerBase
{

    public function showAction()
    {

        $posts = Post::findAll();
        $this->view->posts = $posts;
    }

}

Ajax call and return json value:

$.ajax(
    {
        url:"/posts/show/",
        success: function (result){
            console.log(result); /* Result: {success: true, message: '', posts: [{...}{...}{...}...}] */
        }
    }
);

sszdh, how I can return parsed html as JSON element. For example I need:

{
    status: true,
    newsItems: [{...},{...}],
    someRenderedPartial: 'renderedPartialHTML'
}

Arthur Halma, If you want to put HTML in JSON Just use json_encode but make sure you encode it to UTF8 first otherwise unicode characters will break it resulting in empty output!

@sszdh, I used method from "Get rendered view contents and transform it into a json-object on ajax requests with the use of events" thread where $view->getContent() is used (what I was asking for).



4.6k

$this->view->disable();
header('Content-type:application/json;charset=utf-8');
echo json_encode([1, 2, 3]);

What about someting like this?

    abstract class MyController extends Phalcon\Mvc\Controller {

      // Sends the json response
      public function sendJson($data) {
        $this->view->disable();
        $this->response->setContentType('application/json', 'UTF-8');
        $this->response->setContent(json_encode($data));
        return $this->response;
      }
    }

Then in the controller:

    class AnyController extends MyController {

       public function anyAction()  {
            $response = ['success' => 1];
            return $this->sendJson($response);
       }

    }