ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilExerciseManagementCollectFilesJob.php
Go to the documentation of this file.
1 <?php
8 
9 /* Copyright (c) 1998-2018 ILIAS open source, Extended GPL, see docs/LICENSE */
10 
18 {
22  private $logger = null;
26  protected $target_directory;
28  protected $assignment;
29  protected $user_id;
30  protected $exercise_id;
31  protected $exercise_ref_id;
32  protected $temp_dir;
33  protected $lng;
34  protected $sanitized_title; //sanitized file name/sheet title
35  protected $excel; //ilExcel
36  protected $criteria_items; //array
37  protected $title_columns;
38  protected $ass_types_with_files; //TODO will be deprecated when use the new assignment type interface
39  protected $participant_id;
40 
41  const FBK_DIRECTORY = "Feedback_files";
42  const LINK_COLOR = "0,0,255";
43  const BG_COLOR = "255,255,255";
44  //Column number incremented in ilExcel
51 
55  public function __construct()
56  {
57  global $DIC;
58  $this->lng = $DIC->language();
59  $this->lng->loadLanguageModule('exc');
60  //TODO will be deprecated when use the new assignment type interface
61  $this->ass_types_with_files = array(
66  );
67  $this->logger = $DIC->logger()->exc();
68  }
69 
73  public function getInputTypes()
74  {
75  return
76  [
77  new SingleType(IntegerValue::class),
78  new SingleType(IntegerValue::class),
79  new SingleType(IntegerValue::class),
80  new SingleType(IntegerValue::class),
81  new SingleType(IntegerValue::class)
82  ];
83  }
84 
88  public function getOutputType()
89  {
90  return new SingleType(StringValue::class);
91  }
92 
93  public function isStateless()
94  {
95  return true;
96  }
97 
104  public function run(array $input, Observer $observer)
105  {
106  $this->exercise_id = $input[0]->getValue();
107  $this->exercise_ref_id = $input[1]->getValue();
108  $assignment_id = $input[2]->getValue();
109  $participant_id = $input[3]->getValue();
110  $this->user_id = $input[4]->getValue();
111 
112  //if we have assignment
113  if ($assignment_id > 0) {
114  $this->collectAssignmentData($assignment_id);
115  $final_directory = $this->target_directory;
116  }
117 
118  if ($participant_id > 0) {
119  $this->participant_id = $participant_id;
120  $assignments = ilExAssignment::getInstancesByExercise($this->exercise_id);
121  foreach ($assignments as $assignment) {
122  $this->collectAssignmentData($assignment->getId());
123  }
124  $final_directory = $this->temp_dir . DIRECTORY_SEPARATOR . ilExSubmission::getDirectoryNameFromUserData($participant_id);
125  }
126 
127  $out = new StringValue();
128  $out->setValue($final_directory);
129  return $out;
130  }
131 
138  public function copyFileToSubDirectory($a_directory, $a_file)
139  {
140  $dir = $this->target_directory . "/" . $a_directory;
141 
142  if (!is_dir($dir)) {
144  }
145 
146  copy($a_file, $dir . "/" . basename($a_file));
147 
148  /*global $DIC;
149  $fs = $DIC->filesystem();
150 
151  $fs->storage()->copy($a_file, $this->temp_dir."/".basename($a_file));*/
152  }
153 
158  {
159  return 30;
160  }
161 
165  protected function addColumnTitles()
166  {
167  $col = 0;
168  foreach ($this->title_columns as $title) {
169  $this->excel->setCell(1, $col, $title);
170  $col++;
171  }
172  }
173 
178  protected function createUniqueTempDirectory()
179  {
180  $this->temp_dir = ilUtil::ilTempnam();
181  ilUtil::makeDirParents($this->temp_dir);
182  }
183 
187  protected function createTargetDirectory()
188  {
189  $path = $this->temp_dir . DIRECTORY_SEPARATOR;
190  if ($this->participant_id > 0) {
191  $user_dir = ilExSubmission::getDirectoryNameFromUserData($this->participant_id);
192  $path .= $user_dir . DIRECTORY_SEPARATOR;
193  }
194  $this->target_directory = $path . $this->sanitized_title;
195 
196  ilUtil::makeDirParents($this->target_directory);
197  }
201  protected function createSubmissionsDirectory()
202  {
203  $this->logger->debug("lang key => " . $this->lng->getLangKey());
204  $this->submissions_directory = $this->target_directory . DIRECTORY_SEPARATOR . $this->lng->txt("exc_ass_submission_zip");
205  ilUtil::createDirectory($this->submissions_directory);
206  }
207 
213  public function collectSubmissionFiles()
214  {
215  $members = array();
216 
217  $exercise = new ilObjExercise($this->exercise_id, false);
218 
219  if ($this->participant_id > 0) {
220  $exc_members_id = array($this->participant_id);
221  } else {
222  $exc_members_id = $exercise->members_obj->getMembers();
223  }
224 
225  $filter = new ilExerciseMembersFilter($this->exercise_ref_id, $exc_members_id, $this->user_id);
226  $exc_members_id = $filter->filterParticipantsByAccess();
227 
228  foreach ($exc_members_id as $member_id) {
229  $submission = new ilExSubmission($this->assignment, $member_id);
230  $submission->updateTutorDownloadTime();
231 
232  // get member object (ilObjUser)
233  if (ilObject::_exists($member_id)) {
234  // adding file metadata
235  foreach ($submission->getFiles() as $file) {
236  $members[$file["user_id"]]["files"][$file["returned_id"]] = $file;
237  }
238 
239  $tmp_obj = &ilObjectFactory::getInstanceByObjId($member_id);
240  $members[$member_id]["name"] = $tmp_obj->getFirstname() . " " . $tmp_obj->getLastname();
241  unset($tmp_obj);
242  }
243  }
244 
245  ilExSubmission::downloadAllAssignmentFiles($this->assignment, $members, $this->submissions_directory);
246  }
247 
253  protected function isExcelNeeded($a_ass_type, $a_has_fbk)
254  {
255  if ($a_ass_type == ilExAssignment::TYPE_TEXT) {
256  return true;
257  } elseif ($a_has_fbk && $a_ass_type != ilExAssignment::TYPE_UPLOAD_TEAM) {
258  return true;
259  }
260  return false;
261  }
262 
270  protected function addCriteriaToExcel($feedback_giver, $participant_id, $row, $col)
271  {
272  $submission = new ilExSubmission($this->assignment, $participant_id);
273 
274  //Possible TODO: This getPeerReviewValues doesn't return always the same array structure then the client classes have
275  //to deal with this. Use only one data structure will avoid this extra work.
276  //values can be [19] => "blablablab" or ["text"] => "blablabla"
277  $values = $submission->getPeerReview()->getPeerReviewValues($feedback_giver, $participant_id);
278 
279  foreach ($this->criteria_items as $item) {
280  $col++;
281 
282  //Criteria without catalog doesn't have ID nor TITLE. The criteria instance is given via "type" ilExcCriteria::getInstanceByType
283  $crit_id = $item->getId();
284  $crit_type = $item->getType();
285  $crit_title = $item->getTitle();
286  if ($crit_title == "") {
287  $crit_title = $item->getTranslatedType();
288  }
289 
290  if (!in_array($crit_title, $this->title_columns)) {
291  $this->title_columns[] = $crit_title;
292  }
293  switch ($crit_type) {
294  case 'bool':
295  if ($values[$crit_id] == 1) {
296  $this->excel->setCell($row, $col, $this->lng->txt("yes"));
297  } elseif ($values[$crit_id] == -1) {
298  $this->excel->setCell($row, $col, $this->lng->txt("no"));
299  }
300  break;
301  case 'rating':
302  /*
303  * Get the rating data from the DB in the current less expensive way.
304  * assignment_id -> used in il_rating.obj_id
305  * object type as string -> used in il_rating.obj_type
306  * participant id -> il_rating.sub_obj_id
307  * "peer_" + criteria_id -> il_rating.sub_obj_type (peer or e.g. peer_12)
308  * peer id -> il_rating.user_id
309  */
310  // Possible TODO: refactor ilExAssignment->getPeerReviewCriteriaCatalogueItems somehow to avoid client
311  // classes to deal with ilExCriteria instances with persistence (by id) or instances on the fly (by type)
312  $sub_obj_type = "peer";
313  if ($crit_id) {
314  $sub_obj_type .= "_" . $crit_id;
315  }
317  $this->assignment->getId(),
318  'ass',
320  $sub_obj_type,
321  $feedback_giver
322  );
323  if ($rating_int = round((int) $rating)) {
324  $this->excel->setCell($row, $col, $rating_int);
325  }
326  break;
327  case 'text':
328  //again another check for criteria id (if instantiated via type)
329  if ($crit_id) {
330  $this->excel->setCell($row, $col, $values[$crit_id]);
331  } else {
332  $this->excel->setCell($row, $col, $values['text']);
333  }
334  break;
335  case 'file':
336  if ($crit_id) {
337  $crit_file_obj = ilExcCriteriaFile::getInstanceById($crit_id);
338  } else {
339  $crit_file_obj = ilExcCriteriaFile::getInstanceByType($crit_type);
340  }
341  $crit_file_obj->setPeerReviewContext($this->assignment, $feedback_giver, $participant_id);
342  $files = $crit_file_obj->getFiles();
343 
344  $extra_crit_column = 0;
345  foreach ($files as $file) {
346  if ($extra_crit_column) {
347  $this->title_columns[] = $crit_title . "_" . $extra_crit_column;
348  }
349  $extra_crit_column++;
350  $this->copyFileToSubDirectory(self::FBK_DIRECTORY, $file);
351  $this->excel->setCell($row, $col, "./" . self::FBK_DIRECTORY . DIRECTORY_SEPARATOR . basename($file));
352  $this->excel->addLink($row, $col, './' . self::FBK_DIRECTORY . DIRECTORY_SEPARATOR . basename($file));
353  $this->excel->setColors($this->excel->getCoordByColumnAndRow($col, $row), self::BG_COLOR, self::LINK_COLOR);
354  }
355  break;
356  }
357  }
358  }
359 
367  public function getExtraColumnsForSubmissionFiles($a_obj_id, $a_ass_id)
368  {
369  global $DIC;
370  $ilDB = $DIC->database();
371 
372  $and = "";
373  if ($this->participant_id > 0) {
374  $and = " AND user_id = " . $this->participant_id;
375  }
376 
377  $query = "SELECT MAX(max_num) AS max" .
378  " FROM (SELECT COUNT(user_id) AS max_num FROM exc_returned" .
379  " WHERE obj_id=" . $a_obj_id . ". AND ass_id=" . $a_ass_id . $and . " AND mimetype IS NOT NULL" .
380  " GROUP BY user_id) AS COUNTS";
381 
382  $set = $ilDB->query($query);
383  $row = $ilDB->fetchAssoc($set);
384  return $row['max'];
385  }
386 
394  public function addLink($a_row, $a_col, $a_submission_file)
395  {
396  $user_id = $a_submission_file['user_id'];
398 
399  $filepath = './' . $this->lng->txt("exc_ass_submission_zip") . DIRECTORY_SEPARATOR . $targetdir . DIRECTORY_SEPARATOR;
400  switch ($this->assignment->getType()) {
402  $filepath .= $a_submission_file['filetitle'];
403  break;
404 
406  include_once "Services/PersonalWorkspace/classes/class.ilWorkspaceTree.php";
407  $wsp_tree = new ilWorkspaceTree($user_id);
408  // #12939
409  if (!$wsp_tree->getRootId()) {
410  $wsp_tree->createTreeForUser($user_id);
411  }
412  $node = $wsp_tree->getNodeData((int) $a_submission_file['filetitle']);
413  $filepath .= "blog_" . $node['obj_id'] . DIRECTORY_SEPARATOR . "index.html";
414  break;
415 
417  $filepath .= "prt_" . $a_submission_file['filetitle'] . DIRECTORY_SEPARATOR . "index.html";
418  break;
419 
420  default:
421  $filepath = "";
422  }
423  $this->excel->addLink($a_row, $a_col, $filepath);
424  }
425 
426  protected function collectAssignmentData($assignment_id)
427  {
428  $ass_has_feedback = false;
429  $ass_has_criteria = false;
430 
431  //assignment object
432  $this->assignment = new ilExAssignment($assignment_id);
433  $assignment_type = $this->assignment->getType();
434 
435  //Sanitized title for excel file and target directory.
436  $this->sanitized_title = ilUtil::getASCIIFilename($this->assignment->getTitle());
437 
438  // directories
439  if (!isset($this->temp_dir)) {
440  $this->createUniqueTempDirectory();
441  }
442  $this->createTargetDirectory();
443 
444  //Collect submission files if needed by assignment type.
445  if (in_array($assignment_type, $this->ass_types_with_files)) {
447  $this->collectSubmissionFiles();
448  }
449 
450  if ($this->assignment->getPeerReview()) {
451  $ass_has_feedback = true;
452  //obj to get the reviews in the foreach below.
453  $peer_review = new ilExPeerReview($this->assignment);
454  //default start column for revisions.
455  $first_excel_column_for_review = self::FIRST_DEFAULT_REVIEW_COLUMN;
456  }
457 
463  if ($this->isExcelNeeded($assignment_type, $ass_has_feedback)) {
464  // PhpSpreadsheet object
465  include_once "./Services/Excel/classes/class.ilExcel.php";
466  $this->excel = new ilExcel();
467 
468  //Excel sheet title
469  $this->excel->addSheet($this->sanitized_title);
470 
471  //add common excel Columns
472  #25585
473  $this->title_columns = array(
474  $this->lng->txt('lastname'),
475  $this->lng->txt('firstname'),
476  $this->lng->txt('login'),
477  $this->lng->txt('exc_last_submission')
478  );
479  switch ($assignment_type) {
481  $this->title_columns[] = $this->lng->txt("exc_submission_text");
482  break;
484  $num_columns_submission = $this->getExtraColumnsForSubmissionFiles($this->exercise_id, $assignment_id);
485  if ($num_columns_submission > 1) {
486  for ($i = 1; $i <= $num_columns_submission; $i++) {
487  $this->title_columns[] = $this->lng->txt("exc_submission_file") . " " . $i;
488  }
489  } else {
490  $this->title_columns[] = $this->lng->txt("exc_submission_file");
491  }
492 
493  $first_excel_column_for_review += $num_columns_submission - 1;
494  break;
495  default:
496  $this->title_columns[] = $this->lng->txt("exc_submission");
497  break;
498  }
499  if ($ass_has_feedback) {
500  $this->title_columns[] = $this->lng->txt("exc_peer_review_giver");
501  $this->title_columns[] = $this->lng->txt('exc_last_submission');
502  }
503 
504  //criteria
505  //Notice:getPeerReviewCriteriaCatalogueItems can return just an empty instance without data.
506  if ($this->criteria_items = $this->assignment->getPeerReviewCriteriaCatalogueItems()) {
507  $ass_has_criteria = true;
508  }
509 
510  if ($this->participant_id > 0) {
511  $participants = array($this->participant_id);
512  } else {
513  $participants = $this->getAssignmentMembersIds();
514  }
515 
516  $filter = new ilExerciseMembersFilter($this->exercise_ref_id, $participants, $this->user_id);
517  $participants = $filter->filterParticipantsByAccess();
518 
519  //SET THE ROW AT SECOND POSITION TO START ENTERING VALUES BELOW THE TITLE.
520  $row = 2;
521  // Fill the excel
522  foreach ($participants as $participant_id) {
523  $submission = new ilExSubmission($this->assignment, $participant_id);
524  $submission_files = $submission->getFiles();
525 
526  if ($submission_files) {
527  $participant_name = ilObjUser::_lookupName($participant_id);
528  $this->excel->setCell($row, self::PARTICIPANT_LASTNAME_COLUMN, $participant_name['lastname']);
529  $this->excel->setCell($row, self::PARTICIPANT_FIRSTNAME_COLUMN, $participant_name['firstname']);
530  $this->excel->setCell($row, self::PARTICIPANT_LOGIN_COLUMN, $participant_name['login']);
531 
532  //Get the submission Text
533  if (!in_array($assignment_type, $this->ass_types_with_files)) {
534  foreach ($submission_files as $submission_file) {
535  $this->excel->setCell($row, self::SUBMISSION_DATE_COLUMN, $submission_file['timestamp']);
536  $this->excel->setCell($row, self::FIRST_DEFAULT_SUBMIT_COLUMN, $submission_file['atext']);
537  }
538  } else {
539  $col = self::FIRST_DEFAULT_SUBMIT_COLUMN;
540  foreach ($submission_files as $submission_file) {
541  $this->excel->setCell($row, self::SUBMISSION_DATE_COLUMN, $submission_file['timestamp']);
542 
543  if ($assignment_type == ilExAssignment::TYPE_PORTFOLIO || $assignment_type == ilExAssignment::TYPE_BLOG) {
544  $this->excel->setCell($row, $col, $this->lng->txt("open"));
545  } else {
546  $this->excel->setCell($row, $col, $submission_file['filetitle']);
547  }
548  $this->excel->setColors($this->excel->getCoordByColumnAndRow($col + 1, $row), self::BG_COLOR, self::LINK_COLOR);
549  $this->addLink($row, $col, $submission_file);
550  $col++; //does not affect blogs and portfolios.
551  }
552  }
553 
554  if ($ass_has_feedback) {
555  if ($col < $first_excel_column_for_review) {
556  $col = $first_excel_column_for_review;
557  }
558  $reviews = $peer_review->getPeerReviewsByPeerId($participant_id);
559 
560  //extra lines
561  $current_review_row = 0;
562  foreach ($reviews as $review) {
563  //not all reviews are done, we check it via date of review.
564  if ($review['tstamp']) {
565  $current_review_row++;
566  if ($current_review_row > 1) {
567  for ($i = 0; $i < $first_excel_column_for_review; $i++) {
568  $cell_to_copy = $this->excel->getCell($row, $i);
569  // $i-1 because ilExcel setCell increments the column by 1
570  $this->excel->setCell($row + 1, $i - 1, $cell_to_copy);
571  if ($i > self::FIRST_DEFAULT_SUBMIT_COLUMN) {
572  $this->excel->setColors($this->excel->getCoordByColumnAndRow($i, $row + 1), self::BG_COLOR, self::LINK_COLOR);
573  }
574  }
575  ++$row;
576  }
577 
578  $feedback_giver = $review['giver_id']; // user who made the review.
579 
580  $feedback_giver_name = ilObjUser::_lookupName($feedback_giver);
581 
582  $this->excel->setCell(
583  $row,
584  $col,
585  $feedback_giver_name['lastname'] . ", " . $feedback_giver_name['firstname'] . " [" . $feedback_giver_name['login'] . "]"
586  );
587 
588  $this->excel->setCell($row, $col + 1, $review['tstamp']);
589 
590  if ($ass_has_criteria) {
591  $this->addCriteriaToExcel($feedback_giver, $participant_id, $row, $col + 1);
592  }
593  }
594  }
595  }
596 
597  $row++;
598  }
599  }
600 
601  $this->addColumnTitles();
602  $this->excel->writeToFile($this->target_directory . "/" . $this->sanitized_title);
603  }
604  }
605 
606  // get ONLY the members ids for this assignment
607  public function getAssignmentMembersIds()
608  {
609  global $DIC;
610 
611  $ilDB = $DIC->database();
612  $members = array();
613 
614  $set = $ilDB->query("SELECT usr_id" .
615  " FROM exc_mem_ass_status" .
616  " WHERE ass_id = " . $ilDB->quote($this->assignment->getId(), "integer"));
617 
618  while ($rec = $ilDB->fetchAssoc($set)) {
619  $members[] = $rec['usr_id'];
620  }
621 
622  return $members;
623  }
624 }
static getInstanceByType($a_type)
static _lookupName($a_user_id)
lookup user name
static makeDirParents($a_dir)
Create a new directory and all parent directories.
$path
Definition: aliased.php:25
Exercise assignment.
$files
Definition: metarefresh.php:49
global $DIC
Definition: saml.php:7
static _exists($a_id, $a_reference=false, $a_type=null)
checks if an object exists in object_data
static getInstanceById($a_id)
static downloadAllAssignmentFiles(ilExAssignment $a_ass, array $members, $to_path)
Download all submitted files of an assignment (all user)
copyFileToSubDirectory($a_directory, $a_file)
Copy a file in the Feedback_files directory TODO use the new filesystem.
Class ilExerciseMembersFilter.
createSubmissionsDirectory()
Create the directory with the assignment title.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static getDirectoryNameFromUserData($a_user_id)
Tree handler for personal workspace.
createTargetDirectory()
Create the directory with the assignment title.
static getRatingForUserAndObject( $a_obj_id, $a_obj_type, $a_sub_obj_id, $a_sub_obj_type, $a_user_id, $a_category_id=null)
Get rating for a user and an object.
Exercise peer review.
Class ilObjExercise.
addLink($a_row, $a_col, $a_submission_file)
Mapping the links to use them on the excel.
$values
static getInstancesByExercise($a_exc_id)
run(array $input, Observer $observer)
run the job
static createDirectory($a_dir, $a_mod=0755)
create directory
$query
static getInstanceByObjId($a_obj_id, $stop_on_error=true)
get an instance of an Ilias object by object id
getExpectedTimeOfTaskInSeconds()
int the amount of seconds this task usually taskes. If your task-duration scales with the the amount ...
$row
collectSubmissionFiles()
Store the zip file which contains all submission files in the target directory.
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
global $ilDB
$i
Definition: disco.tpl.php:19
Exercise submission //TODO: This class has to much static methods related to delivered "files"...
getExtraColumnsForSubmissionFiles($a_obj_id, $a_ass_id)
Get the number of max amount of files submitted by a single user in the assignment.
addCriteriaToExcel($feedback_giver, $participant_id, $row, $col)
Add criteria data to the excel.