You are here

regcode_api.inc.php in Registration codes 5.3

regcode_api.inc.php contains general low-level functions for the registration-code module, for tasks like

  • data handling
  • internal field info
  • import

File

regcode_api.inc.php
View source
<?php

/**
 * @file
 * regcode_api.inc.php contains general low-level
 * functions for the registration-code module, for tasks like
 * - data handling
 * - internal field info
 * - import
 */

// ===========================
// = common helper functions =
// ===========================

/**
 * Return text message requested by given identifier/constant
 *
 * @param $id1
 *  The primary section-identifier (string) for the message
 * @param $id2
 *  The secondary sub-identifier (constant) for the message
 * @return
 *  The text of the message.
 */
function regcode_message($id1, $id2 = NULL) {
  switch ($id1) {
    case 'VALIDITY_ERROR':
      switch ($id2) {
        case REGCODE_VALIDITY_NOTEXISTING:
          return 'This registration code does not exist.';
        case REGCODE_VALIDITY_NOTAVAILABLE:
          return 'This registration code is not available.';
        case REGCODE_VALIDITY_TAKEN:
          return 'This registration code has already been used.';
        case REGCODE_VALIDITY_EXPIRED:
          return 'This registration code has expired.';
      }
  }
}

// ===================================
// = registration code data handling =
// ===================================

/**
 * Retrieve a particular registration code identified by given code id,
 * or assign it to a given user
 *
 * @param $code
 *  The code identifiert string
 * @param $assign_to_uid
 *  Optional user id to assign the given code to
 * @return
 *  The data array of the code to retrieve, or a boolean result (TRUE=successfully assigned to given uid) if assign_to_uid has been given.
 */
function regcode_get_code($code, $assign_to_uid = FALSE) {

  // look up and retrieve code record from DB
  $code = db_fetch_array(db_query("SELECT * FROM {regcode} WHERE code = '%s'", $code));

  // check validity
  if (!is_array($code)) {
    return REGCODE_VALIDITY_NOTEXISTING;
  }
  if ($code['uid']) {
    return REGCODE_VALIDITY_TAKEN;
  }
  if (!$code['available']) {
    return REGCODE_VALIDITY_NOTAVAILABLE;
  }
  if ($code['expire'] && $code['expire'] < $_SERVER["REQUEST_TIME"]) {
    return REGCODE_VALIDITY_EXPIRED;
  }

  // optionally mark this code as taken for the given user uid
  if ($assign_to_uid) {
    if ($code['reuse']) {
      $result = db_query("UPDATE {regcode} SET used_count = (used_count + 1), used = UNIX_TIMESTAMP() WHERE code = '%s'", $code['code']);
    }
    else {
      $result = db_query("UPDATE {regcode} SET available = 0, used_count = 1, used = UNIX_TIMESTAMP(), uid = %d WHERE code = '%s'", $assign_to_uid, $code['code']);
    }
  }
  return $code;
}

/**
 * Return the database query result for the given options to list codes
 *
 * @param $options
 *   An array of options for retrieving registration codes:
 *    filter_field    -  registration code field to filter the results by (see regcode_get_fields)
 *    filter_operand  -  The filter operand: contains / equals / not / greater / smaller (see regcode_get_filter_operands)
 *    filter_data     -  The data to filter on, string or number
 *    start           -  db result sequence number of first code to retrieve, see regcode_get_fields
 *    limit           -  number of codes to retrieve
 *    order           -  registration code field to order the results by (see regcode_get_fields)
 *    sort            -  sort order to order the results by: ASC / DESC
 *    pager           -  the pager identifier if a paging mechanism should be used
 *
 * @return
 *   An array list of code data arrays
 */
