# Class Enrolment v1.4.00 – bug fixes and server-side checks (for review)

**URL:** <https://ask.gibbonedu.org/t/class-enrolment-v1-4-00-bug-fixes-and-server-side-checks-for-review/15605>\
**Category:** General\
**Created:** [October 7, 2026, 3:59am UTC](https://ask.gibbonedu.org/t/class-enrolment-v1-4-00-bug-fixes-and-server-side-checks-for-review/15605 "2026-10-07T03:59:19Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![tiekubd](https://ask.gibbonedu.org/user_avatar/ask.gibbonedu.org/tiekubd/32/163_2.png) [@tiekubd](https://ask.gibbonedu.org/u/tiekubd)\
**Post date:** [October 7, 2026, 3:59am UTC](https://ask.gibbonedu.org/t/class-enrolment-v1-4-00-bug-fixes-and-server-side-checks-for-review/15605/1 "2026-10-07T03:59:19Z")

</div>

Hi @ross @sandra and @Ali ,

I’ve been working with the Class Enrolment module and ended up with a set of fixes. The complete module folder (v1.4.00, based on v1.3.01) is here for you to look over. Feel free to take any or all of it:

- Code: [GitHub - tiekubd/class-enrolment-1.4: Class Enrolment module for Gibbon, v1.4.00 (based on v1.3.01): bug fixes and server-side checks, shared for review · GitHub](https://github.com/tiekubd/class-enrolment-1.4)
- Download (drop-in replacement for the existing folder): [Release Class Enrolment v1.4.00 · tiekubd/class-enrolment-1.4 · GitHub](https://github.com/tiekubd/class-enrolment-1.4/releases/tag/v1.4.00)
- Line-by-line changes from v1.3.01: [class-enrolment-1.4/changes-v1.3.01-to-v1.4.00.diff at main · tiekubd/class-enrolment-1.4 · GitHub](https://github.com/tiekubd/class-enrolment-1.4/blob/main/changes-v1.3.01-to-v1.4.00.diff)

**Bugs fixed**

1. **Fatal error on Core v31.** `enrolmentProcess.php` calls `CourseGateway::getCourseClassByID()`. In the v31.0.00 branch that method moved to `CourseClassGateway` (the “Departments: Refactoring into Gateway Classes” commit, #2004), so every enrolment submit would fail after upgrading. The process script no longer calls it; it uses the row from `selectEnrolableClassesByYearGroup()` instead, which works on both v30 and v31.
2. **Maximum enrolment off by one.** A class was treated as full only when `studentCount > enrolmentMax`, so one extra student could always join. It’s now `>=`, in both the picker and the process.
3. **Settings always reported success.** `$partialFail &= !$updated` starts from `false`, so it can never become true. Settings save now reports real failures.
4. **Delete error message lost.** In `enrolment_deleteProcess.php`, the “no access” branch added `error0` to `$URL` but redirected to `$URLDelete`.
5. **PHP 8 warning on non-students.** Choosing a family adult who isn’t an enrolled student read `$student['gibbonYearGroupID']` from `false`.

**Checks now enforced on the server, not just in the UI**

- The open/close window is checked in the enrolment and delete process scripts, not only on the page. Before, a page left open could still submit after the window closed.
- Submitted class IDs must belong to courses for the student’s year group in the current school year. Before, any `gibbonCourseClassID` was accepted.
- The settings page rejects a close date that isn’t after the open date.

**Behaviour changes, open to discussion**

- **Who appears in the student list:** only people with a `gibbonStudentEnrolment` in the current year (status Full or Expected). Children appear as before, and adults who are students themselves still work (the v1.0.02/v1.1.00 use case). Adults who aren’t students no longer appear.
- **Unenrolment:**
  - only rows with `role='Student'` can be removed, so Teacher and other roles are never touched;
  - only classes in the student’s year-group offering can be removed;
  - a new setting, **Allow Parent Unenrolment** (Y/N, default Y so existing behaviour is kept), lets schools turn removal off entirely.

- **Minimum enrolment** is informational, matching how core uses it. Classes below their minimum show “(needs N more students to run)” in the picker. Nothing is blocked.
- **The class picker** marks classes the student is already in as “(Enrolled)” and greys them out, the same as “(Full)”. This uses plain JS instead of the jQuery snippet, and the group heading’s extra `--` is removed because Gibbon already adds dashes.

**Structure**

- Access rules (who you can act for, the window, enrolable classes, unenrolment checks) are in a new `moduleFunctions.php`. It replaces the family lookup that was copy-pasted into four files, so the pages and the process scripts can’t drift apart.
- `LOCK TABLES` is narrowed to `gibbonCourseClassPerson WRITE, gibbonPerson READ`, and `UNLOCK TABLES` runs in a `finally` block so an exception can’t leave the table locked. Capacity is counted again inside the lock.
- Re-submitting a class the student is already in is skipped quietly. A “Student - Left” row is reactivated instead of a duplicate being inserted.
- `CHANGEDB.php` has a v1.4.00 entry that adds the new setting. `version.php` still requires Core 29.0.00.

**Testing**

I installed Core v30.0.00 with the official demo data and ran a scripted test suite as a parent account against both v1.3.01 and v1.4.00. The upgrade went through the normal System Admin › Update path. Every bug above reproduced on v1.3.01. On v1.4.00 they were all blocked with a clear message, the normal paths (enrol, unenrol, re-enrol, taking the last place, saving settings) worked, and the PHP log was clean. With locking on, three families racing for one last place over 15 rounds never overfilled a class. I haven’t run it on v31 itself; that fix was checked against the v31 branch source.

**Coming next**

There’s a university who wants students to choose their own classes. My plan is to add an `Enrolment_my` action with `categoryPermissionStudent='Y'`, which the shared access function already mostly supports. I’d welcome your thoughts on whether that belongs in this module or whether Course Selection is the better place.

A small aside: the Extend page lists Class Enrolment as requiring Core v25+, but `version.php` already said 29.0.00 in v1.3.01.

Thanks,  
Tieku
