You are here

comment_sort_created.module in Comment sort by created 7

Sorts comments by creation date.

File

comment_sort_created.module
View source
<?php

/**
 * @file
 * Sorts comments by creation date.
 */

/**
 * Default sort order: Oldest first.
 */
define('COMMENT_SORT_CREATED_OLDER_FIRST', 'ASC');

/**
 * Sort order: Newest first.
 */
define('COMMENT_SORT_CREATED_NEWER_FIRST', 'DESC');

/**
 * Implements hook_query_TAG_alter().
 *
 * Alter comments query to join with the comment_sort_created table and sort
 * by the 'created_thread' column instead.
 * The 'created_thread' is just like the 'thread' column in the comment table
 * but using the 'created' timestamp instead of the comment id for sorting.
 */
function comment_sort_created_query_comment_filter_alter(QueryAlterableInterface $query) {
  if (get_class($query) == 'PagerDefault' && ($node = $query
    ->getMetaData('node'))) {

    // Should the order of comments for this content type be corrected?
    if (!variable_get('comment_sort_created_' . $node->type, FALSE)) {
      return;
    }

    // Get the configured default sort ordering for this node type.
    $order = variable_get('comment_sort_created_order_' . $node->type, COMMENT_SORT_CREATED_OLDER_FIRST);
    $orderby =& $query
      ->getOrderBy();
    $expressions =& $query
      ->getExpressions();

    // Sorting for threaded comments.
    if (isset($orderby['torder'])) {

      // Remove standard sorting expressions.
      unset($expressions['torder']);
      unset($orderby['torder']);

      // Join with our table.
      $query
        ->join('comment_sort_created', 'csc', 'c.cid = csc.cid');

      // Add expression to order by created_thread.
      $query
        ->addExpression('SUBSTRING(csc.created_thread, 1, (LENGTH(csc.created_thread) - 1))', 'torder');
      $query
        ->orderBy('torder', $order);
    }
    else {

      // To make cid a secondary criterium we have to remove it first.
      if (isset($orderby['c.cid'])) {
        unset($orderby['c.cid']);
      }

      // Now first sort aftetr created timestamp, and if timestamps are
      // equal, use comment id instead.
      $orderby['c.created'] = $order;
      $orderby['c.cid'] = $order;
    }
  }
}

/**
 * Implements hook_comment_insert().
 *
 * Creates an entry in the comment_sort_created table
 * after a comment has been created.
 */
function comment_sort_created_comment_insert($comment) {

  // Generate a thread string based upon the creation date.
  $created_thread = comment_sort_created_get_timestamp_thread($comment);

  // Write new entry to table.
  $record = array(
    'cid' => $comment->cid,
    'created_thread' => $created_thread,
  );
  drupal_write_record('comment_sort_created', $record);
}

/**
 * Implements hook_comment_update().
 *
 * Updates the entry in the comment_sort_created table
 * after a comment has been updated.
 */
function comment_sort_created_comment_update($comment) {

  // Generate a thread string based upon the creation date.
  $created_thread = comment_sort_created_get_timestamp_thread($comment);

  // Write new entry to table.
  $record = array(
    'cid' => $comment->cid,
    'created_thread' => $created_thread,
  );
  drupal_write_record('comment_sort_created', $record, 'cid');
}

/**
 * Implements hook_comment_delete().
 *
 * Removes the entry in the comment_sort_created table
 * after a comment has been deleted.
 */
function comment_sort_created_comment_delete($comment) {

  // Delete entry from table.
  db_delete('comment_sort_created')
    ->condition('cid', $comment->cid)
    ->execute();
}

/**
 * Generates a thread string based upon the creation date.
 *
 * Note that this function may only work correctly if the given comment
 * parents' threads are already known in the comment_sort_created table!
 *
 * @param string $comment
 *   The comment object to build the thread string for.
 *
 * @return string
 *   The thread string based upon the creation timestamp.
 */
