course_code = $course_code; $this->semester = $semester; $this->students = array(); $this->errors = array(); $this->errors = array(); $dir = $this->get_course_results_directory_path(); // ---------- // For every file name in the corresponding directory, // matching the student result file name syntax, and read the // data. // ---------- foreach ( glob($dir . "?.students.????-??.xml" ) as $file_name) { // ---------- // Split file name and extract some info so we know where // to store the data in an organized manner. // ---------- $split_file_name = explode(".", $file_name); $tmp = explode("/", $split_file_name[0]); $first_char = end($tmp); $first_reg = $split_file_name[2]; // ---------- // Ensure that we have somewhere to store the data from // each file. // ---------- if ( ! isset($this->students[$first_reg]) ) { $this->students[$first_reg] = array(); } if ( ! isset($this->students[$first_reg][$first_char]) ) { $this->students[$first_reg][$first_char] = array(); } // Get an xml handler for this file, and extract the array // of students from it. $handler = xml_handler::get_xml_handler_for_file($file_name); $students_data = $handler->get_node_array('/students/student'); // ---------- // For each student in the above array, extract the data // and send it to the student result class for extraction. // ---------- if ( isset($students_data) and ( ! empty($students_data) ) ) { foreach ( $students_data as $student_res ) { $this->students[$first_reg][$first_char][] = new Student_Result($student_res); } } } } // ---------------------------------------- // get_course_code // // Returns the course_code. // ---------------------------------------- public function get_course_code() { return $this->course_code; } // ---------------------------------------- // get_semester // // Returns the semester. // ---------------------------------------- public function get_semester() { return $this->semester; } // ---------------------------------------- // get_errors // // Returns an array of errors for this student. // ---------------------------------------- public function get_errors() { return $this->errors; } // ---------------------------------------- // has_errors // // Returns a boolean signifying whether this student has any errors. // ---------------------------------------- public function has_errors() { return ( isset($this->errors) && ( ! empty($this->errors) ) ); } // ---------------------------------------- // get_students // // Returns an array with all the students and their results. // ---------------------------------------- public function get_students() { return $this->students; } // ---------------------------------------- // get_student_by_uid // // Returns the student corresponding to $uid, null if no such // student exists. // // Arguments: // $uid is the uid of the sought student // ---------------------------------------- public function get_student_by_uid($uid) { // ---------- // Iterate over the result matrix in an attempt to find the // sought student. // ---------- foreach ( $this->students as $first_reg => $first_chars ) { foreach ( $first_chars as $first_char => $students ) { if ( $first_char == $uid[0] ) { // Found a matching array for the first char of // the uid. foreach ( $students as $student ) { if ( $student->get_uid() == $uid ) { // Student found. return $student; } } } } } // Student not found. return null; } // ---------------------------------------- // get_student_by_uid_and_semester // // Returns the student corresponding to $uid, null if no such // student exists. Also takes semester into consideration to // reduce redundant searching. // // Arguments: // $uid is the uid of the sought student // $semester is the semester where the student was first // registered // ---------------------------------------- public function get_student_by_uid_and_semester($uid, $semester) { // ---------- // Iterate over the result array found for the given semester // and uid in an attempt to find the sought student. // ---------- if ( isset($this->students[$semester][$uid[0]]) ) { foreach ( $this->students[$semester][$uid[0]] as $student ) { if ( $student->get_uid() == $uid ) { // Student found. return $student; } } } // Student not found. return null; } // ---------------------------------------- // add_student // // Add a student to the course. // ---------------------------------------- public function add_student($student) { $uid = strtolower($student->get_uid()); $first_reg = $student->get_first_reg(); // ---------- // Check if there is an array for students with the same first // registered semester and first letter of the uid as // $student, if not, create such an array. // ---------- if ( ! isset($this->students[$first_reg]) ) { $this->students[$first_reg] = array(); } if ( ! isset($this->students[$first_reg][$uid[0]]) ) { $this->students[$first_reg][$uid[0]] = array(); } $this->students[$first_reg][$uid[0]][] = $student; } // ---------------------------------------- // get_students_by_first_reg // // Returns an array containing the students corresponding to // $first_reg, null if no such student exists. // // Arguments: // $first_reg is the semester the student was first registered // to the course. // ---------------------------------------- public function get_students_by_first_reg($first_reg) { $res = array(); foreach ( $this->students as $first_reg => $first_chars ) { foreach ( $first_chars as $first_char => $students ) { foreach ( $students as $student ) { if ( $student->get_first_reg() == $first_reg ) { $res[] = $student; } } } } return $res; } // ---------------------------------------- // print_dump // // Print function for debugging / testing. // ---------------------------------------- public function print_dump() { print "Course results for: " . $this->course_code . ", " . $this->semester . "\n"; foreach ( $this->students as $first_reg => $first_chars ) { foreach ( $first_chars as $first_char => $students ) { foreach ( $students as $student ) { $student->print(); } } } } // ---------------------------------------- // insert_post_data_results // // Inserts the post data results reported into the corresponding // student. If the student has no previously recorded results it // will be created in accordance with LUPP version 1.0. // // Arguments: // $data is the post data received from client // $deadlines is the array of deadlines from course description // $active_students is an active students class object for this // course // // ---------------------------------------- public function insert_post_data_results($data, $deadlines, $active_students) { // Iterate over the outer array of the post data. foreach ( $data as $char=>$students ) { insert_group_of_results($students, $deadlines, $active_students); } } // ---------------------------------------- // get_csv_formated_list_of_passing_results // // Creates and returns a list of student results for the current // semester of a given course. The output is a newline separated // list of students on the following format: // uid01;PART:SUBPART;PART:SUBPART; ... // uid02;PART:SUBPART;PART:SUBPART; ... // ---------------------------------------- public function get_csv_formated_list_of_passing_results() { $result = ''; // ---------- // Iterate over the students in the course and extract the // passing results for each. // ---------- foreach ( $this->students as $first_reg => $first_chars ) { foreach ( $first_chars as $first_char => $students ) { foreach ( $students as $student ) { foreach ( $student->get_results() as $part ) { $current = ''; foreach ( $part->get_sub_parts() as $sub ) { if ( $sub->get_state() == "passed" ) { if ( $current == '' ) { $current .= $student->get_uid() . ";"; } $current .= $part->get_name() . ":" . $sub->get_id() . ";"; } } if ( $current != '' ) { $result .= $current . "\n"; } } } } } return $result; } // ---------------------------------------- // strip_tags // // Strips the tags related to a particular instance of the course, // to aid in transfering from one year to the next. //---------------------------------------- public function strip_tags() { // TODO: Implement. } // ---------------------------------------- // get_results_file // // Returns full path to actual result file depending on arguments (or NULL // if not existing result file matching arguments). // // Arguments: // $uid = LiUid (using first character in filename) // $first_reg_semester = first semester student is registered on course // $create = true => we create nonexisting directory // false => we don't. May give NULL as return value. // // VERSION UPDATE: $first_reg_semester is a new argument. We have new format // on result file name including the semester students are first registered // in course. // ---------------------------------------- public function get_results_file($uid, $first_reg_semester, $create = false) { // Create result directory if not existing (and called with "$create=true") $dir = $this->get_path_to_course_and_semester_results_directory() . '/'; if ( ( ! is_dir($dir) ) && $create ) { log_to_file($dir); mkdir($dir, 0777, true); // "mkdir -p", recursive ... } // Setup result filename regarding this student $path = $dir . $uid[0] . '.students.' . $first_reg_semester . '.xml'; // Create "result file" if not existing (if "$create=true") if ( ( realpath($path) === FALSE ) && $create) { $doc = new DOMDocument("1.0", "UTF-8"); $s = $doc->createElement('students'); $doc->appendChild($s); $doc->save($path); } // If not existing result file: return null if ( realpath($path) === FALSE ) { return NULL; } // Return xmlHandler for content of result file return xml_handler::get_xml_handler_for_file($path); } // ---------------------------------------- // get_path_to_course_and_semester_results_directory // // Returns the path to the area used to save student results for current // semester. // // Example: $COURSE_RESULTS_PATH/TDDD87/2021-HT // ---------------------------------------- public function get_path_to_course_and_semester_results_directory() { global $COURSE_RESULTS_PATH; return realpath($COURSE_RESULTS_PATH . '/' . $this->course_code . '/' . $this->semester); } // ---------------------------------------- // insert_group_of_results // // Handles inserting the results for a group of students (grouped // by first character in uid). // // Arguments: // $students_in_group is an array containing the results for a // group of students // $deadlines is an array of the course deadlines // $active_students is an active students class object for this // course // ---------------------------------------- private function insert_group_of_results($students_in_group, $deadlines, $active_students) { foreach ( $students_in_group as $uid => $student_result ) { $student = $this->get_student_by_uid($uid); // ---------- // If no results exist for this student previously, create // it. // ---------- if ( $student == null ) { // if ( $student $student = new Student_Result($uid, true); } $student->insert_results($results, $deadlines); } } // ---------------------------------------- // save_to_file // // Save the changes to file. // // Arguments: // $deadlines is an array of deadlines from the course description. // ---------------------------------------- public function save_to_file($deadlines) { // ---------- // Iterate over the various first registrations / character // combinations in the course, and check each student if they // have data to save to file. When a student with changes has // been found, store the new data on file. // ---------- if ( isset($this->students) and ! empty($this->students) ) { foreach ( $this->students as $first_reg => $first_chars ) { foreach ( $first_chars as $first_char => $students ) { $count = 0; // Get the necessary file data to modify the file // contents for this particular combination of // firstreg and first character of uid. $handler = $this->get_results_file($first_char, $first_reg, true); $xml_doc = null; $xml_path = null; foreach ( $students as $student ) { if ( $student->has_changes() or $student->is_new() ) { // We have found students to save, so we // lock the document. No need to work on // files that are not affected by changes. if ( $count == 0 ) { $count += 1; $xml_doc = $handler->lock_document(); $xml_path = new DOMXPath($xml_doc); } // This student has been modified. // Let the student class save the results into the xml object. if ( ! $student->save_results_to_file($xml_path, $xml_doc, $deadlines) ) { // Failed to save student, handle. $this->errors[] = $student; } } } // If we had students to save, unlock document // (stores changes to file). if ( $count > 0 ) { $handler->unlock_document($xml_doc); } } } } } // ---------------------------------------- // get_course_results_directory_path // // Helper function that returns the path to the directory // containing the course result data files. // ---------------------------------------- private function get_course_results_directory_path() { global $COURSE_RESULTS_PATH; $path = $COURSE_RESULTS_PATH . "/" . $this->course_code . "/" . $this->semester . "/"; return $path; } // ---------------------------------------- // End of Course_Results class definition // ---------------------------------------- } // ---------------------------------------------------------------------------- ?>