Skip to main content

Overview

The Course Management system allows administrators to create courses by linking teachers with subjects. Courses form the foundation for enrollments, grade tracking, and timetable scheduling.

Course Creation

Link teachers with subjects to create courses

Course Listing

View all active courses with teacher and subject details

Course Deletion

Remove courses and cascade-delete related data

Teacher Assignment

Assign specific teachers to courses

What is a Course?

A course represents a specific subject taught by a specific teacher. For example:
  • “Mathematics taught by Mr. Smith”
  • “Physics taught by Dr. Johnson”
  • “English taught by Ms. Williams”
Course Components:
  • Subject: The academic subject (e.g., Mathematics, Physics)
  • Teacher: The assigned instructor for this course instance
  • Unique Instance: Each teacher-subject combination is a separate course

Course Architecture

Database Schema

CREATE TABLE courses (
    id INT PRIMARY KEY AUTO_INCREMENT,
    subject_id INT NOT NULL,
    teacher_id INT NOT NULL,
    FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE,
    FOREIGN KEY (teacher_id) REFERENCES teachers(id) ON DELETE CASCADE
);

CREATE TABLE subjects (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL
);
The courses table creates relationships between subjects and teachers, enabling:
  • Multiple teachers teaching the same subject
  • One teacher teaching multiple subjects
  • Flexible course assignment

Course Operations

Viewing All Courses

Administrators can view all courses with detailed information:
// CourseController.php - index()
public function index()
{
    Auth::admin(); // Only admins can view all courses

    $courseModel = new Course();
    $courses = $courseModel->getAll();

    require __DIR__ . '/../views/courses/index.php';
}
// Course.php - getAll()
public function getAll()
{
    return $this->db->query("
        SELECT 
            courses.id, 
            subjects.name AS subject_name, 
            users.name AS teacher_name
        FROM courses
        JOIN subjects ON courses.subject_id = subjects.id
        JOIN teachers ON courses.teacher_id = teachers.id
        JOIN users ON teachers.id = users.id
    ")->fetchAll(PDO::FETCH_ASSOC);
}
This query performs three JOINs:
  1. courses → subjects: Get the subject name
  2. courses → teachers: Link to teacher records
  3. teachers → users: Get teacher’s actual name and details
The result includes course ID, subject name, and teacher name for display.

Creating Courses

Course creation requires selecting a subject and teacher:
// CourseController.php - create()
public function create()
{
    Auth::admin();

    $subjectModel = new Subject();
    $teacherModel = new Teacher();

    // Load available subjects and teachers for dropdown selection
    $subjects = $subjectModel->all();
    $teachers = $teacherModel->all();

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $courseModel = new Course();
        $courseModel->create(
            $_POST['subject_id'],
            $_POST['teacher_id']
        );

        header("Location: /courses");
        exit;
    }

    require __DIR__ . '/../views/courses/create.php';
}
// Course.php - create()
public function create($subject_id, $teacher_id)
{
    $stmt = $this->db->prepare(
        "INSERT INTO courses (subject_id, teacher_id) VALUES (?, ?)"
    );
    $stmt->execute([$subject_id, $teacher_id]);
}
Creation Workflow:
  1. Admin navigates to course creation page
  2. System loads all available subjects and teachers
  3. Admin selects subject from dropdown
  4. Admin selects teacher from dropdown
  5. System creates course linking the two

Deleting Courses

Deleting a course removes it and all related data:
// CourseController.php - delete()
public function delete()
{
    Auth::admin();

    $courseModel = new Course();
    $courseModel->delete($_GET['id']);

    header("Location: /courses");
    exit;
}
// Course.php - delete()
public function delete($id)
{
    $stmt = $this->db->prepare("DELETE FROM courses WHERE id = ?");
    $stmt->execute([$id]);
}
Cascade Effects: Deleting a course automatically removes:
  • All student enrollments in this course
  • All grades associated with this course
  • All timetable entries for this course
