Archive 1.x:Anatomy of a Page Template File

From OSF Wiki
Jump to: navigation, search

Here are some example templates:

Synchronizing with the Drupal Content Type

A layout is an aggregation of a series of pages dedicated to support a certain CCK content type. Most of the pages accessible in what we call a "layout" shares the same CCK content type (except for a few exceptions depending on the usecase). For example, the "map" layout section is populated of a series of "map" content types.

That custom "map" content type defines a few custom CCK fields that are used to setup a specific page of the layout. In the case of the "map" layout, it may be a new custom field that, for example, lets people pre-load markers and polygons on the webmap.

Each of the content types used to populate each of these layouts have their own template page in the theme. These content type template pages are defined in each theme folder, and looks like "page-map.tpl.php" where "map" is the name of the content type to skin.

Basic Layout

The basic layout of a template is generally inherited from the main node template (page-node.tpl.php). The same overall layout is generally used, except that the body of the page will be filled with the information related to the layout to skin.

Specifying OSF Web Services Queries

Depending on the layout, information about different records, from different datasets, may be needed to properly display the desired information on a layout page. All of this information is queried to the running OSF Web Services instance. All the web services can be queried, but generally the developer will query one of these endpoints:

  1. Search
  2. Crud: Read
  3. SPARQL

depending on the information it needs to populate the layout page.

Incorporating External Applications and Semantic Components

Sometimes external libraries may need to be employed to display information about the record(s). These external applications may be other JavaScript tools, or semantic components.

Once the OSF Web Services endpoints get properly queried, the developer will have to create the data structure that feeds these external applications in order to display the information in these different applications.

Loading, using and feeding these external applications really depends on the application you want to use and is beyond the scope of this document.

Auto-completion

Sometimes, when you define the custom fields for your new custom content type, you may want to be able to perform auto-completion tasks to help the system administrator to know what to put in these custom fields (this particularly may happen when the value to put in one of these fields is a URI reference to a specific record from a specific dataset).

