ajoute Quiz flash (chantier vrai cockpit, étape 2) : QCM et vrai/faux, lancé en direct, indépendant d'une séance de lab

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Adam Belkacemi 2026-10-13 12:14:30 +02:00
parent 45f8a69e26
commit 16d1293911
24 changed files with 1249 additions and 5 deletions

View file

@ -0,0 +1,96 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* Lancement en direct d'un Quiz (chantier « vrai cockpit », étape 2).
* Indépendant d'une séance de lab : les élèves de la classe la voient
* apparaître sur leur tableau de bord dès qu'elle passe en_cours.
*/
class SessionQuiz extends Model
{
public const EN_ATTENTE = 'en_attente';
public const EN_COURS = 'en_cours';
public const TERMINEE = 'terminee';
protected $table = 'sessions_quiz';
protected $fillable = ['quiz_id', 'statut', 'question_quiz_courante_id', 'demarree_a', 'terminee_a'];
protected $casts = [
'demarree_a' => 'datetime',
'terminee_a' => 'datetime',
];
/** @return BelongsTo<Quiz, $this> */
public function quiz(): BelongsTo
{
return $this->belongsTo(Quiz::class);
}
/** @return BelongsTo<QuestionQuiz, $this> */
public function questionCourante(): BelongsTo
{
return $this->belongsTo(QuestionQuiz::class, 'question_quiz_courante_id');
}
/** @return HasMany<ReponseQuiz, $this> */
public function reponses(): HasMany
{
return $this->hasMany(ReponseQuiz::class);
}
/**
* Passe à la question suivante du quiz (dans l'ordre), ou termine la
* session s'il n'y en a plus. Idempotent : rejouable sans effet si déjà
* terminée.
*/
public function passerALaQuestionSuivante(): void
{
if ($this->statut === self::TERMINEE) {
return;
}
$questions = $this->quiz->questions;
$indiceActuel = $this->question_quiz_courante_id
? $questions->search(fn ($q) => $q->id === $this->question_quiz_courante_id)
: -1;
$suivante = $questions->get($indiceActuel + 1);
if ($suivante) {
$this->forceFill(['statut' => self::EN_COURS, 'question_quiz_courante_id' => $suivante->id])->save();
} else {
$this->terminer();
}
}
public function terminer(): void
{
if ($this->statut !== self::TERMINEE) {
$this->forceFill(['statut' => self::TERMINEE, 'terminee_a' => now()])->save();
}
}
/**
* Décompte des réponses à la question en cours, pour le panneau du
* prof : combien d'élèves ont déjà répondu, combien ont juste.
*
* @return array{repondu: int, correctes: int}
*/
public function decompteQuestionCourante(): array
{
if (! $this->question_quiz_courante_id) {
return ['repondu' => 0, 'correctes' => 0];
}
$reponses = $this->reponses->where('question_quiz_id', $this->question_quiz_courante_id);
return ['repondu' => $reponses->count(), 'correctes' => $reponses->where('correcte', true)->count()];
}
}