diff --git a/application/modules/courses/models/ApprovalActionMakeOfficialModel.php b/application/modules/courses/models/ApprovalActionMakeOfficialModel.php index 87f2451ca2d419d66c5bb5e9a4721d4347d77120..a2a5051629ebe5fb7ac5d8f684b76ceeb4f59470 100644 --- a/application/modules/courses/models/ApprovalActionMakeOfficialModel.php +++ b/application/modules/courses/models/ApprovalActionMakeOfficialModel.php @@ -105,6 +105,30 @@ class Courses_ApprovalActionMakeOfficialModel extends Requests_ApprovalActionMod Requests_RequestModel::save($requests); $courses = Courses_CourseModel::findLatestOfRequest($requests); + $parentCourses = Courses_CourseModel::findParentOfRequest($requests); + + // Update all references to changed course codes in other courses. + foreach ($requests as $request) { + $course = $courses[$request->getId()]; + $parentCourse = $parentCourses[$request->getId()]; + if (!$parentCourse) { + continue; + } + + foreach ($course->getChangedCourseCodes($parentCourse) as $change) { + if ($change['from']['subject'] != $change['to']['subject']) { + continue; + } + Courses_CourseModel::updateCourseNumber( + $change['from']['subject'], + $change['from']['courseNumber'], + $change['from']['courseLetter'], + $change['to']['courseNumber'], + $change['to']['courseLetter'] + ); + } + } + foreach ($courses as $course) { $course->setType('official'); } diff --git a/application/modules/courses/models/CourseModel.php b/application/modules/courses/models/CourseModel.php index bd06fce75f70a38c0a349e02f9d09e87a4112a13..ce627ffeeffff150e23386bb0c2dcf13bf302e47 100644 --- a/application/modules/courses/models/CourseModel.php +++ b/application/modules/courses/models/CourseModel.php @@ -3645,5 +3645,100 @@ class Courses_CourseModel extends Unl_Model ) ); } + + public function getChangedCourseCodes(self $parentCourse = NULL) + { + if (!$parentCourse) { + return array(); + } + + $parentCrosslistings = array(); + foreach ($parentCourse->getCrosslistings() as $crosslisting) { + $parentCrosslistings[$crosslisting['type']][$crosslisting['subject']][] = array( + 'subject' => $crosslisting['subject'], + 'courseNumber' => $crosslisting['courseNumber'], + 'courseLetter' => $crosslisting['courseLetter'] + ); + usort($parentCrosslistings[$crosslisting['type']][$crosslisting['subject']], function($a, $b) { + return strcmp($a['courseNumber'] . $a['courseLetter'], $b['courseNumber'] . $b['courseLetter']); + }); + ksort($parentCrosslistings[$crosslisting['type']]); + } + + $currentCrosslistings = array(); + foreach ($this->getCrosslistings() as $crosslisting) { + $currentCrosslistings[$crosslisting['type']][$crosslisting['subject']][] = array( + 'subject' => $crosslisting['subject'], + 'courseNumber' => $crosslisting['courseNumber'], + 'courseLetter' => $crosslisting['courseLetter'] + ); + usort($currentCrosslistings[$crosslisting['type']][$crosslisting['subject']], function($a, $b) { + return strcmp($a['courseNumber'] . $a['courseLetter'], $b['courseNumber'] . $b['courseLetter']); + }); + ksort($currentCrosslistings[$crosslisting['type']]); + } + + foreach ($parentCrosslistings as $type => $p) { + foreach ($p as $subject => $courseNumbers) { + foreach ($courseNumbers as $courseNumber) { + if (($key = array_search($courseNumber, $currentCrosslistings[$type][$subject])) !== FALSE) { + unset($currentCrosslistings[$type][$subject][$key]); + } + } + } + } + foreach ($currentCrosslistings as $type => $p) { + foreach ($p as $subject => $courseNumbers) { + foreach ($courseNumbers as $courseNumber) { + if (($key = array_search($courseNumber, $parentCrosslistings[$type][$subject])) !== FALSE) { + unset($parentCrosslistings[$type][$subject][$key]); + } + } + } + } + + $changes = array(); + $map = function($fromNumbers, $toNumbers) use (&$map, &$changes) { + if (count($fromNumbers) == 0 || count($toNumbers) == 0) { + return array(); + } + + $minDiff = 9999999; + $minTiebreaker = 9999999; + foreach ($fromNumbers as $fromKey => $fromNumber) { + foreach ($toNumbers as $toKey => $toNumber) { + $diff = levenshtein(implode('', $fromNumber), implode('', $toNumber)); + $tieBreaker = abs($fromNumber['courseNumber'] - $toNumber['courseNumber']); + if ($diff <= $minDiff && $tieBreaker < $minTiebreaker) { + $minDiff = $diff; + $minTiebreaker = $tieBreaker; + $finalFromKey = $fromKey; + $finalToKey = $toKey; + } + } + } + + $change = array( + 'from' => $fromNumbers[$finalFromKey], + 'to' => $toNumbers[$finalToKey], + ); + + unset($fromNumbers[$finalFromKey]); + unset($toNumbers[$finalToKey]); + + $changes += $map($fromNumbers, $toNumbers); + $changes[] = $change; + + return $changes; + }; + + foreach ($parentCrosslistings as $type => $p) { + foreach ($p as $subject => $courseNumbers) { + $map($courseNumbers, $currentCrosslistings[$type][$subject]); + } + } + + return $changes; + } }