The field handler API

Last updated on
9 May 2017

Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites

The field handler API is designed to add extra address fields, such as a gender field. To add extra address fields, you'll need to declare a field handler in your module and implement this handler. You will also need to declare one or more fields that will be using that handler. You can also declare a field that is using an existing handler (if that handler suite the needs for your field).

Table of contents

Declaration of a field handler

Implement hook_uc_addresses_field_handlers() and return an array of field handler definitions.

The handler definition must contain a parent handler name, the class name of the handler, the file and path identifying the location of the implementation of the handler. Ubercart Addresses distinguishes between the key of the handler definition (the key of the handler in the $info array) and the class name of the handler. However, most of the times the class name and the key are the same. Every handler must be derived either directly or indirectly from UcAddressesFieldHandler. The value of the parent property refers to the handler key of another handler, not its class name.

<?php
/**
 * Implementation of hook_uc_addresses_field_handlers().
 *
 * @return array
 */
function mymodule_uc_addresses_field_handlers() {
  $info = array();

  $info['MyCustomFieldHandler'] = array(
    'handler' => array(
      'parent' => 'UcAddressesFieldHandler',
      'class' => 'MyCustomFieldHandler',
      'file' => 'MyCustomFieldHandler.class.php',
      'path' => drupal_get_path('module', 'mymodule'),
    ),
  );

  return $info;
}
?>

Implementation of a field handler

The implementation of the field handler is a class extending UcAddressesFieldHandler that needs to reside in the file indicated in hook_uc_addresses_field_handlers(). When the handler is requested, it is dynamically loaded from this file.

The handler is responsible for:

  • generating the form field (required).
  • generating the field title (optional).
  • determining whether the field is enabled (required).
  • determining whether the field is required (required).
  • returning a default value (optional).
  • validating the field's value (optional).
  • setting the field's value (optional).
  • outputting the "safe" field's value (optional).

Generate the form field: getFormField()

Required. Every field handler should return the form field by implementing getFormField(). It should return an array of a form field definition using the Drupal form API.

<?php
/**
 * Implementation of UcAddressesFieldHandler::getFormField().
 */
public function getFormField($form, $form_values) {
  $fieldName = $this->getFieldName();
  $fieldValue = $this->getAddress()->getField($fieldName);
  $default = (isset($form_values[$fieldName]))? $form_values[$fieldName]:$fieldValue;

  return array(
    $fieldName => array(
      '#type' => 'textfield',
      '#title' => $this->getFieldTitle(),
      '#required' => $this->isFieldRequired(),
      '#default_value' => $default,
    ),
  );
}
?>

Generate the field title: getFieldTitle()

Optional. While the field title can be used in edit forms (see getFormField()), it is also used on pages where the field's value is displayed, such as the address book page and the order review page. The return value of this method is expected to be safe for output.
By default the field's title is taken from the field definition (see "Declaration of a Field" below for details), but with implementing this method you can override that behaviour.

<?php
/**
 * Override of UcAddressesFieldHandler::getFieldTitle().
 */
public function getFieldTitle() {
  return $this->getProperty('title');
}
?>

Determine whether the field is enabled: isFieldEnabled()

Required. Most fields used in Ubercart Addresses can be enabled or disabled. Disabled fields are not shown on any page produced by Ubercart Addresses. If you want the end user to be able to enable or disable the field, you should care yourself for the presentation of the setting somewhere. You can also just return TRUE if the field should always be enabled.

<?php
/**
 * Implementation of UcAddressesFieldHandler::isFieldEnabled().
 */
public function isFieldEnabled() {
  // This field is enabled by default.
  return variable_get('mymodule_myfield_enabled', TRUE);
}
?>

Determine whether the field is required: isFieldRequired()

Required. With this method you can say if your field is required. This method should be called in the getFormField() implementation. Just as the isFieldEnabled()-method, you should care yourself to show the setting somewhere in the user interface. You can also return TRUE if your field is always required and FALSE if it is never required. Note that a field can be forced to be not required when $element['#uc_addresses_required'] is set to FALSE.

<?php
/**
 * Implementation of UcAddressesFieldHandler::isFieldRequired().
 */
public function isFieldRequired() {
  // This field is never required.
  return FALSE;
}
?>

Validate the field's value: validateValue()

Optional. If your field requires specific validation, you can add any validation rules in an implementation of this method.

<?php
/**
 * Implementation of UcAddressesFieldHandler::validateValue().
 */
public function validateValue(&$value) {
  // Example: only allow lowercase characters (and nothing else).
  if (!preg_match('/[a-z]+/', $value)) {
    form_set_error($this->getFieldName(), t('The field %field may only contain lowercase characters and no spaces.', array('%field' => $this->getFieldName())));
  }
}
?>

Setting the field's value: setValue()

Optional. Implement this method if you want to set the field's value in a different way than that is done by default or if you want to perform actions before or after the value of your field is set.

<?php
/**
 * Implementation of UcAddressesFieldHandler::setValue().
 */
public function setValue($value) {
  // Example: convert to lowercase characters.
  $value = strtolower($value);
  // Let the parent class handle the rest.
  parent::setValue($value);
}
?>

