ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilExPeerReview.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
11 {
15  protected $db;
16 
20  protected $user;
21 
22  protected $assignment; // [$a_assignment]
23  protected $assignment_id; // [int]
24 
25  public function __construct(ilExAssignment $a_assignment)
26  {
27  global $DIC;
28 
29  $this->db = $DIC->database();
30  $this->user = $DIC->user();
31  $this->assignment = $a_assignment;
32  $this->assignment_id = $a_assignment->getId();
33  }
34 
35  public function hasPeerReviewGroups()
36  {
37  $ilDB = $this->db;
38 
39  $set = $ilDB->query("SELECT count(*) cnt" .
40  " FROM exc_assignment_peer" .
41  " WHERE ass_id = " . $ilDB->quote($this->assignment_id, "integer"));
42  $cnt = $ilDB->fetchAssoc($set);
43  return (bool) $cnt["cnt"];
44  }
45 
46  protected function getValidPeerReviewUsers()
47  {
48  $ilDB = $this->db;
49 
50  $user_ids = array();
51 
52  // returned / assigned ?!
53  $set = $ilDB->query("SELECT DISTINCT(user_id)" .
54  " FROM exc_returned" .
55  " WHERE ass_id = " . $ilDB->quote($this->assignment_id, "integer") .
56  " AND (filename IS NOT NULL OR atext IS NOT NULL)");
57  while ($row = $ilDB->fetchAssoc($set)) {
58  $user_ids[] = $row["user_id"];
59  }
60 
61  return $user_ids;
62  }
63 
64  protected function initPeerReviews()
65  {
66  $ilDB = $this->db;
67 
68  // see #22246
69  if (!$this->assignment->afterDeadlineStrict()) {
70  return false;
71  }
72 
73  if (!$this->hasPeerReviewGroups()) {
74  $user_ids = $this->getValidPeerReviewUsers();
75 
76  // forever alone
77  if (sizeof($user_ids) < 2) {
78  return false;
79  }
80 
81  $rater_ids = $user_ids;
82  $matrix = array();
83 
84  $max = min(sizeof($user_ids)-1, $this->assignment->getPeerReviewMin());
85  for ($loop = 0; $loop < $max; $loop++) {
86  $run_ids = array_combine($user_ids, $user_ids);
87 
88  foreach ($rater_ids as $rater_id) {
89  $possible_peer_ids = $run_ids;
90 
91  // may not rate himself
92  unset($possible_peer_ids[$rater_id]);
93 
94  // already has linked peers
95  if (array_key_exists($rater_id, $matrix)) {
96  $possible_peer_ids = array_diff($possible_peer_ids, $matrix[$rater_id]);
97  }
98 
99  // #15665 / #15883
100  if (!sizeof($possible_peer_ids)) {
101  // no more possible peers left? start over with all valid users
102  $run_ids = array_combine($user_ids, $user_ids);
103 
104  // see above
105  $possible_peer_ids = $run_ids;
106 
107  // may not rate himself
108  unset($possible_peer_ids[$rater_id]);
109 
110  // already has linked peers
111  if (array_key_exists($rater_id, $matrix)) {
112  $possible_peer_ids = array_diff($possible_peer_ids, $matrix[$rater_id]);
113  }
114  }
115 
116  // #14947
117  if (sizeof($possible_peer_ids)) {
118  $peer_id = array_rand($possible_peer_ids);
119  if (!array_key_exists($rater_id, $matrix)) {
120  $matrix[$rater_id] = array();
121  }
122  $matrix[$rater_id][] = $peer_id;
123  }
124 
125  // remove peer_id from possible ids in this run
126  unset($run_ids[$peer_id]);
127  }
128  }
129 
130  foreach ($matrix as $rater_id => $peer_ids) {
131  foreach ($peer_ids as $peer_id) {
132  $ilDB->manipulate("INSERT INTO exc_assignment_peer" .
133  " (ass_id, giver_id, peer_id)" .
134  " VALUES (" . $ilDB->quote($this->assignment_id, "integer") .
135  ", " . $ilDB->quote($rater_id, "integer") .
136  ", " . $ilDB->quote($peer_id, "integer") . ")");
137  }
138  }
139  }
140  return true;
141  }
142 
143  public function resetPeerReviews()
144  {
145  $ilDB = $this->db;
146 
147  $all = array();
148 
149  if ($this->hasPeerReviewGroups()) {
150  foreach ($this->getAllPeerReviews(false) as $peer_id => $reviews) {
151  foreach (array_keys($reviews) as $giver_id) {
152  $all[] = $giver_id;
153 
154  foreach ($this->assignment->getPeerReviewCriteriaCatalogueItems() as $crit) {
155  $crit->setPeerReviewContext($this->assignment, $giver_id, $peer_id);
156  $crit->resetReview();
157  }
158  }
159  }
160 
161  // peer groups
162  $ilDB->manipulate("DELETE FROM exc_assignment_peer" .
163  " WHERE ass_id = " . $ilDB->quote($this->assignment_id, "integer"));
164  }
165 
166  return $all;
167  }
168 
169  public function validatePeerReviewGroups()
170  {
171  if ($this->hasPeerReviewGroups()) {
172  include_once "./Modules/Exercise/classes/class.ilExerciseMembers.php";
173  $all_exc = ilExerciseMembers::_getMembers($this->assignment->getExerciseId());
174  $all_valid = $this->getValidPeerReviewUsers(); // only returned
175 
176  $peer_ids = $invalid_peer_ids = $invalid_giver_ids = $all_reviews = array();
177  foreach ($this->getAllPeerReviews(false) as $peer_id => $reviews) {
178  $peer_ids[] = $peer_id;
179 
180  if (!in_array($peer_id, $all_valid) ||
181  !in_array($peer_id, $all_exc)) {
182  $invalid_peer_ids[] = $peer_id;
183  }
184  foreach ($reviews as $giver_id => $valid) {
185  if (!in_array($giver_id, $all_valid) ||
186  !in_array($peer_id, $all_exc)) {
187  $invalid_giver_ids[] = $giver_id;
188  } else {
189  $all_reviews[$peer_id][$giver_id] = $valid;
190  }
191  }
192  }
193  $invalid_giver_ids = array_unique($invalid_giver_ids);
194 
195  $missing_user_ids = array();
196  foreach ($all_valid as $user_id) {
197  // a missing peer is also a missing giver
198  if (!in_array($user_id, $peer_ids)) {
199  $missing_user_ids[] = $user_id;
200  }
201  }
202 
203  $not_returned_ids = array();
204  foreach ($all_exc as $user_id) {
205  if (!in_array($user_id, $all_valid)) {
206  $not_returned_ids[] = $user_id;
207  }
208  }
209 
210  return array(
211  "invalid" => (sizeof($missing_user_ids) ||
212  sizeof($invalid_peer_ids) ||
213  sizeof($invalid_giver_ids)),
214  "missing_user_ids" => $missing_user_ids,
215  "not_returned_ids" => $not_returned_ids,
216  "invalid_peer_ids" => $invalid_peer_ids,
217  "invalid_giver_ids" => $invalid_giver_ids,
218  "reviews" => $all_reviews);
219  }
220  }
221 
222  public function getPeerReviewValues($a_giver_id, $a_peer_id)
223  {
224  $peer = null;
225  foreach ($this->getPeerReviewsByGiver($a_giver_id) as $item) {
226  if ($item["peer_id"] == $a_peer_id) {
227  $peer = $item;
228  }
229  }
230  if (!$peer) {
231  return;
232  }
233  $data = $peer["pcomment"];
234  if ($data) {
235  $items = @unserialize($data);
236  if (!is_array($items)) {
237  // v1 - pcomment == text
238  $items = array("text"=>$data);
239  }
240  return $items;
241  }
242  }
243 
244  public function getPeerReviewsByGiver($a_user_id)
245  {
246  $ilDB = $this->db;
247 
248  $res = array();
249 
250  if ($this->initPeerReviews()) {
251  $idx = 0;
252  $set = $ilDB->query("SELECT *" .
253  " FROM exc_assignment_peer" .
254  " WHERE giver_id = " . $ilDB->quote($a_user_id, "integer") .
255  " AND ass_id = " . $ilDB->quote($this->assignment_id, "integer") .
256  " ORDER BY peer_id");
257  while ($row = $ilDB->fetchAssoc($set)) {
258  $row["seq"] = ++$idx;
259  $res[] = $row;
260  }
261  }
262 
263  return $res;
264  }
265 
266  public function getPeerMaskedId($a_giver_id, $a_peer_id)
267  {
268  foreach ($this->getPeerReviewsByGiver($a_giver_id) as $idx => $peer) {
269  if ($peer["peer_id"] == $a_peer_id) {
270  return $peer["seq"];
271  }
272  }
273  }
274 
275  protected function validatePeerReview(array $a_data)
276  {
277  $all_empty = true;
278 
279  // see getPeerReviewValues()
280  $values = null;
281  $data = $a_data["pcomment"];
282  if ($data) {
283  $values = @unserialize($data);
284  if (!is_array($values)) {
285  // v1 - pcomment == text
286  $values = array("text"=>$data);
287  }
288  }
289 
290  /* #18491 - values can be empty, text is optional (rating/file values are handled internally in criteria)
291  if(!$values)
292  {
293  return false;
294  }
295  */
296 
297  foreach ($this->assignment->getPeerReviewCriteriaCatalogueItems() as $crit) {
298  $crit_id = $crit->getId()
299  ? $crit->getId()
300  : $crit->getType();
301  $crit->setPeerReviewContext(
302  $this->assignment,
303  $a_data["giver_id"],
304  $a_data["peer_id"]
305  );
306  if (!$crit->validate($values[$crit_id])) {
307  return false;
308  }
309  if ($crit->hasValue($values[$crit_id])) {
310  $all_empty = false;
311  }
312  }
313 
314  return !$all_empty;
315  }
316 
317  public function getPeerReviewsByPeerId($a_user_id, $a_only_valid = false)
318  {
319  $ilDB = $this->db;
320 
321  $res = array();
322 
323  $idx = 0;
324  $set = $ilDB->query("SELECT *" .
325  " FROM exc_assignment_peer" .
326  " WHERE peer_id = " . $ilDB->quote($a_user_id, "integer") .
327  " AND ass_id = " . $ilDB->quote($this->assignment_id, "integer") .
328  " ORDER BY peer_id");
329  while ($row = $ilDB->fetchAssoc($set)) {
330  if (!$a_only_valid ||
331  $this->validatePeerReview($row)) {
332  // this would be correct but rather senseless
333  // $row["seq"] = $this->getPeerMaskedId($row["giver_id"], $a_user_id);
334  $row["seq"] = ++$idx;
335  $res[] = $row;
336  }
337  }
338 
339  return $res;
340  }
341 
342  public function getAllPeerReviews($a_only_valid = true)
343  {
344  $ilDB = $this->db;
345 
346  $res = array();
347 
348  $set = $ilDB->query("SELECT *" .
349  " FROM exc_assignment_peer" .
350  " WHERE ass_id = " . $ilDB->quote($this->assignment_id, "integer") .
351  " ORDER BY peer_id");
352  while ($row = $ilDB->fetchAssoc($set)) {
353  $valid = $this->validatePeerReview($row);
354  if (!$a_only_valid ||
355  $valid) {
356  $res[$row["peer_id"]][$row["giver_id"]] = $valid;
357  }
358  }
359 
360  return $res;
361  }
362 
363  public function hasPeerReviewAccess($a_peer_id)
364  {
365  $ilDB = $this->db;
367 
368  $set = $ilDB->query("SELECT ass_id" .
369  " FROM exc_assignment_peer" .
370  " WHERE giver_id = " . $ilDB->quote($ilUser->getId(), "integer") .
371  " AND peer_id = " . $ilDB->quote($a_peer_id, "integer") .
372  " AND ass_id = " . $ilDB->quote($this->assignment_id, "integer"));
373  $row = $ilDB->fetchAssoc($set);
374  return (bool) $row["ass_id"];
375  }
376 
377  public function updatePeerReviewTimestamp($a_peer_id)
378  {
379  $ilDB = $this->db;
381 
382  $ilDB->manipulate("UPDATE exc_assignment_peer" .
383  " SET tstamp = " . $ilDB->quote(ilUtil::now(), "timestamp") .
384  " WHERE giver_id = " . $ilDB->quote($ilUser->getId(), "integer") .
385  " AND peer_id = " . $ilDB->quote($a_peer_id, "integer") .
386  " AND ass_id = " . $ilDB->quote($this->assignment_id, "integer"));
387  }
388 
389  public function updatePeerReview($a_peer_id, array $a_values)
390  {
391  $ilDB = $this->db;
393 
394  $sql = "UPDATE exc_assignment_peer" .
395  " SET tstamp = " . $ilDB->quote(ilUtil::now(), "timestamp") .
396  ",pcomment = " . $ilDB->quote(serialize($a_values), "text") .
397  " WHERE giver_id = " . $ilDB->quote($ilUser->getId(), "integer") .
398  " AND peer_id = " . $ilDB->quote($a_peer_id, "integer") .
399  " AND ass_id = " . $ilDB->quote($this->assignment_id, "integer");
400 
401  $ilDB->manipulate($sql);
402  }
403 
404  public function countGivenFeedback($a_validate = true, $a_user_id = null)
405  {
406  $ilDB = $this->db;
408 
409  if (!$a_user_id) {
410  $a_user_id = $ilUser->getId();
411  }
412 
413  $cnt = 0;
414 
415  include_once './Services/Rating/classes/class.ilRating.php';
416 
417  $set = $ilDB->query("SELECT *" .
418  " FROM exc_assignment_peer" .
419  " WHERE ass_id = " . $ilDB->quote($this->assignment_id, "integer") .
420  " AND giver_id = " . $ilDB->quote($a_user_id, "integer"));
421  while ($row = $ilDB->fetchAssoc($set)) {
422  if (!(bool) $a_validate ||
423  $this->validatePeerReview($row)) {
424  $cnt++;
425  }
426  }
427 
428  return $cnt;
429  }
430 
431  protected function getMaxPossibleFeedbacks()
432  {
433  $ilDB = $this->db;
434 
435  // check if number of returned assignments is lower than assignment peer min
436  $set = $ilDB->query("SELECT COUNT(DISTINCT(user_id)) cnt" .
437  " FROM exc_returned" .
438  " WHERE ass_id = " . $ilDB->quote($this->assignment_id, "integer"));
439  $cnt = $ilDB->fetchAssoc($set);
440  $cnt = (int) $cnt["cnt"];
441  return $cnt-1;
442  }
443 
445  {
446  $max = $this->getMaxPossibleFeedbacks();
447 
448  // #16160 - forever alone
449  if (!$max) {
450  return;
451  }
452 
453  // are all required or just 1?
454  if (!$this->assignment->getPeerReviewSimpleUnlock()) {
455  $needed = $this->assignment->getPeerReviewMin();
456  } else {
457  $needed = 1;
458  }
459 
460  // there could be less participants than stated in the min required setting
461  $min = min($max, $needed);
462 
463  return max(0, $min-$this->countGivenFeedback());
464  }
465 
466  public function isFeedbackValidForPassed($a_user_id)
467  {
468  // peer feedback is not required for passing
469  if ($this->assignment->getPeerReviewValid() == ilExAssignment::PEER_REVIEW_VALID_NONE) {
470  return true;
471  }
472 
473  // #16227 - no processing before reaching the peer review period
474  if (!$this->assignment->afterDeadlineStrict()) {
475  return false;
476  }
477 
478  // forever alone - should be valid
479  $max = $this->getMaxPossibleFeedbacks();
480  if (!$max) {
481  return true;
482  }
483 
484  $no_of_feedbacks = $this->countGivenFeedback(true, $a_user_id);
485 
486  switch ($this->assignment->getPeerReviewValid()) {
488  return (bool) $no_of_feedbacks;
489 
491  // there could be less participants than stated in the min required setting
492  $min = min($max, $this->assignment->getPeerReviewMin());
493 
494  return (($min-$no_of_feedbacks) < 1);
495  }
496  }
497 }
Exercise assignment.
global $DIC
Definition: saml.php:7
updatePeerReview($a_peer_id, array $a_values)
getId()
Get assignment id.
countGivenFeedback($a_validate=true, $a_user_id=null)
$valid
isFeedbackValidForPassed($a_user_id)
static now()
Return current timestamp in Y-m-d H:i:s format.
user()
Definition: user.php:4
hasPeerReviewAccess($a_peer_id)
getPeerMaskedId($a_giver_id, $a_peer_id)
getAllPeerReviews($a_only_valid=true)
Exercise peer review.
updatePeerReviewTimestamp($a_peer_id)
foreach($_POST as $key=> $value) $res
validatePeerReview(array $a_data)
$ilUser
Definition: imgupload.php:18
getPeerReviewsByGiver($a_user_id)
Create styles array
The data for the language used.
global $ilDB
getPeerReviewsByPeerId($a_user_id, $a_only_valid=false)
getPeerReviewValues($a_giver_id, $a_peer_id)
static _getMembers($a_obj_id)
__construct(ilExAssignment $a_assignment)