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

чт, 01.04.2010 13:47 :: olk

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

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

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

  1. <?php
  2. // $Id$
  3. /**
  4.  * File: cctracker.module
  5.  * Enables extending tracking.
  6.  */
  7.  
  8. /**
  9.  * Implementation of hook_menu().
  10.  */
  11. function cctracker_menu() {
  12.   $items['admin/settings/cctracker'] = array(
  13.     'title' => 'Cctracker',
  14.     'page callback' => 'drupal_get_form',
  15.     'page arguments' => array('cctracker_settings'),
  16.     'access arguments' => array('administer site configuration'),
  17.     'type' => MENU_NORMAL_ITEM,
  18.     'file' => 'cctracker.admin.inc',
  19.   );
  20.    $items[$base_page] = array(
  21.     'title' => 'Recent posts',
  22.     'page callback' => 'cctracker_track',
  23.     'page arguments' => array(NULL, 'all'),
  24.     'access arguments' => array('access content'),
  25.     'file' => 'cctracker.page.inc',
  26.   );
  27.  
  28.   $items[$base_page . '/all'] = array(
  29.     'title' => 'All recent posts',
  30.     'type' => MENU_DEFAULT_LOCAL_TASK,
  31.   );
  32.   $items[$base_page . '/my-recent-posts/%user_uid_optional'] = array(
  33.     'title' => 'My recent posts',
  34.     'page arguments' => array(2, 'my-recent-posts'),
  35.     'access callback' => '_cctracker_myrecent_access',
  36.     'access arguments' => array(2),
  37.     'type' => MENU_LOCAL_TASK,
  38.   );
  39.   $items[$base_page . '/my-posts/%user_uid_optional'] = array(
  40.     'title' => 'My posts',
  41.     'page arguments' => array(2, 'my-posts'),
  42.     'access callback' => '_cctracker_myrecent_access',
  43.     'access arguments' => array(2),
  44.     'type' => MENU_LOCAL_TASK,
  45.   );
  46.   $tab_types = variable_get('cctracker_tab_types', array());
  47.   foreach ($tab_types as $key => $value) {
  48.   if ($value) {
  49.     $items[$base_page . '/' . $key] = array(
  50.       'title' => check_plain(node_get_types('name', $value)),
  51.       'page arguments' => array(1, 'tab-types'),
  52.       'access arguments' => array('access content'),
  53.       'type' => MENU_LOCAL_TASK,
  54.      );
  55.    }
  56.   }
  57.   return $items;
  58. }
  59.  
  60. function _cctracker_myrecent_access($account) {
  61.   // This path is only allowed for authenticated users looking at their own posts.
  62.   return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
  63. }
  64.  
  65. /**
  66.  * Implementation of hook_theme().
  67.  */
  68. function cctracker_theme() {
  69.   return array(
  70.       // определяем файл шаблона для вывода трэкера
  71.       'cctracker_page_wrapper' => array(
  72.       'template' => 'cctracker-page-wrapper',
  73.       'arguments' => array('tracker' => NULL, 'pager' => NULL),
  74.       ),
  75.       // определяем функцию темизации для рендеринга трэкера
  76.       'cctracker_page' => array(
  77.       'arguments' => array('tracker' => array(), 'tp' => NULL),
  78.       'file' => 'cctracker.page.inc',
  79.       ),
  80.     );
  81. }
Заметьте, что мы изменили так же функцию темизации, так как нам понадобился дополнительный аргумент в функции theme_cctracker_page.

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

  1. <?php
  2. // $Id$
  3.  
  4. /**
  5.  * @file
  6.  */
  7. function cctracker_settings() {
  8.   $form['cctracker'] = array(
  9.     '#type' => 'fieldset',
  10.     '#title' => t('Cctracker settings'),
  11.     '#collapsible' => TRUE,
  12.     '#collapsed' => FALSE,
  13.   );
  14.  
  15.   $form['cctracker']['cctracker_node_per_page'] = array(
  16.     '#type' => 'select',
  17.     '#title' => t('Node per page'),
  18.     '#options' => drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 50, 100, 150, 200, 300)),
  19.     '#default_value' => variable_get('cctracker_node_per_page', 50),
  20.     '#description' => t('Number of nodes to show per page.'),
  21.   );
  22.  
  23.   $form['cctracker']['cctracker_node_types'] = array(
  24.     '#type' => 'checkboxes',
  25.     '#title' => t('Allowed content types'),
  26.     '#options' => node_get_types('names'),
  27.     '#default_value' => variable_get('cctracker_node_types', array()),
  28.     '#description' => t('Select node types for see in tracker.'),
  29.   );
  30.   $form['cctracker']['cctracker_tab_types'] = array(
  31.     '#type' => 'checkboxes',
  32.     '#title' => t('Allowed tab page of content types'),
  33.     '#options' => node_get_types('names'),
  34.     '#default_value' => variable_get('cctracker_tab_types', array()),
  35.     '#description' => t('Select node types for see in tab page tracker.'),
  36.   );
  37.   $form['#submit'][] = 'cctracker_settings_submit';
  38.   return system_settings_form($form);
  39. }
  40.  
  41. function cctracker_settings_submit($form, &$form_state) {
  42.   if (!form_get_errors()) {
  43.     cache_clear_all();
  44.     menu_rebuild();
  45.   }
  46. }
