11
十二/08
7

用drupal和userpoints实现百度知道的基本功能



百度知道的基本系统有发布问题,回答问题,积分悬赏和选择答案这几项,现在我们用drupal来模拟它。其中积分我们使用的是userpoint接口,把知道系统的积分和用户积分合成到一起。而答题系统用drupal的评论系统,做一些更改和界面定制就行了,这里需要在template.php中向comment的hook传递一些变量,比如哪个评论id是最佳答案等等。

这里我们把知道作为一个新的节点类型,但没有用cck手动创建(因为需要定制的东西太多),而是直接用代码实现。

首先,创建这个模块的install文件,表结构如下:

function zhidao_install() {
  switch ($GLOBALS['db_type']) {
    case’mysql’:
    case’mysqli’:
      db_query("CREATE TABLE {zhidao} (
        nid int unsigned NOT NULL default ’0′,
        vid int unsigned NOT NULL default ’0′,
        product_nid int unsigned NOT NULL default ’0′,
        offer_points int unsigned NOT NULL default ’0′,
        additional_points int unsigned NOT NULL default ’0′,
        best_cid int unsigned NOT NULL default ’0′,
        PRIMARY KEY(nid, vid),
        UNIQUE KEY vid(vid),
        KEY nid(nid)
        ) /*!40100 DEFAULT CHARACTER SET UTF8 */");
      break;
  }
}
/**
 * Implementation of hook_uninstall().
*/
function zhidao_uninstall() {
  db_query(‘DROP TABLE {zhidao}’);
}

模块文件如下:

<?php
/*
 * @file
 * 54user Zhidao system.
 */
 
/** 
 * Implementation of hook_node_info(). 
 */ 