Output the "safe" field's value

Optional. The method outputValue() should return the field's value that is safe for output. If your field has more ways of outputting a field, you can specify the available formats in getOutputFormats(). For every output format an Ubercart Addresses token will be created. If you have only one way of outputting the field's value, then you don't need to implement getOutputFormats(). If only a check_plain() is enough for outputting the value for your field, then you don't need to implement outputValue() either, as that is done by default (when the method is not present in your field handler).

Implementation for the zone field, which can be outputted in two ways: as zone code or as zone name.

<?php
/**
 * Returns an array of output formats for the zone field.
 *
 * @access public
 * @return array
 */
public function getOutputFormats() {
  return array(
    'zone_code' => t('Abbreviation of the zone'),
    'zone_name' => t('Full name of the zone'),
  );
}

/**
 * Output zone name.
 *
 * @param mixed $value
 *   The value to output
 * @param string $format
 *   The format in which the value should be outputted.
 *   Possible formats are declared by field handlers: getOutputFormats().
 * @access public
 * @return string
 */
public function outputValue($value = '', $format = '') {
  if ($value === '') {
    $value = $this->getAddress()->getField($this->getFieldName());
  }

  // Get zone data
  $result = db_query("SELECT * FROM {uc_zones} WHERE zone_id = %d", $value);
  if (!($zone_data = db_fetch_array($result))) {
    $zone_data = array('zone_code' => t('N/A'), 'zone_name' => t('Unknown'));
  }

  if (isset($zone_data[$format])) {
    return $zone_data[$format];
  }

  // If no format is specified, return zone name
  return $zone_data['zone_name'];
}
?>

Declaration of a field

Implement hook_uc_addresses_fields() and return an array of field definitions.

Each field definition must have a name (which is specified in the key) and a handler. In most cases, a title is also required, unless you override getFieldTitle() in the field handler. Optionally you can specify in which contexts the field should be shown in the display_settings-array, specify if the field may be used in address comparisons in compare and define other properties that can be reached from within the handler.

New fields will be automatically assigned to an address, but they will not be automatically saved to the database unless you alter the schemas uc_addresses and uc_orders. If you want to store field values in a different place, you should implement the hooks hook_uc_addresses_address_load(), hook_uc_addresses_address_insert(), hook_uc_addresses_address_update() and hook_uc_addresses_address_delete(). See the uc_addresses.api.php - included with the module - for more information about implementing these hooks.

Overview of the definition of a field

Name: name (string)
The key of the field definition is used as the name of the field. The field definition will automatically get a property "name" assigned when the fields are requested (this happens in the function uc_addresses_get_address_fields()).
Title: title (string)
Fields shoud always have specified a title, except when getFieldTitle() is overridden in the field handler and the property is not used (see the base handler for Ubercart core address fields for an example: UcAddressesUcFieldHandler).
Field handler: handler (string)
Each field should have specified which field handler it uses.
Display settings: display_settings (array)
Not all fields should be displayed in all contexts. When you declare a field you can specify in which contexts it should be shown, such as the checkout page, the address book, the order review page, etc.
Compare: compare (boolean)
To avoid having double addresses in the address book, addresses are sometimes compared. Some of the address fields should be skipped when doing a comparison because they are always unique (address ID, address nickname) or used as a setting (default shipping/default billing). Because of this you can specify if your field should be used in address comparisons.

Optionally, you can declare extra properties that can be reached from within the field handler (call getProperty() in the field handler). If you use extra properties in the handler, these properties will become required in the definition. An UcAddressesInvalidParameterException can be thrown if the handler tries to access a property that does not exist.

Display settings: contexts

An overview of contexts on which the field can be shown:

default
If set to TRUE, the field may always be displayed unless otherwise stated. If set to FALSE, the field is never displayed unless otherwise stated.
address_form
This represents address edit forms in the address book.
address_view
This represents pages in the address book: pages where the address book is completely displayed and pages where single addresses are displayed.
checkout_form
The page where the customer fills in the checkout form, usually cart/checkout.
checkout_review
The page where the customer can review and confirm his/her order just before the order is placed, usually cart/checkout/review.
order_form
The page where the webshop administrator can edit or create the Ubercart order.
order_view
The pages where the Ubercart order can be viewed (by the customer or the webshop administrator).
token
When tokens for the token module are generated.

Example

<?php
/**
 * Implementation of hook_uc_addresses_fields().
 */
function mymodule_uc_addresses_fields() {
  return array(
    'myfield' => array(
      'title' => t('My field'),
      'handler' => 'MyCustomFieldHandler',
      'display_settings' => array(
        'default' => TRUE, // Display it by default
        'address_form' => TRUE, // Display it on the address edit form
        'address_view' => TRUE, // Display it in the address book
        'checkout_form' => FALSE, // Don't display during checkout
        'checkout_review' => FALSE, // Don't display at checkout review
        'order_form' => TRUE, // Display on order edit forms
        'order_view' => TRUE, // Display on order view pages
      ),
      'compare' => TRUE, // Field is used in address comparisons
    );
  );
}
?>

Help improve this page

Page status: No known problems

You can: