diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 294c7db945785..36159a8e19737 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -1237,7 +1237,10 @@ function render_rating(rating $rating) { global $CFG, $USER; static $havesetupjavascript = false; - if( !$havesetupjavascript && !empty($CFG->enableajax) ) { + $useajax = !empty($CFG->enableajax); + + //include required Javascript + if( !$havesetupjavascript && $useajax ) { $this->page->requires->js_init_call('M.core_ratings.init'); $havesetupjavascript = true; } @@ -1325,8 +1328,6 @@ function render_rating(rating $rating) { //output submit button $strratings .= ''; - //ajax code is included by rating::load_ratings() - if ( is_array($rating->settings->scale) ) { //todo andrew where can we get the course id from? //$strratings .= $this->help_icon_scale($course->id, $scale); diff --git a/rating/index.php b/rating/index.php index 20dae501705de..cacf275ac0904 100644 --- a/rating/index.php +++ b/rating/index.php @@ -66,7 +66,11 @@ echo $OUTPUT->header(); //if (!$ratings = forum_get_ratings($post->id, $sqlsort)) { -$ratings = rating::load_ratings_for_item($context, $itemid, $sort); +$ratingoptions = new stdclass(); +$ratingoptions->context = $context; +$ratingoptions->itemid = $itemid; +$ratingoptions->sort = $sort; +$ratings = rating::load_ratings_for_item($ratingoptions); if (!$ratings) { //print_error('noresult', 'forum', '', format_string($post->subject)); print_error('noresult'); diff --git a/rating/lib.php b/rating/lib.php index 636f45e2f924d..56fa4f0d2fe54 100644 --- a/rating/lib.php +++ b/rating/lib.php @@ -75,16 +75,18 @@ class rating implements renderable { /** * Constructor. - * @param context $context the current context object - * @param int $itemid the id of the associated item (forum post, glossary item etc) - * @param int $scaleid the scale to use - * @param int $userid the user submitting the rating + * @param object $options { + * context => context context to use for the rating [required] + * itemid => int the id of the associated item (forum post, glossary item etc) [required] + * scaleid => int The scale in use when the rating was submitted [required] + * userid => int The id of the user who submitted the rating [required] + * } */ - public function __construct($context, $itemid, $scaleid, $userid) { - $this->context = $context; - $this->itemid = $itemid; - $this->scaleid = $scaleid; - $this->userid = $userid; + public function __construct($options) { + $this->context = $options->context; + $this->itemid = $options->itemid; + $this->scaleid = $options->scaleid; + $this->userid = $options->userid; } /** @@ -102,7 +104,13 @@ public function update_rating($rating) { $item->id = $this->itemid; $items = array($item); - $items = rating::load_ratings($this->context, $items, null, $this->scaleid, $this->userid); + $ratingoptions = new stdclass(); + $ratingoptions->context = $this->context; + $ratingoptions->items = $items; + $ratingoptions->aggregate = RATING_AGGREGATE_AVERAGE;//we dont actually care what aggregation is applied + $ratingoptions->scaleid = $this->scaleid; + $ratingoptions->userid = $this->userid; + $items = rating::load_ratings($ratingoptions); if( !isset($items[0]->rating) || !isset($items[0]->rating->id) ) { $data->contextid = $this->context->id; $data->rating = $rating; @@ -172,13 +180,15 @@ public static function get_aggregation_method($aggregate) { /** * Static method that returns an array of ratings for a given item (forum post, glossary entry etc) - * This returns all users ratings for a single item - * @param context $context the context in which the rating exists - * @param int $itemid The id of the forum posts, glossary items or whatever - * @param string SQL sort by clause + * This returns all users ratings for a single item + * @param object $options { + * context => context the context in which the ratings exists [required] + * itemid => int the id of the associated item (forum post, glossary item etc) [required] + * sort => string SQL sort by clause [optional] + * } * @return array an array of ratings */ - public static function load_ratings_for_item($context, $itemid, $sort) { + public static function load_ratings_for_item($options) { global $DB; $userfields = user_picture::fields('u','uid'); @@ -188,10 +198,10 @@ public static function load_ratings_for_item($context, $itemid, $sort) { LEFT JOIN {user} u ON r.userid = u.id WHERE r.contextid = :contextid AND r.itemid = :itemid - $sort"; + {$options->sort}"; - $params['contextid'] = $context->id; - $params['itemid'] = $itemid; + $params['contextid'] = $options->context->id; + $params['itemid'] = $options->itemid; return $DB->get_records_sql($sql, $params); } @@ -199,30 +209,31 @@ public static function load_ratings_for_item($context, $itemid, $sort) { /** * Static method that adds rating objects to an array of items (forum posts, glossary entries etc) * Rating objects are available at $item->rating - * @param context $context the current context object - * @param array $items an array of items such as forum posts or glossary items. They must have an 'id' member ie $items[0]->id - * @param int $aggregate what aggregation method should be applied. AVG, MAX etc - * @param int $scaleid the scale from which the user can select a rating - * @param int $userid the id of the current user - * @param string $returnurl the url to return the user to after submitting a rating. Can be left null for ajax requests. + * @param object $options { + * context => context the context in which the ratings exists [required] + * items => array an array of items such as forum posts or glossary items. They must have an 'id' member ie $items[0]->id[required] + * aggregate => int what aggregation method should be applied. RATING_AGGREGATE_AVERAGE, RATING_AGGREGATE_MAXIMUM etc [required] + * scaleid => int the scale from which the user can select a rating [required] + * userid => int the id of the current user [optional] + * returnurl => string the url to return the user to after submitting a rating. Can be left null for ajax requests [optional] * @return array the array of items with their ratings attached at $items[0]->rating */ - public static function load_ratings($context, $items, $aggregate=RATING_AGGREGATE_AVERAGE, $scaleid=RATING_DEFAULT_SCALE, $userid = null, $returnurl = null) { + public static function load_ratings($options) { global $DB, $USER, $PAGE, $CFG; - if(empty($items)) { - return $items; + if(empty($options->items)) { + return $options->items; } - if (is_null($userid)) { + if (is_null($options->userid)) { $userid = $USER->id; } - $aggregatestr = rating::get_aggregation_method($aggregate); + $aggregatestr = rating::get_aggregation_method($options->aggregate); //create an array of item ids $itemids = array(); - foreach($items as $item) { + foreach($options->items as $item) { $itemids[] = $item->id; } @@ -244,8 +255,8 @@ public static function load_ratings($context, $items, $aggregate=RATING_AGGREGAT GROUP BY r.itemid, ur.rating ORDER BY r.itemid"; - $params['userid'] = $userid; - $params['contextid'] = $context->id; + $params['userid'] = $options->userid; + $params['contextid'] = $options->context->id; $ratingsrecords = $DB->get_records_sql($sql, $params); @@ -255,8 +266,8 @@ public static function load_ratings($context, $items, $aggregate=RATING_AGGREGAT //we could look for a scale id on each item to allow each item to use a different scale - if($scaleid < 0 ) { //if its a scale (not numeric) - $scalerecord = $DB->get_record('scale', array('id' => -$scaleid)); + if($options->scaleid < 0 ) { //if its a scale (not numeric) + $scalerecord = $DB->get_record('scale', array('id' => -$options->scaleid)); if ($scalerecord) { $scaleobj->scaleitems = explode(',', $scalerecord->scale); $scaleobj->id = $scalerecord->id; @@ -266,33 +277,41 @@ public static function load_ratings($context, $items, $aggregate=RATING_AGGREGAT } } else { //its numeric - $scaleobj->scaleitems = $scaleid; - $scaleobj->id = $scaleid; + $scaleobj->scaleitems = $options->scaleid; + $scaleobj->id = $options->scaleid; $scaleobj->name = null; - $scalemax = $scaleid; + $scalemax = $options->scaleid; } //should $settings and $settings->permissions be declared as proper classes? $settings = new stdclass(); //settings that are common to all ratings objects in this context $settings->scale = $scaleobj; //the scale to use now - $settings->aggregationmethod = $aggregate; - $settings->returnurl = $returnurl; + $settings->aggregationmethod = $options->aggregate; + if( !empty($options->returnurl) ) { + $settings->returnurl = $options->returnurl; + } $settings->permissions = new stdclass(); - $settings->permissions->canview = has_capability('moodle/rating:view',$context); - $settings->permissions->canviewall = has_capability('moodle/rating:viewall',$context); - $settings->permissions->canrate = has_capability('moodle/rating:rate',$context); + $settings->permissions->canview = has_capability('moodle/rating:view',$options->context); + $settings->permissions->canviewall = has_capability('moodle/rating:viewall',$options->context); + $settings->permissions->canrate = has_capability('moodle/rating:rate',$options->context); $rating = null; - foreach($items as $item) { + $ratingoptions = new stdclass(); + $ratingoptions->context = $options->context;//context is common to all ratings in the set + foreach($options->items as $item) { $rating = null; //match the item with its corresponding rating foreach($ratingsrecords as $rec) { if( $item->id==$rec->itemid ) { //Note: rec->scaleid = the id of scale at the time the rating was submitted //may be different from the current scale id - $rating = new rating($context, $item->id, $rec->scaleid, $rec->userid); + $ratingoptions->itemid = $item->id; + $ratingoptions->scaleid = $rec->scaleid; + $ratingoptions->userid = $rec->userid; + + $rating = new rating($ratingoptions); $rating->id = $rec->id; //unset($rec->id); $rating->aggregate = $rec->aggrrating; //unset($rec->aggrrating); $rating->count = $rec->numratings; //unset($rec->numratings); @@ -302,8 +321,11 @@ public static function load_ratings($context, $items, $aggregate=RATING_AGGREGAT } //if there are no ratings for this item if( !$rating ) { - $scaleid = $userid = null; - $rating = new rating($context, $item->id, $scaleid, $userid); + $ratingoptions->itemid = $item->id; + $ratingoptions->scaleid = null; + $ratingoptions->userid = null; + + $rating = new rating($ratingoptions); $rating->id = null; $rating->aggregate = null; $rating->count = 0; @@ -325,6 +347,6 @@ public static function load_ratings($context, $items, $aggregate=RATING_AGGREGAT $rating->rating = $scalemax; } } - return $items; + return $options->items; } } //end rating class definition \ No newline at end of file diff --git a/rating/module.js b/rating/module.js index e627358ee91e0..af7b4a861c206 100644 --- a/rating/module.js +++ b/rating/module.js @@ -28,7 +28,7 @@ M.core_ratings={ } this.Y.io.queue.stop(); - this.transaction.push({transaction:this.Y.io.queue(M.cfg.wwwroot+'/rating/rate.php', { + this.transaction.push({transaction:this.Y.io.queue(M.cfg.wwwroot+'/rating/rate_ajax.php', { method : 'POST', data : build_querystring(thedata), on : { diff --git a/rating/rate.php b/rating/rate.php index ba2e1be7f1be2..2fbcca3eabd93 100644 --- a/rating/rate.php +++ b/rating/rate.php @@ -16,12 +16,9 @@ // along with Moodle. If not, see . /** - * This page receives rating submissions + * This page receives non-ajax rating submissions * - * This page can be the target for either ajax or non-ajax rating submissions. - * If a return url is supplied the request is presumed to be a non-ajax request so a page - * is returned. - * If there is no return url the request is presumed to be ajax so a json response is returned. + * It is similar to rate_ajax.php. Unlike rate_ajax.php a return url is required. * * @package moodlecore * @copyright 2010 Andrew Davis @@ -35,29 +32,17 @@ $itemid = required_param('itemid', PARAM_INT); $scaleid = required_param('scaleid', PARAM_INT); $userrating = required_param('rating', PARAM_INT); -$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);//will only be supplied for non-ajax requests +$returnurl = required_param('returnurl', null, PARAM_LOCALURL);//required for non-ajax requests $result = new stdClass; -if( !isloggedin() && !$returnurl ){ //session has expired and its an ajax request - $result->error = get_string('sessionerroruser', 'error'); - echo json_encode($result); - die(); -} - list($context, $course, $cm) = get_context_info_array($contextid); require_login($course, false, $cm); if( !has_capability('moodle/rating:rate',$context) ) { - if( $returnurl ) { //if its a non-ajax request - echo $OUTPUT->header(); - echo get_string('ratepermissiondenied', 'ratings'); - echo $OUTPUT->footer(); - } - else { - $result->error = get_string('ratepermissiondenied', 'ratings'); - echo json_encode($result); - } + echo $OUTPUT->header(); + echo get_string('ratepermissiondenied', 'ratings'); + echo $OUTPUT->footer(); die(); } @@ -71,24 +56,14 @@ //todo how can we validate the forum post,glossary entry or whatever id? //how do we know where to look for the item? how we we work from module to forum_posts, glossary_entries etc? -//if ($rating_context->contextlevel == CONTEXT_COURSE) { -// $courseid = $rating_context->instanceid; -// $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST); -//if ($rating_context->contextlevel == CONTEXT_MODULE) { -// $cm = get_coursemodule_from_id(false, $rating_context->instanceid, 0, false, MUST_EXIST); -// $courseid = $cm->course; -//} -$rating = new Rating($context, $itemid, $scaleid, $userid); +$ratingoptions = new stdclass; +$ratingoptions->context = $context; +$ratingoptions->itemid = $itemid; +$ratingoptions->scaleid = $scaleid; +$ratingoptions->userid = $userid; +$rating = new rating($ratingoptions); + $rating->update_rating($userrating); -//if its a non-ajax request -if($returnurl) { - redirect($CFG->wwwroot.'/'.$returnurl); -} -else { //this is an ajax request - $result = new stdClass; - $result->success = true; - echo json_encode($result); - die(); -} \ No newline at end of file +redirect($CFG->wwwroot.'/'.$returnurl); \ No newline at end of file diff --git a/rating/rate_ajax.php b/rating/rate_ajax.php new file mode 100644 index 0000000000000..5833a18d7d7a3 --- /dev/null +++ b/rating/rate_ajax.php @@ -0,0 +1,76 @@ +. + +/** +* This page receives ajax rating submissions + * + * It is similar to rate.php. Unlike rate.php a return url is NOT required. + * + * @package moodlecore + * @copyright 2010 Andrew Davis + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once('../config.php'); +require_once('lib.php'); + +$contextid = required_param('contextid', PARAM_INT); +$itemid = required_param('itemid', PARAM_INT); +$scaleid = required_param('scaleid', PARAM_INT); +$userrating = required_param('rating', PARAM_INT); + +$result = new stdClass; + +//if session has expired and its an ajax request so we cant do a page redirect +if( !isloggedin() ){ + $result->error = get_string('sessionerroruser', 'error'); + echo json_encode($result); + die(); +} + +list($context, $course, $cm) = get_context_info_array($contextid); +require_login($course, false, $cm); + +if( !has_capability('moodle/rating:rate',$context) ) { + $result->error = get_string('ratepermissiondenied', 'ratings'); + echo json_encode($result); + die(); +} + +//todo andrew deny access to guest user. Petr to define "guest" + +$userid = $USER->id; + +$PAGE->set_url('/lib/rate.php', array( + 'contextid'=>$contextid + )); + +//todo how can we validate the forum post,glossary entry or whatever id? +//how do we know where to look for the item? how we we work from module to forum_posts, glossary_entries etc? + +$ratingoptions = new stdclass; +$ratingoptions->context = $context; +$ratingoptions->itemid = $itemid; +$ratingoptions->scaleid = $scaleid; +$ratingoptions->userid = $userid; +$rating = new rating($ratingoptions); + +$rating->update_rating($userrating); + +$result = new stdClass; +$result->success = true; +echo json_encode($result); \ No newline at end of file