Sincronização de envio (SGA → Moodle)¶
Visão geral do fluxo¶
O SGA envia, em uma única requisição POST, um JSON contendo listas de categorias, cursos,
usuários, coortes, métodos de inscrição (enrols), matrículas (enrolments) e grupos.
sync_up_enrolments_service::do_call() (api/sync/up/index.php) processa essas listas
na ordem fixa:
sync_categories()sync_courses()import_template_courses_backup()— só roda no modo síncrono (ver abaixo)sync_users()sync_cohorts()sync_cohorts_members()sync_enrols()sync_enrolments()sync_groups()sync_groups_members()
Cada JSON bruto recebido é sempre persistido (independentemente de sucesso ou falha do
processamento) na tabela sga_enrolment_to_sync via insertSyncDB() — veja
Painel administrativo para como consultar esse histórico.
Possível problema de inicialização do endpoint¶
Danger
api/sync/up/index.php (e o
equivalente de notas, api/sync/down/index.php) carregam api/servicelib.php via
require_once. Esse arquivo, além de definir a classe base service, também contém
— no seu escopo global, fora de qualquer função — um bloco try/catch que lê
$_SERVER["QUERY_STRING"], valida contra uma lista branca (sync_up_enrolments,
sync_down_grades, health) e chama die() com um erro 404 (“Serviço não
existe”) caso a query string não corresponda a nenhum desses nomes. Como uma chamada normal
a /api/sync/up/ (conforme o próprio exemplo de uso do plugin) não tem query string, esse
bloco pode interromper a execução antes do restante de api/sync/up/index.php ser
alcançado — incluindo a definição da classe sync_up_enrolments_service e a linha final
(new sync_up_enrolments_service())->call();. Isto não foi confirmado em um Moodle rodando
de verdade (está fora do escopo desta tarefa alterar código), mas é uma leitura direta do
fluxo de execução do PHP e merece verificação antes de depender deste endpoint em produção.
Da mesma lista branca, apenas health tem um arquivo correspondente em api/ (
api/health.php); não existem api/sync_up_enrolments.php nem
api/sync_down_grades.php, então o dispatcher de api/index.php (descrito abaixo)
também não consegue servir esses dois serviços pelo nome.
Dois pontos de entrada distintos¶
O plugin expõe a mesma família de serviços por dois caminhos diferentes:
Caminho |
Comportamento |
|---|---|
|
Dispatcher genérico: lê o primeiro parâmetro da query string, valida contra a lista
branca ( |
|
Scripts autocontidos: fazem seus próprios |
Formato do payload¶
Cada seção do JSON (categories, courses, users etc.) segue o mesmo formato geral,
processado por request_iterator():
{
"<secao>": {
"update_fields": ["campo1", "campo2", ...], // opcional — quais campos atualizar em registros existentes
"list": [ { ... }, { ... } ] // um objeto por registro
}
}
Cada objeto da lista é identificado por uma chave natural (idnumber, username, ou
combinação de campos, dependendo da seção) usada para decidir se o registro já existe
(UPD) ou precisa ser criado (ADD). Um exemplo completo está em
api/examples/sync.up.full.request.json; um segundo exemplo (sync_up.request-full.json)
e os esquemas de referência em api/schemas/ documentam o formato esperado — os esquemas
não são aplicados automaticamente (ver nota sobre validação abaixo).
Seção |
Chave natural |
Campos obrigatórios ( |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note
O código-fonte (api/sync/up/index.php) contém duas definições do método
sync_enrolments() na classe sync_up_enrolments_service (uma logo após
sync_enrols(), outra logo após sync_groups()). Em PHP, declarar o mesmo método duas
vezes na mesma classe é um erro fatal de compilação (Cannot redeclare method) — o que
sugere que este arquivo, no estado atual, não executa em PHP algum sem antes remover uma das
duas declarações. Esta documentação apenas registra a observação; a correção está fora do
escopo desta tarefa (documentação apenas).
Validação do JSON¶
validate_json() decodifica o JSON e garante que é um objeto válido, mas o bloco de
validação estrutural contra um esquema (usando a biblioteca vendorizada Jsv4\Validator em
classes/Jsv4/) está comentado no código. Ou seja, atualmente nenhum campo é validado
contra os esquemas em api/schemas/ — eles servem apenas como documentação de referência
do formato esperado, não como validação ativa.
Restrições e tratamento de erro por item¶
check_banned_fields()rejeita, por seção, um conjunto de campos que nunca podem ser enviados (tipicamente colunas internas do Moodle comoid,timecreated,sortorder) — se presentes, a requisição inteira para aquele item falha.set_updatable_fields()nunca permite atualizaridnumber— lança exceção seupdate_fieldsincluir esse campo.Erros em um item não interrompem os demais:
request_iterator()captura qualquer\Throwablepor item, registra a mensagem em$this->errors[]no formato"Erro ao processar(ADD|UPD) o <seção>#<índice> '<chave>': `<mensagem>`."e segue para o próximo item da lista.A resposta final sempre inclui três chaves:
urls(URLs de acesso no Moodle para cada registro processado com sucesso, por seção),errosesuccesses(usada apenas porimport_template_courses_backup(), ver abaixo).
Restauração de modelo de curso (template_path)¶
Se um curso novo (op == 'ADD') tiver o atributo template_path (uma lista ordenada de
idnumber``s candidatos), ``import_template_courses_backup() localiza o primeiro curso
dessa lista que já existe no Moodle, faz um backup completo dele
(backup::TYPE_1COURSE) e restaura esse backup dentro do curso recém-criado — replicando
atividades, configurações e conteúdo do curso-modelo. Falhas aqui não interrompem o restante
da sincronização; são registradas em $this->errors[].
Note
import_template_courses_backup() só é chamada quando process() é invocado em modo
síncrono ($assync = true em do_call()); não há, no código atual, um caminho que
chame process() em modo assíncrono ($assync = false) — o parâmetro existe na
assinatura do método, mas apenas o valor true é usado.
Registro para suporte/auditoria¶
Cada requisição de sincronização de envio — processada com sucesso ou não — é gravada em
sga_enrolment_to_sync (json, timecreated, processed). O campo processed é
sempre inserido como 0 por insertSyncDB(); nenhum código do plugin atualiza esse campo
posteriormente para 1 (sucesso) ou 2 (falha), apesar de admin/index.php e
admin/view.php já traduzirem esses três valores para os rótulos “Não processado”,
“Sucesso” e “Falha” — na prática, todo registro aparece hoje como “Não processado”. Veja
Painel administrativo.