Skip to main content

Overview

The Enrollment Management system allows administrators to register students in courses, manage course rosters, and prevent duplicate enrollments. Enrollments create the link between students and courses, enabling grade tracking and timetable access.

Student Enrollment

Register students in specific courses

Enrollment Listing

View all active enrollments with student and course details

Duplicate Prevention

Automatic detection of duplicate enrollments

Enrollment Deletion

Remove students from courses

What is an Enrollment?

An enrollment represents a student’s registration in a specific course. For example:
  • “John Doe enrolled in Mathematics (taught by Mr. Smith)”
  • “Jane Smith enrolled in Physics (taught by Dr. Johnson)”
Enrollment Components:
  • Student: The enrolled student
  • Course: The specific course instance (subject + teacher)
  • Composite Key: Combination of student_id and course_id must be unique

Database Schema

CREATE TABLE enrollments (
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    PRIMARY KEY (student_id, course_id),
    FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
    FOREIGN KEY (course_id) REFERENCES courses(id) ON DELETE CASCADE
);
Composite Primary Key:
  • Uses both student_id and course_id as primary key
  • Automatically prevents duplicate enrollments at database level
  • A student can only be enrolled once in any given course
Cascade Deletion:
  • If student is deleted, all their enrollments are removed
  • If course is deleted, all enrollments in that course are removed
  • Maintains data integrity automatically

Enrollment Operations

Viewing All Enrollments

