Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'MDL-27845_rating_aggregation_21' into MOODLE_21_STABLE

  • Loading branch information...
commit 26e3dce4666c5a415b2ab6ba9f6089068ea3145d 2 parents a4f85cc + b312305
Petr Škoda authored August 15, 2011
59  rating/lib.php
@@ -567,22 +567,25 @@ public function get_ratings($options) {
567 567
         $params['component']    = $options->component;
568 568
         $params['ratingarea'] = $options->ratingarea;
569 569
 
570  
-        $sql = "SELECT r.itemid, r.component, r.ratingarea, r.contextid,
571  
-                       $aggregatestr(r.rating) AS aggrrating, COUNT(r.rating) AS numratings,
572  
-                       ur.id, ur.userid, ur.scaleid, ur.rating AS usersrating
  570
+        $sql = "SELECT r.id, r.itemid, r.userid, r.scaleid, r.rating AS usersrating
  571
+                  FROM {rating} r
  572
+                 WHERE r.userid = :userid AND
  573
+                       r.contextid = :contextid AND
  574
+                       r.itemid {$itemidtest} AND
  575
+                       r.component = :component AND
  576
+                       r.ratingarea = :ratingarea
  577
+              ORDER BY r.itemid";
  578
+        $userratings = $DB->get_records_sql($sql, $params);
  579
+
  580
+        $sql = "SELECT r.itemid, $aggregatestr(r.rating) AS aggrrating, COUNT(r.rating) AS numratings
573 581
                   FROM {rating} r
574  
-             LEFT JOIN {rating} ur ON ur.contextid = r.contextid AND
575  
-                                      ur.itemid = r.itemid AND
576  
-                                      ur.component = r.component AND
577  
-                                      ur.ratingarea = r.ratingarea AND
578  
-                                      ur.userid = :userid
579 582
                  WHERE r.contextid = :contextid AND
580 583
                        r.itemid {$itemidtest} AND
581 584
                        r.component = :component AND
582 585
                        r.ratingarea = :ratingarea
583  
-              GROUP BY r.itemid, r.component, r.ratingarea, r.contextid, ur.id, ur.userid, ur.scaleid
  586
+              GROUP BY r.itemid, r.component, r.ratingarea, r.contextid
584 587
               ORDER BY r.itemid";
585  
-        $ratingsrecords = $DB->get_records_sql($sql, $params);
  588
+        $aggregateratings = $DB->get_records_sql($sql, $params);
586 589
 
587 590
         $ratingoptions = new stdClass;
588 591
         $ratingoptions->context = $options->context;
@@ -590,25 +593,37 @@ public function get_ratings($options) {
590 593
         $ratingoptions->ratingarea = $options->ratingarea;
591 594
         $ratingoptions->settings = $this->generate_rating_settings_object($options);
592 595
         foreach ($options->items as $item) {
593  
-            if (array_key_exists($item->{$itemidcol}, $ratingsrecords)) {
594  
-                // Note: rec->scaleid = the id of scale at the time the rating was submitted
595  
-                // may be different from the current scale id
596  
-                $rec = $ratingsrecords[$item->{$itemidcol}];
  596
+            $founduserrating = false;
  597
+            foreach($userratings as $userrating) {
  598
+                //look for an existing rating from this user of this item
  599
+                if ($item->{$itemidcol} == $userrating->itemid) {
  600
+                    // Note: rec->scaleid = the id of scale at the time the rating was submitted
  601
+                    // may be different from the current scale id
  602
+                    $ratingoptions->scaleid = $userrating->scaleid;
  603
+                    $ratingoptions->userid = $userrating->userid;
  604
+                    $ratingoptions->id = $userrating->id;
  605
+                    $ratingoptions->rating = min($userrating->usersrating, $ratingoptions->settings->scale->max);
  606
+
  607
+                    $founduserrating = true;
  608
+                    break;
  609
+                }
  610
+            }
  611
+            if (!$founduserrating) {
  612
+                $ratingoptions->scaleid = null;
  613
+                $ratingoptions->userid = null;
  614
+                $ratingoptions->id = null;
  615
+                $ratingoptions->rating =  null;
  616
+            }
  617
+
  618
+            if (array_key_exists($item->{$itemidcol}, $aggregateratings)) {
  619
+                $rec = $aggregateratings[$item->{$itemidcol}];
597 620
                 $ratingoptions->itemid = $item->{$itemidcol};
598  
-                $ratingoptions->scaleid = $rec->scaleid;
599  
-                $ratingoptions->userid = $rec->userid;
600  
-                $ratingoptions->id = $rec->id;
601 621
                 $ratingoptions->aggregate = min($rec->aggrrating, $ratingoptions->settings->scale->max);
602 622
                 $ratingoptions->count = $rec->numratings;
603  
-                $ratingoptions->rating = min($rec->usersrating, $ratingoptions->settings->scale->max);
604 623
             } else {
605 624
                 $ratingoptions->itemid = $item->{$itemidcol};
606  
-                $ratingoptions->scaleid = null;
607  
-                $ratingoptions->userid = null;
608  
-                $ratingoptions->id = null;
609 625
                 $ratingoptions->aggregate = null;
610 626
                 $ratingoptions->count = 0;
611  
-                $ratingoptions->rating =  null;
612 627
             }
613 628
 
614 629
             $rating = new rating($ratingoptions);
225  rating/simpletest/testrating.php
... ...
@@ -0,0 +1,225 @@
  1
+<?php
  2
+// This file is part of Moodle - http://moodle.org/
  3
+//
  4
+// Moodle is free software: you can redistribute it and/or modify
  5
+// it under the terms of the GNU General Public License as published by
  6
+// the Free Software Foundation, either version 3 of the License, or
  7
+// (at your option) any later version.
  8
+//
  9
+// Moodle is distributed in the hope that it will be useful,
  10
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+// GNU General Public License for more details.
  13
+//
  14
+// You should have received a copy of the GNU General Public License
  15
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16
+
  17
+/**
  18
+ * Unit tests for rating/lib.php
  19
+ *
  20
+ * @package    moodlecore
  21
+ * @subpackage rating
  22
+ * @copyright  2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  23
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24
+ */
  25
+
  26
+defined('MOODLE_INTERNAL') || die();
  27
+
  28
+// Include all the needed stuff
  29
+require_once($CFG->dirroot . '/rating/lib.php');
  30
+
  31
+/**
  32
+ * Unit test case for all the rating/lib.php requiring DB mockup & manipulation
  33
+ */
  34
+class rating_db_test extends UnitTestCaseUsingDatabase {
  35
+
  36
+    public static $includecoverage = array(
  37
+        'rating/lib.php'
  38
+    );
  39
+
  40
+    protected $testtables = array(
  41
+            'lib' => array(
  42
+                'rating', 'scale'));
  43
+
  44
+    public function setUp() {
  45
+        parent::setUp();
  46
+
  47
+        $this->switch_to_test_db(); // Switch to test DB for all the execution
  48
+
  49
+        foreach ($this->testtables as $dir => $tables) {
  50
+            $this->create_test_tables($tables, $dir); // Create tables
  51
+        }
  52
+    }
  53
+
  54
+    /**
  55
+     * Test the current get_ratings method main sql
  56
+     */
  57
+    function test_get_ratings_sql() {
  58
+
  59
+        // We load 3 items. Each is rated twice. For simplicity itemid == user id of the item owner
  60
+        $ctxid = SYSCONTEXTID;
  61
+        $this->load_test_data('rating',
  62
+                array('contextid', 'component', 'ratingarea', 'itemid', 'scaleid', 'rating', 'userid', 'timecreated', 'timemodified'), array(
  63
+
  64
+                //user 1's items. Average == 2
  65
+                array(    $ctxid , 'mod_forum',       'post',       1 ,       10 ,       1 ,       2 ,            1 ,              1),
  66
+                array(    $ctxid , 'mod_forum',       'post',       1 ,       10 ,       3 ,       3 ,            1 ,              1),
  67
+
  68
+                //user 2's items. Average == 3
  69
+                array(    $ctxid , 'mod_forum',       'post',       2 ,       10 ,       1 ,       1 ,            1 ,              1),
  70
+                array(    $ctxid , 'mod_forum',       'post',       2 ,       10 ,       5 ,       3 ,            1 ,              1),
  71
+
  72
+                //user 3's items. Average == 4
  73
+                array(    $ctxid , 'mod_forum',       'post',       3 ,       10 ,       3 ,       1 ,            1 ,              1),
  74
+                array(    $ctxid , 'mod_forum',       'post',       3 ,       10 ,       5 ,       2 ,            1 ,              1)
  75
+                ));
  76
+
  77
+        // a post (item) by user 1 (rated above by user 2 and 3 with average = 2)
  78
+        $user1posts = array(
  79
+                (object)array('id' => 1, 'userid' => 1, 'message' => 'hello'));
  80
+        // a post (item) by user 2 (rated above by user 1 and 3 with average = 3)
  81
+        $user2posts = array(
  82
+                (object)array('id' => 2, 'userid' => 2, 'message' => 'world'));
  83
+        // a post (item) by user 3 (rated above by user 1 and 2 with average = 4)
  84
+        $user3posts = array(
  85
+                (object)array('id' => 3, 'userid' => 3, 'message' => 'moodle'));
  86
+
  87
+        // Prepare the default options
  88
+        $defaultoptions = array (
  89
+                'context'    => get_context_instance(CONTEXT_SYSTEM),
  90
+                'component'  => 'mod_forum',
  91
+                'ratingarea' => 'post',
  92
+                'scaleid'    => 10,
  93
+                'aggregate'  => RATING_AGGREGATE_AVERAGE);
  94
+
  95
+        $rm = new rating_manager();
  96
+
  97
+        // STEP 1: Retreive ratings using the current user
  98
+
  99
+        // Get results for user 1's item (expected average 1 + 3 / 2 = 2)
  100
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
  101
+        $result = $rm->get_ratings($toptions);
  102
+        $this->assertEqual(count($result), count($user1posts));
  103
+        $this->assertEqual($result[0]->id, $user1posts[0]->id);
  104
+        $this->assertEqual($result[0]->userid, $user1posts[0]->userid);
  105
+        $this->assertEqual($result[0]->message, $user1posts[0]->message);
  106
+        $this->assertEqual($result[0]->rating->count, 2);
  107
+        $this->assertEqual($result[0]->rating->aggregate, 2);
  108
+        // Note that $result[0]->rating->rating is somewhat random
  109
+        // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
  110
+
  111
+        // Get results for items of user 2 (expected average 1 + 5 / 2 = 3)
  112
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
  113
+        $result = $rm->get_ratings($toptions);
  114
+        $this->assertEqual(count($result), count($user2posts));
  115
+        $this->assertEqual($result[0]->id, $user2posts[0]->id);
  116
+        $this->assertEqual($result[0]->userid, $user2posts[0]->userid);
  117
+        $this->assertEqual($result[0]->message, $user2posts[0]->message);
  118
+        $this->assertEqual($result[0]->rating->count, 2);
  119
+        $this->assertEqual($result[0]->rating->aggregate, 3);
  120
+        // Note that $result[0]->rating->rating is somewhat random
  121
+        // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
  122
+
  123
+        // Get results for items of user 3 (expected average 3 + 5 / 2 = 4)
  124
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user3posts));
  125
+        $result = $rm->get_ratings($toptions);
  126
+        $this->assertEqual(count($result), count($user3posts));
  127
+        $this->assertEqual($result[0]->id, $user3posts[0]->id);
  128
+        $this->assertEqual($result[0]->userid, $user3posts[0]->userid);
  129
+        $this->assertEqual($result[0]->message, $user3posts[0]->message);
  130
+        $this->assertEqual($result[0]->rating->count, 2);
  131
+        $this->assertEqual($result[0]->rating->aggregate, 4);
  132
+        // Note that $result[0]->rating->rating is somewhat random
  133
+        // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
  134
+
  135
+        // Get results for items of user 1 & 2 together (expected averages are 2 and 3, as tested above)
  136
+        $posts = array_merge($user1posts, $user2posts);
  137
+        $toptions = (object)array_merge($defaultoptions, array('items' => $posts));
  138
+        $result = $rm->get_ratings($toptions);
  139
+        $this->assertEqual(count($result), count($posts));
  140
+        $this->assertEqual($result[0]->id, $posts[0]->id);
  141
+        $this->assertEqual($result[0]->userid, $posts[0]->userid);
  142
+        $this->assertEqual($result[0]->message, $posts[0]->message);
  143
+        $this->assertEqual($result[0]->rating->count, 2);
  144
+        $this->assertEqual($result[0]->rating->aggregate, 2);
  145
+        // Note that $result[0]->rating->rating is somewhat random
  146
+        // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
  147
+
  148
+        $this->assertEqual($result[1]->id, $posts[1]->id);
  149
+        $this->assertEqual($result[1]->userid, $posts[1]->userid);
  150
+        $this->assertEqual($result[1]->message, $posts[1]->message);
  151
+        $this->assertEqual($result[1]->rating->count, 2);
  152
+        $this->assertEqual($result[1]->rating->aggregate, 3);
  153
+        // Note that $result[0]->rating->rating is somewhat random
  154
+        // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
  155
+
  156
+        // STEP 2: Retrieve ratings by a specified user
  157
+        //         We still expect complete aggregations and counts
  158
+
  159
+        // Get results for items of user 1 rated by user 2 (avg 2, rating 1)
  160
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 2));
  161
+        $result = $rm->get_ratings($toptions);
  162
+        $this->assertEqual(count($result), count($user1posts));
  163
+        $this->assertEqual($result[0]->id, $user1posts[0]->id);
  164
+        $this->assertEqual($result[0]->userid, $user1posts[0]->userid);
  165
+        $this->assertEqual($result[0]->message, $user1posts[0]->message);
  166
+        $this->assertEqual($result[0]->rating->count, 2);
  167
+        $this->assertEqual($result[0]->rating->aggregate, 2);
  168
+        $this->assertEqual($result[0]->rating->rating, 1); //user 2 rated user 1 "1"
  169
+        $this->assertEqual($result[0]->rating->userid, $toptions->userid); // Must be the passed userid
  170
+
  171
+        // Get results for items of user 1 rated by user 3
  172
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 3));
  173
