Пишем модуль под Drupal. Часть 4. Добавляем закладку «Сообщения с моим участием»

чт, 01.04.2010 13:47 :: olk

Ну что же, для того, что бы повторить функционал стандартного трэкера, добавим закладку «Сообщения с моим участием» для зарегистрированных пользователей.

Ну а что бы было совсем интересно (не повторять же код модуля tracker), добавим еще закладочку с материалами, опубликованными текущим пользователем, и закладочки с разбивкой по типам материалов (выбрать тип материалов можно будет на странице настройки модуля)

Шаг номер 8:
Первое, что надо сделать, это модифицировать код функции cctracker_menu, что бы определить закладки на странице вывода.

<?php
// $Id$
/**
 * File: cctracker.module
 * Enables extending tracking.
 */

/**
 * Implementation of hook_menu().
 */

function cctracker_menu() {
  $items['admin/settings/cctracker'] = array(
    'title' => 'Cctracker',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('cctracker_settings'),
    'access arguments' => array('administer site configuration'),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'cctracker.admin.inc',
  );
   $items[$base_page] = array(
    'title' => 'Recent posts',
    'page callback' => 'cctracker_track',
    'page arguments' => array(NULL, 'all'),
    'access arguments' => array('access content'),
    'file' => 'cctracker.page.inc',
  );

  $items[$base_page . '/all'] = array(
    'title' => 'All recent posts',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items[$base_page . '/my-recent-posts/%user_uid_optional'] = array(
    'title' => 'My recent posts',
    'page arguments' => array(2, 'my-recent-posts'),
    'access callback' => '_cctracker_myrecent_access',
    'access arguments' => array(2),
    'type' => MENU_LOCAL_TASK,
  );
  $items[$base_page . '/my-posts/%user_uid_optional'] = array(
    'title' => 'My posts',
    'page arguments' => array(2, 'my-posts'),
    'access callback' => '_cctracker_myrecent_access',
    'access arguments' => array(2),
    'type' => MENU_LOCAL_TASK,
  );
  $tab_types = variable_get('cctracker_tab_types', array());
  foreach ($tab_types as $key => $value) {
  if ($value) {
    $items[$base_page . '/' . $key] = array(
      'title' => check_plain(node_get_types('name', $value)),
      'page arguments' => array(1, 'tab-types'),
      'access arguments' => array('access content'),
      'type' => MENU_LOCAL_TASK,
     );
   }
  }
  return $items;
}

function _cctracker_myrecent_access($account) {
  // This path is only allowed for authenticated users looking at their own posts.
  return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
}

/**
 * Implementation of hook_theme().
 */

function cctracker_theme() {
  return array(
      // определяем файл шаблона для вывода трэкера
      'cctracker_page_wrapper' => array(
      'template' => 'cctracker-page-wrapper',
      'arguments' => array('tracker' => NULL, 'pager' => NULL),
      ),
      // определяем функцию темизации для рендеринга трэкера
      'cctracker_page' => array(
      'arguments' => array('tracker' => array(), 'tp' => NULL),
      'file' => 'cctracker.page.inc',
      ),
    );
}

Заметьте, что мы изменили так же функцию темизации, так как нам понадобился дополнительный аргумент в функции theme_cctracker_page.

Шаг номер 9:
Дальше, немного изменим страницу настройки, добавим группу чекбоксов с типами материалов, закладки по которым добавим в вывод трэкера.
Изменяем файл cctracker.admin.inc

<?php
// $Id$

/**
 * @file
 */

function cctracker_settings() {
  $form['cctracker'] = array(
    '#type' => 'fieldset',
    '#title' => t('Cctracker settings'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );

  $form['cctracker']['cctracker_node_per_page'] = array(
    '#type' => 'select',
    '#title' => t('Node per page'),
    '#options' => drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 50, 100, 150, 200, 300)),
    '#default_value' => variable_get('cctracker_node_per_page', 50),
    '#description' => t('Number of nodes to show per page.'),
  );

  $form['cctracker']['cctracker_node_types'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Allowed content types'),
    '#options' => node_get_types('names'),
    '#default_value' => variable_get('cctracker_node_types', array()),
    '#description' => t('Select node types for see in tracker.'),
  );
  $form['cctracker']['cctracker_tab_types'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Allowed tab page of content types'),
    '#options' => node_get_types('names'),
    '#default_value' => variable_get('cctracker_tab_types', array()),
    '#description' => t('Select node types for see in tab page tracker.'),
  );
  $form['#submit'][] = 'cctracker_settings_submit';
  return system_settings_form($form);
}

