is_modified = false; $args = func_get_args(); $arg_count = func_num_args(); if (method_exists($this, $function = '__construct'.$arg_count)) { call_user_func_array(array($this, $function), $args); } } // ---------------------------------------- // Constructor // // Initiates instance variables and creates classes based // on the xml data received. // // Arguments: // $xml_data is an xml data object supposed to contain relevant // data retrieved from the *_students.year-semester file(s). // $is_new indicates whether a student is new, // ---------------------------------------- public function __construct1($xml_data) { $this->result_parts = array(); $this->changes = array(); $this->errors = array(); $this->is_new = false; $this->first_reg = $xml_data->getAttribute('firstreg'); $this->uid = $xml_data->getAttribute('uid'); $this->fr = $xml_data->getAttribute('fr'); $this->ladok_registration = $xml_data->getAttribute('ladokreg'); $this->ladok_reported = $xml_data->getAttribute('ladokreported'); $parts_data = $xml_data->getElementsByTagName('part'); foreach ( $parts_data as $part ) { $this->result_parts[] = new Result_Part($part); } } // ---------------------------------------- // Constructor // // Initiates instance variables and creates classes based // on the data sent. // // Arguments: // $uid is the uid of the student. // $first_reg is the semester the student was first registered. // ---------------------------------------- public function __construct2($uid, $first_reg) { $this->result_parts = array(); $this->changes = array(); $this->errors = array(); $this->is_new = true; $this->uid = $uid; $this->first_reg = $first_reg; } // ---------------------------------------- // get_jsonversion // // Returns the jsonversion. // ---------------------------------------- public function get_jsonversion() { return $this->jsonversion; } // ---------------------------------------- // set_jsonversion // // Set the jsonversion. // // Arguments: // $version is a string containing the new jsonversion // ---------------------------------------- public function set_jsonversion($version) { $this->jsonversion = $version; } // ---------------------------------------- // get_first_reg // // Returns the first_reg. // ---------------------------------------- public function get_first_reg() { return $this->first_reg; } // ---------------------------------------- // get_uid // // Returns the uid for the student. // ---------------------------------------- public function get_uid() { return $this->uid; } // ---------------------------------------- // get_fr // // Returns the fr corresponding to this student. // // Arguments: // $fr is the new fr for this student. // ---------------------------------------- public function get_fr() { return $this->fr; } // ---------------------------------------- // set_fr // // Set fr corresponding to this student. // ---------------------------------------- public function set_fr($fr) { $this->fr = $fr; $this->is_modified = true; } // ---------------------------------------- // get_student_ladok_registration_date // // Returns when the student was ladok registered. // ---------------------------------------- public function get_ladok_registration_date() { return $this->ladok_registration; } // ---------------------------------------- // set_student_ladok_registration_date // // Set the date when the student was ladok registered. // // Arguments: // $ladok_registration_date is the date when the student was // Ladok registered on this course. // ---------------------------------------- public function set_ladok_registration_date($ladok_registration_date) { $this->ladok_registration = $ladok_registration_date; $this->is_modified = true; } // ---------------------------------------- // get_ladok_report_date // // Returns when the results for this student were resported to Ladok. // ---------------------------------------- public function get_ladok_report_date() { return $this->ladok_reported; } // ---------------------------------------- // set_ladok_report_date // // Set the date for when this student were resported to Ladok. // // Arguments: // $ladok_reported_date is the date this student grade was // reported to Ladok. // ---------------------------------------- public function set_ladok_report_date($ladok_reported_date) { $this->ladok_reported = $ladok_reported_date; $this->is_modified = true; } // ---------------------------------------- // get_results // // Returns an array of results for this student. // ---------------------------------------- public function get_results() { return $this->result_parts; } // ---------------------------------------- // 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_results_by_part_name // // Returns a result_part object matching the part_name, if no such // part exists null will be returned. // ---------------------------------------- public function get_results_by_part_name($part_name) { foreach ( $this->result_parts as $res ) { if ( strcasecmp($res->get_name(), $part_name) == 0) { return $res; } } return null; } // ---------------------------------------- // has_changes // // Returns true if any modifications have been done to this // student or their results, false otherwise. // ---------------------------------------- public function has_changes() { return ( ( isset($this->changes) and ! empty($this->changes) ) || $this->is_modified ); } // ---------------------------------------- // add changed part // // If manual changes have been made outside of the student scope, // this has to be notified in order for the changes to follow into // the save file. // // Arguments: // $course_part is the modified course part. // ---------------------------------------- public function add_changed_part($course_part) { $this->changes[] = $course_part; } // ---------------------------------------- // get_finished_unreported_course_parts // // Compiles a list of course parts that have been finished but not // yet reported. Uses the course description object for the course // to ensure correctness. // // Arguments: // $course_description is the course description oject for this // course, used to ensure that the student has fulfilled all // mandatory goals of the course parts. // ---------------------------------------- public function get_finished_unreported_course_parts($course_description) { $result = ""; // DELETE THIS $debug = false; // --------- // Iterate over the course parts in the course description. // ---------- foreach ( $course_description->get_course_parts() as $course_desc_part) { $student_part = $this->get_results_by_part_name($course_desc_part->get_name()); // --------- // Attempt to look at LUPP results for this student in the // current course part. If not reported to LADOK, check if // all mandatory parts are passed. // ---------- if ( ! isset($student_part) ) { // There are no results for this course part, break. continue; } if ($debug) { print("Found result: " . $student_part->get_name() . "\n"); } // ---------- // If this part doesn't contain grading sub-parts we want // to skip it, since it doesn't get reported to Ladok. // ---------- if ( ! $course_desc_part->contains_grading_sub_parts() ) { continue; } if ($debug) { print("Found mandatory course parts in: " . $student_part->get_name() . "\n"); } // ---------- // If this course part has already been reported, break. // ---------- // TODO: BIG TODO, FIX THIS URGENTLY. $reported = $student_part->get_reported(); if ( isset($reported) && ( ! empty($reported) ) ) { if ($debug) { print("Found that: " . $student_part->get_name() . " is reported, aborting\n"); } continue; } // ---------- // Check if this part has a grade that has yet to be reported. // ---------- $current_grade = $student_part->get_grade(); if ( isset($current_grade) && ( ! empty($current_grade)) && ( strcasecmp($current_grade, "U") != 0) ) { if ($debug) { print("Found that: " . $student_part->get_name() . " has another grade than U set\n"); } $result .= $course_desc_part->get_name() . ":" . $student_part->get_grade() . ";"; continue; } $grading_system = $course_desc_part->get_grading(); // -------------------- // This part is graded solely with U or G. If all // mandatory assignments are passed, send grade G // -------------------- if ( strcasecmp($grading_system, "U/G") == 0 || strcasecmp($grading_system, "T/U/G") == 0 ) { // ---------- // Check all sub parts // ---------- if ($debug) { print("Found that: " . $student_part->get_name() . " has U/G grading system\n"); } $passed = false; foreach ( $course_desc_part->get_sub_parts() as $sub_part ) { if ( $sub_part->is_mandatory() ) { $passed = $this->is_sub_part_passed($student_part, $sub_part->get_name()); if ( ! $passed ) { break; } } } // ---------- // We have a passing grade, return that. // ---------- if ( $passed ) { $result .= $course_desc_part->get_name() . ":G;" ; if ($debug) { print("Found that: " . $student_part->get_name() . " should have grade G\n"); } } } // -------------------- // This part is graded either U/G/VG or U/3/4/5. // -------------------- else { if ($debug) { print("Found that: " . $student_part->get_name() . " has a wider grading system (not U/G)\n"); } $intended_grade = null; // -------------------- // Check all sub parts. // -------------------- foreach ( $course_desc_part->get_sub_parts() as $sub_part ) { if ( $this->is_sub_part_passed($student_part, $sub_part->get_name()) ) { $shortest_name = explode(".", $sub_part->get_name())[1]; // ---------- // Check if the grade we have found is // better than the currently best found. // ---------- if ( $intended_grade === null || strcasecmp($intended_grade, $shortest_name) < 0 ) { $intended_grade = $shortest_name; } } } if ( isset($intended_grade) && ( ! empty($intended_grade) ) && string_contains($intended_grade, "B") ) { $intended_grade = explode("B", $intended_grade)[1]; if ($debug) { print("\tIntended grade: " . $intended_grade . "\n"); } } } } return $result; } // ---------------------------------------- // insert_new_result // // Insert a new result for this student. // // Arguments: // $part_name is the new result part name // $grade is the grade to set for the result part, send null if // there is no grade // $reported is the date this part was reported, send null if // there is no result // $force_flag is a flag to the program that forces changes, // even though they may normally not be allowed. // // Returns the new result part. If a result part by this name // already exists, that part will be modified according to the // parameters and returned. // ---------------------------------------- // TODO: Consider reporting for parts that have changed name from // previous iterations of the course. Ex: TEN1 -> DAT1. // TODO: We may need to take course_description as a parameter in // order for us to determine whether we should be allowed to raise // a grade for this part. // TODO: Check if force_flag needs to be here, we may remove the // forced function. public function insert_new_result($part_name, $grade, $reported, $force_flag) { $part = $this->get_results_by_part_name($part_name); // We check whether this part existed before or not, for this // student. if ( ! isset($part) ) { // We had no previous results for this part // TODO: Remove null parameter / change constructor for // result part. $part = new Result_Part($part_name, $grade, $reported, null); $this->result_parts[] = $part; } // Check if we are reporting a grade for this specific part. if ( $grade == null ) { // We did not attempt to report a grade, but just wanted // to created it and report sub-parts. $this->changes[] = $part; return $part; } // We now know that we wanted to modify the grade of this // student. // If new grade is higher than old reported grade, we want // to update with the new grade, store old grade, and // store old reported grade. Should require force flag to // update G/VG grades. if ( $part->get_reported() == null || ( empty($part->get_reported()) ) ) { // We do not have a reported grade from before. Saving // results. $part->set_grade($grade); $part->set_reported($reported); $this->changes[] = $part; return $part; } // -------------------- // We have a reported grade for this student. // -------------------- // ---------- // We need to determine whether we should allow for the // new grade. // ---------- if ( strcasecmp($part->get_grade(), $grade) == 0 ) { // The new grade is the same as the old grade, no changes // made. print("NOTICE: Attempted to insert the same LADOK grade again.\n"); return null; } if ( strcasecmp($part->get_grade(), "U") == 0 ) { // We have old grade U which is always safe to overwrite. // TODO: Log oldreported and oldgrade for example. // Saving results $part->set_grade($grade); $part->set_reported($reported); $this->changes[] = $part; return $part; } if ( strcasecmp($part->get_grade(), $grade) < 0 ) { // We have determined that the grade we are setting is an // increase. // Saving results $part->set_grade($grade); $part->set_reported($reported); $this->changes[] = $part; return $part; } // Should we "force" the new report, regardless of what was // previously reported? if ( $force_flag ) { // We have force flag, yes! // Saving results $part->set_grade($grade); $part->set_reported($reported); $this->changes[] = $part; return $part; } print("ERROR: Attempted to lower a LADOK grade in part: " . $part_name . " (old grade: " . $part->get_grade() . ", new grade: " . $grade . ") without using force flag!\n"); return null; } // ---------------------------------------- // insert_new_result_forced // // Insert a new result for this student. // // Arguments: // $part_name is the new result part name // $grade is the grade to set for the result part, send null if // there is no grade // $reported is the date this part was reported, send null if // there is no result // $report_name is a default null parameter, if this course part // has a different report name (Ex: DAT1 might be TEN1 in some // courses), this is the parameter to control this // // Returns the new result part. If a result part by this name // already exists, that part will be modified according to the // parameters and returned. // ---------------------------------------- public function insert_new_result_forced($part_name, $grade, $reported, $report_name = null) { $part = $this->get_results_by_part_name($part_name); if ( ! isset($part) ) { $part = new Result_Part($part_name, $grade, $reported, $report_name); $this->result_parts[] = $part; } else { if ( isset($grade) ) { $part->set_grade($grade); } if ( isset($report_name) && $report_name != $part->get_report_name() ) { $part->set_report_name($report_name); } } $this->changes[] = $part; return $part; } // ---------------------------------------- // save_results_to_file // // Stores the results for this student on the given file. We know // the student exists in active students for this course // // Arguments: // $xml_path is the DOMDXpath for the xml_handler document. // $xml_document is the DOMDocument in which to store the changes // $deadlines is an array of deadlines fetched from course info // // Returns true if successfully saved, false otherwise, to handle // errors outside. // ---------------------------------------- public function save_results_to_file($xml_path, $xml_document, $deadlines) { $clean_save = true; // Retrieve the xml object corresponding to this student. $xml_element = $xml_path->query('//student[@uid=\'' . $this->uid . '\']'); if ( $xml_element->length == 0 || ( ! isset($xml_element) ) ) { // ---------- // The student did not previously exist in the results // document, so we create it and append the attributes. // ---------- $student_elem = $xml_document->createElement('student'); $student_elem->setAttribute('uid', $this->uid); $student_elem->setAttribute('firstreg', $this->first_reg); // ---------- // Store the optional attributes that have a set value. // ---------- if ( isset($this->ladok_registration) and ! empty($this->ladok_registration) ) { $student_elem->setAttribute('ladokreg', $this->ladok_registration); } if ( isset($this->ladok_reported) and ! empty($this->ladok_reported) ) { $student_elem->setAttribute('ladokreported', $this->ladok_reported); } if ( isset($this->fr) and ! empty($this->fr) ) { $student_elem->setAttribute('fr', $this->fr); } $xml_document->documentElement->appendChild($student_elem); } elseif ( $xml_element->length > 1 ) { // Multiple entries of this student $this->errors[] = "Multiple entries of student with uid: |" . $uid . "| in the result xml file!"; return false; } else { // Only one entry of this student existed. $student_elem = $xml_element->item(0); } if ( $this->is_modified ) { if ( isset($this->ladok_reported) and ! empty($this->ladok_reported) ) { $student_elem->setAttribute('ladokreported', $this->ladok_reported); } } // ---------- // Check the result parts, and save them if they have changes. // ---------- if ( isset($this->changes) and ! empty($this->changes) ) { foreach ( $this->changes as $part ) { if ( $part->has_changes() or $part->is_new() ) { try { if ( ! $part->save_results_to_file($xml_path, $xml_document, $deadlines, $student_elem, $this->uid) ) { $clean_save = false; } } catch (Multiple_Entries_Exception $e) { $this->errors[] = "Multiple entries of student with uid: |" . $uid . "| for course part: |" . $part->get_name() . "| in result xml file!\n"; } } } } $this->is_modified = false; return $clean_save; } // ---------------------------------------- // is_new // // Returns a boolean, showing if the student has been created // (doesn't previously exist in the results). // ---------------------------------------- public function is_new() { return $this->is_new; } // ---------------------------------------- // to_json // // Creates a json string representation of the student result. // // Arguments: // $indentation is the count of tabs to indent the json data, // default 0. Used for when the json data should be nested // inside another json object. // // Returns a string containing the json representation of the // student result // ---------------------------------------- public function to_json($indentation = 0) { // Extract and "jsonify" attributes that are always present. $res = str_repeat("\t", $indentation) . "{\n" . str_repeat("\t", $indentation+1) . "\"firstreg\": \"" . $this->first_reg . "\",\n" . str_repeat("\t", $indentation+1) . "\"jsonversion\": \"" . $this->jsonversion . "\",\n" . str_repeat("\t", $indentation+1) . "\"uid\": \"" . $this->uid ."\""; // ---------- // Check if the attributes the can be empty contain data, if // so "jsonify" and add them. // ---------- if ( isset($this->fr) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"firstreg\": \"" . $this->first_reg . "\""; } if ( isset($this->ladok_registration) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"ladokreg\": \"" . $this->ladok_registration . "\""; } if ( isset($this->ladok_reported) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"ladokreported\": \"" . $this->ladok_reported . "\""; } if ( isset($this->json_version) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"jsonversion\": \"" . $this->json_version . "\""; } // ---------- // Check if the students have any results reported, if so // retrieve and append their json representations. // ---------- if ( isset($this->result_parts) ) { // We have results for this student. $count = count($this->result_parts); $res .= ",\n" . str_repeat("\t", $indentation+1) . "\"parts\": [\n"; for ($i = 0; $i < $count; $i++) { $part = $this->result_parts[$i]; $res .= $part->to_json($indentation + 2); if ( $i < $count - 1 ) { // We're not on the last element $res .= ",\n"; } else { // Last element $res .= "\n" . str_repeat("\t", $indentation + 1) . "]\n"; } } } else { // We have no results for this student. $res .= "\n"; } $res .= str_repeat("\t", $indentation) . "}"; return $res; } // ---------------------------------------- // to_json_full // // Creates a json string representation of the student result. // // Arguments: // $course_descript is the course description object used to // find all mandatory course sub parts for old students. // $indentation is the count of tabs to indent the json data, // default 0. Used for when the json data should be nested // inside another json object. // // Returns a string containing the json representation of the // student result // ---------------------------------------- public function to_json_full($course_description, $indentation = 0) { // Extract and "jsonify" attributes that are always present. $res = str_repeat("\t", $indentation) . "{\n" . str_repeat("\t", $indentation+1) . "\"firstreg\": \"" . $this->first_reg . "\",\n" . str_repeat("\t", $indentation+1) . "\"jsonversion\": \"" . $this->jsonversion . "\",\n" . str_repeat("\t", $indentation+1) . "\"uid\": \"" . $this->uid ."\""; // ---------- // Check if the attributes the can be empty contain data, if // so "jsonify" and add them. // ---------- if ( isset($this->fr) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"firstreg\": \"" . $this->first_reg . "\""; } if ( isset($this->ladok_registration) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"ladokreg\": \"" . $this->ladok_registration . "\""; } if ( isset($this->ladok_reported) ) { $res .= ",\n" . str_repeat("\t", $indentation) . "\t\"ladokreported\": \"" . $this->ladok_reported . "\""; } // ---------- // Check if the students have any results reported, if so // retrieve and append their json representations. // ---------- if ( isset($this->result_parts) ) { // We have results for this student. $count = count($this->result_parts); $res .= ",\n" . str_repeat("\t", $indentation+1) . "\"parts\": [\n"; for ($i = 0; $i < $count; $i++) { $part = $this->result_parts[$i]; $res .= $part->to_json_full($course_description, $indentation + 2); if ( $i < $count - 1 ) { // We're not on the last element $res .= ",\n"; } else { // Last element $res .= "\n" . str_repeat("\t", $indentation + 1) . "]\n"; } } } else { // We have no results for this student. $res .= "\n"; } $res .= str_repeat("\t", $indentation) . "}"; return $res; } // ---------------------------------------- // print_dump // // Print function for debugging / testing. // ---------------------------------------- public function print_dump() { print "\tStudent UID: " . $this->uid . ", firstreg: " . $this->first_reg . ", fr: " . $this->fr . ", ladokreg: " . $this->ladok_registration . ", ladokreported: " . $this->ladok_reported . "\n"; foreach ( $this->result_parts as $part ) { $part->print_dump(); } } // ---------------------------------------- // strip_tags // // Strips the tags related to this student to aid in transfering // from one year to the next. //---------------------------------------- public function strip_tags() { // TODO: Implement. } // ---------------------------------------- // is_sub_part_passed // // Helper function that checks if a sub part is passed. // ---------------------------------------- private function is_sub_part_passed($student_part, $sub_part_id) { $student_sub_part = $student_part->get_sub_part_by_id($sub_part_id); if ( isset($student_sub_part) ) { return strcasecmp($student_sub_part->get_state(), "passed") == 0; } return false; } // ---------------------------------------- // End of Student_Result class definition // ---------------------------------------- } // ---------------------------------------------------------------------------- ?>