_DegreePlan.php

Classes

NameDescription
_DegreePlan

File

classes/_DegreePlan.php
View source
  1. <?php
  2. class _DegreePlan
  3. {
  4. public $major_code, $title, $degree_type, $degree_class, $short_description, $long_description;
  5. public $list_semesters, $list_degree_plans, $list_groups, $db, $degree_id, $catalog_year;
  6. public $track_code, $track_title, $track_description, $student_array_significant_courses;
  7. public $bool_has_tracks, $array_semester_titles, $db_exclude;
  8. public $public_note;
  9. public $total_major_hours, $total_core_hours, $total_degree_hours;
  10. public $fulfilled_major_hours, $fulfilled_core_hours, $fulfilled_degree_hours;
  11. public $major_qpts_hours, $core_qpts_hours, $degree_qpts_hours;
  12. public $major_qpts, $degree_qpts, $core_qpts;
  13. public $bool_use_draft;
  14. /**
  15. * $major_code ACCT, CSCI, etc.
  16. * $title Accounting, Computer Science, etc.
  17. * $degree_type BBA, BS, AS, etc.
  18. * $short_description These are a text description of this degree plan. Useful
  19. * for descriptions of "Tracks" or "Options." The short
  20. * $long_description one appears in a pull down, the long one is a more
  21. * complete text description. Will probably be unused
  22. * by most degrees.
  23. * $list_semesters A list of semesters that this DegreePlan requires.
  24. * $list_degree_plans If this degree plan has multiple tracks or options, then
  25. * they would be spelled out as other degree plans, and listed
  26. * here. For example, Biology has multiple "tracks" which,
  27. * internally, should be treated as different degree plans.
  28. **/
  29. function __construct($degree_id = "", DatabaseHandler $db = NULL, $bool_load_minimal = false, $array_significant_courses = false, $bool_use_draft = false)
  30. {
  31. $this->list_semesters = new ObjList();
  32. $this->list_groups = new GroupList();
  33. $this->bool_use_draft = $bool_use_draft;
  34. // Always override if the global variable is set.
  35. if ($GLOBALS["fp_advising"]["bool_use_draft"] == true) {
  36. $this->bool_use_draft = true;
  37. }
  38. $this->db = $db;
  39. if ($db == NULL)
  40. {
  41. $this->db = get_global_database_handler();
  42. }
  43. $this->student_array_significant_courses = $array_significant_courses;
  44. if ($degree_id != "")
  45. {
  46. $this->degree_id = $degree_id;
  47. $this->load_descriptive_data();
  48. if (!$bool_load_minimal)
  49. {
  50. $this->load_degree_plan();
  51. }
  52. // Add the "Add a Course" semester to the semester list.
  53. $this->add_semester_courses_added();
  54. }
  55. }
  56. function calculate_progress_hours()
  57. {
  58. $this->total_major_hours = $this->get_progress_hours("m");
  59. $this->total_core_hours = $this->get_progress_hours("c");
  60. $this->total_degree_hours = $this->get_progress_hours("");
  61. $this->fulfilled_major_hours = $this->get_progress_hours("m", false);
  62. $this->fulfilled_core_hours = $this->get_progress_hours("c", false);
  63. $this->fulfilled_degree_hours = $this->get_progress_hours("", false);
  64. $this->major_qpts_hours = $this->get_progress_hours("m", false, TRUE);
  65. $this->core_qpts_hours = $this->get_progress_hours("c", false, TRUE);
  66. $this->degree_qpts_hours = $this->get_progress_hours("", false, TRUE);
  67. }
  68. /**
  69. * Calculate the quality points of our completed courses, so we can use
  70. * that to figure out GPA.
  71. *
  72. */
  73. function calculate_progress_quality_points() {
  74. $this->major_qpts = $this->get_progress_quality_points("m");
  75. $this->core_qpts = $this->get_progress_quality_points("c");
  76. $this->degree_qpts = $this->get_progress_quality_points("");
  77. }
  78. function get_progress_hours($requirement_type = "", $bool_required_hours_only = TRUE, $bool_qpts_grades_only = FALSE)
  79. {
  80. // Returns the number of hours required (or fulfilled) in a degree plan
  81. // for courses & groups with the specified requirement_type.
  82. // ex: "m", "s", etc. leave blank for ALL required hours.
  83. // if boolRequiredHours is FALSE, then we will only look for the courses
  84. // which got fulfilled.
  85. $hours = 0;
  86. $this->list_semesters->reset_counter();
  87. while ($this->list_semesters->has_more())
  88. {
  89. $sem = $this->list_semesters->get_next();
  90. if ($bool_required_hours_only == true)
  91. {
  92. $hours += $sem->list_courses->count_hours($requirement_type, true, false);
  93. } else {
  94. $temp = $sem->list_courses->count_credit_hours($requirement_type, true, true, $bool_qpts_grades_only);
  95. $hours += $temp;
  96. }
  97. }
  98. // Also, add in groups matching this requirement type.
  99. $this->list_groups->reset_counter();
  100. while ($this->list_groups->has_more())
  101. {
  102. $g = $this->list_groups->get_next();
  103. if ($g->group_id < 0)
  104. { // Skip Add a course group.
  105. continue;
  106. }
  107. $g_hours = $g->hours_required;
  108. if ($bool_required_hours_only == false)
  109. { // only count the fulfilled hours, then.
  110. $g_hours = $g->get_fulfilled_hours(true, false, true, -1, true, $bool_qpts_grades_only);
  111. }
  112. if ($requirement_type == "")
  113. {
  114. $hours += $g_hours;
  115. } else {
  116. // A requirement is specified, so make sure
  117. // the group is of this requirement.
  118. if ($bool_required_hours_only == true)
  119. { // make sure it's of the right type.
  120. $g_hours = $g->hours_required_by_type[$requirement_type]*1;
  121. $hours += $g_hours;
  122. continue;
  123. }
  124. if ($g->requirement_type == $requirement_type)
  125. {
  126. $hours += $g_hours;
  127. }
  128. }
  129. }
  130. return $hours;
  131. }
  132. /**
  133. * Similar to get_progress_hours, this will return back the quality points a student has earned
  134. * towards this degree. It can then be used to calculate GPA.
  135. *
  136. * @param unknown_type $requirement_type
  137. * @param unknown_type $bool_required_hours_only
  138. * @return unknown
  139. */
  140. function get_progress_quality_points($requirement_type = "") {
  141. // Returns the number of hours required (or fulfilled) in a degree plan
  142. // for courses & groups with the specified requirement_type.
  143. // ex: "m", "s", etc. leave blank for ALL required hours.
  144. // if boolRequiredHours is FALSE, then we will only look for the courses
  145. // which got fulfilled.
  146. $points = 0;
  147. $this->list_semesters->reset_counter();
  148. while ($this->list_semesters->has_more())
  149. {
  150. $sem = $this->list_semesters->get_next();
  151. $p = $sem->list_courses->count_credit_quality_points($requirement_type, true, true);
  152. $points = $points + $p;
  153. }
  154. // Also, add in groups matching this requirement type.
  155. $this->list_groups->reset_counter();
  156. while ($this->list_groups->has_more())
  157. {
  158. $g = $this->list_groups->get_next();
  159. if ($g->group_id < 0)
  160. { // Skip Add a course group.
  161. continue;
  162. }
  163. if ($g->requirement_type == $requirement_type || $requirement_type == "") {
  164. //fpm("$requirement_type - group $g->title - $g_points");
  165. $g_points = $g->get_fulfilled_quality_points(TRUE, -1, TRUE, TRUE);
  166. $points = $points + $g_points;
  167. }
  168. }
  169. return $points;
  170. }
  171. function load_degree_plan()
  172. {
  173. // Load this degree plan from the database and fully
  174. // assemble it.
  175. $degree_id = $this->degree_id;
  176. $old_semester = "";
  177. $table_name1 = "degrees";
  178. $table_name2 = "degree_requirements";
  179. if ($this->bool_use_draft) {
  180. $table_name1 = "draft_$table_name1";
  181. $table_name2 = "draft_$table_name2";
  182. }
  183. $res = $this->db->db_query("SELECT * FROM $table_name1 a, $table_name2 b
  184. WHERE a.degree_id = '?'
  185. AND a.degree_id = b.degree_id
  186. ORDER BY semester_num ", $this->degree_id);
  187. while ($cur = $this->db->db_fetch_array($res))
  188. {
  189. $this->title = $cur["title"];
  190. $this->major_code = $cur["major_code"];
  191. $this->degree_class = strtoupper(trim($cur["degree_class"]));
  192. $semester_num = $cur["semester_num"];
  193. if ($semester_num != $old_semester)
  194. {
  195. // This is a new semester object we are dealing with.
  196. $old_semester = $semester_num;
  197. $obj_semester = new Semester($semester_num);
  198. $obj_semester->title = trim($this->array_semester_titles[$semester_num]);
  199. if ($obj_semester->title == "") { $obj_semester->assign_title(); }
  200. $this->list_semesters->add($obj_semester);
  201. }
  202. if ($cur["course_id"]*1 > 0)
  203. {
  204. // A course is the next degree requirement.
  205. //if ($this->bool_use_draft) $cat_year = $this->catalog_year;
  206. $cat_year = $this->catalog_year;
  207. $course_c = new Course($cur["course_id"], false, $this->db, false, $cat_year, $this->bool_use_draft);
  208. $course_c->assigned_to_semester_num = $semester_num;
  209. $course_c->min_grade = trim(strtoupper($cur["course_min_grade"]));
  210. if ($course_c->min_grade == "")
  211. { // By default, all courses have a
  212. // min grade requirement of D.
  213. $course_c->min_grade = "D";
  214. }
  215. $course_c->requirement_type = trim($cur["course_requirement_type"]);
  216. //adminDebug($course_c->to_string() . $course_c->getCatalogHours());
  217. $obj_semester->list_courses->add($course_c);
  218. }
  219. if ($cur["group_id"]*1 > 0)
  220. {
  221. // A group is the next degree requirement.
  222. //$group_g = new Group($cur["group_id"], $this->db, $semester_num);
  223. $title = "";
  224. $icon_filename = "";
  225. // Add the real Group (with all the courses, branches, etc)
  226. // to the DegreePlan's group list!
  227. // First, see if this group alread exists. If it does,
  228. // simply add the number of hours required to it. If not,
  229. // create it fresh.
  230. if ($new_group = $this->find_group($cur["group_id"]))
  231. {
  232. // Was already there (probably in another semester),
  233. // so, just increment the required hours.
  234. $new_group->hours_required = $new_group->hours_required + ($cur["group_hours_required"] * 1);
  235. $new_group->hours_required_by_type[$cur["group_requirement_type"]] += ($cur["group_hours_required"] * 1);
  236. $title = $new_group->title;
  237. $icon_filename = $new_group->icon_filename;
  238. } else {
  239. // Was not already there; insert it.
  240. $group_n = new Group($cur["group_id"], $this->db, $semester_num, $this->student_array_significant_courses, $this->bool_use_draft);
  241. $group_n->hours_required = $cur["group_hours_required"] * 1;
  242. $group_n->hours_required_by_type[$cur["group_requirement_type"]] += $group_n->hours_required;
  243. if (trim($cur["group_min_grade"]) != "")
  244. {
  245. $group_n->assign_min_grade(trim(strtoupper($cur["group_min_grade"])));
  246. }
  247. $group_n->requirement_type = $cur["group_requirement_type"];
  248. $title = $group_n->title;
  249. $icon_filename = $group_n->icon_filename;
  250. $this->list_groups->add($group_n);
  251. }
  252. // Add a placeholder to the Semester....
  253. $group_g = new Group();
  254. $group_g->bool_use_draft = $this->bool_use_draft;
  255. $group_g->group_id = $cur["group_id"];
  256. $group_g->load_descriptive_data();
  257. $group_g->requirement_type = $cur["group_requirement_type"];
  258. if (trim($cur["group_min_grade"]) != "")
  259. {
  260. $group_g->assign_min_grade(trim(strtoupper($cur["group_min_grade"])));
  261. }
  262. $group_g->assigned_to_semester_num = $semester_num;
  263. $group_g->title = "$title";
  264. $group_g->icon_filename = $icon_filename;
  265. $group_g->hours_required = $cur["group_hours_required"] * 1;
  266. $group_g->bool_placeholder = true;
  267. $obj_semester->list_groups->add($group_g);
  268. }
  269. }
  270. $this->list_groups->sort_priority();
  271. }
  272. function get_title($bool_include_track = false)
  273. {
  274. // This will return the title of this degree, possibly
  275. // including the track's title as well.
  276. $rtn = $this->title;
  277. if ($bool_include_track == true)
  278. {
  279. if ($this->track_title != "")
  280. {
  281. $rtn .= " with " . $this->track_title . "";
  282. }
  283. }
  284. return $rtn;
  285. }
  286. function get_title2()
  287. {
  288. // This will simply return the degree's title. If it does not
  289. // exist, it will try to find another degree with the same major_code.
  290. // This is to fix the problem with students with catalog years outside
  291. // of FlightPath's database, but with major codes that have titles.
  292. $this->load_descriptive_data();
  293. if ($this->title != "")
  294. {
  295. return $this->title;
  296. }
  297. // Still no title? Try to load ANY degree title with this degree's
  298. // major_code.
  299. $table_name = "degrees";
  300. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  301. $res = $this->db->db_query("SELECT * FROM $table_name
  302. WHERE major_code = '?'
  303. ORDER BY catalog_year DESC LIMIT 1", $this->major_code);
  304. $cur = $this->db->db_fetch_array($res);
  305. $this->title = $cur["title"];
  306. return $this->title;
  307. }
  308. function load_descriptive_data()
  309. {
  310. $table_name = "degrees";
  311. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  312. $res = $this->db->db_query("SELECT * FROM $table_name
  313. WHERE degree_id = '?' ", $this->degree_id);
  314. if ($this->db->db_num_rows($res) > 0)
  315. {
  316. $cur = $this->db->db_fetch_array($res);
  317. $this->major_code = $cur["major_code"];
  318. $this->title = $cur["title"];
  319. $this->public_note = $cur["public_note"];
  320. $this->catalog_year = $cur["catalog_year"];
  321. $this->degree_type = trim($cur["degree_type"]);
  322. $this->db_exclude = trim($cur["exclude"]);
  323. // Get the semester titles.
  324. $temp = trim($cur["semester_titles_csv"]);
  325. $this->array_semester_titles = explode(",",$temp);
  326. if (strstr($this->major_code, "_"))
  327. {
  328. // This means that there is a track. Get all the information
  329. // you can about it.
  330. $temp = explode("_", $this->major_code);
  331. $this->track_code = trim($temp[1]);
  332. $this->major_code = trim($temp[0]);
  333. // The major_code might now have a | at the very end. If so,
  334. // get rid of it.
  335. if (substr($this->major_code, strlen($this->major_code)-1, 1) == "|")
  336. {
  337. $this->major_code = str_replace("|","",$this->major_code);
  338. }
  339. // Now, look up information on the track.
  340. $table_name = "degree_tracks";
  341. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  342. $res = $this->db->db_query("SELECT * FROM $table_name
  343. WHERE major_code = '?'
  344. AND track_code = '?'
  345. AND catalog_year = '?' ", $this->major_code, $this->track_code, $this->catalog_year);
  346. $cur = $this->db->db_fetch_array($res);
  347. $this->track_title = $cur["track_title"];
  348. $this->track_description = $cur["track_description"];
  349. }
  350. // Does this major have any tracks at all? If so, set a bool.
  351. if ($this->db->get_degree_tracks($this->major_code, $this->catalog_year))
  352. {
  353. $this->bool_has_tracks = true;
  354. }
  355. }
  356. }
  357. function get_advised_courses_list()
  358. {
  359. // Return a courseList object containing every course
  360. // in this degreePlan which is marked as boolAdvisedToTake=true.
  361. $rtn_list = new CourseList();
  362. $this->list_semesters->reset_counter();
  363. while ($this->list_semesters->has_more())
  364. {
  365. $semester = $this->list_semesters->get_next();
  366. $rtn_list->add_list($semester->list_courses->get_advised_courses_list());
  367. }
  368. $rtn_list->add_list($this->list_groups->get_advised_courses_list());
  369. return $rtn_list;
  370. }
  371. /**
  372. * Returns a simple array with values seperated by " ~~ "
  373. * in this order: track_code ~~ track_title ~~ trackDesc
  374. *
  375. * @return array
  376. */
  377. function get_available_tracks()
  378. {
  379. $rtn_array = array();
  380. $rtn_array[] = " ~~ None ~~ Select this option to display
  381. the base degree plan (may not be available for all majors).";
  382. $table_name = "degree_tracks";
  383. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  384. $res = $this->db->db_query("SELECT * FROM $table_name
  385. WHERE major_code = '?'
  386. AND catalog_year = '?'
  387. ORDER BY track_title ", $this->major_code, $this->catalog_year);
  388. while($cur = $this->db->db_fetch_array($res))
  389. {
  390. $track_code = $cur["track_code"];
  391. $track_title = $cur["track_title"];
  392. $track_description = $cur["track_description"];
  393. //adminDebug($track_code);
  394. $rtn_array[] = "$track_code ~~ $track_title ~~ $track_description";
  395. }
  396. if (count($rtn_array))
  397. {
  398. return $rtn_array;
  399. } else {
  400. return false;
  401. }
  402. }
  403. function add_semester_developmental($student_id)
  404. {
  405. // This will add the developmental courses in as
  406. // a semester. Will check the studentID to see if any
  407. // developmentals are required.
  408. // -55 is the developmental semester.
  409. $sem = new Semester(-55);
  410. $sem->title = "Developmental Requirements";
  411. $is_empty = true;
  412. $temp_array = $this->db->get_developmental_requirements($student_id);
  413. // We expect this to give us back an array like:
  414. // 0 => ART~101
  415. // 1 => MATH~090
  416. foreach($temp_array as $temp_course_name) {
  417. $temp = explode("~", $temp_course_name);
  418. $c = new Course($this->db->get_course_id($temp[0], $temp[1]));
  419. $c->min_grade = "C";
  420. $c->requirement_type = "dev";
  421. $sem->list_courses->add($c);
  422. $is_empty = false;
  423. }
  424. $sem->notice = t("According to our records, you are required to
  425. complete the course(s) listed above.
  426. For some transfer students, your record may
  427. not be complete. If you have any questions,
  428. please ask your advisor.");
  429. if (!$is_empty)
  430. {
  431. $this->list_semesters->add($sem);
  432. }
  433. }
  434. function add_semester_courses_added()
  435. {
  436. // The "Add a Course" box on screen is really just a
  437. // semester, with the number -88, with a single group,
  438. // also numbered -88.
  439. $semester_courses_added = new Semester(-88);
  440. $semester_courses_added->title = t("Courses Added by Advisor");
  441. // Now, we want to add the Add a Course group...
  442. $g = new Group();
  443. $g->group_id = -88;
  444. // Since it would take a long time during page load, we will
  445. // leave this empty of courses for now. It doesn't matter anyway,
  446. // as we will not be checking this group for course membership
  447. // anyway. We only need to load it in the popup.
  448. $g->hours_required = 99999; // Nearly infinite selections may be made.
  449. $g->assigned_to_semester_num = -88;
  450. $semester_courses_added->list_groups->add($g);
  451. $this->list_semesters->add($semester_courses_added);
  452. // Also, add it to the list of groups OUTSIDE of semesters.
  453. $this->list_groups->add($g);
  454. }
  455. function find_group($group_id)
  456. {
  457. // Locate the group with group_id in the
  458. // list of groups, and return it.
  459. $this->list_groups->reset_counter();
  460. while($this->list_groups->has_more())
  461. {
  462. $group = $this->list_groups->get_next();
  463. if ($group->group_id == $group_id)
  464. {
  465. return $group;
  466. }
  467. if (!$group->list_groups->is_empty)
  468. {
  469. $group->list_groups->reset_counter();
  470. while($group->list_groups->has_more())
  471. {
  472. $branch = $group->list_groups->get_next();
  473. if ($branch->group_id == $group_id)
  474. {
  475. return $branch;
  476. }
  477. }
  478. }
  479. }
  480. return false;
  481. }
  482. function find_placeholder_group($group_id, $semester_num)
  483. {
  484. // Locate the group within the semesters that matches
  485. // this group_id and semesterNum. The assumption here
  486. // is that no one semester will list the same
  487. // group twice. In other words, Core Fine Arts
  488. // can only have 1 entry for Freshman Year.
  489. // Create a dummy semester with the correct semesterNum...
  490. $new_semester = new Semester($semester_num);
  491. // Create dummy group as well... don't use the constructor, just
  492. // set the group_id manually to same time. (no DB calls)
  493. $new_group = new Group();
  494. $new_group->group_id = $group_id;
  495. //print_pre($this->list_semesters->to_string());
  496. // Find the semester in the list of semesters with this same semesterNum...
  497. if (!$semester = $this->list_semesters->find_match($new_semester))
  498. {
  499. // The semester wasn't found!
  500. return false;
  501. }
  502. // Okay, now go through $semester and find the group_id...
  503. if (!$group = $semester->list_groups->find_match($new_group))
  504. {
  505. // It wasn't found in the top-level groups. Look one deeper...
  506. if (!$semester->list_groups->is_empty)
  507. {
  508. $semester->list_groups->reset_counter();
  509. while($semester->list_groups->has_more())
  510. {
  511. $group = $semester->list_groups->get_next();
  512. if ($g = $group->list_groups->find_match($new_group))
  513. {
  514. //$g->assign_to_semester($semester_num);
  515. return $g;
  516. }
  517. }
  518. }
  519. } else {
  520. // Meaning, we found it!
  521. //$group->assign_to_semester($semester_num);
  522. return $group;
  523. }
  524. return false;
  525. }
  526. function find_courses($course_id, $group_id = 0, $semester_num)
  527. {
  528. // This will locate a course within the degree plan, and return
  529. // back either that course object, or FALSE.
  530. $new_course = new Course($course_id);
  531. $new_semester = new Semester($semester_num);
  532. $rtn_course_list = new CourseList();
  533. // Okay, if the course is within a group, then
  534. // we can first use the find_group method.
  535. if ($group_id != 0)
  536. {
  537. if ($group = $this->find_group($group_id))
  538. {
  539. if (!($group->list_courses->is_empty))
  540. {
  541. if ($cL = $group->find_courses($new_course))
  542. {
  543. $rtn_course_list->add_list($cL);
  544. }
  545. }
  546. if (!($group->list_groups->is_empty))
  547. {
  548. // Look within each sub group for the course...
  549. $group->list_groups->reset_counter();
  550. while($group->list_groups->has_more())
  551. {
  552. $branch = $group->list_groups->get_next();
  553. if (!$branch->list_courses->is_empty)
  554. {
  555. if ($cL = $branch->find_courses($new_course))
  556. {
  557. $rtn_course_list->add_list($cL);
  558. }
  559. }
  560. // Here we can look for groups within groups...
  561. }
  562. }
  563. }
  564. return $rtn_course_list;
  565. } else if ($semester_num != -1) {
  566. // No group specified. This course is on the
  567. // bare degree plan. We were given a specific semester,
  568. // so try to find it there...
  569. if ($semester = $this->list_semesters->find_match($new_semester))
  570. {
  571. if ($cL = $semester->list_courses->find_all_matches($new_course))
  572. {
  573. $rtn_course_list->add_list($cL);
  574. return $rtn_course_list;
  575. }
  576. }
  577. } else if ($semester_num == -1)
  578. {
  579. // Meaning, we do not know which semester it goes in, so
  580. // attempt all semesters, and return with the first instance.
  581. $this->list_semesters->reset_counter();
  582. while($this->list_semesters->has_more())
  583. {
  584. $sem = $this->list_semesters->get_next();
  585. if ($cL = $sem->list_courses->find_all_matches($new_course))
  586. {
  587. $rtn_course_list->add_list($cL);
  588. return $rtn_course_list;
  589. }
  590. }
  591. }
  592. return false;
  593. }
  594. function to_string()
  595. {
  596. // Output this degree plan object in a helpful manner.
  597. $rtn = "";
  598. $rtn .= "Degree Plan: $this->title ($this->major_code) \n";
  599. $rtn .= $this->list_semesters->to_string();
  600. $rtn .= "----------------------------------------- \n";
  601. $rtn .= "-- ALL GROUPS \n";
  602. $rtn .= $this->list_groups->to_string();
  603. return $rtn;
  604. }
  605. } // end class DegreePlan