function zhidao_node_info() { 
  // We return an array since a module can define multiple node types. 
  // We’re only defining one node type, type ‘zhidao’. 
  return array( 
    ‘zhidao’ => array( 
      ‘name’ => ‘知道’, // Required. 
      ‘module’ => ‘zhidao’, // Required. 
      ‘description’ => ‘模仿百度知道系统’, // Required. 
      ‘has_title’ => TRUE,
      ‘title_label’ => ‘问题’,
      ‘has_body’ => TRUE, 
      ‘body_label’ => ‘问题’, 
      ‘locked’ => TRUE 
    ) 
  ); 

 
/*
 * Implementation of hook_menu(). 
 */
function zhidao_menu($may_cache) {
  $items = array();
  
  if ($may_cache) {
    $items[] = array(‘path’ => ‘zhidao/best’,
      ‘title’ => t(‘select the best answer’),
      ‘type’ => MENU_CALLBACK,
      ‘callback’ => ‘zhidao_best_page’,
      ‘access’ => TRUE, // pending.
    );
  }
  else {
    // Do not cache this menu item during the development of this module.
    $items[] = array(‘path’ => ‘node/add/zhidao’,
      ‘title’ => t(‘Zhidao’),
      ‘access’ => user_access(‘create zhidao’),
    );
  }
  return $items;
}
 
/**
 * Implementation of hook_perm().
 */
function zhidao_perm() {
  return array(‘create zhidao’, ‘edit own zhidao’, ‘do zhidao’);
}
 
/**
 * Implementation of hook_access().
 */
function zhidao_access($op, $node) {
  global $user;
  if ($op == ‘create’) {
    return (user_access(‘create zhidao’));
  }
  if ($op == ‘update’ || $op == ‘delete’) {
    return (user_access(‘edit own zhidao’) && ($user->uid == $node->uid));
  }
}
 
/**
 * Implementation of hook_form().
 */
function zhidao_form($node) {
 
  global $user;
  
  if (‘node’ == arg(0) && ‘add’ == arg(1) && ‘zhidao’ == arg(2) && is_numeric(arg(3))) {
    $product = node_load(arg(3));
  }
  $form = array();
  if ($product) {
    $form['product_nid'] = array(‘#type’ => ‘value’, ‘#value’ => $product->nid);
    $form['product_name'] = array(‘#prefix’ => ‘<h3 class="head">’, ‘#value’ => ‘产品名称: ‘ .check_plain($product->title), ‘#suffix’ => ‘</h3>’);
  }
    
  // Get metadata for this node type
  // (we use it for labeling title and body fields).
  // We defined this in zhidao_node_info().
  $type = node_get_types(‘type’, $node);
  $form['#theme'] = ‘zhidao_form’;
  $form['title'] = array(
    ‘#type’ => ‘textfield’,
    ‘#title’ => check_plain($type->title_label),
    ‘#required’ => TRUE,
    ‘#default_value’ => $node->title,
    ‘#weight’ => -5
  );
  $form['body_filter']['filter'] = filter_form($node->format);
  
  $options = array();
  for ($i = 0; $i <= 100; $i+=20) {
    $options[$i] = $i;
  }
  $form['current_user_points'] = array(
    ‘#value’ => ‘你的积分: <span class="new">’. userpoints_get_current_points($user->uid) .’</span>’,
  );
  $form['offer_points'] = array(
    ‘#type’ => ‘select’,
    ‘#title’ => ‘悬赏积分’,
    ‘#options’ => $options,
    ‘#default_value’ => $node->offer_points,
    ‘#weight’ => 5
  );
  return $form;
}
 
function theme_zhidao_form($form) {
 
  $output = ”;
  $output .= drupal_render($form['product_name']); 
  
  $output .= ‘<div id="zhidao_form">’;
  
  $output .= ‘<div id="zhidao_similar_question"></div>’;
  $output .= drupal_render($form);
  $output .= ‘</div>’;
  
  return $output;
}
 
/**
 * Implementation of hook_validate().
 */
function zhidao_validate($node) {
  global $user;
  $current_user_points = userpoints_get_current_points($user->uid);
 
  // Enforce a minimum word length of 3.
  if (isset($node->offer_points) && $node->offer_points > $current_user_points) {
    form_set_error(‘offer_points’, t(‘you do not have enough points.’));
  }
}
 
/**
 * Implementation of hook_insert().
 */
function zhidao_insert($node) {
  db_query("INSERT INTO {zhidao} (nid, vid, product_nid, offer_points) VALUES (%d, %d, %d, %d)", $node->ni
d, $node->vid, $node->product_nid, (int) $node->offer_points);
}
 
/**
 * Implementation of hook_update().
 */
function zhidao_update($node) {
  if ($node->revision) {
    zhidao_insert($node);
  }
  else {
    db_query("UPDATE {zhidao} SET offer_points = %d WHERE vid = %d", (int) $node->offer_points, $node->vid);
  }
}
 
/**
 * Implementation of hook_delete().
 */
function zhidao_delete(&$node) {
  // Delete the related information we were saving for this node.
  db_query(‘DELETE FROM {zhidao} WHERE nid = %d’, $node->nid);
}
 
/**
 * Implementation of hook_load().
 */
function zhidao_load($node) {
  return db_fetch_object(db_query(‘SELECT offer_points FROM {zhidao} WHERE vid = %d’,
$node->vid));
}
 
/**
 * Implementation of hook_view().
 */
function zhidao_view($node, $teaser = FALSE, $page = FALSE) {
  if (!$teaser) {
    // Use Drupal’s default node view.
    $node = node_prepare($node, $teaser);
    $node->content['offer_points'] = array(
      ‘#value’ => theme(‘zhidao_offer_points’, $node),
      ‘#weight’ => 2
    );
  }
  if ($teaser) {
    // Use Drupal’s default node view.
    $node = node_prepare($node, $teaser);
  }
  return $node;
}
 
function theme_zhidao_offer_points($node) {
  $output = ‘<span class="zhidao_offer_points">’ .t(‘offer points: @points’, array(‘@points’ => $node->offer_points)). ‘</span>’;
  if (user_access(‘do zhidao’)) {
    $output .= ‘<a href="#comment-form" class="do_zhidao"></a>’;
  }
  return $output;
}
 
function zhidao_additional_points($node, $comment) {
  $form = array();
  $best_cid = 0;
  if (is_numeric(arg(2)) && ‘best’ == arg(1)) {
    $best_cid = arg(2);
  }
  for ($i = 0; $i <= 50; $i+=10) {
    $options[$i] = $i;
  }
  $form['additional_points'] = array(‘#type’ => ‘select’, ‘#options’ => $options, ‘#default_value’ => 0);
  $form['submit'] = array(‘#type’ => ‘submit’, ‘#value’ => t(‘submit’));
  $form['offer_points'] = array(‘#type’ => ‘value’, ‘#value’ => $node->offer_points);
  $form['nid'] = array(‘#type’ => ‘value’, ‘#value’ => $node->nid);
  $form['comment_uid'] = array(‘#type’ => ‘value’, ‘#value’ => $comment->uid);
  $form['best_cid'] = array(‘#type’ => ‘value’, ‘#value’ => $best_cid);
  
  return $form;
}
 
function zhidao_additional_points_validate($form) {
  global $user;
  $current_user_points = userpoints_get_current_points($user->uid);
  // Enforce a minimum word length of 3.
  if ($form['offer_points'] + $form['additional_points'] > $current_user_points) {
    form_set_error(‘additional_points’, t(‘you do not have enough points.’));
  }
}
 
function zhidao_additional_points_submit($form_id, $form_values) {
  
  global $user;
  
  $points = (int) $form_values['offer_points'] + (int) $form_values['additional_points'];
  
  $to = user_load(array(‘uid’ => $form_values['comment_uid']));
 
  $params = array(
    ‘uid’ => $to->uid,
    ‘points’ => $points,
    ‘operation’ => ‘Zhidao: FROM ‘ . $user->name,
  );
  userpoints_userpointsapi($params);
  
  $params = array(
    ‘uid’ => $user->uid,
    ‘points’ => -$points,
    ‘operation’ => ‘Zhidao: To ‘ . $to->name,
  );
  userpoints_userpointsapi($params);
  
  if ($form_values['best_cid']) {
    db_query(‘UPDATE {zhidao} SET best_cid = %d, additional_points = %d WHERE nid = %d’, $form_values['best_cid'], $form_values['additional_points'], $form_values['nid']);
  }
  return "node/{$form_values['nid']}";
}
 
function zhidao_best_page($cid) {
  $output = ”; 
  
  if (is_numeric($cid)) {
    $comment = db_fetch_object(db_query(‘SELECT * FROM {comments} WHERE cid = %d’, $cid));
    if ($comment) {
      $node = node_load($comment->nid);
 
      if (‘zhidao’ == $node->type) {
        $output .= ‘<div id="zhidao_best_page">’;
        $output .= ‘<div>’. check_plain($node->title). ‘</div>’;
        $output .= ‘<label>’ .t(‘you select the best answer is: ‘). ‘</label><div>’.check_plain($comment->comment). ‘</div>’;
        $output .= ‘<label>’ .t(‘additional userpoints’). ‘</label><div>’ .drupal_get_form(‘zhidao_additional_points’, $node, $comment). ‘</div>’;
        $output .= ‘</div>’;
        
        return $output;
      }
      else {
        return drupal_not_found();
      }
    }
    else {
      return drupal_not_found();
    }
  }
}


相关文章

评论 (7) Trackbacks (0)
  1. doexcel
    18:21 on 二月 16th, 2009

    天啊,真的很深奥,代码还没看完,头都晕了。Drupal 对于新手要谈定制,真的比登天还难。留个脚印。

  2. terrysco
    00:49 on 二月 17th, 2009

    看看文档,熟悉下drupal的机制,定制起来还是蛮方便的。有很多钩子可以使用,看module目录里面内置的几个模块,大部分实现都有了,呵呵

  3. 上善若水
    00:17 on 五月 28th, 2010

    最近剛好在折騰一個相似的系統,謝謝了。

  4. terrysco
    02:34 on 六月 1st, 2010

    这个版本后来我更新了很多次,感谢您的访问。

  5. 书生
    14:45 on 六月 4th, 2010

    请问有成品吗,不太清楚如何使用。谢谢

  6. 看不懂
    22:25 on 六月 5th, 2011

    你发出来你自己测试过没啊,你那个留言本和这个都有问题,都报错,真搞不懂你这里还有没有能用的,看你像高手,又竞发些瞥脚的东西

  7. terrysco
    17:05 on 六月 15th, 2011

    搞清楚2点:
    1. 本文代码是放在drupal5.x版本运行,6.x变化很大。
    2. 只做逻辑展示,不做模块直接使用。

发表评论

No trackbacks yet.