ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
342
343 $data = [
344 "pcomment" => serialize($a_values),
345 "peer_id" => $a_peer_id,
346 "giver_id" => $ilUser->getId()
347 ];
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 {
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 {
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}
user()
Definition: user.php:4
An exception for terminatinating execution or to throw for unit testing.
Exercise assignment.
getId()
Get assignment id.
Exercise peer review.
countGivenFeedback($a_validate=true, $a_user_id=null)
hasPeerReviewAccess($a_peer_id)
getAllPeerReviews($a_only_valid=true)
isFeedbackValidForPassed($a_user_id)
updatePeerReview($a_peer_id, array $a_values)
getPeerReviewsByGiver($a_user_id)
__construct(ilExAssignment $a_assignment)
getPeerReviewsByPeerId($a_user_id, $a_only_valid=false)
static lookupGiversWithPendingFeedback($a_ass_id)
validatePeerReview(array $a_data)
updatePeerReviewTimestamp($a_peer_id)
getPeerMaskedId($a_giver_id, $a_peer_id)
getPeerReviewValues($a_giver_id, $a_peer_id)
static _getMembers($a_obj_id)
static getLogger($a_component_id)
Get component logger.
static now()
Return current timestamp in Y-m-d H:i:s format.
$valid
foreach($_POST as $key=> $value) $res
global $ilDB
$data
Definition: storeScorm.php:23
$ilUser
Definition: imgupload.php:18
$DIC
Definition: xapitoken.php:46