十二/085
用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();
}
}
}