+        $result = $rm->get_ratings($toptions);
  174
+        $this->assertEqual(count($result), count($user1posts));
  175
+        $this->assertEqual($result[0]->id, $user1posts[0]->id);
  176
+        $this->assertEqual($result[0]->userid, $user1posts[0]->userid);
  177
+        $this->assertEqual($result[0]->message, $user1posts[0]->message);
  178
+        $this->assertEqual($result[0]->rating->count, 2);
  179
+        $this->assertEqual($result[0]->rating->aggregate, 2);
  180
+        $this->assertEqual($result[0]->rating->rating, 3); //user 3 rated user 1 "3"
  181
+        $this->assertEqual($result[0]->rating->userid, $toptions->userid); // Must be the passed userid
  182
+
  183
+        // Get results for items of user 1 & 2 together rated by user 3
  184
+        $posts = array_merge($user1posts, $user2posts);
  185
+        $toptions = (object)array_merge($defaultoptions, array('items' => $posts, 'userid' => 3));
  186
+        $result = $rm->get_ratings($toptions);
  187
+        $this->assertEqual(count($result), count($posts));
  188
+        $this->assertEqual($result[0]->id, $posts[0]->id);
  189
+        $this->assertEqual($result[0]->userid, $posts[0]->userid);
  190
+        $this->assertEqual($result[0]->message, $posts[0]->message);
  191
