Using descriptors

From Achievo/ATK Wiki

Jump to: navigation, search

ATK Howto: Using descriptors

Complexity: Easy
Author: Ivo Jansch <ivo@achievo.org>

List of other Howto's


Contents

What is a descriptor?

A descriptor is a piece of text that identifies a record to a user. For example, say you have a table with products. Each product has a unique id. The 'id' field is what we call the 'identifier' or the 'key'. This is how the database recognizes a record.


Say you have the following products in your database:

 ID      NAME
 -------------------------
 102     Nintendo Wii
 294     Apple MacBook Pro


The database identifies these records by their id. So if you want to delete the Nintendo Wii (hypothetically speaking; there's no reason to delete a Wii of course), you'd say 'DELETE FROM products WHERE id=102'.

Humans don't like id's though. If in your application you need to display a dropdown of products, the numbers '102' and '294' wouldn't mean anything to the average user.

Humans would identify the product by their name. So we call the 'name' field the 'descriptor' of the record.

If we tell ATK what the descriptor of a certain node is, ATK will take care of displaying it to the user whenever a record is displayed on screen.

What is a descriptor template?

Sometimes a descriptor consists of a single field, as in the example above. But there may be situations where this is not enough information for the user to distinguish the record. Take the following example:

 ID      PRODUCT            FLAVOUR
 -------------------------------------------
 913     Milkshake          Banana
 213     Milkshake          Strawberry

The product name in this case is not unique enough, nor is the flavour. A good descriptor in this case would be: "Milkshake (Banana flavour)".

We can tell ATK to create descriptors for records this way using a 'descriptor template'. This is similar to an HTML template, and basically consists of a string with a few fieldnames in them.

The descriptor template for our milkshake example would be:

"[product] ([flavour] flavour)"

The [Product] and [flavour] fields will be replaced at runtime by their actual values, depending on which record the system is rendering.

How do I set the descriptor template?

The canonical way

The easiest way is to create a small method inside your node that provides the system the descriptor template. This is a method that is from a distant past, so its name does not adhere to modern naming conventions, but here is an example:

function descriptor_def()
{
  return "[product] ([flavour] flavour)";
}

Whenever ATK needs to render a descriptor for your node, it will call this function to find out what the template is.

The setDescriptorTemplate way

You can call this in the constructor of your node (or anywhere else, but usually the constructor is suitable):

  $this->setDescriptorTemplate("[product] ([flavour] flavour)");

In a relationship

If some node has a relationship with a different node but it doesn't like the descriptor that is set in the related node, it can change it on the fly:

  $rel = &$this->add(new atkManyToOneRelation("product", "shop.product"));
  $rel->setDescriptorTemplate("[flavour] [product]");

Dynamic descriptors

Sometimes you will want descriptors to not be just a template, but to depend on the values of a record.

There are 2 ways to do this.

The canonical way

Instead of a descriptor_def method, implement a combination of descriptorFields() and descriptor(). It's difficult to describe their purpose without an example, so take the following code:

  function descriptor($record)
  {
     if ($record["type"]=="food") return $record["name"]." - ".$record["calories"]." calories";
     else return $record["name"];
  }

This creates a descriptor on the fly, based on the values of the $record that is being rendered.

ATK has some optimisations that make sure that data is only loaded if necessary. ATK doesn't know that you'll be needing the name and calories fields in this function, so they won't be present by default in $record.

This is why you need the second function:

  function descriptorFields()
  {
    return array("name", "type", "calories");
  }

ATK will call this function prior to calling your descriptor. It will now know that you'll be needing the name, type and calories fields, and will make sure that $record is populated accordingly.

Using a handler

It is also possible to place the descriptor method in an object, so you can reuse it's logic:

$this->setDescriptorHandler(new myCustomDescriptor());

Then, you'd implement this class like this:

class myCustomDescriptor
{
  function descriptor($record)
  {
    return $record["name"];
  }
}
Personal tools
Navigation