Consuming a JSON service

JSON (JavaScript Object Notation) is probably one of the best formats available for exposing data, due to its easy-to-read syntax, which greatly simplifies the parsing. In fact, PHP (as of its 5.2.0 release) provides built-in methods to convert data from a JSON-formatted string to a PHP native data type and from PHP types to JSON.

In this recipe, we will learn how to use the HttpSocket class to consume a JSON service from a foreign site. This time, we are going to use the YouTube JSON API to allow our users to search for YouTube videos that match a given search query.

The JSON service we will be consuming from YouTube uses a variant of JSON, called JSON-C. JSON-C is nothing more than JSON, but Google is making a distinction between what YouTube used to provide as JSON, and the new version it is now producing. YouTube's JSON-C-based responses are far simpler than their JSON service. Consequently, Google has decided to deprecate JSON in favor of JSON-C in the near future.

How to do it...

  1. Start by creating the main controller in a file named videos_controller.php and place it in your app/controllers folder, with the following contents:
    <?php
    class VideosController extends AppController {
    public function index() {
    if (!empty($this->data)) {
    $videos = $this->Video->search($this->data);
    $this->set(compact('videos'));
    }
    }
    }
    ?>
    
  2. Create the required model in a file named video.php and place it in your app/models folder, with the following contents:
    <?php
    App::import('Core', 'HttpSocket'),
    class Video extends AppModel {
    public $useTable = false;
    protected $_httpSocket;
    public function __construct($id = false, $table = null, $ds = null) {
    parent::__construct($id, $table, $ds);
    $this->_httpSocket = new HttpSocket();
    }
    public function search($data) {
    $query = !empty($data[$this->alias]['q']) ?
    $data[$this->alias]['q'] :
    '';
    $this->_httpSocket->reset();
    $response = $this->_httpSocket->get(
    'http://gdata.youtube.com/feeds/api/videos',
    array(
    'v' => '2',
    'alt' => 'jsonc',
    'q' => $query,
    'orderby' => 'updated'
    )
    );
    $videos = array();
    if (!empty($response)) {
    $response = json_decode($response);
    if (empty($response) || empty($response->data->items)) {
    return $videos;
    }
    foreach($response->data->items as $item) {
    $videos[] = array('Video' => array(
    'url' => $item->player->default,
    'title' => $item->title,
    'uploaded' => strtotime($item->uploaded),
    'category' => $item->category,
    'description' => $item->description,
    'thumbnail' => $item->thumbnail->sqDefault
    ));
    }
    }
    return $videos;
    }
    }
    ?>
    
  3. Create a view folder named videos in your app/views folder. Then, create a file named index.ctp and place it in your app/views/videos folder, with the following contents:
    <?php
    echo $this->Form->create();
    echo $this->Form->input('q', array('label'=>'Search terms:'));
    echo $this->Form->end('Search'),
    if (!empty($videos)) {
    ?>
    <h1>Search results</h1>
    <?php foreach($videos as $video) { ?>
    <div style="float: left; clear: both; margin-bottom: 10px;">
    <h4><?php echo $this->Html->link($video['Video']['title'], $video['Video']['url']); ?></h4>
    <?php echo $this->Html->image($video['Video']['thumbnail'], array(
    'url' => $video['Video']['url'],
    'align' => 'left',
    'style' => 'margin-right: 10px;'
    )); ?>
    <p><?php echo $video['Video']['description']; ?></p>
    <br />
    <p><small>
    Uploaded on <?php echo date('F d, Y H:i', $video['Video']['uploaded']); ?>
    in <?php echo $video['Video']['category']; ?>
    -
    <strong><?php echo $this->Html->link('PLAY', $video['Video']['url']); ?></strong>
    </small></p>
    </div>
    <?php
    }
    }
    ?>
    

    If you now browse to http://localhost/videos, you will see a search form. Entering CakePHP and clicking the button Search should give you a set of results similar to those shown in the following screenshot:

    How to do it...

How it works...

The controller class (ArticlesController) and the view file (index.ctp) have no connection with the underlying web service we are consuming. In fact, if you look closely at their code, they look like a regular controller and a standard view file. This is because we decided to encapsulate the service logic in a model.

Doing so allows us to change how we communicate with the service provider without having to modify neither the controller nor the view. That is one of the many advantages of the MVC (Model View Controller) architecture that is the foundation of CakePHP.

We could have taken a more complex approach, and decided to build a datasource to interact with the server. Instead, we chose a simpler route, by creating a model method that would perform the actual search and return the results in a data format typical of any CakePHP application.

This is what the Video model is there for. As there's no underlying table for our videos, we set the model $useTable property to false. We also import the HttpSocket class, part of CakePHP's core, because it will be the mechanism we will use to communicate with the server.

The search() method is where the magic happens. The first thing we do is extract the search terms out of the submitted data. We then create an instance of HttpSocket, and use its get method to perform the request.

HttpSocket::get() takes three parameters:

  • $uri: The URL to which we are making the request. This can be either a string, or an array that contains the different elements of the URL, such as scheme, host, port, and path.
  • $query: An array of parameters to append to the URL. The indexes in this array are the parameter names and the values their respective values.
  • $request: An array with any additional request information to send to the URL, such as method, header, and body.

In our case we specify the URL to the YouTube video API, and we set the following query parameters:

  • v: The API version to use.
  • alt: The format to get results in.
  • q: The query to use for searching.
  • orderby: The order in which to get the results.

Once we get the response, we decode it using PHP's json_decode() function, which converts a JSON string into a PHP object or to null if it is not a valid JSON string. For example, the following JSON:

{
"name": "Mariano Iglesias",
"profile": {
"url": "http://marianoiglesias.com.ar"
}
}

Would be evaluated to a PHP class with two public attributes: name, and profile. The profile attribute will itself be a class, with one public attribute: url. If we had the above JSON string in a variable called $json, the following code would output Mariano Iglesias has a website in http://marianoiglesias.com.ar:

$user = json_decode($json);
echo $user->name . ' has a website in ' . $user->profile->url;

Back to the Video::search() method. Once we have decoded the JSON response, we check to make sure there are resulting videos available in the $response->data->items property. If so, we iterate through them, and we add elements to our response array, specifying only a subset of the data we obtained.

Once we have the data prepared, we return it back to the controller, which sends it to the view to render the results.

See also

  • Chapter 5, Datasources
  • Building REST services with JSON
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.120.87