_Course.php

Classes

NameDescription
_Course

File

classes/_Course.php
View source
  1. <?php
  2. /*
  3. Class definition for the Course object.
  4. */
  5. class _Course
  6. {
  7. // Some public variables and what they are used for.
  8. // Database & misc related:
  9. public $random_id, $db_advised_courses_id;
  10. public $bool_placeholder, $db, $db_substitution_id, $db_unassign_transfer_id;
  11. public $db_exclude, $data_entry_comment, $array_index, $data_entry_value;
  12. public $db_group_requirement_id; // the id from the group_requirements table where this was specified.
  13. // Course catalog data related:
  14. public $subject_id, $course_num, $course_id, $requirement_type, $catalog_year;
  15. public $min_hours, $max_hours, $list_prereqs, $repeat_hours;
  16. public $array_valid_names;
  17. // Student record related:
  18. public $bool_taken, $term_id, $section_number, $grade, $hours_awarded, $quality_points;
  19. public $bool_transfer, $institution_id, $institution_name, $course_transfer;
  20. public $transfer_eqv_text, $transfer_footnote, $bool_outdated_sub;
  21. public $bool_substitution, $course_substitution, $substitution_hours, $sub_remarks, $sub_faculty_id;
  22. public $bool_substitution_split, $substitution_footnote, $bool_substitution_new_from_split;
  23. // Major or Group Requirement related:
  24. public $min_grade, $specified_repeats, $bool_specified_repeat, $required_on_branch_id;
  25. public $assigned_to_group_id, $assigned_to_semester_num, $bool_exclude_repeat;
  26. // advising & in-system logic related:
  27. public $advised_hours, $bool_selected, $bool_advised_to_take;
  28. public $course_list_fulfilled_by; //$course_fulfilled_by,
  29. public $bool_has_been_assigned, $bool_added_course, $group_list_unassigned;
  30. public $advised_term_id, $temp_old_course_id;
  31. public $bool_use_draft;
  32. //public $bool_has_been_assignedToBareDegreePlan;
  33. // Display related:
  34. public $display_status, $icon_filename, $description, $title;
  35. public $title_text, $temp_flag, $bool_has_been_displayed;
  36. public $bool_unselectable;
  37. public $bool_hide_grade, $bool_ghost_hour, $bool_ghost_min_hour;
  38. /**
  39. * The constructor for a Course object.
  40. *
  41. * @param int $course_id
  42. * - Numeric course_id of the course to try to load. Leave blank
  43. * if you simply wish to instantiate a course object.
  44. *
  45. * @param bool $is_transfer
  46. * - Is this course a transfer course? Meaning, from another
  47. * school.
  48. *
  49. * @param DatabaseHandler $db
  50. * @param bool $is_blank
  51. * @param int $catalog_year
  52. * - What catalog_year does this Course belong to? This is
  53. * used later when we call load_descriptive_data() to get its
  54. * description, hour count, etc.
  55. *
  56. * @param bool $bool_use_draft
  57. */
  58. function __construct($course_id = "", $is_transfer = false, DatabaseHandler $db = NULL, $is_blank = false, $catalog_year = "", $bool_use_draft = false)
  59. {
  60. $this->advised_hours = -1;
  61. if ($is_blank == true)
  62. { // Do nothing if this is a "blank" course.
  63. return;
  64. }
  65. $array_valid_names = array(); // will hold all "valid" names for this course (non excluded names).
  66. $this->course_id = $course_id*1; // Force it to be numeric.
  67. $this->temp_old_course_id = 0; // Used in case we delete the course_id, we can get it back (good with substitutions of transfers that are outdated).
  68. $this->catalog_year = $catalog_year;
  69. $this->assigned_to_semester_num = -1;
  70. $this->assigned_to_group_id = 0;
  71. $this->bool_advised_to_take = false;
  72. $this->bool_added_course = false;
  73. $this->specified_repeats = 0;
  74. $this->bool_exclude_repeat = false;
  75. $this->bool_specified_repeat = false;
  76. $this->random_id = rand(1,9999);
  77. $this->display_status = "eligible";
  78. $this->course_list_fulfilled_by = new CourseList();
  79. $this->group_list_unassigned = new ObjList();
  80. $this->bool_use_draft = $bool_use_draft;
  81. // Always override if the global variable is set.
  82. if ($GLOBALS["fp_advising"]["bool_use_draft"] == true) {
  83. $this->bool_use_draft = true;
  84. }
  85. $this->db = $db;
  86. if ($db == NULL)
  87. {
  88. $this->db = get_global_database_handler();;
  89. if (!is_object($this->db))
  90. {
  91. $this->db = new DatabaseHandler();
  92. }
  93. }
  94. if ($course_id != "")
  95. {
  96. $this->load_course($course_id, $is_transfer);
  97. }
  98. }
  99. /**
  100. * This function will create a "data string" of the course.
  101. * Think of it as a poor man's serialize. I can't actually use
  102. * serialize, as I have to call this for every course on the screen,
  103. * and the page load time was too long when using serialize, probably
  104. * because of all the extra fields which I did not need.
  105. *
  106. * The string returned will be used to send information about this
  107. * course to a popup window.
  108. *
  109. * Important details about the course are put into a particular order,
  110. * separated by commas. Booleans are converted to either 1 or 0.
  111. *
  112. * This function is the mirror of load_course_from_data_string().
  113. *
  114. * @return string
  115. */
  116. function to_data_string()
  117. {
  118. $rtn = "";
  119. $rtn .= $this->course_id . "~";
  120. $rtn .= $this->assigned_to_semester_num . "~";
  121. $rtn .= $this->assigned_to_group_id . "~";
  122. $rtn .= intval($this->bool_advised_to_take) . "~";
  123. $rtn .= $this->specified_repeats . "~";
  124. $rtn .= intval($this->bool_specified_repeat) . "~";
  125. $rtn .= $this->grade . "~";
  126. $rtn .= $this->hours_awarded . "~";
  127. $rtn .= $this->term_id . "~";
  128. $rtn .= $this->advised_hours . "~";
  129. $rtn .= intval($this->bool_transfer) . "~";
  130. // If this is a transfer, then we will put in various information
  131. // about the original transfer course...
  132. if ($this->bool_transfer == true)
  133. {
  134. $rtn .= $this->course_transfer->course_id . "~";
  135. } else {
  136. // Just enter blank.
  137. $rtn .= "~";
  138. }
  139. $rtn .= intval($this->bool_added_course) . "~";
  140. $rtn .= $this->db_advised_courses_id . "~";
  141. $rtn .= $this->random_id . "~";
  142. $rtn .= intval($this->bool_substitution) . "~";
  143. // If this is a substitution, what is the original requirement?
  144. if ($this->bool_substitution == true)
  145. {
  146. $rtn .= $this->course_substitution->course_id . "~";
  147. } else {
  148. // Just enter blank.
  149. $rtn .= "~";
  150. }
  151. $rtn .= $this->db_substitution_id . "~";
  152. $rtn .= $this->min_hours . "~";
  153. $rtn .= $this->max_hours . "~";
  154. $rtn .= intval($this->bool_substitution_new_from_split) . "~";
  155. $rtn .= intval($this->bool_substitution_split) . "~";
  156. $rtn .= intval($this->bool_has_been_assigned) . "~";
  157. $rtn .= $this->display_status . "~";
  158. $rtn .= intval($this->bool_ghost_hour) . "~";
  159. return $rtn;
  160. }
  161. /**
  162. * This will take a data string, as created by
  163. * the function to_data_string(), and make $this object
  164. * match the original object. It is a poor man's
  165. * unserialize. See to_data_string()'s description for a fuller
  166. * picture of what is going on.
  167. *
  168. * To use:
  169. * - $newCourse = new Course();
  170. * - $newCourse->load_course_from_data_string($data);
  171. *
  172. *
  173. * @param string $str
  174. */
  175. function load_course_from_data_string($str)
  176. {
  177. $temp = explode("~",$str);
  178. $this->course_id = $temp[0];
  179. $this->load_course($this->course_id);
  180. $this->assigned_to_semester_num = $temp[1];
  181. $this->assigned_to_group_id = $temp[2];
  182. $this->bool_advised_to_take = (bool) $temp[3];
  183. $this->specified_repeats = $temp[4];
  184. $this->bool_specified_repeat = (bool) $temp[5];
  185. $this->grade = $temp[6];
  186. $this->hours_awarded = $temp[7] * 1; // *1 to force numeric, and trim extra zeros.
  187. $this->term_id = $temp[8];
  188. $this->advised_hours = $temp[9] * 1;
  189. $this->bool_transfer = (bool) $temp[10];
  190. // Was this a transfer course?
  191. if ($this->bool_transfer == true)
  192. {
  193. $t_course = new Course($temp[11], true);
  194. $t_course->term_id = $this->term_id;
  195. $this->course_transfer = $t_course;
  196. }
  197. $this->bool_added_course = (bool) $temp[12];
  198. $this->db_advised_courses_id = $temp[13];
  199. $this->random_id = $temp[14];
  200. $this->bool_substitution = (bool) $temp[15];
  201. // Was this a substitution course?
  202. if ($this->bool_substitution == true)
  203. {
  204. $t_course = new Course($temp[16]); // original course requirement.
  205. $this->course_substitution = $t_course;
  206. }
  207. $this->db_substitution_id = $temp[17];
  208. $this->min_hours = $temp[18] * 1;
  209. $this->max_hours = $temp[19] * 1;
  210. $this->bool_substitution_new_from_split = (bool) $temp[20];
  211. $this->bool_substitution_split = (bool) $temp[21];
  212. $this->bool_has_been_assigned = (bool) $temp[22];
  213. $this->display_status = $temp[23];
  214. $this->bool_ghost_hour = (bool) $temp[24];
  215. }
  216. /**
  217. * This function will return a CSV string of all the possible
  218. * names for this course, in alphabetical order.
  219. *
  220. * This function is used by DataEntry primarily.
  221. *
  222. * @param bool $bool_add_white_space
  223. * @param bool $bool_add_exclude
  224. * @return string
  225. */
  226. function get_all_names($bool_add_white_space = false, $bool_add_exclude = true)
  227. {
  228. $rtn = "";
  229. $used_array = array();
  230. $table_name = "courses";
  231. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  232. // took out: and `catalog_year`='$this->catalog_year'
  233. // because we don't care what catalog year it comes from...
  234. $res = $this->db->db_query("SELECT * FROM $table_name
  235. WHERE course_id = '?'
  236. AND delete_flag = '0'
  237. ORDER BY subject_id, course_num ", $this->course_id);
  238. while($cur = $this->db->db_fetch_array($res))
  239. {
  240. if (in_array($cur["subject_id"] . "~" . $cur["course_num"], $used_array))
  241. { // skip ones we have already seen.
  242. continue;
  243. }
  244. $used_array[] = $cur["subject_id"] . "~" . $cur["course_num"];
  245. $rtn .= $cur["subject_id"] . " " . $cur["course_num"];
  246. if ($cur["exclude"] != '0' && $bool_add_exclude == true)
  247. {
  248. $rtn .= " exclude";
  249. }
  250. $rtn .= ",";
  251. if ($bool_add_white_space == true)
  252. {
  253. $rtn .= " ";
  254. }
  255. }
  256. $rtn = trim($rtn);
  257. // remove last comma.
  258. $rtn = substr($rtn,0,-1);
  259. return $rtn;
  260. }
  261. /**
  262. * The function returns either an integer of the the number of
  263. * hours the course is worth, or, a range in the form of
  264. * min-max (if the course has variable hours)
  265. *
  266. * Examples: 3 or 1-6
  267. *
  268. * @return string
  269. */
  270. function get_catalog_hours()
  271. {
  272. if (!$this->has_variable_hours())
  273. {
  274. return $this->min_hours;
  275. } else {
  276. // Meaning this does course have variable hours.
  277. $min_h = $this->min_hours;
  278. $max_h = $this->max_hours;
  279. // Convert back from ghosthours.
  280. if ($this->bool_ghost_min_hour) {
  281. $min_h = 0;
  282. }
  283. if ($this->bool_ghost_hour) {
  284. $max_h = 0;
  285. }
  286. return "$min_h-$max_h";
  287. }
  288. }
  289. /**
  290. * Returns how many hours this course has been advised for.
  291. * This is used with courses which have variable hours. If
  292. * the course has not been advised for any particular number
  293. * of hours, then it's min_hours are returned.
  294. *
  295. * @return unknown
  296. */
  297. function get_advised_hours()
  298. {
  299. if ($this->advised_hours > -1)
  300. {
  301. return $this->advised_hours;
  302. } else {
  303. // No, the user has not selected any hours yet. So,
  304. // just display the min_hours.
  305. // Correct for ghost hours, if any.
  306. $min_h = $this->min_hours;
  307. if ($this->bool_ghost_min_hour) {
  308. $min_h = 0;
  309. }
  310. return $min_h;
  311. }
  312. }
  313. /**
  314. * This will assign the $this->display_status string
  315. * based on the grade the student has made on the course.
  316. * The display_status is used by other display functions to decide
  317. * what color the course should show up as.
  318. *
  319. */
  320. function assign_display_status()
  321. {
  322. // Assigns the display status, based on grade.
  323. $grade = $this->grade;
  324. // Get these grade definitions from our system settings
  325. // Configure them in custom/settings.php
  326. $retake_grades = csv_to_array($GLOBALS["fp_system_settings"]["retake_grades"]);
  327. $enrolled_grades = csv_to_array($GLOBALS["fp_system_settings"]["enrolled_grades"]);
  328. if (in_array($grade, $retake_grades))
  329. {
  330. $this->display_status = "retake";
  331. }
  332. if (in_array($grade, $enrolled_grades))
  333. {
  334. $this->display_status = "enrolled";
  335. }
  336. }
  337. /**
  338. * Returns TRUE if the student has completed the course
  339. * (and did not make a failing grade on it).
  340. *
  341. *
  342. *
  343. * @return bool
  344. */
  345. function is_completed()
  346. {
  347. // returns true if the course has been completed.
  348. $grade = $this->grade;
  349. // Get these grade definitions from our system settings
  350. // Configure them in custom/settings.php
  351. $retake_grades = csv_to_array($GLOBALS["fp_system_settings"]["retake_grades"]);
  352. $enrolled_grades = csv_to_array($GLOBALS["fp_system_settings"]["enrolled_grades"]);
  353. if ($grade == "") {
  354. return false;
  355. }
  356. if (in_array($grade, $enrolled_grades)) {
  357. return false;
  358. }
  359. if (in_array($grade, $retake_grades)) {
  360. return false;
  361. }
  362. return true;
  363. }
  364. /**
  365. * Does $this meed the minimum grade requirement of the
  366. * supplied course requirement? You may specify either
  367. * a Course object, or just enter the min_grade in the mGrade
  368. * variable.
  369. *
  370. * @param Course $course_req
  371. * - The Course object who has the min grade requirement.
  372. * Set to NULL if using $m_grade.
  373. *
  374. * @param string $m_grade
  375. * - The min grade which $this must meet. Do not use if using
  376. * $course_req.
  377. *
  378. * @return bool
  379. */
  380. function meets_min_grade_requirement_of(Course $course_req = NULL, $m_grade = "")
  381. {
  382. // Does $this course meet the min grade requirement
  383. // of the supplied course requirement?
  384. // Get these grade definitions from our system settings
  385. // Configure them in custom/settings.php
  386. $b_or_better = csv_to_array($GLOBALS["fp_system_settings"]["b_or_better"]);
  387. $c_or_better = csv_to_array($GLOBALS["fp_system_settings"]["c_or_better"]);
  388. $d_or_better = csv_to_array($GLOBALS["fp_system_settings"]["d_or_better"]);
  389. $enrolled_grades = csv_to_array($GLOBALS["fp_system_settings"]["enrolled_grades"]);
  390. if ($course_req != null) {
  391. $min_grade = $course_req->min_grade;
  392. } else {
  393. $min_grade = $m_grade;
  394. }
  395. if ($min_grade == "")
  396. { // There is no min grade requirement for this course.
  397. return true;
  398. }
  399. // If the student is currently enrolled, return true.
  400. if (in_array($this->grade, $enrolled_grades))
  401. {
  402. return true;
  403. }
  404. if ($min_grade == "A" && $this->grade == "A")
  405. {
  406. return true;
  407. }
  408. if ($min_grade == "B" && in_array($this->grade, $b_or_better))
  409. {
  410. return true;
  411. }
  412. if ($min_grade == "C" && in_array($this->grade, $c_or_better))
  413. {
  414. return true;
  415. }
  416. if ($min_grade == "D" && in_array($this->grade, $d_or_better))
  417. {
  418. return true;
  419. }
  420. return false;
  421. }
  422. /**
  423. * Simply returns TRUE if $this has variable hours.
  424. *
  425. * @return bool
  426. */
  427. function has_variable_hours()
  428. {
  429. $min_h = $this->min_hours;
  430. $max_h = $this->max_hours;
  431. // Convert back from ghosthours, for the comparison.
  432. if ($this->bool_ghost_min_hour) {
  433. $min_h = 0;
  434. }
  435. if ($this->bool_ghost_hour) {
  436. $max_h = 0;
  437. }
  438. if ($min_h == $max_h)
  439. {
  440. return false;
  441. } else {
  442. return true;
  443. }
  444. }
  445. /**
  446. * Figure out the number of hours this particular
  447. * instance of the course is worth. In the case
  448. * of variable hours, it will return the number
  449. * of hours selected. If that does not exist,
  450. * it will return the MIN HOURS.
  451. *
  452. * @return int
  453. */
  454. function get_hours()
  455. {
  456. // This course might be set to 1 hour, but be a "ghost hour",
  457. // meaning the student actually earned 0 hours, but we recorded 1
  458. // to make FP's math work out. So, let's return back 0 hours.
  459. if ($this->bool_ghost_hour)
  460. {
  461. $h = 0;
  462. return $h;
  463. }
  464. // Do they have any hours_awarded? (because they completed
  465. // the course)
  466. if ($this->hours_awarded > 0)
  467. {
  468. $h = $this->hours_awarded;
  469. return $h;
  470. }
  471. if ($this->has_variable_hours() && $this->advised_hours > -1) {
  472. return $this->advised_hours;
  473. }
  474. // No selected hours, but it's a variable hour course.
  475. // So, return the min_hours for this course.
  476. return $this->min_hours;
  477. }
  478. /**
  479. * Calculate the quality points for this course's grade and hours.
  480. *
  481. * @param string $grade
  482. * @param int $hours
  483. * @return int
  484. */
  485. function get_quality_points(){
  486. $hours = $this->get_hours();
  487. $grade = $this->grade;
  488. $pts = 0;
  489. $qpts_grades = array();
  490. // Let's find out what our quality point grades & values are...
  491. if (isset($GLOBALS["qpts_grades"])) {
  492. // have we already cached this?
  493. $qpts_grades = $GLOBALS["qpts_grades"];
  494. }
  495. else {
  496. $tlines = explode("\n", variable_get("quality_points_grades", "A ~ 4\nB ~ 3\nC ~ 2\nD ~ 1\nF ~ 0\nI ~ 0"));
  497. foreach ($tlines as $tline) {
  498. $temp = explode("~", trim($tline));
  499. if (trim($temp[0]) != "") {
  500. $qpts_grades[trim($temp[0])] = trim($temp[1]);
  501. }
  502. }
  503. $GLOBALS["qpts_grades"] = $qpts_grades; // save to cache
  504. }
  505. // Okay, find out what the points are by multiplying value * hours...
  506. if (isset($qpts_grades[$grade])) {
  507. $pts = $qpts_grades[$grade] * $hours;
  508. }
  509. return $pts;
  510. }
  511. /**
  512. * This function is used for comparing a course name to the subject_id
  513. * and course_num of $this.
  514. * We expect a space between the subject_id and CourseNum in $str.
  515. *
  516. * For example: MATH 1010
  517. *
  518. * You may also ONLY specify a subject, ex: BIOL. If you do that,
  519. * then only the subject will be compared.
  520. *
  521. * Example of use: if ($c->name_equals("ART 101")) then do this etc.
  522. *
  523. * @param string $str
  524. * @return bool
  525. */
  526. function name_equals($str)
  527. {
  528. // We expect the str to be given to us
  529. // with a space b/t the subject_id and course_num.
  530. // ex: MATH 111
  531. // may also ONLY specify the subject. ex: BIOL
  532. $temp = explode(" ",$str);
  533. if ($this->subject_id == $temp[0] && ($this->course_num == $temp[1] || trim($temp[1]) == ""))
  534. {
  535. return true;
  536. }
  537. return false;
  538. }
  539. /**
  540. * Convienience function. Simply compare the course_id of
  541. * another course to $this to see if they are equal.
  542. *
  543. * This is also used by CourseList and ObjList to determine
  544. * matches.
  545. *
  546. * Usage: if ($newCourse.equals($otherCourse)) { ... }
  547. *
  548. * @param Course $course_c
  549. * @return bool
  550. */
  551. function equals(Course $course_c = null)
  552. {
  553. if ($this->course_id == $course_c->course_id)
  554. {
  555. return true;
  556. }
  557. return false;
  558. }
  559. /**
  560. * Load $this as a new course based on the subject_id and course_num,
  561. * instead of the course_id. This is a useful function for when you
  562. * know a subject_id and course_num, but not course_id (for example, if
  563. * it comes from human input).
  564. *
  565. * @param string $subject_id
  566. * @param string $course_num
  567. */
  568. function load_course_from_name($subject_id, $course_num)
  569. {
  570. // Load a course based on its name. In otherwords,
  571. // find the CourseID this way first.
  572. $course_id = $this->db->get_course_id($subject_id, $course_num);
  573. $this->load_course($course_id);
  574. }
  575. /**
  576. * Loads $this as a new course, based on course_id.
  577. *
  578. * @param int $course_id
  579. * @param bool $is_transfer
  580. */
  581. function load_course($course_id, $is_transfer = false)
  582. {
  583. if ($this->db == NULL)
  584. {
  585. $this->db = get_global_database_handler();
  586. }
  587. $catalog_line = "";
  588. if ($this->catalog_year != "") {
  589. $catalog_line = " AND catalog_year = '$this->catalog_year' ";
  590. }
  591. if ($is_transfer == false) {
  592. $this->load_descriptive_data();
  593. } else {
  594. // This is a transfer course. Find out its eqv, if any...
  595. $res = $this->db->db_query("SELECT * FROM
  596. transfer_courses a,
  597. transfer_institutions b
  598. WHERE
  599. a.transfer_course_id = '?'
  600. AND a.institution_id = b.institution_id ", $course_id);
  601. $cur = $this->db->db_fetch_array($res);
  602. $this->subject_id = $cur["subject_id"];
  603. $this->course_num = $cur["course_num"];
  604. $this->course_id = $course_id;
  605. $this->bool_transfer = true;
  606. $this->institution_id = $cur["institution_id"];
  607. $this->institution_name = $cur["name"];
  608. }
  609. $this->assign_display_status();
  610. }
  611. /**
  612. * This function will correct capitalization problems in course titles.
  613. *
  614. * @param string $str
  615. *
  616. * @return string
  617. *
  618. */
  619. function fix_title($str = "")
  620. {
  621. if ($str == "")
  622. {
  623. $str = $this->title;
  624. }
  625. // Should we do this at all? We will look at the "autocapitalize_course_titles" setting.
  626. $auto = $GLOBALS["fp_system_settings"]["autocapitalize_course_titles"];
  627. if ($auto == "no") {
  628. // Nope! Just return.
  629. $this->title = $str;
  630. return $str;
  631. }
  632. // Otherwise, we may continue with the capitalization scheme:
  633. $str = str_replace("/", " / ", $str);
  634. $str = str_replace("/", " / ", $str);
  635. $str = str_replace("-", " - ", $str);
  636. $str = str_replace(":", ": ", $str);
  637. $str = str_replace("(", "( ", $str);
  638. // Only pad an ampersand if we are not talking about
  639. // an HTML character.
  640. if (!strstr($str,"&#"))
  641. {
  642. $str = str_replace("&", " & ", $str);
  643. }
  644. // Let's also get rid of extra spaces.
  645. $str = str_replace(" ", " ", $str);
  646. $str = str_replace(" ", " ", $str);
  647. // convert to ucwords and fix some problems introduced by that.
  648. $str = trim(ucwords(strtolower($str)));
  649. $str = str_replace("Iii", "III", $str);
  650. $str = str_replace("Ii", "II", $str);
  651. $str = str_replace(" Iv"," IV",$str);
  652. $str = str_replace(" Vi"," VI",$str);
  653. $str = str_replace(" Of "," of ",$str);
  654. $str = str_replace(" The "," the ",$str);
  655. $str = str_replace(" In "," in ",$str);
  656. $str = str_replace(" And "," and ",$str);
  657. $str = str_replace(" An "," an ",$str);
  658. $str = str_replace(" A "," a ",$str);
  659. $str = str_replace(" To "," to ",$str);
  660. $str = str_replace(" For "," for ",$str);
  661. // Strange words and abreviations which should be changed.
  662. $str = str_replace("Afrotc","AFROTC",$str);
  663. $str = str_replace("Gis","GIS",$str);
  664. $str = str_replace("Dna","DNA",$str);
  665. $str = str_replace(" Cpr","CPR",$str);
  666. $str = str_replace(" Rn"," RN",$str);
  667. $str = str_replace(" Micu"," MICU",$str);
  668. $str = str_replace(" Sicu"," SICU",$str);
  669. $str = str_replace(" Picu"," PICU",$str);
  670. $str = str_replace(" Nicu"," NICU",$str);
  671. $str = str_replace("Uas ","UAS ",$str);
  672. $str = str_replace(" Uas"," UAS",$str);
  673. // Cleanup
  674. $str = str_replace("( ", "(", $str);
  675. $str = str_replace(" - ", "-", $str);
  676. // Is this just a course name by itself? If so, it should
  677. // all be capitalized.
  678. $temp = explode(" ", $str);
  679. if (count($temp) == 2
  680. && strlen($temp[0]) <= 4
  681. && strlen($temp[1]) <= 4)
  682. {// We could also test to see if there are numbers starting the
  683. // second token.
  684. $str = strtoupper($str);
  685. }
  686. // If this contains the word "formerly" then we need to pull out what's
  687. // there and make it all uppercase, except for the word Formerly.
  688. if (strstr(strtolower($str), strtolower("formerly ")))
  689. {
  690. $formline = preg_replace("/.*\((formerly .*)\).*/i", "$1", $str);
  691. $str = str_replace($formline, strtoupper($formline), $str);
  692. $str = str_replace("FORMERLY ", "Formerly ", $str);
  693. }
  694. $this->title = $str;
  695. return $str;
  696. }
  697. /**
  698. * This function will load $this will all sorts of descriptive data
  699. * from the database. For example, hours, title, description, etc.
  700. *
  701. * It must be called before any attempts at sorting (by alphabetical order)
  702. * are made on lists of courses.
  703. *
  704. * It will by default try to load this information from cache. If it cannot
  705. * find it in the cache, it will query the database, and then add what it finds
  706. * to the cache.
  707. *
  708. *
  709. * @param bool $bool_load_from_global_cache
  710. * - If set to TRUE, this will attempt to load the course data
  711. * from the "global cache", that is, the cache which is held in the
  712. * GLOBALS array. This should usually be set to TRUE, since this is
  713. * much faster than querying the database.
  714. *
  715. * @param bool $bool_ignore_catalog_year_in_cache
  716. * - If set to TRUE, we will grab whatever is in the cache for this
  717. * course's course_id, regardless of if the catalog years match.
  718. * If set to FALSE, we will try to match the course's catalog year
  719. * in the cache as well.
  720. *
  721. * @param bool $bool_limit_current_catalog_year
  722. * - If set to TRUE, then we will only *query* for the course's
  723. * catalog_year in the db, and those before it (if we do not find
  724. * the exact catalog_year). We will not look for any catalog years
  725. * after it. If set to FALSE, we will look through any
  726. * valid catalog year.
  727. *
  728. * @param bool $bool_force_catalog_year
  729. * - If set to TRUE, we will only look for the course's catalog
  730. * year in the database.
  731. *
  732. * @param bool $bool_ignore_exclude
  733. * - If set to TRUE, we will ignore courses marked as "exclude" in the
  734. * database.
  735. *
  736. */
  737. function load_descriptive_data($bool_load_from_global_cache = true, $bool_ignore_catalog_year_in_cache = true, $bool_limit_current_catalog_year = true, $bool_force_catalog_year = false, $bool_ignore_exclude = false)
  738. {
  739. if ($this->db == null)
  740. {
  741. $this->db = get_global_database_handler();
  742. }
  743. $db = $this->db;
  744. if ($this->catalog_year == "")
  745. {
  746. $this->catalog_year = variable_get("current_catalog_year", 2006); // current catalog_year.
  747. }
  748. $setting_current_catalog_year = variable_get("current_catalog_year", 2006) * 1;
  749. if ($this->bool_use_draft) {
  750. $setting_current_catalog_year = variable_get("current_catalog_draft_year", 2006) * 1;
  751. }
  752. $earliest_catalog_year = variable_get("earliest_catalog_year", 2006);
  753. if ($setting_current_catalog_year < $earliest_catalog_year)
  754. { // If it has not been set, assume the default.
  755. $setting_current_catalog_year = $earliest_catalog_year;
  756. }
  757. if ($bool_limit_current_catalog_year == true && $setting_current_catalog_year > $earliest_catalog_year)
  758. {
  759. if ($this->catalog_year*1 > $setting_current_catalog_year)
  760. {
  761. $this->catalog_year = $setting_current_catalog_year; // current catalog_year.
  762. }
  763. }
  764. if ($this->catalog_year < $earliest_catalog_year && $this->catalog_year != 1900)
  765. {
  766. // Out of range, so set to default
  767. $this->catalog_year = $earliest_catalog_year;
  768. }
  769. $cat_line = "";
  770. if ($bool_force_catalog_year == true)
  771. {
  772. $cat_line = " AND catalog_year = '$this->catalog_year' ";
  773. }
  774. $cache_catalog_year = $this->catalog_year;
  775. if ($bool_ignore_catalog_year_in_cache == true)
  776. {
  777. $cache_catalog_year = 0;
  778. }
  779. if (!isset($this->array_valid_names))
  780. {
  781. $this->array_valid_names = array();
  782. }
  783. // First-- is this course in our GLOBALS cache for courses?
  784. // If it is, then load from that.
  785. if ($bool_load_from_global_cache == true && $this->course_id != 0 &&
  786. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["subject_id"] != "")
  787. {
  788. $this->subject_id = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["subject_id"];
  789. $this->course_num = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["course_num"];
  790. $this->title = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["title"];
  791. $this->description = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["description"];
  792. $this->min_hours = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["min_hours"];
  793. // Reset the ghosthours to default.
  794. $this->bool_ghost_hour = $this->bool_ghost_min_hour = FALSE;
  795. if ($this->min_hours <= 0) {
  796. $this->min_hours = 1;
  797. $this->bool_ghost_min_hour = TRUE;
  798. }
  799. $this->max_hours = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["max_hours"];
  800. if ($this->max_hours <= 0) {
  801. $this->max_hours = 1;
  802. $this->bool_ghost_hour = TRUE;
  803. }
  804. $this->repeat_hours = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["repeat_hours"];
  805. $this->db_exclude = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["db_exclude"];
  806. $this->array_valid_names = $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["array_valid_names"];
  807. return;
  808. }
  809. if ($this->course_id != 0)
  810. {
  811. $exclude_line = " AND exclude = '0' ";
  812. if ($bool_ignore_exclude) {
  813. $exclude_line = "";
  814. }
  815. $table_name = "courses";
  816. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  817. $res = $this->db->db_query("SELECT * FROM $table_name
  818. WHERE course_id = '?'
  819. AND catalog_year = '?'
  820. AND delete_flag = '0'
  821. $exclude_line ", $this->course_id, $this->catalog_year);
  822. $cur = $this->db->db_fetch_array($res);
  823. if ($this->db->db_num_rows($res) < 1)
  824. {
  825. // No results found, so instead pick the most recent
  826. // entry.
  827. $table_name = "courses";
  828. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  829. $res2 = $db->db_query("SELECT * FROM $table_name
  830. WHERE course_id = '?'
  831. AND subject_id != ''
  832. AND delete_flag = '0'
  833. $exclude_line
  834. AND catalog_year <= '$setting_current_catalog_year'
  835. $cat_line
  836. ORDER BY `catalog_year` DESC LIMIT 1", $this->course_id);
  837. $cur = $db->db_fetch_array($res2);
  838. if ($db->db_num_rows($res2) < 1)
  839. {
  840. // Meaning, there were no results found that didn't have
  841. // the exclude flag set.
  842. // So, try to retrieve any course, even if it has
  843. // been excluded (but within our catalog year range)
  844. //$db3 = new DatabaseHandler();
  845. $table_name = "courses";
  846. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  847. $res3 = $db->db_query("SELECT * FROM $table_name
  848. WHERE course_id = '?'
  849. AND subject_id != ''
  850. AND delete_flag = '0'
  851. AND catalog_year <= '$setting_current_catalog_year'
  852. $cat_line
  853. ORDER BY `catalog_year` DESC LIMIT 1", $this->course_id);
  854. $cur = $db->db_fetch_array($res3);
  855. }
  856. }
  857. $this->title = $this->fix_title($cur["title"]);
  858. $this->description = trim($cur["description"]);
  859. $this->subject_id = trim(strtoupper($cur["subject_id"]));
  860. $this->course_num = trim(strtoupper($cur["course_num"]));
  861. $this->min_hours = $cur["min_hours"] * 1; //*1 will trim extra zeros from end of decimals
  862. $this->max_hours = $cur["max_hours"] * 1;
  863. // Reset the ghosthours to default.
  864. $this->bool_ghost_hour = $this->bool_ghost_min_hour = FALSE;
  865. if ($this->min_hours <= 0) {
  866. $this->min_hours = 1;
  867. $this->bool_ghost_min_hour = TRUE;
  868. }
  869. if ($this->max_hours <= 0) {
  870. $this->max_hours = 1;
  871. $this->bool_ghost_hour = TRUE;
  872. }
  873. $this->repeat_hours = $cur["repeat_hours"] * 1;
  874. if ($this->repeat_hours <= 0)
  875. {
  876. $this->repeat_hours = $this->max_hours;
  877. }
  878. $this->db_exclude = $cur["exclude"];
  879. $this->data_entry_comment = $cur["data_entry_comment"];
  880. // Now, lets get a list of all the valid names for this course.
  881. // In other words, all the non-excluded names. For most
  882. // courses, this will just be one name. But for cross-listed
  883. // courses, this will be 2 or more (probably just 2 though).
  884. // Example: MATH 373 and CSCI 373 are both valid names for that course.
  885. $table_name = "courses";
  886. if ($this->bool_use_draft) {$table_name = "draft_$table_name";}
  887. $res = $this->db->db_query("SELECT * FROM $table_name
  888. WHERE course_id = '?'
  889. AND exclude = '0' ", $this->course_id);
  890. while($cur = $this->db->db_fetch_array($res))
  891. {
  892. $si = $cur["subject_id"];
  893. $cn = $cur["course_num"];
  894. if (in_array("$si~$cn", $this->array_valid_names))
  895. {
  896. continue;
  897. }
  898. $this->array_valid_names[] = "$si~$cn";
  899. }
  900. } else if ($this->bool_transfer == true)
  901. {
  902. // This is a transfer credit which did not have a local
  903. // course eqv. At the moment, the subject_id and
  904. // course_num are empty. So, let's fill them in with the
  905. // transfer credit's information.
  906. if ($this->course_transfer != null)
  907. {
  908. $this->subject_id = $this->course_transfer->subject_id;
  909. $this->course_num = $this->course_transfer->course_num;
  910. if ($this->course_transfer->hours_awarded > 0)
  911. {
  912. $this->hours_awarded = $this->course_transfer->hours_awarded;
  913. }
  914. }
  915. }
  916. if ($this->description == "")
  917. {
  918. $this->description = "There is no course description available at this time.";
  919. }
  920. if ($this->title == "")
  921. {
  922. $this->title = "$this->subject_id $this->course_num";
  923. }
  924. // Now, to reduce the number of database calls in the future, save this
  925. // to our GLOBALS cache...
  926. // We do need to go back and correct the ghost hours, setting them
  927. // back to 0 hrs, or else this will be a problem.
  928. $min_hours = $this->min_hours;
  929. $max_hours = $this->max_hours;
  930. if ($this->bool_ghost_min_hour) $min_hours = 0;
  931. if ($this->bool_ghost_hour) $max_hours = 0;
  932. // Since we may have trouble characters in the description (like smart quotes) let's
  933. // do our best to try to clean it up a little.
  934. $this->description = utf8_encode($this->description);
  935. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["subject_id"] = $this->subject_id;
  936. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["course_num"] = $this->course_num;
  937. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["title"] = $this->title;
  938. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["description"] = $this->description;
  939. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["min_hours"] = $min_hours;
  940. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["max_hours"] = $max_hours;
  941. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["repeat_hours"] = $this->repeat_hours;
  942. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["db_exclude"] = $this->db_exclude;
  943. $GLOBALS["fp_course_inventory"][$this->course_id][$cache_catalog_year]["array_valid_names"] = $this->array_valid_names;
  944. $GLOBALS["cache_course_inventory"] = true; // rebuild this cache before it closes.
  945. }
  946. /**
  947. * Similar to load_descriptive_data(), this will load whatever we have
  948. * for $this transfer course.
  949. *
  950. * @param int $student_id
  951. * - If > 0, we will look for the course data which has been
  952. * assigned for this particular student. If it == 0, we will
  953. * just use the first bit of data we find.
  954. *
  955. */
  956. function load_descriptive_transfer_data($student_id = 0)
  957. {
  958. // This method should be called to load transfer course data
  959. // into THIS object. It assumes that $this->course_id is a transfer
  960. // course's ID, which can be looked up in flightpath.transfer_courses.
  961. // If a student_id is specified, it will load eqv information.
  962. if ($this->db == null)
  963. {
  964. $this->db = get_global_database_handler();
  965. }
  966. $res = $this->db->db_query("SELECT * FROM transfer_courses
  967. WHERE transfer_course_id = '?' ", $this->course_id);
  968. $cur = $this->db->db_fetch_array($res);
  969. $this->subject_id = $cur["subject_id"];
  970. $this->course_num = $cur['course_num'];
  971. $this->title = $this->fix_title($cur['title']);
  972. $this->min_hours = $cur["min_hours"] * 1;
  973. $this->max_hours = $cur["max_hours"] * 1;
  974. $this->institution_id = $cur["institution_id"];
  975. // Try to figure out the institution name for this course...
  976. $this->institution_name = $this->db->get_institution_name($this->institution_id);
  977. if ($student_id > 0)
  978. {
  979. // Because transfer credit titles may differ from student
  980. // to student, let's look up the title in the per-student transfer courses table...
  981. $res = $this->db->db_query("SELECT * FROM student_transfer_courses
  982. WHERE student_id = '?'
  983. AND transfer_course_id = '?'
  984. ", $student_id, $this->course_id);
  985. $cur = $this->db->db_fetch_array($res);
  986. if (trim($cur["student_specific_course_title"]) != "") {
  987. $this->title = trim($cur["student_specific_course_title"]);
  988. }
  989. // Also assign hours_awarded while we are here.
  990. $this->hours_awarded = $cur["hours_awarded"] * 1;
  991. $already = array(); // to prevent duplicates from showing up, keep up with
  992. // eqv's we've already recorded.
  993. $res2 = $this->db->db_query("SELECT * FROM transfer_eqv_per_student
  994. WHERE student_id = '?'
  995. AND transfer_course_id = '?'
  996. ", $student_id, $this->course_id);
  997. while($cur2 = $this->db->db_fetch_array($res2))
  998. {
  999. if (!in_array($cur2["local_course_id"], $already)) {
  1000. $c = new Course($cur2["local_course_id"]);
  1001. $this->transfer_eqv_text .= "$c->subject_id $c->course_num
  1002. (" . $c->get_catalog_hours() . " " . t("hrs") . ") ";
  1003. $already[] = $cur2["local_course_id"];
  1004. }
  1005. }
  1006. }
  1007. }
  1008. /**
  1009. * Based on $this->term_id, set what catalog year should go with
  1010. * the course.
  1011. *
  1012. */
  1013. function set_catalog_year_from_term_id()
  1014. {
  1015. if ($this->db == null)
  1016. {
  1017. $this->db = new DatabaseHandler();
  1018. }
  1019. if (strstr($this->term_id, "1111"))
  1020. {
  1021. $this->catalog_year = $GLOBALS["fp_system_settings"]["earliest_catalog_year"];
  1022. }
  1023. $this->catalog_year = trim(substr($this->term_id,0,4));
  1024. // If the catalog year is greater than the currentCatalogYear
  1025. // setting, then set it to that.
  1026. if ($this->catalog_year > $GLOBALS["fp_system_settings"]["current_catalog_year"])
  1027. {
  1028. $this->catalog_year = $GLOBALS["fp_system_settings"]["current_catalog_year"];
  1029. }
  1030. }
  1031. /**
  1032. * Based on $this->term_id, returns a plain english description
  1033. * of the term. For example, 20061 would return "Spring of 2006".
  1034. *
  1035. * @param bool $bool_abbreviate
  1036. * - If set to TRUE, abbreviations will be used. For example,
  1037. * Spring will be "Spr" and 2006 will be '06.
  1038. *
  1039. *
  1040. * @return unknown
  1041. */
  1042. function get_term_description($bool_abbreviate = false)
  1043. {
  1044. // Let's use the built-in FP function
  1045. return get_term_description($this->term_id, $bool_abbreviate);
  1046. }
  1047. /**
  1048. * Basically, this is a comparator function that will return true
  1049. * if $this equals many of the attributes of $course_c. Useful for
  1050. * seeing if $this is an "instance of" a particular course, but not
  1051. * necessairily the course that the student took. Example: if you want
  1052. * to test if MATH 101 is part of a group. You wouldn't use ==, since
  1053. * all the attributes might not be the same.
  1054. *
  1055. * @param Course $course_c
  1056. *
  1057. * @return bool
  1058. */
  1059. function equals_placeholder(Course $course_c)
  1060. {
  1061. // First, see if the courses are identical.
  1062. if ($this->equals($course_c))
  1063. {
  1064. return true;
  1065. }
  1066. // Okay, now we go through and test for particular attributes
  1067. // to be equal.
  1068. if ($this->subject_id == $course_c->subject_id
  1069. && $this->course_num == $course_c->course_num
  1070. && $this->institution == $course_c->institution)
  1071. {
  1072. return true;
  1073. }
  1074. return false;
  1075. }
  1076. /**
  1077. * This is the to_string method for Course. Because we want to pass it
  1078. * values, we are not using the magic method of "__to_string". So, to use,
  1079. * invoke this method directly. Ex:
  1080. *
  1081. * $x = $newCourse->to_string("", true);
  1082. *
  1083. * @param string $pad
  1084. * - How much padding to use. Specified in the form of a string
  1085. * of spaces. Ex: " "
  1086. *
  1087. * @param bool $bool_show_random
  1088. * - Display the randomly assigned number which goes with
  1089. * this course.
  1090. *
  1091. * @return string
  1092. */
  1093. function to_string($pad = " ", $bool_show_random = false)
  1094. {
  1095. $rtn = "";
  1096. if ($this->subject_id == "") {
  1097. $this->load_descriptive_data();
  1098. }
  1099. if ($bool_show_random) {$x = "rnd:$this->random_id -";}
  1100. $rtn = $pad . "$this->course_id $x- $this->subject_id $this->course_num ($this->hours_awarded) $this->grade $this->term_id";
  1101. if ($this->course_list_fulfilled_by->is_empty != true) {
  1102. // In other words, if this is a requirement, and it is
  1103. // being fulfilled by one of the student's courses,
  1104. // then let's see it.
  1105. $rtn .= " ->fulfilled by " . $this->course_list_fulfilled_by->get_first()->to_string("");
  1106. }
  1107. if ($this->bool_transfer == true && is_object($this->course_transfer))
  1108. {
  1109. $rtn .= " - XFER eqv to " . $this->course_transfer->to_string("");
  1110. } else if ($this->bool_transfer == true){
  1111. $rtn .= " - XFER no eqv ";
  1112. }
  1113. if ($this->bool_advised_to_take) {
  1114. $rtn .= " - adv in sem " . $this->assigned_to_semester_num . ".";
  1115. }
  1116. if ($this->bool_substitution) {
  1117. $rtn .= " - substitution.";
  1118. }
  1119. if ($this->bool_exclude_repeat) {
  1120. $rtn .= " - excluded repeat.";
  1121. }
  1122. if ($this->db_exclude > 0) {
  1123. $rtn .= " - db_exclude = $this->db_exclude";
  1124. }
  1125. if ($this->specified_repeats > 0) {
  1126. $rtn .= " reps: $this->specified_repeats";
  1127. }
  1128. $rtn .= "\n";
  1129. return $rtn;
  1130. }
  1131. /**
  1132. * This is the magic method __sleep(). PHP will call this method any time
  1133. * this object is being serialized. It is supposed to return an array of
  1134. * all the variables which need to be serialized.
  1135. *
  1136. * What we are doing in it is skipping
  1137. * any variables which we are not using or which do not need to be
  1138. * serialized. This will greatly reduce the size of the final serialized
  1139. * string.
  1140. *
  1141. * It may not seem worth it at first, but consider that we may be serializing
  1142. * an entire degree plan, with a dozen groups, each with every course in the
  1143. * catalog. That could easily be 10,000+ courses which get serialized!
  1144. *
  1145. * @return array
  1146. */
  1147. function __sleep()
  1148. {
  1149. // This is supposed to return an array with the names
  1150. // of the variables which are supposed to be serialized.
  1151. $arr = array(
  1152. "db_advised_courses_id",
  1153. "db_substitution_id", "db_unassign_transfer_id",
  1154. "db_exclude", "array_index", "db_group_requirement_id", "array_valid_names",
  1155. "data_entry_value",
  1156. "subject_id", "course_num", "course_id", "requirement_type", "catalog_year",
  1157. "min_hours", "max_hours", "repeat_hours", "bool_outdated_sub",
  1158. "bool_taken", "term_id", "section_number", "grade", "hours_awarded", "quality_points",
  1159. "bool_transfer", "institution_id", "institution_name", "course_transfer", "transfer_footnote",
  1160. "bool_substitution", "course_substitution", "substitution_hours",
  1161. "bool_substitution_split", "substitution_footnote", "bool_substitution_new_from_split",
  1162. "min_grade", "specified_repeats", "bool_specified_repeat", "required_on_branch_id",
  1163. "assigned_to_group_id", "assigned_to_semester_num",
  1164. "advised_hours", "bool_selected", "bool_advised_to_take", "bool_use_draft",
  1165. "course_fulfilled_by", "course_list_fulfilled_by",
  1166. "bool_has_been_assigned", "bool_added_course", "group_list_unassigned",
  1167. "display_status", "bool_has_been_displayed", "bool_hide_grade", "bool_ghost_hour",
  1168. "bool_ghost_min_hour",
  1169. );
  1170. // Okay, remove any variables we are not using
  1171. // from the array.
  1172. $rtn = array();
  1173. foreach($arr as $var)
  1174. {
  1175. if (isset($this->$var)) // This checks to see if we are using
  1176. { // the variable or not.
  1177. $rtn[] = $var;
  1178. }
  1179. }
  1180. return $rtn;
  1181. }
  1182. } // end of Course class.