function regcode_get_codes($options = array()) {
  $o = array_merge(array(
    'filter_operand' => 'equals',
    'start' => 0,
    'limit' => 100,
    'order' => 'code',
    'sort' => 'asc',
    'pager' => NULL,
  ), $options);
  $fields = regcode_get_fields(TRUE);
  if (isset($o['filter_field']) && isset($o['filter_data'])) {
    if ($fields[$o['filter_field']]) {
      $filter = $o['filter_field'];
    }
    $operand = regcode_get_filter_operands('sql', $o['filter_operand']);
    $sql_where = "WHERE     {$filter} {$operand} ";
  }
  $order = isset($fields[$o['order']]) ? $o['order'] : 'code';
  $sort = drupal_strtoupper($o['sort']) == 'DESC' ? 'DESC' : 'ASC';
  foreach (array_keys($fields) as $f) {
    $sql_fields[] = $f . ' as ' . str_replace('.', '___', $f);
  }
  $sql = "SELECT " . implode(', ', $sql_fields) . "\n          FROM      {regcode} c\n          LEFT JOIN {users} u ON (u.uid = c.uid)\n          LEFT JOIN {role}  r ON (r.rid = c.rid)\n          {$sql_where}\n          ORDER BY  {$order} {$sort}\n          ";
  $args = array(
    $o['filter_data'],
  );
  if (isset($o['pager'])) {
    $result = pager_query($sql, $o['limit'], $o['pager'], NULL, $args);
  }
  else {
    $result = db_query_range($sql, $args, $o['start'], $o['limit']);
  }
  while ($row = db_fetch_object($result)) {
    foreach ((array) $row as $key => $data) {
      $row_temp[str_replace('___', '.', $key)] = $data;
    }
    $rows[] = $row_temp;
  }
  return $rows;
}

/**
 * Save given code array to a record in the db
 *
 * @param $code
 *   An array of code data fields, containing the fields:
 *     code       -  code identifier string (unique)
 *     available  -  is code available for user registration? ('1' = available)
 *     reuse      -  is code re-usable for many user registrations? ('1' = re-use)
 *     uid        -  user id to assign this code to a particular user (and thus mark is as "taken" by that user)
 *     rid        -  role id of the role this code will grant to the user that registers with it
 *     created    -  unix timestamp of the date this code has been created/added
 *     used       -  unix timestamp of the date this code has been used for registration
 *     revoke     -  unix timestamp of the date this code and its granted role will be revoked from the user that used it (not implemented)
 *     expire     -  unix timestamp of the date this code's availability for registration will expire (not touching already used codes)
 *     info       -  string (up to 255 characters) for any arbitrary information data
 * @param $action
 *   Action to perform when saving the code:
 *     overwrite  -  overwrite any existing code with same code identifier
 *     skip       -  skip and do not save code if there is any existing code with same code identifier
 *     *          -    "
 *
 * @return
 *   An array list of code data arrays
 */
function regcode_save_code($code, $action = 'overwrite') {
  if (empty($code)) {
    return FALSE;
  }
  if (empty($code['code'])) {
    return FALSE;
  }

  // empty template
  $row = array(
    'code' => '',
    'available' => 1,
    'reuse' => 0,
    'uid' => 'NULL',
    'rid' => 'NULL',
    'created' => $_SERVER['REQUEST_TIME'],
    'used' => 0,
    'revoke' => 0,
    'expire' => 0,
    'info' => 'NULL',
  );

  // fill row template with filtered and escaped input for fields which actually exist
  foreach ($code as $key => $value) {
    if (isset($row[$key])) {
      $row[$key] = "'" . db_escape_string(check_plain($value)) . "'";
    }
  }

  // optionally delete old record
  if ($action == 'overwrite') {
    db_query("DELETE FROM {regcode} WHERE code = '%s' LIMIT 1", $code['code']);
  }

  // insert record into db
  $sql = "INSERT INTO {regcode} (`" . implode('`, `', array_keys($row)) . "`) VALUES (" . implode(", ", $row) . ")";

  // implode(',', $placeholders)
  $result = db_query($sql);

  // , $row);
  return $result;
}

/**
 * Clean all codes from the db
 *
 * @param $action
 *   Action to perform when cleaning the code:
 *     clean      -  clean codes from db
 *     *          -  do nothing
 */
function regcode_clean_codes($action = 'clean') {
  if ($action == 'clean') {
    db_query("TRUNCATE {regcode}");
  }
}

// =========================
// = backend API functions =
// =========================

/**
 * Get the list of regcode db fields as key/title pairs
 *
 * @param $include_related
 *   Whether to include foreign key field from related tables used by regcode queries
 * @param $translated
 *   Whether to return translated titles
 * @return
 *   An array list of field name/title pairs
 */
function regcode_get_fields($include_related = FALSE, $translated = FALSE) {
  $fields = array(
    'c.code' => 'Code',
    'c.available' => 'Available',
    'c.reuse' => 'Reuse',
    'c.uid' => 'User ID',
    'c.rid' => 'Role ID',
    'c.created' => 'Created',
    'c.used' => 'Used',
    'c.expire' => 'Expire',
    'c.revoke' => 'Revoke',
    'c.info' => 'Info',
  );

  // optionally include related fields from other tables for db filtering etc.
  if ($include_related) {
    $fields['r.name'] = 'Role';
    $fields['u.name'] = 'User';
  }
  if ($translated) {
    foreach ($fields as $field_name => $field_title) {
      $fields[$field_name] = t($field_title);
    }
  }
  return $fields;
}

