Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Ratings 2.0: Difference between revisions

From MoodleDocs
Line 186: Line 186:
== Moodle modules callback ==
== Moodle modules callback ==


Do we really need to do this stuff?
 
:''Is there a better way to check the user's permission to add ratings? Checking and filtering ratings seems somewhat pointless.:''--[[User:Andrew Davis|Andrew Davis]] 03:10, 01 February 2010 (UTC)


Ratings API allows modules/blocks/blog controlling ratings
Ratings API allows modules/blocks/blog controlling ratings

Revision as of 03:11, 1 February 2010

Objectives

The goals of ratings 2.0:

  • Manage ratings centrally
  • Use a consistent approach for all ratings throughout Moodle
  • Easily integrate ratings 2.0 with existing modules
  • Remove duplicate implementations of ratings functionality

Andrew, did you see I had dumped some unsolicited comments on the talk page?--Tim Hunt 11:13, 21 January 2010 (UTC)

Overview

The ratings 2.0 provides APIs to:

  1. Add ratings
  2. Update ratings
  3. Access collected ratings for grade calculation purposes

Ratings database table

Field Type Default Info
id int(10) auto-incrementing The unique ID for this comment.
contextid int(10) The context id defined in context table - identifies the instance of plugin owning the comment.
itemid int(10) Some plugin specific item id (eg. forum post blog entry)
scaleid int(10) ID of the scale (1-5, 0-100, custom) from which the user selected their rating. Including this allows smarter handling of scales being changed.
rating int(10) for example, in user profile, you can comment user's description or interests, but they share the same itemid(==userid), we need comment_area to separate them
userid int(10) who wrote this comment
timecreated int(10)
timemodified int(10)

Removed database tables

The following tables will be have their data migrated to the above ratings table and then be removed:

data_ratings

forum_ratings

glossary_ratings

Unaltered database relationships

Course modules will continue to store the scale associated with their ratings. For example the glossary table has a scale column. Numbers greater than zero indicate a numerical rating should be used with the scale value being the maximum value. Numbers below zero are the primary key of a row in the scale table (-2 = a primary key of 2). The behaviour of a scale with the value 0 is currently unknown.

When a rating is made the scale id will be included in the new row in the rating table. This will allow for intelligent handling of entered ratings should the scale be changed after some ratings have been entered.

Ratings API

lib/ratinglib.php will contain...

class Rating

__construct($contextid, $itemid, $scaleid, $userid)

Initialize a class instance.

add($userid, $rating)

Add rating to database

delete($userid)

delete the rating for the supplied user

get($userid)

get the rating for the supplied user

get()

get an array of ratings for the current context and item

render($page = null)

Load the rating renderer and use it to output this rating's UI

Ratings Renderer

Located in mod/ratings/renderer.php the new class core_rating_renderer should extend plugin_renderer_base defined in lib/outputrenderers.php Almost all renderers appear to inherit from plugin_renderer_base rather than core_renderer.

core_rating_renderer methods

rating($rating)

returns rating UI html snippet. Used to include ratings in pages.

Using the rating renderer

I just fixed the above code to match my understanding of how it should work. I also fixed the coding style. Actually more below:--Tim Hunt 12:04, 29 January 2010 (UTC)
That is a vast improvement over what I had. I've made a few alterations to what you suggested.:--Andrew Davis 02:25, 01 February 2010 (UTC)

The process to render ratings is as follows:

// in mod/forum/discuss.php (for example)

$posts = // Some forum/lib.php function call.

//The current scaleid comes from the forum or glossary object and may be changed at any time so supply it each time //Also, a user should only see their own ratings $ratings = rating_system::load_ratings($scaleid, $userid, $contextid, $itemids = null/* Optional array of items ids. If null returns all ratings for the context by the user*/);

//Or, just return all ratings for the given context. Used when you want to aggregate the ratings in some way. $ratings = rating_system::load_ratings($contextid); /* This will probably return a multidimensional array accessed by item id (the forum post or glossary item id) then user id. $ratings[$itemid][$userid]

foreach($ratings[$itemid] as $itemrating) { //do something with the ratings for this item }

  • /

// $posts and $ratings are both indexed by $postid == $itemid. // alternatively, perhaps the ratings are loaded as a field in the $post object // by the forum/lib.php function. So you have $post->rating. Yes, that is probably // a better design. //Andrew: see comments below.

foreach ($posts as $postid => $post) {

   $forumoutput->post($post, $ratings[$postid]);

}


// in mod/forum/renderer.php, in the post(post, $rating) method:

// ... output most of the post ... echo $rating->render($this->page); // ... output the rest.


// and finally in rating/lib.php in the rating class:

public function render($page = null) {

   if (is_null($page) {
       global $PAGE;
       $page = $PAGE;
   }
   $ratingoutput = $page->get_renderer('core', 'rating');
   return $ratingoutput->rating($this);

}


The key points there are:

  1. the details of how the rating is rendered (that is, that you need to get a particular sort of renderer) should be encapsulated, rather than having to be duplicated everywhere that a rating is output. This is the approach I have adopted in my new question engine, where there is even more complication to hide. Try following though the code for outputting a question, starting from http://github.com/timhunt/Moodle-Question-Engine-2/blob/new_qe/mod/quiz/attempt.php#L150.
  2. the rating data for all the ratings needed by a particular page need to be loaded from the database in a single query, that should be hidden behind some convenient API. It has to be a single query for performance reasons. Actually, it would be even better if the ratings could be loaded as part of the same query that loads the forum posts, by left-joining on the ratings table. That requires closer coupling between the forum and rating code, but is worth it for the performance gain.


We can definitely fetch all ratings in a single query. Fetching forum posts and their ratings in one query however seems like binding the two too tight. That would require the forum, glossary and anywhere else we want to use ratings to do the same. $forumpost->rating would be handy but $ratings[$postid] isn't bad and allows us to add ratings to just about anything without making major changes to the thing being rated:--Andrew Davis 02:25, 01 February 2010 (UTC)

Rating Submission

lib/rating.php will be the target for posted ratings.

Javascript API

A Javascript API will not be required initially.

Moodle modules callback

Is there a better way to check the user's permission to add ratings? Checking and filtering ratings seems somewhat pointless.:--Andrew Davis 03:10, 01 February 2010 (UTC)

Ratings API allows modules/blocks/blog controlling ratings

Permission control

Modules can implement a function named modname_rating_permissions to control post and view permission.

Blocks need to overwrite rating_permissions function of block_base.

Blog need to implement blog_rating_permissions function.

This function will return an array: array('post'=>true)

Check new added rating

Modules can implement a function named modname_rating_add.

Blocks need to overwrite rating_add function.

Blog need to implement blog_rating_add function.

Ratings API will pass the rating to this function which allow modules check/modify ratings, or reject this rating.

Filter ratings

Modules can implement a function named modname_rating_display.

Blocks need to overwrite rating_display function.

Blog need to implement blog_rating_display function.

This callback allows modules check ratings when user requests to display rating.

Interface

RatingUI.gif

When Javascript is enabled ajax submission means the button can be removed. In the future it would be possible to automatically interpret a 1 to 5 rating as a star rating style UI element.