Grade synchronization (Moodle → SGA)¶
Unlike upload synchronization (which pushes data from the SGA into Moodle), this flow is the
reverse: the SGA queries Moodle to obtain the grades already recorded for a specific class
(diário).
Endpoint¶
sync_down_grades_service::do_call() (api/sync/down/index.php) responds to a request
identifying the class through the diario_id query-string parameter:
GET /admin/tool/sga/api/sync/down/?diario_id=20231.1.15806.1E.TEC.1386
Note
The comment at the top of the file shows this URL format as an example, but the same
warning about endpoint initialization made at Possible endpoint initialization issue (on the
Upload synchronization (SGA → Moodle) page) also applies here, since this file also includes
api/servicelib.php.
Query¶
The SQL query locates, via course.idnumber LIKE '%#' || :diario_id, the course whose
idnumber ends with #<diario_id> (the naming convention used by courses created through
Upload synchronization (SGA → Moodle)), lists all users enrolled with the student archetype role in
that course and, for each one, builds a JSON object (jsonb_object_agg) mapping the
idnumber of each grade_items — restricted to the list configured in Notes to sync
(notes_to_sync, see Installation) — to the recorded final grade
(grade_grades.finalgrade).
Warning
The query uses jsonb_object_agg, a function specific to PostgreSQL. Since the CI
pipeline (ci.yml) also tests against MariaDB, this endpoint likely fails on a Moodle
installation running on MySQL/MariaDB — behaviour not verified in a real environment, only
inferred from the SQL syntax used.
Response¶
A JSON array, one object per enrolled student, ordered by full name:
[
{
"matricula": "20231015806001",
"nome_completo": "Fulano de Tal",
"notas": {"N1": 8.5, "N2": 9.0}
}
]
notas is null when the student has no grade recorded in any of the configured items;
when present, it is an object {item_idnumber: grade} containing only the items the student
actually has in grade_grades.
Error handling¶
The error handling block is catch (Exception $ex) with no leading backslash. Since the
file declares namespace tool_sga; at the top, this unqualified name resolves to
\tool_sga\Exception — a class that does not exist in this plugin — rather than to PHP’s
global \Exception. In practice, this means the catch block likely never catches a real
exception thrown by Moodle’s database layer (typically a dml_exception or similar, outside
the tool_sga namespace): the error tends to propagate uncaught. Even if the catch block
did catch something, the code inside it calls die("error") before any other line — the
following lines (http_response_code(500) and the echo json_encode(...) with the
detailed message) are unreachable. In other words, the detailed error handling the code
appears to have been written to produce is not, in fact, reached by any execution path.