/**
 * Get the key of a given field name (redundant) or title
 * This function is quite stupid, but is necessary to compensate a bug in Drupal
 * for correctly retrieving a column key from table sorting querystring-argument "order",
 * which is wrongfully set to the table column's header NAME (=title) instead of FIELD,
 *  - see http://drupal.org/comment/reply/61931 -
 * which has to be taken into account by searching for the fieldname (array key)
 * by array search by column name
 *
 * @param $field_key_or_title
 *   The field key (redundant) or title to look up
 * @param $fields
 *   Optionally a field/title array to use for lookup
 * @param $translated
 *   Whether to compare translated field titles
 *
 * @return
 *   An array list of code data arrays
 */
function regcode_get_field_key($field_key_or_title, $fields = NULL, $translated = TRUE) {
  if ($fields == NULL) {
    $fields = regcode_get_fields($include_related = TRUE);
  }

  // if argument found as field array key, return it
  if (isset($fields['field_key_or_title'])) {
    return $field_key_or_title;
  }

  // else, look for first matching (opt. localized) field array title matching the argument, and return its key
  foreach ($fields as $key => $title) {
    if ($translated) {
      $title = t($title);
    }
    if ($field_key_or_title == $title) {
      return $key;
    }
  }
}

/**
 * Get the list of available filter operands for code retrieval
 *
 * @param $part
 *   Which part data of the operand(s) to return: title / sql
 *     title  -  return the operand(s) titles
 *     sql    -  return the operand(s) sql filter code
 * @param $operand
 *   Specific operand to look up
 *
 * @return
 *   Either an array of operand/title or operand/sql pairs, or the title resp. sql for one operand if the operand argument has been given
 */
function regcode_get_filter_operands($part = 'title', $operand = NULL) {
  $operands = array(
    'contains' => array(
      'title' => 'contains',
      'sql' => "LIKE '%%%s%%'",
    ),
    'equals' => array(
      'title' => 'equals',
      'sql' => "=    '%s'",
    ),
    'not' => array(
      'title' => 'not equals',
      'sql' => "<>   '%s'",
    ),
    'greater' => array(
      'title' => 'is greater than',
      'sql' => ">    '%s'",
    ),
    'smaller' => array(
      'title' => 'is smaller than',
      'sql' => "<    '%s'",
    ),
  );
  foreach (array_keys(next($operands)) as $part_key) {
    foreach ($operands as $operand_key => $operand_value) {
      $operand_parts[$part_key][$operand_key] = $operand_value[$part_key];
    }
  }
  if ($operand != NULL) {
    return $operands[$operand][$part];
  }
  return $operand_parts[$part];
}

// ====================
// = import functions =
// ====================

/**
 * Import codes from a file (plain list or CSV)
 *
 * @param $filepath
 *   File system path of the file to import from
 * @param $action
 *   Import action:
 *     overwrite  -  overwrite any existing codes with same code identifiers as the imported ones
 *     skip       -  skip any import of a codes, if any code with same code identifier exists
 *     clean      -  completely wipe the code database befor importing all codes
 * @param $code_template
 *   Optional code data template to use as default data setting for each imported code (key/value pairs for any applicable code field, see regcode_save_code)
 *
 * @return
 *   Whether the import operation has been successful (TRUE) or not (FALSE)
 */
function regcode_import_file($filepath, $action = NULL, $code_template = NULL) {

  // open file as stream and delegate to regcode_import_stream
  $handle = fopen($filepath, "r");
  $result = regcode_import_stream($handle, $action, $code_template);
  fclose($handle);
  return $result;
}

/**
 * Import codes from a multi-line string (plain list or CSV)
 *
 * @param $text
 *   Multi-line string to import from
 * @param $action
 *   Import action:
 *     overwrite  -  overwrite any existing codes with same code identifiers as the imported ones
 *     skip       -  skip any import of a codes, if any code with same code identifier exists
 *     clean      -  completely wipe the code database befor importing all codes
 * @param $code_template
 *   Optional code data template to use as default data setting for each imported code (key/value pairs for any applicable code field, see regcode_save_code)
 *
 * @return
 *   Whether the import operation has been successful (TRUE) or not (FALSE)
 */
