student_priority.module

File

modules/student_priority/student_priority.module
View source
  1. <?php
  2. // TODO: There should be a UI where organizations can turn on and off calculations, assign scores, etc.
  3. function student_priority_menu() {
  4. $items = array();
  5. $items["student-profile/priority-calculations"] = array(
  6. "title" => "Priority Calculations",
  7. "page_callback" => "student_priority_display_priority_calculations_page",
  8. "access_callback" => "system_can_access_student", // make sure we are allowed to access the student specified by current_student_id.
  9. "type" => MENU_TYPE_TAB,
  10. "tab_family" => "priority-calculations",
  11. "page_settings" => array(
  12. "display_currently_advising" => TRUE,
  13. "screen_mode" => "not_advising",
  14. ),
  15. );
  16. return $items;
  17. }
  18. /**
  19. * Displays the calculations used to get the priority values. Can be displayed in either the dialog or stand-alone.
  20. */
  21. function student_priority_display_priority_calculations_page() {
  22. global $current_student_id, $user;
  23. $student_id = $current_student_id;
  24. $rtn = "";
  25. fp_add_css(fp_get_module_path('student_profile') . '/css/style.css');
  26. fp_add_js(fp_get_module_path('advise') . '/js/advise.js');
  27. fp_set_title('');
  28. $rtn .= "";
  29. if ($_GET['window_mode'] == 'popup') {
  30. $rtn .= "<a class='tests-expand-link' href='javascript:parent.window.location=\"" . fp_url("student-profile/priority-calculations", "current_student_id=$current_student_id") . "\"; void(0);'><i class='fa fa-expand'></i> " . t("View full page") . "</a>";
  31. }
  32. $rtn .= "<p>" . t("This system is able to make calculations as to the student's \"Academic Priority\", or, how at-risk the
  33. student is of experiencing significant difficulties.") . "</p>";
  34. $rtn .= "<h3>" . t("Current Academic Priority:") . "</h3>";
  35. $rtn .= "<!--current-academic-priority-->";
  36. $rtn .= "<h3>" . t("Calculations:") . "</h3>";
  37. $rtn .= "<div>" . t("The following calculations were used to determine the student's current Academic Priority. The score value increases their priority average.") . "</div>";
  38. $rtn .= "
  39. <table border='1' style='max-width: 600px;' class='calc-tests-table'>
  40. <tr>
  41. <th width='70%'>Test</th>
  42. <th width='15%'>Result</th>
  43. <th width='15%'>Score</th>
  44. </tr>";
  45. // Get student calculations
  46. $calcs = student_priority_get_calculations_for_student($student_id, TRUE);
  47. foreach ($calcs['calc_test_results'] as $machine_name => $details) {
  48. $result = $result_label = $details['result'];
  49. if (isset($details['result_label'])) $result_label = $details['result_label'];
  50. $score = $details['score'];
  51. $extra = isset($details['extra']) ? trim($details['extra']) : '';
  52. $test_title = $calcs['calc_tests'][$machine_name]['title'];
  53. $test_description = @$calcs['calc_tests'][$machine_name]['description'];
  54. $more_content = "";
  55. $more_toggle = "";
  56. if ($extra != "") {
  57. // click to toggle div
  58. $rnd = md5(mt_rand(0,9999) . mt_rand(99,99999) . microtime());
  59. $more_toggle = "<a href='javascript:void(0);' onclick='jQuery(\"#test-extra-$rnd\").toggle();' class='test-more-toggle' title='Click for more details'><i class='fa fa-ellipsis-h'></i></a>";
  60. $more_content = "<div id='test-extra-$rnd' class='test-extra' style='display:none;'>
  61. $extra
  62. </div>";
  63. }
  64. $bgcolor='white';
  65. if (is_numeric($score)) {
  66. if ($score > 0) $bgcolor = '#fff4f4';
  67. $score = (strlen("$score") == 1) ? number_format($score, 1) : $score; // force at least X num of decimals
  68. }
  69. $rtn .= "<tr>
  70. <td style='background-color: $bgcolor; color: black;'>$more_toggle$test_title$more_content</td>
  71. <td style='background-color: $bgcolor;'>$result_label</td>
  72. <td style='background-color: $bgcolor;'>$score</td>
  73. </tr>";
  74. } // foreach priority_tests
  75. $rtn .= "</table>";
  76. $total_score = $calcs['total'];
  77. $count = $calcs['count'];
  78. $avg = $calcs['avg'];
  79. $percent = $calcs['percent'];
  80. $max_possible = $calcs['max_possible'];
  81. // TODO: these might be controlled by setting one day
  82. $academic_priority_desc = array(
  83. "high" => t("High"),
  84. "medium" => t("Medium"),
  85. "normal" => t("Normal"),
  86. );
  87. $rtn .= "<p><b>Totals:</b> $total_score score / $max_possible max = <b>" . $percent . "</b>%.
  88. </p>
  89. <p>
  90. <b>" . t("Percent Scoring:") . "</b>
  91. <br><span class='profile-priority-bar priority-normal'>" . $academic_priority_desc['normal'] . "</span> 0 to 30
  92. <br><span class='profile-priority-bar priority-medium'>" . $academic_priority_desc['medium'] . "</span> 31 to 70
  93. <br><span class='profile-priority-bar priority-high'>" . $academic_priority_desc['high'] . "</span> 71 to 100
  94. </p>
  95. ";
  96. // Update the "academic priority" field at the top of the page, based on ranges.
  97. $academic_priority = student_priority_get_student_academic_priority_label($percent);
  98. $machine = $academic_priority['machine'];
  99. $label = $academic_priority['label'];
  100. $priority_html = "<span class='profile-priority-bar priority-$machine'>" . $label . "</span>";
  101. $rtn = str_replace("<!--current-academic-priority-->", $priority_html, $rtn);
  102. // Let's set our breadcrumbs
  103. $db = get_global_database_handler();
  104. $crumbs = array();
  105. $crumbs[] = array(
  106. 'text' => 'Students',
  107. 'path' => 'student-search',
  108. );
  109. $crumbs[] = array(
  110. 'text' => $db->get_student_name($current_student_id) . " ($current_student_id)",
  111. 'path' => 'student-profile',
  112. 'query' => "current_student_id=$current_student_id",
  113. );
  114. $crumbs[] = array(
  115. 'text' => t("Student Profile"),
  116. 'path' => 'student-profile',
  117. 'query' => "current_student_id=$current_student_id",
  118. );
  119. fp_set_breadcrumbs($crumbs);
  120. return $rtn;
  121. } //student_priority_display_priority_calculations_page
  122. /**
  123. * Returns 'normal', 'medium', or 'high' based on values.
  124. *
  125. * TODO: Make those values be able to be set by configuration.
  126. *
  127. * TODO: If we have have a student specified, then see if we have a special priority value for them?
  128. *
  129. */
  130. function student_priority_get_student_academic_priority_label($priority_val, $student_id = NULL) {
  131. $academic_priority_label = array(
  132. "high" => "High",
  133. "medium" => "Medium",
  134. "normal" => "Normal",
  135. );
  136. //if ($priority_val == -1) {
  137. // $priority_val = @floatval($student_node->field_priority_value['und'][0]['value']);
  138. //}
  139. $machine = 'normal';
  140. if ($priority_val >= 31 && $priority_val <= 70) $machine = "medium";
  141. if ($priority_val > 70 ) $machine = "high";
  142. $rtn = array();
  143. $rtn['val'] = $priority_val;
  144. $rtn['machine'] = $machine;
  145. $rtn['label'] = $academic_priority_label[$machine];
  146. return $rtn;
  147. }
  148. /**
  149. * Queries for the academic priority value, and if its older than the set number of seconds, we will re-calculate for
  150. * this student. Set to zero to force it to recalculate every time.
  151. */
  152. function student_priority_get_academic_priority_value($student_id, $recalculate_if_older_than = 86400) {
  153. $check_ts = time() - $recalculate_if_older_than;
  154. $val = db_result(db_query('SELECT priority_value FROM student_priority WHERE student_id = ? AND updated > ?', array($student_id, $check_ts)));
  155. if (!$val) {
  156. // Recalculate!
  157. //fpm('recalculating');
  158. $calcs = student_priority_get_calculations_for_student($student_id, TRUE);
  159. $rtn = $calcs['percent'];
  160. return $rtn;
  161. }
  162. return $val;
  163. } // .. get academic priority value
  164. /**
  165. * Run all of the calculations for a student, and return back the results
  166. * in a formatted array.
  167. *
  168. * If bool_save_to_student is true, then we will write the results to the student_priority.
  169. *
  170. */
  171. function student_priority_get_calculations_for_student($student_cwid, $bool_save_to_student = FALSE) {
  172. global $current_student_id, $user, $student;
  173. if (!isset($student) || $student == null || !is_object($student)) {
  174. $student = new Student($current_student_id);
  175. }
  176. $rtn = array();
  177. //load student as object for use in the calculation tests.
  178. $use_student = $student;
  179. if ($student_cwid != $current_student_id) {
  180. $use_student = new Student($student_cwid);
  181. }
  182. $student_user_id = db_get_user_id_from_cwid($use_student->student_id, 'student');
  183. $calc_test_results = array();
  184. $total = 0;
  185. $max_possible = 0;
  186. $count = 0;
  187. // Invoke a hook to run our priority calculations.
  188. // First, get all our tests from all modules.
  189. $calc_tests = array();
  190. invoke_hook('define_calculation_tests', array(&$calc_tests));
  191. /////////////////////////////////
  192. // sort results by weight, title.
  193. /////////////////////////////////
  194. $sorted_calc_tests = array();
  195. $lines = array();
  196. foreach ($calc_tests as $key => $value) {
  197. $lines[] = str_pad($value['weight'], 5, '0', STR_PAD_LEFT) . " ~~~ " . $value['title'] . " ~~~ " . $key;
  198. }
  199. sort($lines);
  200. foreach ($lines as $line) {
  201. $temp = explode("~~~", $line);
  202. $key = trim($temp[2]);
  203. $sorted_calc_tests[$key] = $calc_tests[$key];
  204. }
  205. $calc_tests = $sorted_calc_tests;
  206. //////////////////////////
  207. $rtn['calc_tests'] = $calc_tests;
  208. foreach ($calc_tests as $callback => $details) {
  209. $file = @$details['file']; // 0 = module, 1 = filename
  210. if ($file) {
  211. $x = include_once(fp_get_module_path($file[0], TRUE, FALSE) . "/" . $file[1]);
  212. if (!$x) {
  213. fpm('Could not load include file:' . fp_get_module_path($file[0], TRUE, FALSE) . "/" . $file[1]);
  214. }
  215. // Now execute the callback.
  216. $calc_test_results[$callback] = call_user_func_array($callback, array($use_student));
  217. }
  218. // Are we instead looking for a user attribute?
  219. if (isset($details['result_from_user_attribute'])) {
  220. $val = user_get_attribute($student_user_id, $details['result_from_user_attribute']);
  221. if ($val == '') {
  222. $val = 'SKIP';
  223. }
  224. $calc_test_results[$callback]['result'] = $val;
  225. $calc_test_results[$callback]['result_label'] = $val;
  226. // If we have the original options we can use for the label, use that.
  227. //fpm($details);
  228. if (isset($details['options'][$val])) {
  229. $calc_test_results[$callback]['result_label'] = $details['options'][$val];
  230. }
  231. }
  232. $raw_score = $details['result_scores'][$calc_test_results[$callback]['result']];
  233. // If the raw_score is "SKIP" then we don't want to count this at all.
  234. if (is_numeric($raw_score)) {
  235. $score = floatval($raw_score);
  236. $calc_test_results[$callback]['score'] = $score;
  237. // Figure out the max possible score from this test.
  238. $test_max_score = 0;
  239. foreach ($details['result_scores'] as $k => $v) {
  240. $v = floatval($v);
  241. if ($v > $test_max_score) $test_max_score = $v;
  242. }
  243. $max_possible += $test_max_score;
  244. $total = $total + $score;
  245. $count++;
  246. }
  247. else {
  248. $calc_test_results[$callback]['score'] = $raw_score;
  249. }
  250. } // foreach
  251. $avg = 0;
  252. if ($count > 0) {
  253. $avg = round($total / $count, 2);
  254. }
  255. $percent = 0;
  256. if ($max_possible > 0) {
  257. $percent = round(($total / $max_possible * 100), 2);
  258. }
  259. $rtn['calc_test_results'] = $calc_test_results;
  260. $rtn['count'] = $count;
  261. $rtn['total'] = $total;
  262. $rtn['avg'] = $avg;
  263. $rtn['max_possible'] = $max_possible;
  264. $rtn['percent'] = $percent;
  265. // Should we save the value to the student_priority table?
  266. if ($bool_save_to_student) {
  267. db_query('REPLACE INTO student_priority (student_id, priority_value, results, updated)
  268. VALUES (?, ?, ?, ?) ', array($student_cwid, $percent, serialize($rtn), time()));
  269. }
  270. return $rtn;
  271. } // student_priority_get_calculations_for_student($student_nid)
  272. // See the *api.php file for an example of how to create tests.

Functions

Namesort descending Description
student_priority_display_priority_calculations_page Displays the calculations used to get the priority values. Can be displayed in either the dialog or stand-alone.
student_priority_get_academic_priority_value Queries for the academic priority value, and if its older than the set number of seconds, we will re-calculate for this student. Set to zero to force it to recalculate every time.
student_priority_get_calculations_for_student Run all of the calculations for a student, and return back the results in a formatted array.
student_priority_get_student_academic_priority_label Returns 'normal', 'medium', or 'high' based on values.
student_priority_menu