You are here

certificate.module in Certificate 6

Certificate module.

File

certificate.module
View source
<?php

/**
 * Certificate module.
 * @file
 */

/**
 * Implementation of hook_node_info().
 */
function certificate_node_info() {
  $items = array(
    'certificate' => array(
      'name' => t('Certificate'),
      'module' => 'certificate',
      'description' => t('A tokenized certificate template that will be converted to a PDF and displayed to users who complete accredited activities.'),
      'has_title' => TRUE,
      'title_label' => t('Title'),
      'has_body' => TRUE,
      'body_label' => t('Certificate Body'),
      'min_word_count' => '0',
      'help' => '',
      'locked' => TRUE,
    ),
  );
  return $items;
}

/**
 * Implementation of hook_access().
 */
function certificate_access($op, $node, $account) {
  if ($op == 'create') {
    return user_access('create certificate content', $account);
  }
  if ($op == 'update') {
    if (user_access('edit any certificate content', $account) || user_access('edit own certificate content', $account) && $account->uid == $node->uid) {
      return TRUE;
    }
  }
  if ($op == 'delete') {
    if (user_access('delete any certificate content', $account) || user_access('delete own certificate content', $account) && $account->uid == $node->uid) {
      return TRUE;
    }
  }
}
function certificate_form(&$node, $form_state) {

  // The site admin can decide if this node type has a title and body, and how
  // the fields should be labeled. We need to load these settings so we can
  // build the node form correctly.
  $type = node_get_types('type', $node);
  if ($type->has_title) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => check_plain($type->title_label),
      '#required' => TRUE,
      '#default_value' => $node->title,
      '#weight' => -5,
    );
  }
  if ($type->has_body) {

    // In Drupal 6, we use node_body_field() to get the body and filter
    // elements. This replaces the old textarea + filter_form() method of
    // setting this up. It will also ensure the teaser splitter gets set up
    // properly.
    $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
  }

  // Now we define the form elements specific to our node type.
  $form['certificate']['#tree'] = TRUE;
  $form['certificate']['orientation'] = array(
    '#type' => 'radios',
    '#title' => t('Orientation'),
    '#default_value' => isset($node->certificate['orientation']) ? $node->certificate['orientation'] : '',
    '#options' => array(
      'portrait' => t('Portrait'),
      'landscape' => t('Landscape'),
    ),
    '#required' => TRUE,
    '#description' => 'The orientation of the generated certificate.',
  );
  $form['options']['status']['#default_value'] = 0;
  $form['options']['promote']['#default_value'] = 0;
  return $form;
}

/**
 * Implementation of hook_help().
 */
function certificate_help($path, $arg) {
  if ($path == 'admin/help#certificate') {
    $txt = 'If you install the !advanced_help module, Views will provide more and better help.';
    $link = l('Advanced help', 'http://drupal.org/project/advanced_help');
    $replace = array(
      '!advanced_help' => $link,
    );
    return '<p>' . t($txt, $replace) . '</p>';
  }
}

/**
 * Implementation of hook_menu().
 */