function regcode_import_text(&$text, $action = NULL, $code_template = NULL) {

  // open string as memory stream and delegate to regcode_import_stream
  $handle = fopen("php://temp/maxmemory:" . 5 * 1024 * 1024, 'rw');
  fputs($handle, $text);
  rewind($handle);
  $result = regcode_import_stream($handle, $action, $code_template);
  fclose($handle);
  return $result;
}

/**
 * Import codes from a stream (plain list or CSV text data)
 *
 * @param $stream
 *   Stream handle of the stream to import from
 * @param $action
 *   Import action:
 *     overwrite  -  overwrite any existing codes with same code identifiers as the imported ones
 *     skip       -  skip any import of a codes, if any code with same code identifier exists
 *     clean      -  completely wipe the code database befor importing all codes
 * @param $code_template
 *   Optional code data template to use as default data setting for each imported code (key/value pairs for any applicable code field, see regcode_save_code)
 *
 * @return
 *   Whether the import operation has been successful (TRUE) or not (FALSE)
 */
function regcode_import_stream($stream, $action = NULL, $code_template = NULL) {
  if (!$stream) {
    return FALSE;
  }
  if (!$action) {
    $action = variable_get('regcode_import_action', 'skip');
  }
  $delimiter = variable_get('regcode_import_csv_delimiter', ',');
  $enclosure = variable_get('regcode_import_csv_text_enclosure', '"');
  $fieldorder = variable_get('regcode_import_csv_fieldorder', 'code');

  // clean codes when needed (depending on action)
  regcode_clean_codes($action);

  // iterate through stream line by line
  while (($row = fgetcsv($stream, 9999, $delimiter, $enclosure)) !== FALSE) {
    if (empty($fieldorder)) {
      $fieldorder = $row;
    }
    else {
      if (regcode_import_code($row, $action, $fieldorder, $code_template)) {
        $count++;
      }
    }
  }
  drupal_set_message(t('!count registration codes imported.', array(
    '!count' => intval($count),
  )));
  watchdog('RegistrationCode', t('!count registration codes imported.', array(
    '!count' => intval($count),
  )));
  return $count > 0;
}

/**
 * Import a single codes from a single ine string (plain one-field or CSV)
 *
 * @param $data
 *   The single-line string containing the code data to import (a single field or CSV)
 * @param $action
 *   Import action:
 *     overwrite  -  overwrite any existing code with same code identifier as the imported one
 *     skip       -  skip import of code, if any code with same code identifier exists
 *     *          -   "^
 * @param $fieldorder
 *   List of field keys indicating the order of field to expect in the $data string (array or delimiter-seperated string of keys)
 * @param $code
 *   Optional code data template to use as default data setting for each imported code (key/value pairs for any applicable code field, see regcode_save_code)
 *
 * @return
 *   Whether the import operation has been successful (TRUE) or not (FALSE)
 */
function regcode_import_code($data, $action, $fieldorder = NULL, $code = array()) {
  if (empty($fieldorder)) {
    $fieldorder = variable_get('regcode_import_csv_fieldorder', 'code');
  }
  if (!is_array($fieldorder)) {
    $fieldorder = explode(variable_get('regcode_import_csv_delimiter', ','), $fieldorder);
  }
  foreach ($data as $key => $value) {
    $code[$fieldorder[$key]] = $value;
  }
  return regcode_save_code($code, $action);
}

Functions

Namesort descending Description
regcode_clean_codes Clean all codes from the db
regcode_get_code Retrieve a particular registration code identified by given code id, or assign it to a given user
regcode_get_codes Return the database query result for the given options to list codes
regcode_get_fields Get the list of regcode db fields as key/title pairs
regcode_get_field_key Get the key of a given field name (redundant) or title This function is quite stupid, but is necessary to compensate a bug in Drupal for correctly retrieving a column key from table sorting querystring-argument "order", which is wrongfully…
regcode_get_filter_operands Get the list of available filter operands for code retrieval
regcode_import_code Import a single codes from a single ine string (plain one-field or CSV)
regcode_import_file Import codes from a file (plain list or CSV)
regcode_import_stream Import codes from a stream (plain list or CSV text data)
regcode_import_text Import codes from a multi-line string (plain list or CSV)
regcode_message Return text message requested by given identifier/constant
regcode_save_code Save given code array to a record in the db