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