Tag Archives: cakephp json

Speed things up with a custom-baked JSON view

Yet another gem of brilliance from Mr. jrbasso.

In a couple of my previous posts regarding CakePHP and JQuery, I’ve shown some basic strategies on setting up the communication between the client and the server.

This post, as one can guess from the title, is going to be more about optimization and making things run smoother and faster while respecting MVC and CakePHP’s methodologies.

Let’s consider a typical scenario… Somewhere in your application’s UI, a user will click an element such as a button, a link or what have ya, which will issue an AJAX request to the server. The response expected by the client (browser) will be a JSON object. (Yep, sounds like this has been done once or twice before…)

In order to respect MVC you’d usually create a controller action to process the AJAX request, perhaps grab some data from the DB and then create a view to output the JSON object.
While this is a proper approach to achieve the task at hand, one can certainly consider the overhead caused by loading the View object, the helpers and other “goodness” that comes with the typical MVC request.
Right away it becomes desirable to just echo out a json_encode()’d string right from your controller. But… whoa… I know that you’d never do something so offensive to the MVC paradigm ;)

Instead, let’s reach a middle ground… we don’t have to break MVC or cake, yet we’ll see how to make our custom JSON view act faster and more robustly.

First, we’ll make up a simple controller action such as the one here:

public function get_json_info() {
    $this->view = 'Json';
    $info = $this->MyModel->getSomeInfo();
    $json = array(
      'variableOne' => $info['some_var'],
      'variableTwo' => $info['another_var']
    );
    $this->set(compact('json'));
  }

As you see this is a totally bogus action, but it works in the same manner as you’d expect many controller actions to work when returning some JSON data.
There are two important things going on here, nonetheless:
1. $this->view = ‘Json'; instructs cake to use our custom JSON view, rather than a standard view class.
2. We’ve created a $json array with some data and set() it to be used by the view.

Now we can finally move on to look at our custom view class.
Create a file called json.php and place it in your app/views/ directory.

This particular implementation comes with a nice, little bonus. If you use Mark Story’s Debug Kit, this custom JSON view will ensure that it is working properly and doesn’t break anything as this tool is quite indispensable for many developers. For those who do not use Debug Kit at all, first you should :), and second you can make the view object even lighter by taking out the Debug Kit specific code (but that is something for your to play with).

Hopefully I didn’t mislead anyone with the title of the post, by making you think that you can “bake” such a view using the console tool. To make up for this, I offer a copy & paste solution instead ;)

Well here’s the little guy in all its glory:

<?php

class JsonView extends View {
  var $content = null;
  var $debugKit = null;

  function __construct(&$controller, $register = true) {
    if (is_object($controller) && isset($controller->viewVars['json'])) {
      if (isset($controller->helpers['DebugKit.Toolbar'])) {
        $this->debugKit = $controller->helpers['DebugKit.Toolbar'];
        parent::__construct($controller, $register);
      }
      $this->content = $controller->viewVars['json'];
    }
    if ($register) {
      ClassRegistry::addObject('view', $this);
    }
    Configure::write('debug', 0);
  }

  function render($action = null, $layout = null, $file = null) {
    if ($this->debugKit !== null) {
      DebugKitDebugger::startTimer('viewRender', __d('debug_kit', 'Rendering View', true));
      $this->loaded = $this->_loadHelpers($this->loaded, array('DebugKit.toolbar' => $this->debugKit, 'DebugKit.simpleGraph', 'html', 'number'));
      $this->_triggerHelpers('beforeRender');
    }

    if ($this->content === null) {
      $data = '';
    } else {
      $data = json_encode($this->content);
    }

    if ($this->debugKit !== null) {
      $this->_triggerHelpers('afterRender');

      DebugKitDebugger::stopTimer('viewRender');
      DebugKitDebugger::stopTimer('controllerRender');
      DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'View render complete', true));

      $backend = $this->loaded['toolbar']->getName();
      $this->loaded['toolbar']->{$backend}->send();
    }

    return $data;
  }
}

As you see, our JsonView is a child of CakePHP’s core View class. It implements and overrides a couple of methods and does so in a much lighter fashion.

Just a few things to point out:

  • $this->content = $controller->viewVars['json'];
  • remember our bogus action where we’ve set() $json var for the view? Well, this is exactly what the view is going to expect to transform into the JSON object.

  • It does so quite easily: $data = json_encode($this->content);

And there you have it… light and speedy, not too greedy ;) Perfectly optimized for JSON output.
Enjoy.