+        $this->assertEqual($result[0]->rating->count, 2);
  192
+        $this->assertEqual($result[0]->rating->aggregate, 2);
  193
+        $this->assertEqual($result[0]->rating->rating, 3); //user 3 rated user 1 "3"
  194
+        $this->assertEqual($result[0]->rating->userid, $toptions->userid); // Must be the passed userid
  195
+
  196
+        $this->assertEqual($result[1]->id, $posts[1]->id);
  197
+        $this->assertEqual($result[1]->userid, $posts[1]->userid);
  198
+        $this->assertEqual($result[1]->message, $posts[1]->message);
  199
+        $this->assertEqual($result[1]->rating->count, 2);
  200
+        $this->assertEqual($result[1]->rating->aggregate, 3);
  201
+        $this->assertEqual($result[0]->rating->rating, 3); //user 3 rated user 2 "5"
  202
+        $this->assertEqual($result[1]->rating->userid, $toptions->userid); // Must be the passed userid
  203
+
  204
+        // STEP 3: Some special cases
  205
+
  206
+        // Get results for user 1's items (expected average 1 + 3 / 2 = 2)
  207
+        // supplying a non-existent user id so no rating from that user should be found
  208
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
  209
+        $toptions->userid = 123456; //non-existent user
  210
+        $result = $rm->get_ratings($toptions);
  211
+        $this->assertNull($result[0]->rating->userid);
  212
+        $this->assertNull($result[0]->rating->rating);
  213
+        $this->assertEqual($result[0]->rating->aggregate, 2);//should still get the aggregate
  214
+
  215
+        // Get results for items of user 2 (expected average 1 + 5 / 2 = 3)
  216
+        // Supplying the user id of the user who owns the items so no rating should be found
  217
+        $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
  218
+        $toptions->userid = 2; //user 2 viewing the ratings of their own item
  219
+        $result = $rm->get_ratings($toptions);
  220
+        //these should be null as the user is viewing their own item and thus cannot rate
  221
+        $this->assertNull($result[0]->rating->userid);
  222
+        $this->assertNull($result[0]->rating->rating);
  223
+        $this->assertEqual($result[0]->rating->aggregate, 3);//should still get the aggregate
  224
+    }
  225
+}

0 notes on commit 26e3dce

Please sign in to comment.
Something went wrong with that request. Please try again.