Administrators can view complete enrollment roster:
// EnrollmentController.php - index()
public function index()
{
    Auth::admin(); // Only admins can view all enrollments

    $enrollments = $this->enrollmentModel->getAll();
    require __DIR__ . '/../views/enrollments/index.php';
}
// Enrollment.php - getAll()
public function getAll()
{
    $sql = "SELECT 
                students.id AS student_id,
                users.name AS student_name,
                subjects.name AS subject_name,
                courses.id AS course_id
            FROM enrollments
            JOIN students ON enrollments.student_id = students.id
            JOIN users ON students.id = users.id
            JOIN courses ON enrollments.course_id = courses.id
            JOIN subjects ON courses.subject_id = subjects.id";

    return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
This complex query joins multiple tables:
  1. enrollments → students: Get student information
  2. students → users: Get student name and details
  3. enrollments → courses: Get course information
  4. courses → subjects: Get subject name
Result includes:
  • Student ID and name
  • Course ID and subject name
  • All data needed for enrollment management

Creating Enrollments

Enrollment creation with duplicate prevention:
// EnrollmentController.php - create() and store()
public function create()
{
    Auth::admin();

    // Load students and courses for selection
    $students = $this->studentModel->getAll();
    $courses = $this->courseModel->getAll();

    require __DIR__ . '/../views/enrollments/create.php';
}

public function store()
{
    Auth::admin();

    $student_id = $_POST['student_id'];
    $course_id = $_POST['course_id'];

    // Check if already enrolled
    if ($this->enrollmentModel->isAlreadyEnrolled($student_id, $course_id)) {
        header("Location: /enrollments/create?error=duplicate");
        exit;
    }

    // Create enrollment
    $this->enrollmentModel->create($student_id, $course_id);

    header("Location: /enrollments");
    exit;
}
// Enrollment.php - create()
public function create($student_id, $course_id)
{
    $stmt = $this->db->prepare(
        "INSERT INTO enrollments (student_id, course_id) VALUES (?, ?)"
    );
    return $stmt->execute([$student_id, $course_id]);
}
Enrollment Workflow:
  1. Admin selects student from dropdown
  2. Admin selects course from dropdown
  3. System checks for duplicate enrollment
  4. If duplicate, redirect with error message
  5. If unique, create enrollment record
  6. Student can now access course in their timetable and receive grades

Duplicate Detection

Prevents students from being enrolled multiple times in the same course:
// Enrollment.php - isAlreadyEnrolled()
public function isAlreadyEnrolled($student_id, $course_id)
{
    $stmt = $this->db->prepare(
        "SELECT COUNT(*) FROM enrollments 
         WHERE student_id = ? AND course_id = ?"
    );
    $stmt->execute([$student_id, $course_id]);
    return $stmt->fetchColumn() > 0;
}
Usage pattern:
// Check before inserting
if ($this->enrollmentModel->isAlreadyEnrolled($student_id, $course_id)) {
    // Redirect with error
    header("Location: /enrollments/create?error=duplicate");
    exit;
}

// Safe to insert
$this->enrollmentModel->create($student_id, $course_id);
Why Check Duplicates?
  • Provides user-friendly error messages
  • Allows controlled handling of duplicate attempts
  • Database composite key also prevents duplicates, but checking first gives better UX

Deleting Enrollments

Remove a student from a course:
// EnrollmentController.php - delete()
public function delete()
{
    Auth::admin();

    $this->enrollmentModel->delete(
        $_GET['student_id'],
        $_GET['course_id']
    );

    header("Location: /enrollments");
    exit;
}
// Enrollment.php - delete()
public function delete($student_id, $course_id)
{
    $stmt = $this->db->prepare(
        "DELETE FROM enrollments 
         WHERE student_id=? AND course_id=?"
    );
    $stmt->execute([$student_id, $course_id]);
}
Deletion Effects:
  • Student loses access to course in timetable
  • Grades for this course remain in database (not deleted)
  • Can be re-enrolled later if needed

Student-Specific Queries

Getting Student’s Enrollments

Retrieve all courses a student is enrolled in:
// Enrollment.php - getByStudent()
public function getByStudent($student_id)
{
    $stmt = $this->db->prepare("
        SELECT enrollments.*
        FROM enrollments
        WHERE enrollments.student_id = ?
    ");
    $stmt->execute([$student_id]);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
This is used in:
  • Timetable Generation: Show only enrolled courses in student’s schedule
  • Grade Display: Show grades only for enrolled courses
  • Bulletin Generation: Calculate averages from enrolled courses

Integration with Other Systems

Grade Entry (Teacher Perspective)

Teachers can only enter grades for enrolled students:
// Grade.php - getStudentsByCourse()
public function getStudentsByCourse($course_id)
{
    $stmt = $this->db->prepare("
        SELECT students.id, users.name, grades.grade
        FROM enrollments
        JOIN students ON enrollments.student_id = students.id
        JOIN users ON students.id = users.id
        LEFT JOIN grades 
          ON grades.student_id = students.id 
         AND grades.course_id = enrollments.course_id
        WHERE enrollments.course_id = ?
    ");
    $stmt->execute([$course_id]);
    return $stmt->fetchAll();
}
This query:
  1. Starts with enrollments for the course
  2. Joins to get student information
  3. LEFT JOINs grades (may not exist yet)
  4. Shows all enrolled students with their current grade (or NULL)
Purpose:
  • Teachers see complete enrollment roster
  • Existing grades are displayed
  • Students without grades show NULL (can add grade)
  • Only enrolled students appear in the list

Timetable Access (Student Perspective)

Students only see timetable entries for enrolled courses:
// Timetable.php - getForStudent()
public function getForStudent($student_id)
{
    $sql = "
        SELECT 
            subjects.name AS subject,
            users.name AS teacher,
            timetable.day,
            timetable.start_time,
            timetable.end_time
        FROM timetable
        JOIN courses ON courses.id = timetable.course_id
        JOIN enrollments ON enrollments.course_id = courses.id
        JOIN subjects ON subjects.id = courses.subject_id
        JOIN teachers ON teachers.id = courses.teacher_id
        JOIN users ON users.id = teachers.id
        WHERE enrollments.student_id = ?
        ORDER BY timetable.day, timetable.start_time
    ";

    $stmt = $this->db->prepare($sql);
    $stmt->execute([$student_id]);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Key point: JOIN enrollments filters timetable to only enrolled courses.

Bulletin Generation

Bulletins include grades from all enrolled courses:
// Grade.php - getBulletinData()
public function getBulletinData($student_id)
{
    $sql = "
        SELECT 
            subjects.name AS subject,
            users.name AS teacher,
            grades.grade
        FROM grades
        JOIN courses ON grades.course_id = courses.id
        JOIN subjects ON courses.subject_id = subjects.id
        JOIN users ON courses.teacher_id = users.id
        WHERE grades.student_id = ?
    ";

    $stmt = $this->db->prepare($sql);
    $stmt->execute([$student_id]);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Note: This query uses grades table, not enrollments. Students may be enrolled in courses without grades yet. Bulletin only shows courses with recorded grades.

Complete Enrollment Model

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

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

    // Get all enrollments with details
    public function getAll()
    {
        $sql = "SELECT 
                    students.id AS student_id,
                    users.name AS student_name,
                    subjects.name AS subject_name,
                    courses.id AS course_id
                FROM enrollments
                JOIN students ON enrollments.student_id = students.id
                JOIN users ON students.id = users.id
                JOIN courses ON enrollments.course_id = courses.id
                JOIN subjects ON courses.subject_id = subjects.id";

        return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }

    // Create new enrollment
    public function create($student_id, $course_id)
    {
        $stmt = $this->db->prepare(
            "INSERT INTO enrollments (student_id, course_id) VALUES (?, ?)"
        );
        return $stmt->execute([$student_id, $course_id]);
    }

    // Delete enrollment
    public function delete($student_id, $course_id)
    {
        $stmt = $this->db->prepare(
            "DELETE FROM enrollments WHERE student_id=? AND course_id=?"
        );
        $stmt->execute([$student_id, $course_id]);
    }

    // Get enrollments for specific student
    public function getByStudent($student_id)
    {
        $stmt = $this->db->prepare("
            SELECT enrollments.*
            FROM enrollments
            WHERE enrollments.student_id = ?
        ");
        $stmt->execute([$student_id]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // Check if student already enrolled in course
    public function isAlreadyEnrolled($student_id, $course_id)
    {
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) FROM enrollments 
             WHERE student_id = ? AND course_id = ?"
        );
        $stmt->execute([$student_id, $course_id]);
        return $stmt->fetchColumn() > 0;
    }
}

API Endpoints

MethodEndpointAccessDescription
GET/enrollmentsAdminList all enrollments
GET/enrollments/createAdminShow enrollment form
POST/enrollments/storeAdminCreate new enrollment
GET/enrollments/delete?student_id={sid}&course_id={cid}AdminDelete enrollment

Use Cases

Context: John Doe needs to be enrolled in MathematicsSteps:
  1. Admin navigates to /enrollments/create
  2. Selects “John Doe” from students dropdown
  3. Selects “Mathematics - Mr. Smith” from courses dropdown
  4. Submits form
  5. System checks: isAlreadyEnrolled(john_id, math_course_id)
  6. If not enrolled, creates enrollment record
  7. John can now see Mathematics in his timetable
  8. Mr. Smith can enter grades for John in Mathematics
Context: Admin tries to enroll John in Mathematics againSteps:
  1. Admin selects “John Doe” and “Mathematics - Mr. Smith”
  2. Submits enrollment form
  3. System checks: isAlreadyEnrolled(john_id, math_course_id) → true
  4. Redirects to /enrollments/create?error=duplicate
  5. Shows error message: “Student already enrolled”
  6. No duplicate enrollment created
Context: Jane Smith needs to drop PhysicsSteps:
  1. Admin views enrollment list
  2. Finds “Jane Smith - Physics”
  3. Clicks delete button
  4. System calls delete(jane_id, physics_course_id)
  5. Enrollment record removed
  6. Jane no longer sees Physics in her timetable
  7. Physics teacher no longer sees Jane in course roster
  8. Jane’s Physics grades remain in database (historical record)

Data Flow Diagram

┌──────────┐
│ Students │
└────┬─────┘

     │ student_id

┌──────────────┐      course_id      ┌──────────┐
│ Enrollments  │◄────────────────────│ Courses  │
│──────────────│                     └────┬─────┘
│ student_id   │                          │
│ course_id    │                          │
└──────┬───────┘                          │
       │                                  │
       └──────────┬───────────────────────┘

         Used by: │
                  ├─► Timetable (filter student schedule)
                  ├─► Grades (determine course roster)
                  └─► Bulletin (list enrolled courses)
Central Role of Enrollments: Enrollments are the bridge between students and courses. Without enrollment:
  • Students don’t appear in course rosters
  • Teachers can’t enter grades
  • Students don’t see courses in timetable
  • Courses don’t appear in student bulletins

Best Practices

Validation

  • Always check for duplicate enrollments
  • Verify student and course exist before creating
  • Use composite primary key for database-level enforcement

User Experience

  • Provide clear error messages for duplicates
  • Show course and student names in listings
  • Confirm before deleting enrollments

Data Integrity

  • Use foreign key constraints
  • Enable cascade deletion
  • Keep historical grade data even after unenrollment

Security

  • Restrict enrollment operations to admins only
  • Validate all input data
  • Use prepared statements for all queries

Build docs developers (and LLMs) love