function cctracker_settings_submit($form, &$form_state) {
  if (!form_get_errors()) {
    cache_clear_all();
    menu_rebuild();
  }
}

Тут нам понадобилось добавить дополнительную обработку субмита, что бы перестроить меню (так как оно зависит от текущих настроек модуля).

Шаг номер 10:

Ну и наконец, переделываем вывод нашего трэкера в зависимости от параметров.
Что бы не засорять код функции cctracker_page - код построения запроса, я вынес в отдельную вспомогательную функцию _cctracker_get_query.
<?php
// $Id$
/**
 * File: cctracker.page.inc
 */

function cctracker_page($account = NULL, $tp = 'all') {
  $cnt = variable_get('cctracker_node_per_page', 50);
  $output = '';
  $tracker = array();
  $result = _cctracker_get_query($arg, $tp);
  while ($items = db_fetch_object($result)) {
    $tracker[$items->nid] = $items;
  }
  // здесь мы уже получили массив для с данными для текущей страниц
  // в переменную $outtracker помещаем отренедеренный контент нашего трэкера
  // за выврод трэкера отвечает функция темизации theme_cctracker_page
  // ранее зарегистрированная в файле cctracker.module
  if (count($tracker)) {
  $outtracker = theme('cctracker_page',$tracker,$tp);
  }
  // в переменную $pager мы помещаем отрендеренный пейджинг
  $pager = theme('pager', NULL, $cnt, 0);
  // теперь обе эти переменные передаем в файл шаблона
  $output .= theme('cctracker_page_wrapper',$outtracker,$pager);
  return $output;
}

function _cctracker_get_query($arg, $tp){
  $cnt = variable_get('cctracker_node_per_page', 50);
  $types = variable_get('cctracker_node_types', array());
  $placeholder = db_placeholders($types, 'varchar');
  switch ($tp) {
    // Все материалы определенные для показа
    case 'all':
      // запишем  запрос в строку $sql в формате heredoc (что бы он был более читемым)
      // в принципе данный запрос, возвращает все нужне нам данные
      $sql = <<<EOT
SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
 GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
 l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
 INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder)
 LEFT JOIN {comments} c ON n.nid = c.nid
 LEFT JOIN {users} u ON u.uid=n.uid
 LEFT JOIN {node_counter} nc ON nc.nid = n.nid
 ORDER BY last_update DESC

EOT;
      $sql = db_rewrite_sql($sql);
     // этот запрос даст нам общее количество материалов в трэкере
      $sql_cnt  =  'SELECT COUNT(n.nid) FROM {node} n WHERE n.status=1 AND n.type IN (' . $placeholder. ')';

      $sql_cnt = db_rewrite_sql($sql_cnt);
      $result = pager_query($sql, $cnt, 0, $sql_cnt, $types);
      break;
    // Материалы с опубликованные текущим пользователем
    case 'my-posts':
      $sql = <<<EOT
SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
 GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
 l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
 INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder) AND n.uid =%d
 LEFT JOIN {comments} c ON n.nid = c.nid
 LEFT JOIN {users} u ON u.uid=n.uid
 LEFT JOIN {node_counter} nc ON nc.nid = n.nid
 ORDER BY last_update DESC

EOT;
      $sql = db_rewrite_sql($sql);
      $sql_cnt  =  'SELECT COUNT(n.nid) FROM {node} n WHERE n.status=1 AND n.type IN (' . $placeholder. ') AND n.uid = %d';
      $sql_cnt = db_rewrite_sql($sql_cnt);
      $types[] = $arg;
      $result = pager_query($sql, $cnt, 0, $sql_cnt, $types);
      break;
    // Материалы с участием текущего пользователя
    case 'my-recent-posts':
      $sql = <<<EOT
SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
 GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
 l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
 INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder)
 LEFT JOIN {comments} c ON n.nid = c.nid   AND (c.status = %d OR c.status IS NULL)  
 LEFT JOIN {users} u ON u.uid=n.uid
 LEFT JOIN {node_counter} nc ON nc.nid = n.nid
 WHERE (n.uid = %d OR c.uid=%d)
 ORDER BY last_update DESC

EOT;
      $sql = db_rewrite_sql($sql);
      $sql_cnt = <<<EOT
SELECT COUNT(DISTINCT(n.nid)) FROM {node} n
 INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder)
 LEFT JOIN {comments} c ON n.nid = c.nid   AND (c.status = %d OR c.status IS NULL)    
 WHERE (n.uid = %d OR c.uid=%d)

EOT;
      $sql_cnt = db_rewrite_sql($sql_cnt);
      $types[] = COMMENT_PUBLISHED;
      $types[] = $arg;
      $types[] = $arg;
      $result = pager_query($sql, $cnt, 0, $sql_cnt, $types);
      break;
    // Материалы определенного типа
    case 'tab-types':
      $sql = <<<EOT
SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
 GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
 l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
 INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type = '%s'
 LEFT JOIN {comments} c ON n.nid = c.nid
 LEFT JOIN {users} u ON u.uid=n.uid
 LEFT JOIN {node_counter} nc ON nc.nid = n.nid
 ORDER BY last_update DESC
EOT;
      $sql = db_rewrite_sql($sql);
      $sql_cnt  =  'SELECT COUNT(n.nid) FROM {node} n WHERE n.status=1 AND n.type = \'%s\'';

      $sql_cnt = db_rewrite_sql($sql_cnt);
      $result = pager_query($sql, $cnt, 0, $sql_cnt, $arg);
      break;
  }
  return $result;
}

Ну и в том же файле переделываем функцию темизации

Дело в том, что для разных закладок нам нужен несколько отличный от стандартного вывод трэкера, например на закладке «Мои сообщения», не нужен столбец «Автор», а на закладке с определенным типом материала совсем не нужен столбец «Тип материала».
function theme_cctracker_page($tracker, $tp) {
  $header = array();
  if ($tp != 'tab-types'){
  $header[] = t('Type');
  }
  $header[] =  t('Post');
  if ($tp != 'my-posts') {
  $header[] =  t('Author');
  }
  $header[] =  t('Created');
  $header[] =  t('Replies');
  $header[] =  t('Last updated');
  $rows = array();
  foreach($tracker as $key => $value){
      $comments = 0;
      if ($value->comment_count) {
        $comments = $value->comment_count;
        if ($new = comment_num_new($value->nid)) {
          $comments .= '<br />';
          $comments .= l(format_plural($new, '1 new', '@count new'), 'node/'. $value->nid, array('fragment' => 'new'));
        }
      }
     $row = array();
     if ($tp != 'tab-types'){
       $row[] = array('data' => check_plain(node_get_types('name', $value->type)), 'class' => 'cctracker-type-' . $value->type);
     }
     $row[] = array('data' => l($value->title,'node/'.$key) .' '. theme('mark', node_mark($value->nid, $value->changed)), 'class' => 'cctracker-title');
     if ($tp != 'my-posts') {
       $row[] = array('data' => theme('username',$value), 'class' => 'cctracker-user');
     }
     $row[] = array('data' => format_date($value->created,'small'), 'class' => 'cctracker-date-created');
     $row[] = array('data' => $comments, 'class' => 'cctracker-replies');
     $row[] = array('data' => t('!time ago', array('!time' => format_interval(time()-$value->last_update))), 'class' => 'cctracker-last-update');
     $rows[] = array('data'=>$row, 'id' => 'cctracker-' . $value->nid);
  }
  $output = theme('table', $header, $rows);
  return $output;
}
Добавить комментарий
« Добавить комментарий
» Добавить комментарий