Such an auto completion task is possible by creating a special module (let's call it structCCKFields) that is used to hook a node creation page, and to change its normal text fields into auto-completion text-fields.

When set up properly, such a module manages the different auto-completion fields, from each kind of layout content types. So, for a field A it will make sure that the dataset X is queried; for a field B it will make sure that the dataset Z is queried; etc.

Here is a working example of such a Drupal module:

<?php

function structCCKFields_getForms()
{
  return(array(
    array(
      "form" => "map_node_form",
      "field" => "field_map_preselected_records",
      "wsf" => "http://locahost/ws/",
      "datasets" => "http://locahost/datasets/neighbourhoods/;http://locahost/datasets/Community_characterization_areas/;http://locahost/datasets/NeighbourhoodCluster/;http://locahost/datasets/Wards/"
    )/*,
    array(
      "form" => "",
      "field" => "",
      "wsf" => "",
      "datasets" => ""
    ),*/

  ));
}

function structCCKFields_main()
{
  return("");
}

function structCCKFields_access($op, $node, $account)
{
  return TRUE;
}

function structCCKFields_access_callback()
{
  return TRUE;
}

function structCCKFields_perm()
{
  return array(
    'access conStruct view',
    'administer conStruct view'
  );
}

function structCCKFields_menu()
{
  $forms = structCCKFields_getForms();
 
  $items = array();
 
  foreach($forms as $key => $f)
  {  
    $items['conStruct/structCCKFields_'.$key] = array(
        'title' => '',
        'page callback' => '_structCCKFields_terms',
        'page arguments' => array(1 => $f),
        'access arguments' => array('access content'),
        'type' => MENU_CALLBACK
      );
  }
 
  return $items;
}

function structCCKFields_block($op = 'list', $delta = 0, $edit = array())
{
  return("");
}

function structCCKFields_contents($which_block)
{
  return("");
}
           
function structCCKFields_form_alter(&$form, $form_state, $form_id) {
  $forms = structCCKFields_getForms();

  foreach($forms as $f)
  {
    if ($form_id == $f["form"])
    {
      $form['#after_build'] = array('_structCCKFields_form_afterbuild');
    }
  }
}

function _structCCKFields_form_afterbuild($form, &$form_state) {
 
  $forms = structCCKFields_getForms();

  foreach($forms as $key => $f)
  {
    for($i = 0; $i < 256; $i++)
    {
      if(isset($form[$f["field"]][$i]))
      {
        $form[$f["field"]][$i]['value']['#autocomplete_path'] = 'conStruct/structCCKFields_'.$key;
      }
      else
      {
        break;
      }
    }
  }
 
  return $form;
}

function _structCCKFields_terms($form, $string = '')
{
  include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/WebServiceQuerier.php');
  include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/ProcessorXML.php');
  include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/utilities.php');

  $wsq = new WebServiceQuerier($form["wsf"]."search/", "post", "text/xml",
  "attributes=".urlencode("http://purl.org/ontology/iron#prefLabel")."::".urlencode($string."**")."&datasets=".$form["datasets"]."&items=20"
  . "&inference=on&include_aggregates=false&registered_ip=self");

  $matches = array();
 
  if($wsq->getStatus() == 200)
  {
    // Query the CrudRead web service to getthe whole description of all records of this resultset.
    $xml = new ProcessorXML();
    $xml->loadXML($wsq->getResultset());

    $subjects = $xml->getSubjects();

    $results = array();

    foreach ($subjects as $subject)
    {
      $subjectType = $xml->getType($subject);

      // Get and set the URI
      $subjectUri = $xml->getURI($subject);

      $results[$subjectUri] = array();

      $results[$subjectUri]["type"] = array($subjectType);

      $predicates = $xml->getPredicates($subject);

      foreach ($predicates as $predicate)
      {
        $predicateType = $xml->getType($predicate, FALSE);

        $datasetUri = "";

        if ($predicateType == "http://purl.org/dc/terms/isPartOf")
        {
          $objects = $xml->getObjects($predicate);
          $datasetUri = $xml->getURI($objects->item(0));

          if ($datasetUri != "")
          {
            $results[$subjectUri]["dataset"] = $datasetUri;

            continue;
          }
        }

        $objects = $xml->getObjects($predicate);

        // Check if it is a reified statement
        $nodesList = $xml->getReificationStatements($objects->item(0));

        $objectText = "";

        if ($nodesList->length > 0)
        {
          $objectText = $xml->getValue($nodesList->item(0));
          $objectUri = $xml->getURI($objects->item(0));
        }
        else
        {
          $objectText = $xml->getContent($objects->item(0));
        }

        if (!isset($results[$subjectUri][$predicateType]))
        {
          $results[$subjectUri][$predicateType] = array(array(
            "text" => $objectText,
            "uri" => $objectUri
          ));
        }
        else
        {
          array_push($results[$subjectUri][$predicateType], array(
            "text" => $objectText,
            "uri" => $objectUri
          ));
        }
      }      
    }
  }
 
  foreach($results as $uri => $result)
  {
    $label = preg_replace("/[^A-Za-z0-9_-\s]/", " ", getResourceLabel($result, "Untitled Record"));
   
    $label = preg_replace('/\s+/', ' ', $label);
   
    $matches[$label." (".$uri.")"] = check_plain($label);
  }
 
 
  print drupal_to_js($matches);
  exit;
}

?>

Each time a new auto-completion field is created, the structCCKFields_getForms() function is updated to set up the auto-completion behavior of this field.

Because of the way this Drupal technique works, each time that this function gets updated to handle a new field, the structCCKFields module has to be disabled, and then re-enabled. This will ensure that the Drupal hooks get properly created by Drupal.

Now, each time an administrator of the node proceeds to create or edit a content type, as soon as he will start typing into the auto-completion field, he will get results from a dataset, or a set of datasets, that comes from the Search OSF Web Services web service endpoint.

Other Design Considerations

Like any other Drupal template file (*.tpl.php), it is possible to add standard HTML, other content, or style classes and ids anywhere else on the template page. Typically, of course, this includes calls to headers, footers and other standard layout or block components. See existing *.tpl.php files for examples.