Skip to content

Commit 5fe7a53

Browse files
authored
Merge pull request #158 from ComputerScienceHouse/develop
Updating Parsing Script
2 parents 31887a7 + 613893e commit 5fe7a53

File tree

2 files changed

+550
-520
lines changed

2 files changed

+550
-520
lines changed

tools/Parser.php

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
<?php
2+
3+
namespace Tools;
4+
5+
6+
use mysqli;
7+
use mysqli_result;
8+
9+
/**
10+
* Dump Parser
11+
*
12+
* A parsing object used by the processDump script
13+
*
14+
* @package Tools
15+
*/
16+
class Parser {
17+
18+
private $dbConn;
19+
public $debugMode;
20+
private $quietMode;
21+
22+
public function __construct(mysqli $dbConn, array $arguments) {
23+
$this->dbConn = $dbConn;
24+
$this->debugMode = in_array("-d", $arguments);
25+
$this->quietMode = in_array("-q", $arguments);
26+
if (in_array("-c", $arguments)) {
27+
// Cleanup mode cleans up old partial parses
28+
$this->cleanup();
29+
die();
30+
}
31+
}
32+
33+
function cleanup() {
34+
// Emit a debug message
35+
$this->debug("... Cleaning up temporary tables");
36+
37+
// Drop the temporary tables
38+
if (!mysqli_query($this->dbConn, "DROP TABLE classes")) {
39+
echo("*** Failed to drop table classes (ignored)\n");
40+
echo(" " . mysqli_error($this->dbConn) . "\n");
41+
}
42+
if (!mysqli_query($this->dbConn, "DROP TABLE meeting")) {
43+
echo("*** Failed to drop table meeting (ignored)\n");
44+
echo(" " . mysqli_error($this->dbConn) . "\n");
45+
}
46+
if (!mysqli_query($this->dbConn, "DROP TABLE instructors")) {
47+
echo("*** Failed to drop table instructor (ignored)\n");
48+
echo(" " . mysqli_error($this->dbConn) . "\n");
49+
}
50+
}
51+
52+
function debug($str, $nl = true) {
53+
if ($this->debugMode) {
54+
echo($str . (($nl) ? "\n" : ""));
55+
}
56+
}
57+
58+
function cleanupExtraResults($dbConn) {
59+
// While there are more results, free them
60+
while (mysqli_next_result($dbConn)) {
61+
$set = mysqli_use_result($dbConn);
62+
if ($set instanceof mysqli_result) {
63+
mysqli_free_result($set);
64+
}
65+
}
66+
}
67+
68+
/**
69+
* Outputs error messages, cleans up temporaray tables, then dies
70+
* NOTE: Halts execution via die();
71+
* @param $messages mixed Array of messages to output
72+
*/
73+
function halt($messages) {
74+
// Iterate over the messages, cleanup and die
75+
if (is_array($messages)) {
76+
foreach ($messages as $message) {
77+
echo "*** {$message}\n";
78+
}
79+
} else {
80+
echo "*** {$messages}\n";
81+
}
82+
$this->cleanup();
83+
die();
84+
}
85+
86+
/**
87+
* Inserts or updates a course. This function calls the stored procedure for
88+
* inserting or updating a course.
89+
* @param $quarter int The term that the course is in
90+
* @param $departCode string The code of the department
91+
* @param $classCode string The code for the class
92+
* @param $course int The number of the course
93+
* @param $credits int The credits the course offers
94+
* @param $title string The title of the course
95+
* @param $description string The description for the course
96+
* @return mixed String of error message returned on failure.
97+
* Integer of course ID returned on success
98+
*/
99+
function insertOrUpdateCourse(int $quarter, string $departCode, string $classCode, int $course, int $credits, string $title, string $description) {
100+
global $coursesUpdated, $coursesAdded;
101+
// Call the stored proc
102+
// TODO: Refactor out department ID number (0000)
103+
$query = "CALL InsertOrUpdateCourse({$quarter}, 0000, '{$classCode}', '{$course}', {$credits}, '{$title}', '{$description}')";
104+
$success = mysqli_multi_query($this->dbConn, $query);
105+
106+
// Catch errors or return the id
107+
if (!$success) {
108+
// If the class code errors out, try the department code
109+
// TODO: Refactor out department ID number (0000)
110+
$query = "CALL InsertOrUpdateCourse({$quarter}, 0000, '{$departCode}', '{$course}', {$credits}, '{$title}', '{$description}')";
111+
$success = mysqli_multi_query($this->dbConn, $query);
112+
if (!$success) {
113+
return mysqli_error($this->dbConn);
114+
}
115+
}
116+
117+
// First result set is updated vs inserted
118+
$actionSet = mysqli_store_result($this->dbConn);
119+
$action = mysqli_fetch_assoc($actionSet);
120+
if ($action['action'] == "updated") {
121+
$coursesUpdated++;
122+
} else {
123+
$coursesAdded++;
124+
}
125+
mysqli_free_result($actionSet);
126+
127+
// Second set is the id of the course
128+
mysqli_next_result($this->dbConn);
129+
$idSet = mysqli_store_result($this->dbConn);
130+
$id = mysqli_fetch_assoc($idSet);
131+
132+
// Free up the other calls
133+
mysqli_free_result($idSet);
134+
$this->cleanupExtraResults($this->dbConn);
135+
136+
return $id['id'];
137+
}
138+
139+
function insertOrUpdateSection($courseId, $section, $title, $instructor, $type, $status, $maxenroll, $curenroll) {
140+
global $sectUpdated, $sectAdded;
141+
142+
// Query to call the stored proc
143+
$query = "CALL InsertOrUpdateSection({$courseId}, '{$section}', '{$title}', '{$instructor}', '{$type}', '{$status}',";
144+
$query .= "{$maxenroll},{$curenroll})";
145+
146+
// Error check
147+
if (!mysqli_multi_query($this->dbConn, $query)) {
148+
return mysqli_error($this->dbConn);
149+
}
150+
151+
// First result is the action performed
152+
$actionSet = mysqli_store_result($this->dbConn);
153+
$action = mysqli_fetch_assoc($actionSet);
154+
if ($action['action'] == "updated") {
155+
$sectUpdated++;
156+
} else {
157+
$sectAdded++;
158+
}
159+
mysqli_free_result($actionSet);
160+
161+
// Second result is the
162+
mysqli_next_result($this->dbConn);
163+
$idSet = mysqli_store_result($this->dbConn);
164+
$id = mysqli_fetch_assoc($idSet);
165+
166+
// Free up other results
167+
mysqli_free_result($idSet);
168+
$this->cleanupExtraResults($this->dbConn);
169+
170+
return $id['id'];
171+
}
172+
173+
function getTempSections($courseNum, $offerNum, $term, $sessionNum) {
174+
// Query for the sections of the course
175+
$query = "SELECT class_section,descr,topic,enrl_stat,class_stat,class_type,enrl_cap,enrl_tot,instruction_mode,schedule_print ";
176+
$query .= "FROM classes WHERE crse_id={$courseNum} AND crse_offer_nbr={$offerNum} AND strm={$term} ";
177+
$query .= "AND session_code='{$sessionNum}'";
178+
$results = mysqli_query($this->dbConn, $query);
179+
180+
// Check for errors
181+
if (!$results) {
182+
return mysqli_error($this->dbConn);
183+
}
184+
185+
// Turn the results into an array of results
186+
// @TODO: Can we do this with fetch_all? Do we have mysql_nd?
187+
$list = [];
188+
while ($row = mysqli_fetch_assoc($results)) {
189+
$list[] = $row;
190+
}
191+
return $list;
192+
}
193+
194+
function fileToTempTable(string $tableName, $file, $fields, $fileSize, string $procFunc = null) {
195+
// Process the file
196+
$procBytes = 0;
197+
$outPercent = [0];
198+
$this->debug("... Copying {$tableName} file to temporary table\n0%", false);
199+
while ($str = fgets($file, 4096)) {
200+
// Trim those damn newlines
201+
$str = trim($str);
202+
203+
// Progress bar
204+
if ($this->debugMode) {
205+
$percent = floor(($procBytes / $fileSize) * 100);
206+
if ($percent % 10 == 0 && !in_array($percent, $outPercent)) {
207+
$outPercent[] = $percent;
208+
echo("...{$percent}%");
209+
}
210+
}
211+
212+
// If we don't have 23 pipes, then we need to read another line
213+
$lineSplit = explode("|", $str);
214+
while (count($lineSplit) < $fields + 1) {
215+
$str .= fgets($file, 4096);
216+
$lineSplit = explode("|", $str);
217+
}
218+
$procBytes += strlen($str) + 1;
219+
220+
// If we don't have $fields+1 fields, shit's borked
221+
if (count($lineSplit) != $fields + 1) {
222+
echo("*** Malformed line {$fields}, " . count($lineSplit) . "\n");
223+
echo($str . "\n");
224+
continue;
225+
}
226+
227+
// We only need the first $fields, otherwise imploding will break
228+
$lineSplit = array_splice($lineSplit, 0, $fields, true);
229+
230+
// Call the special attribute processing function
231+
if ($procFunc) {
232+
$lineSplit = call_user_func([$this, $procFunc], $lineSplit);
233+
if ($lineSplit === false) {
234+
// The proc function doesn't want us to proceed with
235+
// this line
236+
continue;
237+
}
238+
}
239+
240+
// Build a query
241+
$insQuery = "INSERT INTO {$tableName} VALUES('" . implode("', '", $lineSplit) . "')";
242+
if (!mysqli_query($this->dbConn, $insQuery)) {
243+
echo("*** Failed to insert {$tableName}\n");
244+
echo(" " . mysqli_error($this->dbConn) . "\n");
245+
continue;
246+
}
247+
}
248+
249+
$this->debug("...100%");
250+
}
251+
252+
// Process the class file
253+
function procClassArray(array $lineSplit): array {
254+
// Escape class title, description, and course number (since it needs to be trimmed)
255+
$lineSplit[6] = $this->dbConn->real_escape_string(trim($lineSplit[6]));
256+
$lineSplit[7] = $this->dbConn->real_escape_string($lineSplit[7]);
257+
$lineSplit[8] = $this->dbConn->real_escape_string(trim($lineSplit[8]));
258+
$lineSplit[23] = $this->dbConn->real_escape_string($lineSplit[23]);
259+
260+
// Grab the integer credit count (they give it to us as a decimal)
261+
preg_match('/(\d)+\.\d\d/', $lineSplit[11], $match);
262+
$lineSplit[11] = $match[1];
263+
264+
// Make the section number at least 2 digits
265+
$lineSplit[4] = str_pad($lineSplit[4], 2, '0', STR_PAD_LEFT);
266+
return $lineSplit;
267+
}
268+
269+
// Process the meeting pattern file
270+
function procMeetArray(array $lineSplit) {
271+
// Turn the start/end times from 03:45 PM to 154500
272+
// Hours must be mod'd by 12 so 12:00 PM does not become
273+
// 24:00 and 12 AM does not become 12:00
274+
$timePreg = "/(\d\d):(\d\d) ([A-Z]{2})/";
275+
if (!preg_match($timePreg, $lineSplit[10], $start) || !preg_match($timePreg, $lineSplit[11], $end)) {
276+
// Odds are the class is TBD (which means we can't represent it)
277+
return false;
278+
}
279+
$lineSplit[10] = (($start[3] == 'PM') ? ($start[1] % 12) + 12 : $start[1] % 12) . $start[2] . "00";
280+
$lineSplit[11] = (($end[3] == 'PM') ? ($end[1] % 12) + 12 : $end[1] % 12) . $end[2] . "00";
281+
282+
// Section number needs to be padded to at least 2 digits
283+
$lineSplit[4] = str_pad($lineSplit[4], 2, '0', STR_PAD_LEFT);
284+
return $lineSplit;
285+
}
286+
287+
function procInstrArray(array $lineSplit): array {
288+
// Escape the instructor names
289+
$lineSplit[6] = mysqli_real_escape_string($this->dbConn, $lineSplit[6]);
290+
$lineSplit[7] = mysqli_real_escape_string($this->dbConn, $lineSplit[7]);
291+
292+
// Section number needs to be padded to at lease 2 digits
293+
$lineSplit[4] = str_pad($lineSplit[4], 2, '0', STR_PAD_LEFT);
294+
return $lineSplit;
295+
}
296+
}

0 commit comments

Comments
 (0)