Тут нам понадобилось добавить дополнительную обработку субмита, что бы перестроить меню (так как оно зависит от текущих настроек модуля).

Шаг номер 10:

Ну и наконец, переделываем вывод нашего трэкера в зависимости от параметров. Что бы не засорять код функции cctracker_page - код построения запроса, я вынес в отдельную вспомогательную функцию _cctracker_get_query.

  1. <?php
  2. // $Id$
  3. /**
  4.  * File: cctracker.page.inc
  5.  */
  6.  
  7. function cctracker_page($account = NULL, $tp = 'all') {
  8.   $cnt = variable_get('cctracker_node_per_page', 50);
  9.   $output = '';
  10.   $tracker = array();
  11.   $result = _cctracker_get_query($arg, $tp);
  12.   while ($items = db_fetch_object($result)) {
  13.     $tracker[$items->nid] = $items;
  14.   }
  15.   // здесь мы уже получили массив для с данными для текущей страниц
  16.   // в переменную $outtracker помещаем отренедеренный контент нашего трэкера
  17.   // за выврод трэкера отвечает функция темизации theme_cctracker_page
  18.   // ранее зарегистрированная в файле cctracker.module
  19.   if (count($tracker)) {
  20.   $outtracker = theme('cctracker_page',$tracker,$tp);
  21.   }
  22.   // в переменную $pager мы помещаем отрендеренный пейджинг
  23.   $pager = theme('pager', NULL, $cnt, 0);
  24.   // теперь обе эти переменные передаем в файл шаблона
  25.   $output .= theme('cctracker_page_wrapper',$outtracker,$pager);
  26.   return $output;
  27. }
  28.  
  29. function _cctracker_get_query($arg, $tp){
  30.   $cnt = variable_get('cctracker_node_per_page', 50);
  31.   $types = variable_get('cctracker_node_types', array());
  32.   $placeholder = db_placeholders($types, 'varchar');
  33.   switch ($tp) {
  34.     // Все материалы определенные для показа
  35.     case 'all':
  36.       // запишем  запрос в строку $sql в формате heredoc (что бы он был более читемым)
  37.       // в принципе данный запрос, возвращает все нужне нам данные
  38.       $sql = <<<EOT
  39. SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
  40. GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
  41. l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
  42. INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder)
  43. LEFT JOIN {comments} c ON n.nid = c.nid
  44. LEFT JOIN {users} u ON u.uid=n.uid
  45. LEFT JOIN {node_counter} nc ON nc.nid = n.nid
  46. ORDER BY last_update DESC
  47. EOT;
  48.       $sql = db_rewrite_sql($sql);
  49.      // этот запрос даст нам общее количество материалов в трэкере
  50.       $sql_cnt  =  'SELECT COUNT(n.nid) FROM {node} n WHERE n.status=1 AND n.type IN (' . $placeholder. ')';
  51.  
  52.       $sql_cnt = db_rewrite_sql($sql_cnt);
  53.       $result = pager_query($sql, $cnt, 0, $sql_cnt, $types);
  54.       break;
  55.     // Материалы с опубликованные текущим пользователем
  56.     case 'my-posts':
  57.       $sql = <<<EOT
  58. SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
  59. GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
  60. l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
  61. INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder) AND n.uid =%d
  62. LEFT JOIN {comments} c ON n.nid = c.nid
  63. LEFT JOIN {users} u ON u.uid=n.uid
  64. LEFT JOIN {node_counter} nc ON nc.nid = n.nid
  65. ORDER BY last_update DESC
  66. EOT;
  67.       $sql = db_rewrite_sql($sql);
  68.       $sql_cnt  =  'SELECT COUNT(n.nid) FROM {node} n WHERE n.status=1 AND n.type IN (' . $placeholder. ') AND n.uid = %d';
  69.       $sql_cnt = db_rewrite_sql($sql_cnt);
  70.       $types[] = $arg;
  71.       $result = pager_query($sql, $cnt, 0, $sql_cnt, $types);
  72.       break;
  73.     // Материалы с участием текущего пользователя
  74.     case 'my-recent-posts':
  75.       $sql = <<<EOT
  76. SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
  77. GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
  78. l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
  79. INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder)
  80. LEFT JOIN {comments} c ON n.nid = c.nid   AND (c.status = %d OR c.status IS NULL)  
  81. LEFT JOIN {users} u ON u.uid=n.uid
  82. LEFT JOIN {node_counter} nc ON nc.nid = n.nid
  83. WHERE (n.uid = %d OR c.uid=%d)
  84. ORDER BY last_update DESC
  85. EOT;
  86.       $sql = db_rewrite_sql($sql);
  87.       $sql_cnt = <<<EOT
  88. SELECT COUNT(DISTINCT(n.nid)) FROM {node} n
  89. INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type IN ($placeholder)
  90. LEFT JOIN {comments} c ON n.nid = c.nid   AND (c.status = %d OR c.status IS NULL)    
  91. WHERE (n.uid = %d OR c.uid=%d)
  92. EOT;
  93.       $sql_cnt = db_rewrite_sql($sql_cnt);
  94.       $types[] = COMMENT_PUBLISHED;
  95.       $types[] = $arg;
  96.       $types[] = $arg;
  97.       $result = pager_query($sql, $cnt, 0, $sql_cnt, $types);
  98.       break;
  99.     // Материалы определенного типа
  100.     case 'tab-types':
  101.       $sql = <<<EOT
  102. SELECT DISTINCT(n.nid) AS nid, n.title, n.type, n.changed, n.uid, n.created, u.name,
  103.  GREATEST(n.changed, l.last_comment_timestamp) AS last_update,
  104.  l.comment_count,nc.totalcount, nc.daycount,nc.timestamp AS lastread FROM {node} n
  105.  INNER JOIN {node_comment_statistics} l ON n.nid = l.nid AND n.status=1 AND n.type = '%s'
  106.  LEFT JOIN {comments} c ON n.nid = c.nid
  107.  LEFT JOIN {users} u ON u.uid=n.uid
  108.  LEFT JOIN {node_counter} nc ON nc.nid = n.nid
  109.  ORDER BY last_update DESC
  110. EOT;
  111.       $sql = db_rewrite_sql($sql);
  112.       $sql_cnt  =  'SELECT COUNT(n.nid) FROM {node} n WHERE n.status=1 AND n.type = \'%s\'';
  113.  
  114.       $sql_cnt = db_rewrite_sql($sql_cnt);
  115.       $result = pager_query($sql, $cnt, 0, $sql_cnt, $arg);
  116.       break;
  117.   }
  118.   return $result;
  119. }

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

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

  1. function theme_cctracker_page($tracker, $tp) {
  2.   $header = array();
  3.   if ($tp != 'tab-types'){
  4.   $header[] = t('Type');
  5.   }
  6.   $header[] =  t('Post');
  7.   if ($tp != 'my-posts') {
  8.   $header[] =  t('Author');
  9.   }
  10.   $header[] =  t('Created');
  11.   $header[] =  t('Replies');
  12.   $header[] =  t('Last updated');
  13.   $rows = array();
  14.   foreach($tracker as $key => $value){
  15.       $comments = 0;
  16.       if ($value->comment_count) {
  17.         $comments = $value->comment_count;
  18.         if ($new = comment_num_new($value->nid)) {
  19.           $comments .= '<br />';
  20.           $comments .= l(format_plural($new, '1 new', '@count new'), 'node/'. $value->nid, array('fragment' => 'new'));
  21.         }
  22.       }
  23.      $row = array();
  24.      if ($tp != 'tab-types'){
  25.        $row[] = array('data' => check_plain(node_get_types('name', $value->type)), 'class' => 'cctracker-type-' . $value->type);
  26.      }
  27.      $row[] = array('data' => l($value->title,'node/'.$key) .' '. theme('mark', node_mark($value->nid, $value->changed)), 'class' => 'cctracker-title');
  28.      if ($tp != 'my-posts') {
  29.        $row[] = array('data' => theme('username',$value), 'class' => 'cctracker-user');
  30.      }
  31.      $row[] = array('data' => format_date($value->created,'small'), 'class' => 'cctracker-date-created');
  32.      $row[] = array('data' => $comments, 'class' => 'cctracker-replies');
  33.      $row[] = array('data' => t('!time ago', array('!time' => format_interval(time()-$value->last_update))), 'class' => 'cctracker-last-update');
  34.      $rows[] = array('data'=>$row, 'id' => 'cctracker-' . $value->nid);
  35.   }
  36.   $output = theme('table', $header, $rows);
  37.   return $output;
  38. }
Добавить комментарий
« Добавить комментарий
» Добавить комментарий