function comment_sort_created_get_timestamp_thread($comment) {

  // This is a comment with no parent comment (depth 0).
  if ($comment->pid == 0) {

    // Generate vancode representation of the created timestamp as thread.
    $created_thread = int2vancode(vancode2int($comment->created) + 1) . '/';
  }
  else {

    // Get the parent comments thread.
    $parent_thread = db_query("SELECT created_thread FROM {comment_sort_created} WHERE cid = :pid", array(
      ':pid' => (int) $comment->pid,
    ))
      ->fetchField();

    // Strip the "/" from the end of the parent thread.
    $parent_thread = (string) rtrim((string) $parent_thread, '/');

    // Concatenate childs thread string to the parents.
    $created_thread = $parent_thread . '.' . int2vancode(0) . '/';
  }
  return $created_thread;
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add comment configuration settings to the edit content type form.
 */
function comment_sort_created_form_node_type_form_alter(&$form, $form_state) {

  // Whether to correct sort order.
  $form['comment']['comment_sort_created'] = array(
    '#title' => t('Sort comments by creation date?'),
    '#description' => t('Instead of sorting by comment id, this will sort the comments by the creation timestamp.'),
    '#type' => 'checkbox',
    '#default_value' => variable_get('comment_sort_created_' . $form['#node_type']->type, FALSE),
  );

  // Sort order.
  $form['comment']['comment_sort_created_order'] = array(
    '#title' => t('Sort order'),
    '#type' => 'select',
    '#states' => array(
      'visible' => array(
        ':input[name="comment_sort_created"]' => array(
          'checked' => TRUE,
        ),
      ),
    ),
    '#options' => array(
      COMMENT_SORT_CREATED_OLDER_FIRST => t('Oldest first'),
      COMMENT_SORT_CREATED_NEWER_FIRST => t('Newest first'),
    ),
    '#default_value' => variable_get('comment_sort_created_order_' . $form['#node_type']->type, COMMENT_SORT_CREATED_OLDER_FIRST),
  );
  $form['#submit'][] = 'comment_sort_created_check_tables_in_sync';
}

/**
 * Check tables for missing entries.
 *
 * This function checks whether comment table and comment_sort_created
 * table are in sync and resyncronises them when needed.
 */
function comment_sort_created_check_tables_in_sync($form, $form_state) {

  // Check sync, when sorting has been enabled.
  if ($form_state['values']['comment_sort_created']) {

    // Get count of entries on both tables.
    $comment_count = db_query("SELECT COUNT(cid) FROM {comment}")
      ->fetchField();
    $comment_sort_created_count = db_query("SELECT COUNT(cid) FROM {comment_sort_created}")
      ->fetchField();

    // If there are comments missing in the comment_sort_created_count table,
    // we start a batch to fill the gap.
    if ($comment_count > $comment_sort_created_count) {
      $operations = array();
      $select = db_select('comment', 'c');
      $select
        ->leftJoin('comment_sort_created', 'csc', 'c.cid = csc.cid');
      $select
        ->addField('c', 'cid');
      $select
        ->orderBy('c.cid');
      $select
        ->isNull('csc.cid');
      $missing_comments = $select
        ->execute()
        ->fetchAll();
      foreach ($missing_comments as $comment) {
        $operations[] = array(
          'comment_sort_created_check_tables_in_sync_operation',
          array(
            $comment->cid,
          ),
        );
      }
      $batch = array(
        'operations' => $operations,
        'title' => t('Filling comment sort table.'),
      );
      batch_set($batch);
    }
  }
}

/**
 * Batch operation callback for table sync.
 */
function comment_sort_created_check_tables_in_sync_operation($cid) {
  $comment = comment_load($cid);

  // Generate a thread string based upon the creation date.
  $created_thread = comment_sort_created_get_timestamp_thread($comment);

  // Write new entry to table.
  $record = array(
    'cid' => $cid,
    'created_thread' => $created_thread,
  );
  drupal_write_record('comment_sort_created', $record);
}