This is handled by database foreign key constraints with ON DELETE CASCADE.

Teacher-Specific Course Queries

Getting Courses by Teacher

Teachers can view only their assigned courses:
// Course.php - getByTeacher()
public function getByTeacher($teacher_id)
{
    $stmt = $this->db->prepare("
        SELECT courses.id, subjects.name
        FROM courses
        JOIN subjects ON courses.subject_id = subjects.id
        WHERE courses.teacher_id = ?
    ");
    $stmt->execute([$teacher_id]);
    return $stmt->fetchAll();
}
Usage example from GradeController:
// GradeController.php - myCourses()
public function myCourses()
{
    Auth::teacher();

    $teacher_id = $_SESSION['user']['id'];
    $courses = $this->courseModel->getByTeacher($teacher_id);

    require __DIR__ . '/../views/grades/my_courses.php';
}

Verifying Course Ownership

Security check to ensure teachers can only access their own courses:
// Course.php - belongsToTeacher()
public function belongsToTeacher($course_id, $teacher_id)
{
    $stmt = $this->db->prepare(
        "SELECT COUNT(*) FROM courses WHERE id = ? AND teacher_id = ?"
    );
    $stmt->execute([$course_id, $teacher_id]);
    return $stmt->fetchColumn() > 0;
}
Usage example with authorization:
// GradeController.php - students()
public function students($course_id)
{
    Auth::teacher();

    $teacher_id = $_SESSION['user']['id'];

    // Security: Ensure course belongs to this teacher
    if (!$this->courseModel->belongsToTeacher($course_id, $teacher_id)) {
        header("Location: /grades");
        exit;
    }

    $students = $this->gradeModel->getStudentsByCourse($course_id);
    require __DIR__ . '/../views/grades/students.php';
}
Security Pattern: Always verify course ownership before allowing teachers to:
  • View enrolled students
  • Enter or modify grades
  • Access course-specific data

Timetable Integration

Getting Courses for Timetable

Special query for timetable creation with full course details:
// Course.php - getForTimetable()
public function getForTimetable()
{
    $sql = "
        SELECT 
            courses.id,
            subjects.name AS subject,
            users.name AS teacher
        FROM courses
        JOIN subjects ON subjects.id = courses.subject_id
        JOIN teachers ON teachers.id = courses.teacher_id
        JOIN users ON users.id = teachers.id
        ORDER BY subjects.name
    ";

    return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
This provides a formatted list showing:
  • Course ID (for database operations)
  • Subject name (e.g., “Mathematics”)
  • Teacher name (e.g., “Mr. Smith”)
  • Sorted alphabetically by subject

Finding Course Details

Retrieve complete course information:
// Course.php - find()
public function find($id)
{
    $stmt = $this->db->prepare("SELECT * FROM courses WHERE id = ?");
    $stmt->execute([$id]);
    return $stmt->fetch(PDO::FETCH_ASSOC);
}
Used in timetable conflict detection:
// TimetableController.php - create()
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $course_id = $_POST['course_id'];
    $day = $_POST['day'];
    $start = $_POST['start_time'];
    $end = $_POST['end_time'];

    // Get teacher from selected course
    $course = $courseModel->find($course_id);
    $teacher_id = $course['teacher_id'];

    // Check if teacher has scheduling conflict
    if ($this->model->teacherHasConflict($teacher_id, $day, $start, $end)) {
        $_SESSION['error'] = "Teacher already has another course at this time.";
        header("Location: /timetable/create");
        exit;
    }

    $this->model->create($course_id, $day, $start, $end);
}

Course Model Complete Reference

// Course.php - Full implementation
class Course
{
    private $db;

    public function __construct()
    {
        $this->db = Database::getInstance()->getConnection();
    }

    // Get all courses with subject and teacher names
    public function getAll()
    {
        return $this->db->query("
            SELECT courses.id, subjects.name AS subject_name, 
                   users.name AS teacher_name
            FROM courses
            JOIN subjects ON courses.subject_id = subjects.id
            JOIN teachers ON courses.teacher_id = teachers.id
            JOIN users ON teachers.id = users.id
        ")->fetchAll(PDO::FETCH_ASSOC);
    }

    // Create new course
    public function create($subject_id, $teacher_id)
    {
        $stmt = $this->db->prepare(
            "INSERT INTO courses (subject_id, teacher_id) VALUES (?, ?)"
        );
        $stmt->execute([$subject_id, $teacher_id]);
    }

    // Delete course
    public function delete($id)
    {
        $stmt = $this->db->prepare("DELETE FROM courses WHERE id = ?");
        $stmt->execute([$id]);
    }

    // Get courses taught by specific teacher
    public function getByTeacher($teacher_id)
    {
        $stmt = $this->db->prepare("
            SELECT courses.id, subjects.name
            FROM courses
            JOIN subjects ON courses.subject_id = subjects.id
            WHERE courses.teacher_id = ?
        ");
        $stmt->execute([$teacher_id]);
        return $stmt->fetchAll();
    }

    // Verify course belongs to teacher
    public function belongsToTeacher($course_id, $teacher_id)
    {
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) FROM courses WHERE id = ? AND teacher_id = ?"
        );
        $stmt->execute([$course_id, $teacher_id]);
        return $stmt->fetchColumn() > 0;
    }

    // Get formatted course list for timetable
    public function getForTimetable()
    {
        $sql = "
            SELECT 
                courses.id,
                subjects.name AS subject,
                users.name AS teacher
            FROM courses
            JOIN subjects ON subjects.id = courses.subject_id
            JOIN teachers ON teachers.id = courses.teacher_id
            JOIN users ON users.id = teachers.id
            ORDER BY subjects.name
        ";
        return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }

    // Find course by ID
    public function find($id)
    {
        $stmt = $this->db->prepare("SELECT * FROM courses WHERE id = ?");
        $stmt->execute([$id]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}

API Endpoints

MethodEndpointAccessDescription
GET/coursesAdminList all courses
GET/courses/createAdminShow course creation form
POST/courses/createAdminCreate new course
GET/courses/delete?id={id}AdminDelete course
GET/gradesTeacherView teacher’s courses

Use Cases

Steps:
  1. Admin navigates to /courses/create
  2. Selects “Mathematics” from subjects dropdown
  3. Selects “Mr. Smith” from teachers dropdown
  4. Submits form
  5. System creates course with subject_id and teacher_id
  6. Course appears in listings as “Mathematics - Mr. Smith”
Steps:
  1. Teacher logs in and navigates to grades section
  2. System calls getByTeacher() with teacher’s ID
  3. Returns only courses assigned to this teacher
  4. Teacher sees list: “Mathematics”, “Algebra”, etc.
  5. Teacher can select course to view enrolled students
Steps:
  1. Admin views course list
  2. Clicks delete on “Physics - Dr. Johnson”
  3. System deletes course record
  4. Database automatically cascades:
    • Removes all enrollments
    • Removes all grades
    • Removes timetable entries
  5. Students no longer see this course

Relationship Diagram

┌─────────────┐
│  Subjects   │
│─────────────│
│ id (PK)     │
│ name        │
└──────┬──────┘

       │ subject_id

┌─────────────┐      teacher_id      ┌─────────────┐
│   Courses   │◄─────────────────────│  Teachers   │
│─────────────│                      │─────────────│
│ id (PK)     │                      │ id (PK)     │
│ subject_id  │                      └─────────────┘
│ teacher_id  │
└──────┬──────┘

       │ course_id (referenced by)

       ├─► Enrollments
       ├─► Grades
       └─► Timetable
Courses are the central entity connecting subjects, teachers, students, grades, and timetables. All academic activities flow through courses.

Build docs developers (and LLMs) love