Search code examples
phpweb-servicesdrupaldrupal-7drupal-modules

Drupal module page from WebService


I am looking for an elegant (as much as possible) solution to build a specific page in a Drupal website.

So, I started with :

function hook_menu() {
    $items = array();

    $items['module/articles'] = array(
        'title' => 'List of articles',
        'page callback' => 'show_article_list',
        'access arguments' => array('access content'),
        'type' => MENU_CALLBACK,
     );
    $items['module/articles/%'] = array(
        'title' => '',
        'page callback' => 'show_article_page',
        'page arguments' => array(2),
        'access arguments' => array('access content'),
        'type' => MENU_CALLBACK,
     );

    return $items;
}

The first item return the list of my articles, and, the second build a page for the article % (where % is an id to make it simple).

The point is, I use a webservice to get the list, and each page. So the page callback makes a call to my webservice (http://api/articles for instance) and build the page according to the result.

It works. But, if I want to set the title of each % page, I have to use a title callback, which is another function. And, I don't want to make another call to my webservice. To make it clear : http://api/articles/id, returns the title and the content in one result. So using two methods makes me calling this url twice : one for the title, and another one for the content.

Is there a better approch to solve this problem ?

Many thanks in advance,


Solution

  • The easiest and fastest solution for this is to use the drupal_set_title() in the page callback for the 'module/articles/%' menu item. See: https://api.drupal.org/api/drupal/includes!bootstrap.inc/function/drupal_set_title/7

    However, with this approach you only solve your particular issue. A more general and elegant solution is to have a function which can load and statically cache an article. For example, let's say your module is called article. You first define a function like this:

    function article_load($id) {
      // The $articles is an array of article objects from the webservice.
      $articles = &drupal_static(__FUNCTION__);
      if (!isset($articles[$id])) {
        $articles[$id] = call_to_your_webservice_to_load_the_article($id);
      }
      return $articles[$id];
    }
    

    Then, one thing is that you can use this function wherever in your code. The second thing is that you can also use the so called 'magic wildcards' in the menu. So you can have something like:

    $items['module/articles/%article'] = array(
        'title' => '',
        'page callback' => 'show_article_page',
        'page arguments' => array(2),
        'access arguments' => array('access content'),
        'type' => MENU_CALLBACK,
     );
    

    This means that, before Drupal will invoke any menu function callback (page, access, title), it will first check if a function with the name article_load exists, will first call that one and will pass the result to the specific menu function callback. And because the article_load will statically cache the data, it will invoke your webservice on the first call, and on all the other calls it will just return the cached article object. So you can also use a title callback again and do not use the drupal_set_title() in the page callback.

    I personally like the second approach better because it allows to load the article at any point during the request without making additional external calls, so it is more generic.

    Also, don't forget to clear the cache when you do changes in the menu hook.