/[drupal]/contributions/modules/userreview/userreview.module
ViewVC logotype

Contents of /contributions/modules/userreview/userreview.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.24 - (show annotations) (download) (as text)
Thu Mar 15 12:57:39 2007 UTC (2 years, 8 months ago) by gerdriesselmann
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.23: +11 -85 lines
File MIME type: text/x-php
Porting JS to jQuery, voting options table now created by JS
1 <?php
2 // $Id: userreview.module,v 1.23 2007/02/17 08:44:34 gerdriesselmann Exp $
3
4 /*
5 * userreview.module
6 * First released March 12, 2006
7 *
8 * by David Donohue
9 * dado@drupal.org
10 *
11 * Maintained as of Dezember 1, 2006
12 * by Gerd Riesselmann
13 * userreview@gerd-riesselmann.net
14 */
15
16 define ('USERREVIEW_VOTINGAPI_VALUE_TYPE', 'percent');
17
18 /**
19 * Implementation of hook_help().
20 */
21 function userreview_help($section) {
22 switch ($section) {
23 case 'admin/help#userreview':
24 return t('The userreview content type is a node, which is attached to another node. It has a 0 to 10 voting scale. You set a number of configuration options at ') . l('admin/settings/userreview', 'admin/settings/userreview') . t('. Here, you can set which node types are reviewable, how many reviews to display beneath the reviewed node per page, and others.') . '<br/><br/>' . t('This module requires views module and the votingapi module. Using views, it is easy to create blocks or pages which display top rated nodes of a given type, for example.') . '<br/><br/>' . t('This module was designed for Drupal version 4.7.');
25 case 'node/add#userreview':
26 // This description shows up when users click "create content."
27 return t('To add a review, fill out the form under the content you wish to review.');
28 case 'userreview_howto':
29 return t('You can submit reviews of content on this site. To submit a review, find the content you wish to review, and fill out the form below it.');
30 }
31 }
32
33 /**
34 * Implementation of hook_node_info(). This function replaces hook_node_name()
35 * and hook_node_types() from 4.6.
36 */
37 function userreview_node_info() {
38 return array(
39 'userreview' => array(
40 'name' => t('review'),
41 'module' => 'userreview',
42 'description' => t('The userreview content type is a node, which is attached to another node. It has a 0 to 10 voting scale. You set a number of configuration options at ') . l('admin/settings/userreview', 'admin/settings/userreview') . t('. Here, you can set which node types are reviewable, how many reviews to display beneath the reviewed node per page, and others.') . '<br/><br/>' . t('This module requires views module and the votingapi module. Using views, it is easy to create blocks or pages which display top rated nodes of a given type, for example.'),
43 )
44 );
45 }
46
47 /**
48 * Implementation of hook_access().
49 */
50 function userreview_access($op, $node) {
51 global $user;
52
53 if ($op == 'create') {
54 // Only users with permission to do so may create this node type.
55 return user_access('create user reviews');
56 }
57
58 if ($op == 'update' || $op == 'delete') {
59 if (user_access('administer user reviews') || (user_access('edit own user reviews') && ($user->uid == $node->uid))) {
60 return TRUE;
61 } else {
62 return FALSE;
63 }
64 }
65 }
66
67 /**
68 * Implementation of hook_perm().
69 */
70 function userreview_perm() {
71 return array('administer user reviews', 'create user reviews', 'edit own user reviews');
72 }
73
74 /**
75 * Implementation of hook_menu().
76 *
77 * Define a callback, which shows a help message on how users can create a user
78 * review. This is a workaround to overcome the issue that Drupal forces there
79 * to be a link to create a new userreview node on the "create content" page.
80 */
81 function userreview_menu($may_cache) {
82 $items = array();
83 if (!$may_cache) {
84 drupal_add_css(drupal_get_path('module', 'userreview') . '/userreview.css');
85 } else {
86 $items[] = array(
87 'path' => 'userreview/howto',
88 'callback' => 'userreview_help',
89 'callback arguments' => array('userreview_howto'),
90 'title' => t('How to Submit a Review'),
91 'access' => true,
92 'type' => MENU_CALLBACK
93 );
94 $items[] = array(
95 'path' => 'admin/settings/userreview',
96 'title' => t('Userreview'),
97 'description' => t('Configure userreview behavior and appearance.'),
98 'callback' => 'drupal_get_form',
99 'callback arguments' => array('userreview_admin_settings'),
100 'access' => user_access('administer site configuration'),
101 'type' => MENU_NORMAL_ITEM, // optional
102 );
103 }
104
105 return $items;
106 }
107
108 /**
109 * Define settings for this module.
110 */
111 function userreview_admin_settings() {
112 $form = array();
113
114 $node_types = node_get_types('names');
115 unset($node_types['userreview']);
116 $form['userreview_node_types'] = array(
117 '#title' => t('Node types to expose user reviewing.'),
118 '#type' => 'checkboxes',
119 '#options' => $node_types,
120 '#default_value' => variable_get('userreview_node_types', array()),
121 '#description' => t('Check all node types you wish users to review.')
122 );
123
124 $form['review form'] = array('#type' => 'fieldset', '#title' => t('Review Form'), '#collapsible' => true, '#collapsed' => true);
125 $form['review form']['userreview_form_title'] = array(
126 '#type' => 'textfield',
127 '#default_value' => variable_get('userreview_form_title',t('Share your opinion!')),
128 '#title' => t('Title for the user review form'),
129 '#description' => t('This is shown before the user review form. %node_type is replaced with the node type being reviewed, and %node_title is replaced with the title of the node being reviewed. Example: Please rate %node_type %node_title!')
130 );
131 $form['review form']['userreview_vote_description'] = array(
132 '#type' => 'textarea',
133 '#default_value' => variable_get('userreview_vote_description',t('Select a value from 0 (worst) to 10 (best)')),
134 '#title' => 'Description for vote element',
135 '#description' => t('This is shown after the voting element in the user review form')
136 );
137 $form['review form']['userreview_default_vote'] = array(
138 '#type' => 'textfield',
139 '#default_value' => variable_get('userreview_default_vote','5'),
140 '#title' => 'Default vote value',
141 '#description' => t('This should be a number, within the voting range')
142 );
143 $form['review form']['userreview_vote_title'] = array(
144 '#type' => 'textfield',
145 '#default_value' => variable_get('userreview_vote_title',t('Your vote')),
146 '#title' => t('Title for the vote selector element'),
147 '#description' => t('This is shown before the voting element in the user review form. Example: Select a number from 0 to 10.')
148 );
149 $form['review form']['userreview_title_required'] = array(
150 '#type' => 'checkbox',
151 '#title' => t('Review Title is required'),
152 '#description' => t('When a user fills out a userreview, is the title field required?'),
153 '#default_value' => variable_get('userreview_title_required', false)
154 );
155 $form['review form']['userreview_review_text_required'] = array(
156 '#type' => 'checkbox',
157 '#title' => t('Review Text is required'),
158 '#description' => t('When a user fills out a userreview, is the descriptive textarea field required?'),
159 '#default_value' => variable_get('userreview_review_text_required', false)
160 );
161 $form['review form']['userreview_form_collapsible'] = array(
162 '#type' => 'checkbox',
163 '#title' => t('User Review form is in a collapsible field set'),
164 '#description' => t('When showing a reviewable node (in full page view), should the user review form be in a collapsible field set?'),
165 '#default_value' => variable_get('userreview_form_collapsible', true)
166 );
167 $form['review form']['userreview_form_collapsed'] = array(
168 '#type' => 'checkbox',
169 '#title' => t('User review form is in a collapsed field set'),
170 '#description' => t('When showing a reviewable node (in full page view), should the user review form be in a collapsed field set?'),
171 '#default_value' => variable_get('userreview_form_collapsed', true)
172 );
173
174 $form['review list'] = array('#type' => 'fieldset', '#title' => t('Review List'), '#collapsible' => true, '#collapsed' => true);
175 $form['review list']['userreview_review_list_title'] = array(
176 '#type' => 'textfield',
177 '#default_value' => variable_get('userreview_review_list_title', t('User Reviews')),
178 '#title' => t('Title for the list of user reviews displayed'),
179 '#description' => t('This is shown before the listing of user reviews.')
180 );
181 $form['review list']['userreview_otheruser_label'] = array(
182 '#type' => 'textfield',
183 '#default_value' => variable_get('userreview_otheruser_label',t('Review of %node_type: %node_title by %user_name')),
184 '#title' => t('Title for displaying a user\'s review of a particular node'),
185 '#description' => t('This is shown when viewing a user review in full page mode, of the non-current user. %node_type is replaced with the node type being reviewed, and %node_title is replaced with the title of the node being reviewed, and %user_name is replaced with the user\'s name. Example: Review of %node_type: %node_title by %user_name')
186 );
187 $form['review list']['userreview_vote_number_caption'] = array(
188 '#type' => 'textfield',
189 '#size' => 15,
190 '#default_value' => variable_get('userreview_vote_number_caption',t('out of 10')),
191 '#title' => 'Caption under vote value',
192 '#description' => t('This is shown under each vote, when showing user reviews.')
193 );
194 $form['review list']['userreview_vote_decimal'] = array(
195 '#type' => 'textfield',
196 '#default_value' => variable_get('userreview_vote_decimal','1'),
197 '#title' => 'Vote Decimal Places',
198 '#description' => t('Number of decimal places to include with the vote value.'),
199 );
200 $form['review list']['userreview_display_num'] = array(
201 '#type' => 'textfield',
202 '#default_value' => variable_get('userreview_display_num','10'),
203 '#title' => 'Number of reviews to display',
204 '#description' => t('When viewing a reviewed node, this number of user reviews will be displayed on that node\'s page, with a pager link to the next page.')
205 );
206 $form['review list']['userreview_show_review_teasers'] = array(
207 '#type' => 'checkbox',
208 '#title' => t('Show previews only'),
209 '#description' => t('If the review is longer than the system wide teaser length, shorten it and display a "read more" link.'),
210 '#default_value' => variable_get('userreview_show_review_teasers', false)
211 );
212 $form['review list']['userreview_list_collapsible'] = array(
213 '#type' => 'checkbox',
214 '#title' => t('List of user reviews is in a collapsible field set'),
215 '#description' => t('When showing a reviewed node (in full page view), should the list of user reviews be in a collapsible field set?'),
216 '#default_value' => variable_get('userreview_list_collapsible', true)
217 );
218 $form['review list']['userreview_list_collapsed'] = array(
219 '#type' => 'checkbox',
220 '#title' => t('List of user reviews is in a collapsed field set'),
221 '#description' => t('When showing a reviewed node (in full page view), should the list of user reviews be in a collapsed field set?'),
222 '#default_value' => variable_get('userreview_list_collapsed', true)
223 );
224
225 $form['current review'] = array('#type' => 'fieldset', '#title' => t('Current User\'s Review'), '#collapsible' => true, '#collapsed' => true);
226 $form['current review']['userreview_currentuser_label'] = array(
227 '#type' => 'textfield',
228 '#default_value' => variable_get('userreview_currentuser_label',t('Your Review')),
229 '#title' => t('Title of the current user\'s review when viewing the reviewed node'),
230 '#description' => t('This is shown before the current user\'s review, when displayin the reviewed node\s page. %node_type is replaced with the node type being reviewed, and %node_title is replaced with the title of the node being reviewed')
231 );
232 $form['current review']['userreview_show_currentuser_review'] = array(
233 '#type' => 'checkbox',
234 '#title' => t('Show current user\'s review'),
235 '#description' => t('When showing a reviewed node (in full page view), should current\'s user review be shown?'),
236 '#default_value' => variable_get('userreview_show_currentuser_review', true)
237 );
238
239 $form['review node'] = array('#type' => 'fieldset', '#title' => t('Reviewed Node Teaser'), '#collapsible' => true, '#collapsed' => true);
240 $form['review node']['userreview_show_average_vote_in_teaser'] = array(
241 '#type' => 'checkbox',
242 '#title' => t('Show average vote in teaser'),
243 '#description' => t('When showing a teaser of a reviewed node, should the average vote be shown?'),
244 '#default_value' => variable_get('userreview_show_average_vote_in_teaser', true)
245 );
246 $form['review node']['userreview_show_count_votes_in_teaser'] = array(
247 '#type' => 'checkbox',
248 '#title' => t('Show number of votes or "rate it" link in teaser'),
249 '#description' => t('When showing a teaser of a reviewed node, should the number of votes or "add new review" be shown as a link?'),
250 '#default_value' => variable_get('userreview_show_count_votes_in_teaser', false)
251 );
252
253 $form['standalone view'] = array('#type' => 'fieldset', '#title' => t('Userreview Standalone Display'), '#collapsible' => true, '#collapsed' => true);
254 $form['standalone view']['userreview_show_link_to_reviewed'] = array(
255 '#type' => 'checkbox',
256 '#title' => t('Show link to reviewed item'),
257 '#description' => t('Show link to reviewed item on review details page?'),
258 '#default_value' => variable_get('userreview_show_link_to_reviewed', false)
259 );
260
261 return system_settings_form($form);
262 }
263
264 /**
265 * Implementation of hook_form().
266 *
267 * This node type is not intended to be accessed by the standard node creation
268 * page ("node/add/nodetype"). Rather, it is created in association with the
269 * node being reviewed.
270 */
271 function userreview_form(&$node) {
272 //if this form is being called without the proper added fields
273 //(i.e. it is being created de novo from the "create content" page)
274 //then display a help message instead.
275 if (!is_numeric($node->content_id) || !$node->vote_tag) {
276 drupal_goto('userreview/howto');
277 }
278
279 //capture the vote value from the request object, if present
280 if (isset($_REQUEST['edit']['vote_value'])) {
281 $node->vote_value = (int)$_REQUEST['edit']['vote_value'];
282 }
283 if (!$node->content_type) {
284 $node->content_type = 'node';
285 }
286
287 //set the breadcrumb
288 userreview_set_breadcrumb($node);
289
290 drupal_add_js(drupal_get_path('module', 'userreview') . '/userreview.js');
291 $add_elements = array();
292 $add_elements['vote_value'] = array(
293 '#type' => 'select',
294 '#title' => variable_get('userreview_vote_title',t('Your vote')),
295 '#description' => variable_get('userreview_vote_description',t('Select a value from 0 (worst) to 10 (best)')),
296 '#default_value' => ($node->vote_value == null) ? variable_get('userreview_default_vote','') : (string)($node->vote_value),
297 '#options' => array('0'=>'0', '1'=>'1', '2'=>'2', '3'=>'3', '4'=>'4', '5'=>'5', '6'=>'6', '7'=>'7', '8'=>'8', '9'=>'9', '10'=>'10'),
298 '#required' => TRUE,
299 '#weight' => -5
300 );
301 $add_elements['title'] = array(
302 '#type' => 'textfield',
303 '#title' => t('Title'),
304 '#size' => 60,
305 '#maxlength' => 128,
306 '#required' => variable_get('userreview_title_required', FALSE),
307 '#weight' => -2,
308 '#default_value' => $node->title
309 );
310 $add_elements['review_text'] = array(
311 '#type' => 'textarea',
312 '#title' => t('Comments'),
313 '#default_value' => $node->review_text,
314 '#required' => variable_get('userreview_review_text_required', FALSE),
315 '#weight' => -1,
316 '#description' => t('Please enter your comments.')
317 );
318 $add_elements['content_id'] = array('#type' => 'value', '#value' => $node->content_id);
319 $add_elements['content_type'] = array('#type' => 'value', '#value' => $node->content_type);
320 $add_elements['vote_tag'] = array('#type' => 'value', '#value' => $node->vote_tag);
321
322 $add_elements['format'] = filter_form($node->format);
323
324 return $add_elements;
325 }
326
327 /**
328 * Implementation oh hook_nodeapi
329 *
330 * Here we add the review list to the reviewed item's body, when it is views
331 */
332 function userreview_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
333 //if this node type is not a reviewable one (as configured in settings page) then return
334 $reviewable_node_types = variable_get('userreview_node_types', array());
335 if (!array_key_exists($node->type, $reviewable_node_types) || $reviewable_node_types[$node->type] == '0') {
336 return;
337 }
338
339 global $user;
340 switch ($op) {
341 case 'view':
342 $count_votes = _userreview_nodeapi_view_prepare(
343 $node,
344 $page || variable_get('userreview_show_average_vote_in_teaser', true),
345 $teaser && variable_get('userreview_show_count_votes_in_teaser', false)
346 );
347 if ($page) {
348 $node->content['userreview_average'] = array(
349 '#value' => $node->userreview->average_vote,
350 '#weight' => 8,
351 );
352
353 //get the current user's review for this content node
354 $userreviewnode = get_userreview_node($node, $user->uid);
355 //if a review exists by this user, show it...
356 if ($userreviewnode) {
357 if (variable_get('userreview_show_currentuser_review', true)) {
358 $node->userreview->current_user_review = theme('userreview', $userreviewnode, true, true);
359 $node->content['userreview_current_user_review'] = array(
360 '#value' => $node->userreview->current_user_review,
361 '#weight' => 9,
362 );
363 }
364 //...otherwise show the form to create a user review IF we are not printing the page (print module)
365 } else if(user_access('create user reviews') && !$node->printing) {
366 $userreviewnode = new StdClass();
367 $userreviewnode->content_id = $node->nid;
368 $userreviewnode->vote_tag = 'userreview:'.$node->type;
369 $userreviewnode->content_type = 'node';
370 $userreviewnode->type = 'userreview';
371 $userreviewnode->uid = $user->uid;
372 $userreviewnode->name = $user->name;
373 $display_title = get_userreview_form_title($node);
374 $node->userreview->review_form = theme('userreview_included_form', $display_title, drupal_get_form('userreview_node_form', $userreviewnode));
375
376 $node->content['userreview_review_form'] = array(
377 '#value' => $node->userreview->review_form,
378 '#weight' => 9,
379 );
380 }
381
382 //next, show a list of user reviews if any reviews
383 if ($count_votes->value > 0) {
384 $node->userreview->review_list .= theme('userreview_list', $node, variable_get('userreview_list_collapsible', true), variable_get('userreview_list_collapsed', true));
385 $node->content['userreview_review_list'] = array(
386 '#value' => $node->userreview->review_list,
387 '#weight' => 10,
388 );
389 }
390 } else {//teaser
391 $node->content['userreview_average'] = array(
392 '#value' => $node->userreview->average_vote,
393 '#weight' => 8,
394 );
395 }
396 break;
397 }
398 }
399
400 /**
401 * Prepare userreview part of node when viewing reviewed node
402 *
403 * This function sets count_votes and average_vote properties on $node->userreview, if module settings state so
404 *
405 * @param Object The node to extend
406 * @param Boolean True, if the average voting should be displayed
407 * @param Boolean True, if the count of votes should be displayed
408 *
409 * @return Object Count of votes as result object as returned by votingapi_get_voting_result()
410 */
411 function _userreview_nodeapi_view_prepare(&$node, $show_average, $show_count) {
412 $count_votes = new StdClass();
413 $count_votes->value = 0;
414 if ($show_average || $show_count) {
415 //first, show the average vote
416 $count_votes = votingapi_get_voting_result('node', $node->nid, USERREVIEW_VOTINGAPI_VALUE_TYPE, 'userreview:'.$node->type, 'count');
417 $node->userreview->count_votes = $count_votes;
418 }
419 if ($show_average && $count_votes->value > 0) {
420 $avg_vote = votingapi_get_voting_result('node', $node->nid, USERREVIEW_VOTINGAPI_VALUE_TYPE, 'userreview:'.$node->type, 'average');
421 $node->userreview->average_vote = theme('userreview_voting_results', $avg_vote->value, $count_votes->value);
422 }
423 return $count_votes;
424 }
425
426 /**
427 * Themes the list of userreviews displayed after a node
428 */
429 function theme_userreview_list($node, $collapsible = true, $collapsed = true) {
430 $view = views_get_view('userreview');
431 $o = views_build_view('embed', $view, array($node->nid), true, variable_get('userreview_display_num',10));
432 $display = array(
433 '#collapsible' => $collapsible,
434 '#collapsed' => $collapsed,
435 '#title' => variable_get('userreview_review_list_title', t('User Reviews')),
436 '#children' => $o
437 );
438 return theme('fieldset', $display);
439 }
440
441 /**
442 * Compute form title from node and user settings
443 *
444 * @param object Node to append review to
445 * @return string Title for form as plain text
446 */
447 function get_userreview_form_title($node) {
448 $display_title = variable_get('userreview_form_title', t('Share your opinion!'));
449 $node_translation_terms = array(
450 '%node_type' => node_get_types('name', $node),
451 '%node_title' => $node->title,
452 );
453 $display_title = t($display_title, $node_translation_terms);
454 /*
455 $display_title = str_replace('%node_type', node_get_name($node->type),
456 $display_title);
457 $display_title = str_replace('%node_title', $node->title, $display_title);
458 */
459 return check_plain($display_title);
460 }
461
462 /**
463 * Given a reviewable node's object and a user ID, retrieves the userreview node
464 * submitted by that user on that reviewable node. If no review has been
465 * submitted, returns $default
466 */
467 function get_userreview_node($content_node, $uid = 0, $default = false) {
468 global $user;
469 $sql = 'select nid from {userreview} where content_id = %d and uid = %d';
470 $result = db_fetch_object(db_query($sql, $content_node->nid, $uid));
471 if (!$result) return $default;
472 $userreview_node = node_load($result->nid);
473 if ($uid == $user->uid) {
474 $display_title = variable_get('userreview_currentuser_label', t('Your Review'));
475 } else {
476 $display_title = variable_get('userreview_otheruser_label', t('Review of %node_type: %node_title by %user_name'));
477 }
478 $display_title = str_replace('%node_type', node_get_types('name', $content_node), $display_title);
479 $display_title = str_replace('%node_title', $content_node->title, $display_title);
480 if (strpos($display_title, '%user_name') >= 0) {
481 $user_criteria = array('uid'=>$uid);
482 $reviewer_obj = user_load($user_criteria);
483 $display_title = str_replace('%user_name', $reviewer_obj->name, $display_title);
484 }
485 $userreview_node->userreview_label = check_plain($display_title);
486 return $userreview_node;
487 }
488
489 /**
490 * Find all the userreviews for a given reviewable node. Not used in module due to views,
491 * but useful when building custom themes.
492 */
493 function get_userreviews($node) {
494 $sql = db_rewrite_sql("
495 SELECT n.nid
496 FROM
497 node n
498 LEFT JOIN userreview ON n.nid = userreview.nid
499 LEFT JOIN users ON n.uid = users.uid
500 WHERE
501 (n.status = '1')
502 AND
503 (userreview.content_id = %d)
504 ORDER BY changed DESC",
505 'n');
506 $result = pager_query($sql, variable_get('userreview_display_num','10'), 0, NULL, $node->nid);
507 $ret = array();
508 while ($node = db_fetch_object($result)) {
509 $ret[] = node_load($node->nid);
510 }
511 return $ret;
512 }
513
514 /**
515 * Implementation of hook_insert().
516 *
517 * As a new node is being inserted into the database, add userreview field data
518 * to the userreview table. Also, insert a new vote using the votingapi.
519 */
520 function userreview_insert($node) {
521 global $user;
522
523 //store the vote using votingapi
524 $vobj = new stdClass();
525 $vobj->value = $node->vote_value;
526 $vobj->value_type = USERREVIEW_VOTINGAPI_VALUE_TYPE;
527 $vobj->tag = $node->vote_tag;
528 votingapi_set_vote($node->content_type, $node->content_id, $vobj, $user->uid);
529
530 //get the new vote's vid
531 $inserted_vobj = votingapi_get_vote($node->content_type, $node->content_id, $vobj->value_type, $vobj->tag, $user->uid);
532 $next_id = db_next_id('userreview');
533 db_query("INSERT INTO {userreview} (nid, content_id, content_type, vote_id, vote_value, vote_tag, uid, review_text) VALUES (%d, %d, '%s', %d, %d, '%s', %d, '%s')", $node->nid, $node->content_id, $node->content_type, $inserted_vobj->vote_id, $node->vote_value, $node->vote_tag, $user->uid, $node->review_text);
534
535 // Update path to usrereview lsit page
536 if (function_exists('pathauto_create_alias')) {
537 $placeholders = userreview_get_placeholders($node);
538 pathauto_create_alias(
539 'userreview',
540 'insert',
541 $placeholders,
542 'userreview/of/' . $node->content_id,
543 'userreview_list');
544 }
545
546 //forward to the reviewed node
547 $_REQUEST['destination'] = 'node/' . $node->content_id;
548 }
549
550 /**
551 * Implementation of hook_update().
552 *
553 * Update the userreview table with all changable info (vote value and review
554 * text only). Also set the new vote value & update the vote cache using the
555 * votingapi.
556 */
557 function userreview_update($node) {
558 if (isset($_REQUEST['edit']['vote_value'])) {
559 $node->vote_value = (int)$_REQUEST['edit']['vote_value'];
560 }
561
562 //update only the vote value in the userreview table.
563 db_query("UPDATE {userreview} set vote_value = %d, review_text = '%s' where nid = %d", $node->vote_value, $node->review_text, $node->nid);
564
565 //store the vote using votingapi
566 $vote = new stdClass();
567 $vote->value = $node->vote_value;
568 $vote->value_type = USERREVIEW_VOTINGAPI_VALUE_TYPE;
569 $vote->tag = $node->vote_tag;
570 votingapi_set_vote($node->content_type, $node->content_id, $vote, $user->uid);
571
572 //forward to the reviewed node
573 $_REQUEST['destination'] = 'node/' . $node->content_id;
574 }
575
576 /**
577 * Implementation of hook_delete().
578 * Deletes the record in table userreviwew.
579 * Also deletes the associated votes and updates the vote cache
580 */
581 function userreview_delete($node) {
582 db_query('DELETE FROM {userreview} WHERE nid = %d', $node->nid);
583 $vote = new stdClass();
584 $vote->vote_id = $node->vote_id;
585 $vote->content_id = $node->content_id;
586 $vote->content_type = 'node';
587 votingapi_delete_vote($vote);
588 votingapi_recalculate_results($vote->content_type, $vote->content_id);
589 }
590
591 /**
592 * Implementation of hook_load().
593 */
594 function userreview_load($node) {
595 $additions = db_fetch_object(db_query('SELECT * FROM {userreview} WHERE nid = %d', $node->nid));
596
597 $vote_value = (int)$_REQUEST['edit']['vote_value'];
598 if ($vote_value && is_numeric($vote_value)) {
599 $additions->vote_value = $vote_value;
600 }
601 return $additions;
602 }
603
604 /**
605 * Set the breadcrumb, given the userreview node. This should be called on
606 * pages where the userreview node or form is being displayed. Since the
607 * userreview is alwasy subordinate to the node it is reviewing, the breadcrumb
608 * should reflect this. This function sets the breadcrumb as simply "Home ->
609 * [reviewed node's title]"
610 */
611 function userreview_set_breadcrumb($node) {
612 $breadcrumb = menu_get_active_breadcrumb();
613 $content_node = node_load($node->content_id);
614 $breadcrumb[] = l("$content_node->title", "node/$node->content_id");
615 drupal_set_breadcrumb($breadcrumb);
616 }
617
618 /**
619 * Implementation of hook_view().
620 *
621 * This is a typical implementation that simply runs the node text through
622 * the output filters.
623 */
624 function userreview_view(&$node, $teaser = FALSE, $page = FALSE) {
625 global $user;
626 if ($page) {
627 /*
628 if ($node->uid == $user->uid) {
629 //if we are viewing the current user's userreview node, redirect to the reviewed node.
630 //Thus, when a user has submitted or updated her review, she will then see the reviewed node as the next page.
631 drupal_goto("node/$node->content_id");
632 } else {
633 userreview_set_breadcrumb($node);
634 }
635 */
636 userreview_set_breadcrumb($node);
637 }
638 $node = node_prepare($node, $teaser); // is this necessary?
639 if ($teaser) {
640 $node->content['teaser'] = array(
641 '#value' => theme('userreview_teaser', $node),
642 '#weight' => 1,
643 );
644 } else {
645 $node->content['body'] = array(
646 '#value' => theme('userreview_teaser', $node),
647 '#weight' => 1,
648 );
649 }
650
651 //remove the title, since the title is shown in the above theming
652 unset($node->title);
653 return $node;
654 }
655
656
657 /**
658 * Implementation of hook_link().
659 *
660 * Appends the following links to the reviewed node:
661 * - "1 review"/"n reviews"/"add new review": if userreview_show_count_votes_in_teaser is true and user has according user rights
662 *
663 * Appends the following links to the userreview itself:
664 * - "See reviewed item": If userreview is displayed standalone and userreview_show_link_to_reviewed is set
665 */
666 function userreview_link($type, $node = 0, $main = 0) {
667 $links = array();
668 if ($type != 'node' || empty($node)) {
669 return $links;
670 }
671
672 if ($node->userreview) {
673 if ($main) {
674 // Main page: display the number of comments that have been posted.
675 if (variable_get('userreview_show_count_votes_in_teaser', false) && user_access('access content')) {
676 $count_votes = $node->userreview->count_votes;
677 if ($count_votes) {
678 $links['userreview_count_votes'] = array(
679 'title' => format_plural($count_votes->value, '1 review', '@count reviews'),
680 'href' => "node/$node->nid",
681 'attributes' => array('title' => t('Jump to the reviews for this item.'))
682 );
683 }
684 else if (user_access('create user reviews')) {
685 $links['userreview_count_votes'] = array(
686 'title' => t('add new review'),
687 'href' => "node/$node->nid",
688 'attributes' => array('title' => t('Add a new review to this item.'))
689 );
690 }
691 }
692 }
693 }
694 if ($node->type == 'userreview' && !$main && variable_get('userreview_show_link_to_reviewed', false)) {
695 $links['userreview_reviewed_item'] = array(
696 'title' => t('See reviewed item'),
697 'href' => "node/$node->content_id",
698 'attributes' => array('title' => t('Open the item that was reviewed'))
699 );
700 }
701 return $links;
702 }
703
704 /**
705 * implementation of form_alter for the userreview creation form. This simply
706 * removed the "preview" button.
707 */
708 function userreview_form_alter($form_id, &$form) {
709 $op = isset($_POST['op']) ? $_POST['op'] : '';
710 if ($form_id == 'userreview_node_form' &&
711 !(variable_get('node_preview', 0) && (form_get_errors() || $op != t('Preview')))) {
712 unset($form['preview']);
713 }
714 }
715
716 /**
717 * Themes a userreview node for full (page) view
718 */
719 function theme_userreview($node, $collapsible = true, $collapsed = true) {
720 global $user;
721 $output = '<table class="userreview_view">';
722
723 $output .= '<tr><td align="left" class="userreview_review_vote_container">';
724 $output .= theme('userreview_vote', $node->vote_value);
725 $output .= '</td><td>';
726 if ($node->title) {
727 $output .= '<div class="userreview_review_title">' . check_plain($node->title) . '</div>';
728 }
729
730 if ($node->review_text) {
731 $output .= '<div class="userreview_review_body">' . check_markup($node->review_text) . '</div>';
732 }
733 $output .= '<br/><span class="userreview_byline">';
734 $output .= t('by '). l($node->name, 'user/' . $node->uid);
735 $output .= t(' on ') . format_date($node->changed);
736 $output .= '</span>';
737 if ($node->uid == $user->uid && user_access("edit own user reviews")) {
738 $output .= '<span class="userreview_review_link">';
739 $output .= l(t('Edit your review'), 'node/'.$node->nid.'/edit');
740 $output .= '</span>';
741 }
742 $output .= '</td></tr></table>';
743 $display = array(
744 '#collapsible' => $collapsible,
745 '#collapsed' => $collapsed,
746 '#title' => $node->userreview_label,
747 '#children' => $output
748 );
749 return theme('fieldset', $display);
750 }
751
752 /**
753 * Themes a userreview node for teaser view. This function is also used for
754 * listing user reviews under each reviewed node, via the views module
755 */
756 function theme_userreview_teaser($node) {
757 global $user;
758 $output = "";
759 $output .= '<table class="userreview_view_teaser">';
760 $output .= '<tr><td align="left" class="userreview_review_vote_container">';
761 $output .= theme('userreview_vote', $node->vote_value);
762 $output .= '</td><td>';
763 if ($node->title) {
764 $output .= '<div class="userreview_review_title">' . check_plain($node->title) . '</div>';
765 }
766
767 if ($node->review_text) {
768 $output .= '<div class="userreview_review_body">';
769 $output .= check_markup($node->review_text);
770 if ($node->readmore) {
771 $output .= l(t('Read more...'), 'node/' . $node->nid, 'Read the full review');
772 }
773 $output .= '</div>';
774 }
775 $output .= '<br/><span class="userreview_byline">';
776 $output .= t('by '). l($node->name, 'user/'. $node->uid);
777 $output .= t(' on ') . format_date($node->changed);
778 $output .= '</span>';
779
780 if ($node->uid == $user->uid && user_access("edit own user reviews")) {
781 $output .= '<span class="userreview_review_link">';
782 $output .= l(t('Edit your review'), 'node/'. $node->nid .'/edit');
783 $output .= '</span>';
784 }
785
786 $output .= '</td></tr></table>';
787 return $output;
788 }
789
790 /**
791 * Themes the userreview form. Adds a header andplaces the form inside a div
792 * tag, permitting theming of this form. By default, the form is rendered with
793 * gray background to set it apart from the reviewed node.
794 */
795 function theme_userreview_included_form($title, $form_html) {
796 $op = isset($_POST['op']) ? $_POST['op'] : '';
797 $output = '';
798 $display = array(
799 '#collapsible' => variable_get('userreview_form_collapsible', true),
800 '#collapsed' => variable_get('userreview_form_collapsed', true) && $op != t('Preview'),
801 '#title' => check_plain($title),
802 '#children' => $form_html
803 );
804 $output .= theme('fieldset', $display);
805 return $output;
806 }
807
808 /**
809 * Themes a userreview vote number. Places the caption below the numnber.
810 * Using table layout for most consistent cross-browser & cross-theme layout.
811 */
812 function theme_userreview_vote($vote_value) {
813 $output = '';
814 if (is_numeric($vote_value)) {
815 $output .= '<table class="userreview_review_vote">';
816 $display_number = $vote_value;
817 if (floor($vote_value) < $vote_value) {
818 $display_number = number_format($vote_value, variable_get('userreview_vote_decimal','1'));
819 }
820 $score_class = 'userreview_review_number userreview_score_' . number_format($vote_value, 0);
821 $output .= '<tr><td class="' . $score_class . '">' . $display_number . '</td></tr>';
822 $caption = variable_get('userreview_vote_number_caption',t('out of 10'));
823 if ($caption) {
824 $output .= '<tr><td class="userreview_review_number_caption">' . $caption . '</td></tr>';
825 }
826 $output .= '</table>';
827 }
828 return $output;
829 }
830
831 /**
832 * Themes the report of average vote value of the voting on a particular node.
833 */
834 function theme_userreview_voting_results($avg_vote, $count_votes) {
835 $output = '';
836 $output .= '<table class="userreview_voting_result"><tr><td>';
837 $output .= '<span class="userreview_voting_result_title">';
838 $output .= t('Average vote');
839 $output .= '</span>';
840 $output .= t(' based on ');
841 $output .= '<span class="userreview_count_votes">';
842 $output .= $count_votes;
843 $output .= '</span>';
844 $output .= format_plural($count_votes, t(' review.'), t(' reviews.'));
845 $output .= '</td><td class="userreview_average_vote">';
846 $output .= theme('userreview_vote', $avg_vote);
847 $output .= '</td>';
848 $output .= '</tr></table>';
849
850 return $output;
851 }
852
853 /* ****************************************
854 * Begin Views module functions
855 * ****************************************/
856
857 /**
858 * The core views module function. Defines the fields, filters, sorts for
859 * viewing userreview nodes
860 */
861 function userreview_views_tables() {
862 $tables['userreview'] = array(
863 'name' => 'userreview',
864 'join' => array(
865 'left' => array(
866 'table' => 'node',
867 'field' => 'nid',
868 ),
869 'right' => array(
870 'field' => 'nid',
871 ),
872 ),
873 'fields' => array(
874 'review_text' => array(
875 'name' => 'Userreview: Review Text',
876 'sortable' => false,
877 'nid' => 'nid',
878 'addlfields' => array('nid'),
879 ),
880 'vote_tag' => array(
881 'name' => 'Userreview: Review Type',
882 'sortable' => true,
883 'nid' => 'nid',
884 'addlfields' => array('nid'),
885 ),
886 'vote_value' => array(
887 'name' => 'Userreview: Vote Value',
888 'sortable' => true,
889 'nid' => 'nid',
890 'addlfields' => array('nid'),
891 ),
892 ),
893 'sorts' => array(
894 'vote_tag' => array('name' => 'Userreview: Review Type'),
895 'vote_value' => array('name' => 'Userreview: Vote Value'),
896 ),
897 );
898 return $tables;
899 }
900
901 /**
902 * Implementation of hook_views_arguments. Defines the content_id argument for
903 * viewing userreview nodes
904 */
905 function userreview_views_arguments() {
906 $arguments = array(
907 'userreview_content_id' => array(
908 'name' => t("Userreview: Content ID"),
909 'handler' => "userreview_views_handler_arg_content_id"
910 )
911 );
912 return $arguments;
913 }
914
915 /**
916 * The handler for the content_id views argument, for viewing userreview nodes
917 */
918 function userreview_views_handler_arg_content_id($op, &$query, $argtype, $arg = '') {
919 switch($op) {
920 case 'summary':
921 $query->add_field("content_id");
922 $query->add_groupby("userreview.content_id");
923 $fieldinfo['field'] = "userreview.content_id";
924 return $fieldinfo;
925 case 'filter':
926 $query->ensure_table("userreview");
927 $query->add_where("userreview.content_id = $arg");
928 break;
929 case 'link':
930 return l($query->type, "userreview/of/$arg");
931 case 'title':
932 return $query;
933 }
934 }
935
936 /**
937 * This generates the list of userreviews which is rendered beneath the reviewed
938 * node. Calls theme_userreview_teaser to render the node
939 */
940 function theme_views_view_userreview($view, $type, $nodes) {
941 if ($view->type == 'list' || $type == 'embed') {
942 $counter = 0;
943 foreach ($nodes as $node) {
944 if ($counter > 0) {
945 $output .= '<hr class="userreview"/>';
946 }
947 $counter++;
948 //map views fields to node fields
949 $node->title = check_plain($node->node_title);
950 $node->changed = $node->node_changed;
951 $node->uid = $node->users_uid;
952 $node->name = $node->users_name;
953 if (variable_get('userreview_show_review_teasers', false)) {
954 // show a shorten version of review text
955 $node->review_text = node_teaser($node->userreview_review_text, $node->format);
956 $node->readmore = (strlen($node->review_text) < strlen($node->userreview_review_text));
957 }
958 else {
959 $node->review_text = check_markup($node->userreview_review_text);
960 $node->readmore = false;
961 }
962 $node->vote_value = $node->userreview_vote_value;
963
964 $output .= theme('userreview_teaser', $node);
965 }
966 }
967 if ($output) {
968 return $output;
969 }
970 }
971
972 /**
973 * Implementation of hook_views_default_views.
974 * Defines the views view, which will
975 * render the lsit of userreview nodes under the reviewed node.
976 */
977 function userreview_views_default_views() {
978 $view = new stdClass();
979 $view->name = 'userreview';
980 $view->description = 'list the userreview nodes by node';
981 $view->access = array (
982 0 => '1',
983 1 => '2',
984 );
985 $view->page = TRUE;
986 $view->page_title = '';
987 $view->page_header = '';
988 $view->page_header_format = '1';
989 $view->page_type = 'list';
990 $view->url = 'userreview/of';
991 $view->use_pager = TRUE;
992 $view->nodes_per_page = '10';
993 $view->block = FALSE;
994 $view->sort = array (
995 array (
996 'tablename' => 'node',
997 'field' => 'changed',
998 'sortorder' => 'DESC',
999 'options' => '',
1000 ),
1001 );
1002 $view->argument = array (
1003 array (
1004 'type' => 'userreview_content_id',
1005 'argdefault' => '1',
1006 'title' => '',
1007 'options' => '',
1008 ),
1009 );
1010 $view->field = array (
1011 array (
1012 'tablename' => 'node',
1013 'field' => 'title',
1014 'label' => 'Title',
1015 'handler' => 'views_handler_field_nodelink',
1016 ),
1017 array (
1018 'tablename' => 'userreview',
1019 'field' => 'vote_value',
1020 'label' => 'Vote',
1021 ),
1022 array (
1023 'tablename' => 'node',
1024 'field' => 'changed',
1025 'label' => 'Date',
1026 'handler' => 'views_handler_field_date',
1027 'defaultsort' => 'DESC',
1028 ),
1029 array (
1030 'tablename' => 'users',
1031 'field' => 'name',
1032 'label' => 'by ',
1033 ),
1034 array (
1035 'tablename' => 'userreview',
1036 'field' => 'review_text',
1037 'label' => 'Remarks',
1038 ),
1039 );
1040 $view->filter = array (
1041 array (
1042 'tablename' => 'node',
1043 'field' => 'status',
1044 'operator' => '=',
1045 'options' => '',
1046 'value' => '1',
1047 ),
1048 );
1049 $view->requires = array(node, userreview, users);
1050 $views[$view->name] = $view;
1051
1052 return $views;
1053 }
1054
1055 ///////////////////////////////////////
1056 // Pathauto integration
1057 ///////////////////////////////////////
1058
1059 /**
1060 * Register a new section "userreviews" on pathauto settings page
1061 */
1062 function userreview_pathauto($op) {
1063 switch ($op) {
1064 case 'settings':
1065 $settings = array();
1066 $settings['module'] = 'userreview';
1067 $settings['groupheader'] = t('Userreview settings');
1068 $settings['patterndescr'] = t('Alias for list of reviews for a node (userreview/of/[reviewed item nid])');
1069 $settings['patterndefault'] = '';
1070 $settings['bulkname'] = t('Bulk update userreview pages');
1071 $settings['bulkdescr'] =
1072 t('Generate aliases for all existing userreview pages which do not already have aliases.');
1073 $settings['placeholders'] = array(
1074 t('[reviewed item nid]') => t('For userreview nodes, the node id of the reviewed item.'),
1075 t('[reviewed item title]') => t('For userreview nodes, the title of the reviewed item.'),
1076 t('[reviewed item path]') => t('For userreview nodes, the path alias for of the reviewed item.')
1077 );
1078
1079 return (object) $settings;
1080 default:
1081 break;
1082 }
1083 }
1084
1085 /**
1086 * Perform a bulk update on all userreview list pages
1087 */
1088 function userreview_pathauto_bulkupdate() {
1089 $sql = "SELECT DISTINCT content_id from {userreview}";
1090 $result = db_query($sql);
1091 $count = 0;
1092 while ($node = db_fetch_object($result)) {
1093 $placeholders = userreview_get_placeholders($node);
1094 $alias = pathauto_create_alias(
1095 'userreview',
1096 'bulkupdate',
1097 $placeholders,
1098 'userreview/of/' .</