OK - this is propably a really, really simple question. But not for me. I use Bookreviewmodule. In this you can rate books. The code for that is like this:

$form['book_infos']['rating'] = array(
    '#type' => 'select',
    '#title' => t('Rating'),
    '#default_value' => $node->rating,
    '#options' => (array('<' . t('none') . '>') + drupal_map_assoc(range(1, 10))),
    '#description' => t('Score of the book on a 1 to 10 scale.'),
  );*/

I would like to have words instead of numbers. How do I change the code. For example I want it to
be
- Rate-
Bad
Average
Good
Very good

Instead av a range 1-10.

Anyone who can tell me how to write that in this code?

Comments

rmpel’s picture

We need to stay compatible with all other code, so we only change this line:
'#options' => (array('<' . t('none') . '>') + drupal_map_assoc(range(1, 10))),
Drupal_map_assoc is able to do two things;
1. make an array associative by itself
2. make an array associative by callback function
As used here; drupal_map_assoc transforms the array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) which for PHP is array( 0=>1, 1=>2, ... 9=>10) to array(1=>1, 2=>2, ..., 10=>10)
When you change the line to:
'#options' => (array('<' . t('none') . '>') + drupal_map_assoc(range(1, 10), 'my_callback_function')),
(where my_callback_function is a correct function name in either a separate module or the module you are editing)
and the function my_callback_function does:

function my_callback_function($element) {
  $names = array(1 => 'Very bad', 2=> 'Bad', 3 => 'Fairly bad' ...... 9 => 'Good', 10 => 'Very good');
  return t($names[$element]);
}

the resulting array would be: array(0 => '', 1 => 'Very bad, 2=> etc etc
(The reason i list 1 through 10 here is because the original code expects it, but it's not obligatory, see my note further down)

This is, however, not the best way to alter existing code.

The Drupal way is to create a module with a form alter function to change the form value $form['book_infos']['rating']['#options'].

this would look someting like:

-- File: book_review_alter.info --

name = "Book Review Alter"
description = "Alters the form for book reviews"
version = "5.x-1.x-dev"
dependencies = bookreview

(the name bookreview in the dependencies line must be identical to the modulename of the module you are altering the form for)

--File: book_review_alter.module--

<?php
/** 
 * Implementation of hook_form_alter()
 */
function book_review_alter_form_alter($form_id, &$form) {
  if ($form_id == 'the_form_id_from_the_form_your_altering_most_likely_the_function_name_defining_the_form') {
    $form['book_infos']['rating']['#options'] = array('<' . t('none') . '>') + book_review_alter_ratings();
  }
}

function book_review_alter_ratings() {
  return array(
    1 => t('Very bad'),
    2 => t('Bad'),
    3 => t('Average'),
    4 => t('Good'),
    5 => t('Very good'),
  );
}

Note: Remember, this just alters the form, but not the presentation of the rating in, for example, a node view. You'll need to dig a bit to find where the ratings are 'read' for viewing it on screen and make similar adjustments.
If you rewrite EVERY spot the rating is used to use your names, it doesn't matter how much or little ratings you define.

I don't know the book review module, so I can't tell you on how many points you need to hook. The idea is hopefully clear to help you a few steps in the right direction.

Remon.

AstaC’s picture

This was a bit to think about. Now I'll start trying it out :)

AstaC’s picture

Really nice. If I may bother you once more for the output. This is the line for the output. Do you have an idea about this to? That about a new module is propably more than I can manage.

 if($node->rating) {
    $output .= '    <div class="rating"><span class="label3">'. t('Rating') .':</span><span class="content3">'. check_markup($node->rating, $node->format, FALSE) ."</span></div>\n";
  }

I guess it is something with if else, or should it be a function here to? This was really learning.

rmpel’s picture

First of all, allow me to apologise for the delayed reaction.

Where did you find this piece of code?

If it's inside a theme_ function, you can alter it by creating a theme override function in your template.php (theme folder).
If not, you probably need to rewrite the $node->rating variable.
Most probably you'll need to implement the hook_nodeapi() hook.

function book_review_alter_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'submit':
    case 'insert':
    case 'update':
      // don't think we need anything done on submittal of node; book review does that for us I assume.
      break;
    case 'view':
      // this should be the point where we alter the output. I can never get straight, however, 
      // if i should hook the 'view' operation or the 'load'. Bit of trial and error is required here.
      // since both load and view are done without altering the node itself, only the representation of it
      // there is no risk of injuring your database
      $my_ratings = book_review_alter_ratings();
      $node->rating = $my_ratings[$node->rating];
      break;
  }
}

now, the

$node->rating = $my_ratings[$node->rating];

line alters the rating to our textual rating.
BUT!
1. this shouldn't be done on node edit pages (the form expects a number, not a text)
2. this should be done AFTER the bookreview adds it to the $node (we need to increase the weight of the module)

solution to 1:

    case 'view':
      // this should be the point where we alter the output. I can never get straight, however, 
      // if i should hook the 'view' operation or the 'load'. Bit of trial and error is required here.
      // since both load and view are done without altering the node itself, only the representation of it
      // there is no risk of injuring your database
      if (! (arg(0) == "node" && arg(2) == "edit") ) { // exclude node editing pages
        $my_ratings = book_review_alter_ratings();
        $node->rating = $my_ratings[$node->rating];
      }
      break;

solution to 2:
as I have not seen an interface for this, you'll have to change the database itself.
I would suggest this piece of code be in the book_review_alter.install file inside the book_review_alter_install function, see the drupal api for hook_install() implementation. This work, however, only upon first activation of the module.

db_query("UPDATE {system} st INNER JOIN {system} ss ON ss.name = 'bookreview' SET st.weight = (ss.weight+1) WHERE st.name = 'book_review_alter'");

notes:
a. 'bookreview' should be the name of the module we're altering
b. this query hasn't been tested by me :P, done by heart, but should work. The trick here is to join a table on itself. Alternatively you could do 2 queries; read the weight of the original module, then write the new weight of the alter module. I was taught to minimise database access so 1 query is better than 2 :P. Naming: st = system target, ss = system source.
c. Never tried this, but you could create an update function. Don't know how, just rip it from a module that does have update functions in its .install file :P

Remon.