You are here

track_field_changes.module in Track Field Changes 7

Same filename and directory in other branches
  1. 8 track_field_changes.module

The Track Field Changes module.

File

track_field_changes.module
View source
<?php

/**
 * @file
 * The Track Field Changes module.
 */
define('TRACK_FIELD_CHANGES_ADMIN_PATH', 'admin/config/system/track_field_changes');

/**
 * Implements hook_permission().
 */
function track_field_changes_permission() {
  return array(
    'administer track field changes' => array(
      'title' => t('Administer Track Field Changes'),
      'description' => t('Enable or disable field tracking'),
    ),
  );
}

/**
 * Implements hook_help().
 */
function track_field_changes_help($path, $arg) {
  switch ($path) {
    case TRACK_FIELD_CHANGES_ADMIN_PATH:
      $output = '<p>' . t('This page lists all the <em>fields audited</em> that are currently defined on this system.') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_menu().
 */
function track_field_changes_menu() {
  $items[TRACK_FIELD_CHANGES_ADMIN_PATH] = array(
    'title' => 'Field Track Changes',
    'description' => 'Enable and disable which content type and fields need to be audited.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'track_field_changes_admin_settings',
    ),
    'access arguments' => array(
      'administer track field changes',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'track_field_changes.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_node_insert().
 */
function track_field_changes_node_insert($node) {

  // Each node type which are audited.
  $node_types = variable_get('track_field_changes_node_types', array());

  // If content type is audited.
  if (in_array($node->type, $node_types)) {

    // Basic or/and advanced audit.
    $basic_audit = variable_get('track_field_changes_basic_new_' . $node->type, FALSE);

    // Get log.
    $log = isset($node->track_field_changes) ? $node->track_field_changes : '';
    if ($basic_audit) {
      track_field_changes_insert_db($node->nid, 'log', '', '', 'bn', $log);
    }
  }
}

/**
 * Implements hook_node_update().
 */
function track_field_changes_node_update($node) {

  // Each node type which are audited.
  $node_types = variable_get('track_field_changes_node_types', array());

  // If content type is audited.
  if (in_array($node->type, $node_types)) {

    // Basic or/and Advanced audit.
    $basic_audit = variable_get('track_field_changes_basic_revision_' . $node->type, FALSE);
    $fields_audit = variable_get('track_field_changes_track_revision_fields_' . $node->type, FALSE);

    // Get log.
    $log = isset($node->track_field_changes) ? $node->track_field_changes : '';
    if ($basic_audit) {
      track_field_changes_insert_db($node->nid, 'log', '', '', 'br', $log);
    }
    if ($fields_audit) {
      $selected_fields = track_field_changes_get_selected_field($node->type);

      // Clone ?
      $newnode = $node;
      $originalnode = $node->original;
      foreach ($selected_fields as $field_name) {
        if ($field_name == 'title') {
          $field_info_type = 'title';
          $newfield = $newnode->title;
          $originalfield = $originalnode->title;
        }
        else {
          $field_info = field_info_field($field_name);
          $field_info_type = $field_info['type'];
          $language = field_language('node', $newnode, $field_name);
          $newfield = field_get_items('node', $newnode, $field_name, $language);
          $language = field_language('node', $originalnode, $field_name);
          $originalfield = field_get_items('node', $originalnode, $field_name, $language);
        }
        if (!track_field_changes_compare_field($field_info_type, $originalfield, $newfield)) {
          $field_before = array();
          $field_before['field_name'] = $field_name;
          $field_before['value'] = $originalfield;
          $field_after = array();
          $field_after['field_name'] = $field_name;
          $field_after['value'] = $newfield;
          if ($field_info_type == 'file') {
            for ($i = 0; $i < count($field_after['value'][LANGUAGE_NONE]); $i++) {
              $file = file_load($field_after['value'][LANGUAGE_NONE][$i][fid]);
              $field_after['value'][LANGUAGE_NONE][$i]['filename'] = $file->filename;
              $field_after['value'][LANGUAGE_NONE][$i]['uri'] = $file->uri;
              $field_after['value'][LANGUAGE_NONE][$i]['filemime'] = $file->filemime;
              $field_after['value'][LANGUAGE_NONE][$i]['filesize'] = $file->filesize;
              $field_after['value'][LANGUAGE_NONE][$i]['status'] = $file->status;
              $field_after['value'][LANGUAGE_NONE][$i]['timestamp'] = $file->timestamp;
            }
          }
          track_field_changes_insert_db($node->nid, $field_name, serialize($field_before), serialize($field_after), 'fr', $log);
        }
      }
    }
  }
}

/**
 * Implements hook_node_delete().
 */
function track_field_changes_node_delete($node) {
  db_delete('track_field_changes_audit')
    ->condition('nid', $node->nid)
    ->execute();
}

/**
 * Implements hook_views_api().
 */
function track_field_changes_views_api() {
  return array(
    'api' => 2.0,
    'path' => drupal_get_path('module', 'track_field_changes') . '/views',
  );
}

/**
 * Get select field for a bundle.
 *
 * @param $bundle
 */
function track_field_changes_get_selected_field($bundle) {
  $track_field_changess = db_select('track_field_changes', 'a')
    ->fields('a')
    ->condition('bundle', $bundle)
    ->execute()
    ->fetchCol();
  $options = array();
  foreach ($track_field_changess as $track_field_changes) {
    $options[$track_field_changes] = $track_field_changes;
  }
  return $options;
}

/**
 * Compare two fields.
 *
 * return FALSE if different
 * return TRUE if egal
 */
function track_field_changes_compare_field($field_info_type, $old_field, $new_field) {
  if ($field_info_type == 'title') {
    return $old_field == $new_field;
  }
  else {
    if ($old_field == NULL && empty($new_field)) {
      return TRUE;
    }
    if ($new_field == NULL && empty($old_field)) {
      return TRUE;
    }
    if ($new_field == NULL && $old_field == NULL) {
      return TRUE;
    }
    if (empty($new_field) && empty($old_field)) {
      return TRUE;
    }
    if (count($new_field) != count($old_field)) {
      return FALSE;
    }
    switch ($field_info_type) {
      case 'datestamp':
      case 'datetime':
      case 'date':
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['value'] != $new_field[$i]['value']) {
            return FALSE;
          }
        }
        return TRUE;
        break;
      case 'tablefield':
      case 'text_long':
      case 'list_text':
      case 'list_boolean':
      case 'text_with_summary':
      case 'number_decimal':
      case 'number_float':
      case 'text':
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['value'] != $new_field[$i]['value']) {
            return FALSE;
          }
          if (isset($old_field[$i]['value2']) && $old_field[$i]['value2'] != $new_field[$i]['value2']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'email':
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['email'] != $new_field[$i]['email']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'link_field':
        for ($i = 0; $i < count($new_field); $i++) {
          if (empty($old_field) || empty($new_field)) {
            return FALSE;

            //if they are both empty, that case is handled at the beginning of this function
          }

          // not all link fields have a title, i.e. static title
          if (array_key_exists('title', $old_field[$i]) && array_key_exists('title', $new_field[$i])) {
            if ($old_field[$i]['title'] != $new_field[$i]['title']) {
              return FALSE;
            }
          }
        }
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['url'] != $new_field[$i]['url']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'image':
      case 'file':
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['fid'] != $new_field[$i]['fid']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'geofield':
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['wkt'] != $new_field[$i]['wkt']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'entityreference':
        for ($i = 0; $i < count($new_field); $i++) {
          if ($old_field[$i]['target_id'] != $new_field[$i]['target_id']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'taxonomy_term_reference':
        if (sizeof($old_field) != sizeof($new_field)) {
          return FALSE;
        }
        foreach ($old_field as $key => $value) {
          if ($old_field[$key]['tid'] != $new_field[$key]['tid']) {
            return FALSE;
          }
        }
        return TRUE;
      case 'list_integer':
      case 'list_float':
      case 'number_integer':
      case 'user_reference':
        return $old_field == $new_field;
      case 'addressfield':
        for ($i = 0; $i < count($new_field); $i++) {

          //do a compare of each part of address field

          // first get a list of the address parts
          $address_items = array_keys($new_field[$i]);

          // use $new_field in case something has change in the address definition
          foreach ($address_items as $address_item) {
            if ($address_item != 'data') {
              if (empty($new_field[$i][$address_item])) {
                if (array_key_exists($address_item, $old_field[$i])) {
                  if (!empty($old_field[$i][$address_item])) {
                    return FALSE;
                  }
                }
                else {
                  return FALSE;
                }
              }
              else {
                if (empty($old_field[$i][$address_item])) {
                  return FALSE;
                }
                else {
                  if ($old_field[$i][$address_item] != $new_field[$i][$address_item]) {
                    return FALSE;
                  }
                }
              }
            }
          }
        }

        // if we made it this far, no changes
        return TRUE;
      default:
        return TRUE;
    }
  }
}

/**
 * Compare if one field is empty.
 *
 * return FALSE if not empty
 * return TRUE if empty
 */
function track_field_changes_is_empty($field_info_type, $field) {
  if ($field_info_type == 'title') {
    return $field == '';
  }
  else {
    switch ($field_info_type) {
      case 'datestamp':
      case 'datetime':
      case 'date':
        return empty($field);
      case 'tablefield':
      case 'text_long':
      case 'list_text':
      case 'list_boolean':
      case 'text_with_summary':
      case 'number_decimal':
      case 'number_float':
      case 'text':
      case 'entityreference':
        $field = $field[LANGUAGE_NONE];
        return empty($field);
      case 'email':
        return FALSE;
      case 'link_field':
        return FALSE;
      case 'image':
      case 'file':
        $field = $field[LANGUAGE_NONE];
        return empty($field);
      case 'taxonomy_term_reference':
      case 'list_integer':
      case 'list_float':
      case 'number_integer':
      case 'user_reference':
      case 'geofield':
        return $field == '';
      default:
        return FALSE;
    }
  }
}
function track_field_changes_insert_db($nid, $field_name, $old_field, $new_field, $type, $log) {
  global $user;
  $track_field_changes_disable_multiple = variable_get('track_field_changes_disable_multiple', array());
  if ($track_field_changes_disable_multiple['checked'] === "checked") {
    $result = db_select('track_field_changes_audit', 't')
      ->fields('t')
      ->condition('nid', $nid, '=')
      ->execute()
      ->fetchAssoc();
    if ($result['nid'] == $nid) {
      db_update('track_field_changes_audit')
        ->fields(array(
        'nid' => $nid,
        'timestamp' => REQUEST_TIME,
        'uid' => $user->uid,
        'field_name' => $field_name,
        'before_value_text' => $old_field,
        'after_value_text' => $new_field,
        'type' => $type,
        'log' => $log,
      ))
        ->condition('nid', $nid, '=')
        ->execute();
    }
    else {
      db_insert('track_field_changes_audit')
        ->fields(array(
        'nid' => $nid,
        'timestamp' => REQUEST_TIME,
        'uid' => $user->uid,
        'field_name' => $field_name,
        'before_value_text' => $old_field,
        'after_value_text' => $new_field,
        'type' => $type,
        'log' => $log,
      ))
        ->execute();
    }
  }
  else {
    db_insert('track_field_changes_audit')
      ->fields(array(
      'nid' => $nid,
      'timestamp' => REQUEST_TIME,
      'uid' => $user->uid,
      'field_name' => $field_name,
      'before_value_text' => $old_field,
      'after_value_text' => $new_field,
      'type' => $type,
      'log' => $log,
    ))
      ->execute();
  }
}

/**
 * Implement hook_form_alter().
 * (cant use hook_form_FORM_ID_alter(). here as the form ID changes from node to node)
 */
function track_field_changes_form_alter(&$form, $form_state, $form_id) {

  // If we're editing a node...
  if (!empty($form['#node_edit_form'])) {
    $node_types = variable_get('track_field_changes_node_types', array());

    // And the show field is enabled for this node type.
    $enable_log = variable_get('track_field_changes_enable_log_' . $form['type']['#value'], FALSE);
    if (in_array($form['type']['#value'], $node_types) && $enable_log) {
      $log = !$form['nid']['#value'] ? 'New ' . $form['type']['#value'] : '';
      $form['track_field_changes'] = array(
        '#type' => 'fieldset',
        '#title' => t('Track Field Information'),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
        '#group' => 'additional_settings',
        '#weight' => 35,
      );
      $form['track_field_changes']['track_field_changes'] = array(
        '#type' => 'textarea',
        '#title' => t('Track field log message'),
        '#rows' => 4,
        '#default_value' => !empty($node->track_field_changes) ? $node->track_field_changes : $log,
        '#description' => t('Provide an explanation of the changes you are making.'),
        '#maxlength' => 256,
      );
    }
  }
}

/**
 * Implement hook_form_FORM_ID_alter().
 */
function track_field_changes_form_user_profile_form_alter(&$form, $form_state) {

  // @todo
}

/**
 * Implement hook_form_FORM_ID_alter().
 */
function track_field_changes_form_taxonomy_form_term_alter(&$form, $form_state) {

  // @todo
}

/**
 * This hook is called right before the execute process. The query is
 * now fully built, but it has not yet been run through db_rewrite_sql.
 *
 * Adding output to the view can be accomplished by placing text on
 * $view->attachment_before and $view->attachment_after.
 */
function track_field_changes_views_pre_execute(&$view) {

  // @todo
}

Functions

Namesort descending Description
track_field_changes_compare_field Compare two fields.
track_field_changes_form_alter Implement hook_form_alter(). (cant use hook_form_FORM_ID_alter(). here as the form ID changes from node to node)
track_field_changes_form_taxonomy_form_term_alter Implement hook_form_FORM_ID_alter().
track_field_changes_form_user_profile_form_alter Implement hook_form_FORM_ID_alter().
track_field_changes_get_selected_field Get select field for a bundle.
track_field_changes_help Implements hook_help().
track_field_changes_insert_db
track_field_changes_is_empty Compare if one field is empty.
track_field_changes_menu Implements hook_menu().
track_field_changes_node_delete Implements hook_node_delete().
track_field_changes_node_insert Implements hook_node_insert().
track_field_changes_node_update Implements hook_node_update().
track_field_changes_permission Implements hook_permission().
track_field_changes_views_api Implements hook_views_api().
track_field_changes_views_pre_execute This hook is called right before the execute process. The query is now fully built, but it has not yet been run through db_rewrite_sql.

Constants

Namesort descending Description
TRACK_FIELD_CHANGES_ADMIN_PATH @file The Track Field Changes module.