function certificate_menu() {
  $items = array();

  // Certificate types.
  $items['admin/settings/certificate'] = array(
    'title' => 'Certificates',
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_admin_settings_form',
    ),
  );
  $items['admin/settings/certificate/clear'] = array(
    'title' => 'Clear',
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_admin_clear_form',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/settings/certificate/types'] = array(
    'title' => 'Settings',
    'description' => 'Select nodes which are certifiable.',
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -100,
  );
  $items['admin/settings/certificate/templates'] = array(
    'title' => 'Templates',
    'access arguments' => array(
      'administer certificates',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'certificate.admin.inc',
    'page callback' => 'certificate_templates_list',
    'weight' => -90,
  );
  $items['admin/settings/certificate/sets'] = array(
    'title' => 'Criteria sets',
    'access arguments' => array(
      'administer certificates',
    ),
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'certificate_sets_page',
    'file' => 'certificate.admin.inc',
    'weight' => -80,
  );
  $items['admin/settings/certificate/sets/list'] = array(
    'title' => 'Sets',
    'description' => 'Set up certificate sets',
    'page callback' => 'certificate_sets_page',
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/settings/certificate/sets/%certificate_set/criteria'] = array(
    'title' => 'Criteria',
    'description' => 'Edit certificate type criteria.',
    'page callback' => 'certificate_sets_checks_page',
    'page arguments' => array(
      4,
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );

  // Edit/delete type.
  $items['admin/settings/certificate/sets/%certificate_set/edit'] = array(
    'title' => 'Edit certificate type',
    'description' => 'Edit certificate type.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_sets_form',
      4,
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
  );
  $items['admin/settings/certificate/sets/%certificate_set/delete'] = array(
    'title' => 'Edit certificate type',
    'description' => 'Edit certificate type.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_set_delete_form',
      4,
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
  );

  // Delete criterion.
  $items['admin/settings/certificate/criteria/%certificate_criterion/delete'] = array(
    'title' => 'Delete Criterion',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_criterion_delete_form',
      4,
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_CALLBACK,
  );

  // Certificate templates.
  $items['admin/settings/certificate/sets/add'] = array(
    'title' => 'New set',
    'description' => 'Add a new set of criteria',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_sets_form',
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'weight' => 1,
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/settings/certificate/templates/add'] = array(
    'title' => 'New template',
    'description' => 'Add a new certificate template',
    'page callback' => 'drupal_goto',
    'page arguments' => array(
      'node/add/certificate',
      array(
        'destination' => 'admin/settings/certificate/templates',
      ),
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'type' => MENU_LOCAL_TASK,
    'tab_parent' => 'admin/settings/certificate',
    'tab_root' => 'admin/settings/certificate',
    'file' => 'certificate.admin.inc',
    'weight' => 100,
  );

  // Certificate template preview.
  $items['admin/settings/certificate/templates/preview/%'] = array(
    'title' => 'Certificate Preview',
    'description' => 'Display earned certificate for this node',
    'page callback' => 'certificate_preview',
    'page arguments' => array(
      5,
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.pages.inc',
    'type' => MENU_LOCAL_TASK,
  );

  // Certificate tab on nodes.
  $items['node/%node/certificate'] = array(
    'title' => 'Certificate',
    'description' => 'Display earned certificate for this node',
    'page callback' => 'certificate_node_certificate',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'certificate_can_access_certificate',
    'access arguments' => array(
      1,
    ),
    'file' => 'certificate.pages.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/settings/certificate/mapping'] = array(
    'title' => 'Mapping',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'certificate_settings_form',
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/settings/certificate/mapping/list'] = array(
    'title' => 'Fields',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/settings/certificate/mapping/groups'] = array(
    'title' => 'Field groups',
    'description' => 'Set up certificate field groups',
    'page callback' => 'certificate_field_grouping_page',
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );
  $items['admin/settings/certificate/mapping/groups/add'] = array(
    'title' => 'Add field group',
    'description' => 'Add a field group',
    'page callback' => 'certificate_field_grouping_add_page',
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/settings/certificate/mapping/groups/delete/%'] = array(
    'title' => 'Delete field group',
    'description' => 'Delete a field group',
    'page callback' => 'certificate_field_grouping_delete_page',
    'page arguments' => array(
      6,
    ),
    'access arguments' => array(
      'administer certificates',
    ),
    'file' => 'certificate.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function certificate_perm() {
  return array(
    'access all certificates',
    'administer certificates',
    'create certificate content',
    'delete own certificate content',
    'delete any certificate content',
    'edit own certificate content',
    'edit any certificate content',
  );
}

/**
 * Implementation of hook_theme().
 *
 * Returns information about every themable function defined by the module.
 */
function certificate_theme() {
  $items = array();
  $items['certificate_history_form'] = array(
    'arguments' => array(
      'form' => array(),
    ),
    'file' => 'certificate.admin.inc',
  );

  // Keep for now - we may want to theme the output specifically for Moodle.
  $items['certificate_certificate'] = array(
    'arguments' => array(
      'certificate' => array(),
    ),
    'file' => 'certificate.pages.inc',
  );
  $items['certificate_admin_clear_form'] = array(
    'arguments' => array(
      'form' => NULL,
    ),
    'file' => 'certificate.admin.inc',
  );
  return $items;
}

/**
 * Helper function to match template to certificate type.
 *
 * @return
 *  The content profile node object.
 *
 * @TODO: this currently assumes the content profile is of type 'profile'.
 * We'll want to make that configurable (later).
 */
function _certificate_get_user_profile($account) {
  $uid = $account->uid;

  // Curently we're using only using content-profile for this feature.
  if (module_exists('content_profile')) {
    $profile = content_profile_load('profile', $uid);
    return $profile;
  }
  return FALSE;
}

/**
 * Define Fields.
 */
function certificate_fields() {
  $field_options = array();
  $field_options[] = 'no field';
  foreach (content_fields() as $key => $field) {

    // If field isn't a profile field with allowed values, do not allow it to be selectable. It wouldn't work anyways.
    if ($field['type_name'] == 'profile' && ($field['allowed_values'] != '' || $field['allowed_values_php'] != '')) {
      $field_options[$key] = $field['widget']['label'];
    }
  }
  return $field_options;
}

/**
 * Get certificate type field.
 *
 * @return the machine readable field name.
 */
function certificate_get_selected_type() {

  // Get selected field.
  return variable_get('certificate_field_certificate_type', 0);
}

/**
 * Get certificate type field options.
 *
 * @return the selected field's options as an array.
 */
function certificate_get_selected_type_options() {

  // Get selected field name.
  $selected = certificate_get_selected_type();

  // Add 'Default' to beginning of options array, whether or not an option field is selected.
  $field_options = array(
    'default' => t('Default'),
  );

  // Get selected field's options.
  if ($selected == 'no field') {
    return NULL;
  }
  else {
    $field = content_fields($selected);

    // Remove non-keyed values (for instance, if '|Please select' workaround is used).
    $allowed_values = content_allowed_values($field);
    $keys = $allowed_values ? array_keys($allowed_values) : array();
    foreach ($keys as $key) {
      if ($key != '') {
        $allowed_values_keys[$key] = $allowed_values[$key];
      }
    }

    // Merge allowed values with default option.
    $field_options_array = $allowed_values_keys;
  }
  return $field_options_array;
}

/**
 * Implementation of hook_function_load().
 *
 * Menu load handler for an certificate type.
 */
function certificate_set_load($id) {
  $sql = "SELECT * FROM {certificate_types} ct\n    left join {node} certificate on certificate.nid = ct.template_id\n    WHERE type_id = %d";
  $result = db_query($sql, $id);
  if ($type = db_fetch_object($result)) {
    return $type;
  }
  else {
    return FALSE;
  }
}
function certificate_criterion_load($id) {
  $sql = "select * from {certificate_criteria} cc\n    left join {certificate_types} ct on ct.type_id = cc.type_id\n    where cc.check_id = %d";
  $query = db_query($sql, $id);
  if ($criterion = db_fetch_object($query)) {
    $criterion->check_key = unserialize($criterion->check_key);
    return $criterion;
  }
  else {
    return FALSE;
  }
}

/**
 * Public loader function for the full collection of certificates.
 *
 * In situations where the module's data rarely changes, or is being used
 * frequently (for example, loaded and processed on every page load), this
 * is a prime candidate for caching. See The Beginner's Guide to Caching at
 * http://www.lullabot.com/articles/a_beginners_guide_to_caching_data for more
 * details.
 *
 * @return
 *   An array of all certificates, keyed by id.
 */
function certificate_certificate_load_all() {
  $sql = "SELECT *,nid as cid FROM {node} node where type='certificate'";
  $result = db_query($sql);
  $certificates = array();
  while ($certificate = db_fetch_array($result)) {
    $certificates[$certificate['cid']] = $certificate;
  }
  drupal_alter('certificate_template_options', $certificates);
  return $certificates;
}

/**
 * Quick get per-node template settings.
 */
function certificate_course_node_template_settings($nid) {
  $sql = "SELECT * FROM {certificate_node} WHERE nid = %d";
  $result = db_query($sql, $nid);
  $node_template_settings = array();
  while ($node_template_setting = db_fetch_array($result)) {
    $node_template_settings[$node_template_setting['type']] = $node_template_setting['template'];
  }
  return $node_template_settings;
}

/**
 * Implements hook_form_alter for course nodes.
 */
function certificate_form_alter(&$form, &$form_state, $form_id) {
  $type = basename($form_id, '_node_form');
  if (certificate_node_is_certifiable($form['#node']) && strpos($form_id, '_node_form') !== FALSE) {

    // Add per-node certificate settings.
    module_load_include('inc', 'certificate', 'certificate.admin');
    certificate_alter_node_form($form, $form_state);
  }
}
function certificate_form_certificate_node_form_alter(&$form, &$form_state) {
  if (module_exists('token')) {

    // Embed token help.
    $form['certificate_tokens'] = array(
      '#title' => 'Certificate tokens',
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
      '#value' => theme('token_tree', array(
        'global',
        'node',
        'user',
        'certificate',
      ), FALSE),
    );
  }

  // No preview - we want users to see it in PDF for accuracy.
  $form['buttons']['preview'] = NULL;
}

/**
 * Submit handler to update node template mappings.
 */
function certificate_update_node_mappings(&$node) {
  $node_settings = $node->certificate['node_settings'];
  if (is_array($node_settings)) {
    db_query("DELETE FROM {certificate_node} WHERE nid = %d", $node->nid);
    foreach ($node_settings as $type => $template) {
      if ($template == 0) {
        continue;
      }
      db_query("INSERT INTO {certificate_node} (nid, type, template) VALUES (%d, '%s', %d)", $node->nid, $type, $template);
    }
  }
}

/**
 * Implements hook_nodeapi.
 */
function certificate_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  if (certificate_node_is_certifiable($node)) {
    switch ($op) {
      case 'insert':
      case 'update':
        if (certificate_node_is_certifiable($node)) {
          certificate_update_node_mappings($node);
        }
        break;
      case 'delete':

        // Clean up the certificate template tables for the deleted node.
        db_query("DELETE FROM {certificate_node} WHERE nid = %d", $node->nid);
        db_query("DELETE FROM {certificate_snapshots} WHERE nid = %d", $node->nid);
        break;
      case 'load':
        return array(
          'certificate' => array(
            'node_settings' => certificate_course_node_template_settings($node->nid),
          ),
        );
        break;
      case 'view':
        if (certificate_can_access_certificate($node)) {
          $node->content['certificate']['#value'] = '<span class="certificate-link">' . l(t('Download certificate'), "node/{$node->nid}/certificate") . '</span>';
        }
        break;
    }
  }
  if ($node->type == 'certificate') {
    switch ($op) {
      case 'insert':
      case 'update':
        $record = $node->certificate;
        $record['nid'] = $node->nid;
        if (db_result(db_query("select 1 from {certificate_node_settings} where nid = %d", $node->nid))) {
          $keys = array(
            'nid',
          );
        }
        drupal_write_record('certificate_node_settings', $record, $keys);
        break;
      case 'load':
        return array(
          'certificate' => db_fetch_array(db_query("select * from {certificate_node_settings} where nid = %d", $node->nid)),
        );
    }
  }
}

/**
 * Implementation of hook_content_extra_fields().
 * Allow the certificate download link to be sorted in the node edit forms.
 */
function certificate_content_extra_fields($type_name) {
  $node->type = $type_name;
  if (certificate_node_is_certifiable($node)) {
    $extras['certificate'] = array(
      'label' => t('Certificate'),
      'description' => t('Certificate link.'),
      'weight' => 10,
    );
  }
  if ($type_name == 'certificate') {
    $extras['certificate_tokens'] = array(
      'label' => t('Certificate tokens'),
      'description' => t('Tokens to insert into the certificate.'),
    );
  }
  return $extras;
}

/**
 * @todo make $types more generic.
 */
function certificate_node_is_certifiable(&$node) {
  return variable_get("certificate_certifiable_{$node->type}", 0);
}

/**
 * Quick certificates snapshot check.
 *
 * @param $account
 * @param $node
 *
 * @return
 *   A single certificate snapshot in array format, or FALSE if none matched the incoming ID.
 */
function certificate_snapshot_load($account, $node) {
  $sql = "SELECT * FROM {certificate_snapshots} WHERE uid = %d AND nid = %d";
  $result = db_query($sql, $account->uid, $node->nid);
  if ($snapshot = db_fetch_array($result)) {
    return $snapshot;
  }
  else {
    return FALSE;
  }
}

/**
 * Inserts a new snapshot, or updates an existing one.
 *
 * @param $certificate
 *   A certificate to be saved. If $certificate['cid'] is set, the certificate will be updated.
 *   Otherwise, a new certificate will be inserted into the database.
 * @return
 *   The saved certificate, with its ID set.
 *
 * @see certificate_single()
 */
function certificate_snapshot_save($snapshot) {
  if (isset($snapshot['csid'])) {
    drupal_write_record('certificate_snapshots', $snapshot, 'csid');
  }
  else {
    drupal_write_record('certificate_snapshots', $snapshot);
  }
  return $snapshot;
}

/**
 * Remove snapshot.
 *
 * @param $account
 * @param $node
 *
 * @return
 *   true
 */
function certificate_snapshot_delete($account, $node) {
  $sql = "DELETE FROM {certificate_snapshots} WHERE uid = %d AND nid = %d";
  db_query($sql, $account->uid, $node->nid);
  return TRUE;
}
function certificate_snapshot_delete_by_node($node) {
  $sql = "DELETE FROM {certificate_snapshots} WHERE nid = %d";
  db_query($sql, $node->nid);
  return TRUE;
}

/**
 *  Actions
 */

/**
 * Implementation of hook_action_info().
 */
function certificate_action_info() {
  $info['certificate_reset_certificates_action'] = array(
    'type' => 'node',
    'description' => t('Reset certificate snapshots for this event'),
    'configurable' => FALSE,
    'hooks' => array(
      'nodeapi' => array(
        'insert',
        'update',
      ),
    ),
  );
  return $info;
}
function certificate_reset_certificates_action($object, $context) {
  $node = $object;
  if ($node->nid && is_numeric($node->nid)) {
    certificate_snapshot_delete_by_node($node);
    watchdog('action', 'Reset certificate snapshots for: %event.', array(
      '%event' => $node->title,
    ));
  }
  else {

    //print_r("No Node");
  }
}

/**
 * Check if a user can access a certificate for this node.
 *
 * This function:
 *  @return TRUE if certificate tab should show and be accessible.
 *  @return string (eval to true for Drupal's menu) if certificate tab should
 *    show but be denied with a message.
 *  @return FALSE if certificate tab should be hidden.
 */
function certificate_can_access_certificate($node, &$account = NULL) {
  static $cert_access = array();
  if (!$account) {
    global $user;
    $account = $user;
  }
  if (!$account->uid) {
    return FALSE;
  }
  if (!isset($cert_access[$node->nid])) {
    $access = module_invoke_all('access_certificate', $node, $account);
    $cert_access[$node->nid] = $access;
  }
  else {
    $access = $cert_access[$node->nid];
  }
  foreach ($access as $item) {
    if ($item === TRUE) {

      // Something said the leaner should access the certificate.
      $found_true = TRUE;
    }
    if (is_string($item)) {

      // Something returned a string, return it (will show the menu, but error)
      return $item;
    }
    if ($item === FALSE) {
      $found_false = TRUE;
    }
  }
  if ($found_true) {
    if ($found_false) {

      // Found TRUE and FALSEs.
      return FALSE;
    }

    // Only found TRUE.
    return TRUE;
  }

  // All were false.
  return FALSE;
}
function certificate_user($op, &$edit, &$account, $category = NULL) {
  if ($op == 'delete') {
    $sql = "delete from {certificate_snapshots} where uid = %d";
    db_query($sql, $account->uid);
  }
}

/**
 * Return an array of certificate templates suitable for use in an options
 * form element.
 */
function certificate_get_template_options() {

  // Get existing templates.
  $templates = certificate_certificate_load_all();
  foreach ($templates as $key => $template) {
    $template_options[$key] = $template['title'];
  }
  return $template_options;
}

Functions

Namesort descending Description
certificate_access Implementation of hook_access().
certificate_action_info Implementation of hook_action_info().
certificate_can_access_certificate Check if a user can access a certificate for this node.
certificate_certificate_load_all Public loader function for the full collection of certificates.
certificate_content_extra_fields Implementation of hook_content_extra_fields(). Allow the certificate download link to be sorted in the node edit forms.
certificate_course_node_template_settings Quick get per-node template settings.
certificate_criterion_load
certificate_fields Define Fields.
certificate_form
certificate_form_alter Implements hook_form_alter for course nodes.
certificate_form_certificate_node_form_alter
certificate_get_selected_type Get certificate type field.
certificate_get_selected_type_options Get certificate type field options.
certificate_get_template_options Return an array of certificate templates suitable for use in an options form element.
certificate_help Implementation of hook_help().
certificate_menu Implementation of hook_menu().
certificate_nodeapi Implements hook_nodeapi.
certificate_node_info Implementation of hook_node_info().
certificate_node_is_certifiable @todo make $types more generic.
certificate_perm Implementation of hook_perm().
certificate_reset_certificates_action
certificate_set_load Implementation of hook_function_load().
certificate_snapshot_delete Remove snapshot.
certificate_snapshot_delete_by_node
certificate_snapshot_load Quick certificates snapshot check.
certificate_snapshot_save Inserts a new snapshot, or updates an existing one.
certificate_theme Implementation of hook_theme().
certificate_update_node_mappings Submit handler to update node template mappings.
certificate_user
_certificate_get_user_profile Helper function to match template to certificate type.