<?php
namespace App\Entity;
use App\Repository\LessonProgressRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\Traits\Timestampable;
/**
* Progression d'une leçon LOCALE (SubjectLesson) pour un Subject réel.
*
* Migration : l'ancien champ `lesson` (→ Lesson national) est conservé
* nullable pendant la transition. `subjectLesson` est désormais la
* référence principale. Utiliser getLessonTitle() dans les templates
* pour être compatible avec les deux systèmes.
*
* 1 LessonProgress = 1 (SubjectLesson, Subject).
*/
#[ORM\HasLifecycleCallbacks]
#[ORM\Entity(repositoryClass: LessonProgressRepository::class)]
class LessonProgress
{
use Timestampable;
public const STATUS_NOT_STARTED = 'not_started';
public const STATUS_IN_PROGRESS = 'in_progress';
public const STATUS_DONE = 'done';
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
/**
* @deprecated Remplacé par $subjectLesson.
* Conservé nullable pour assurer la rétrocompatibilité durant la migration.
* À supprimer après migration complète des données existantes.
*/
#[ORM\ManyToOne(inversedBy: 'progresses')]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
private ?Lesson $lesson = null;
/**
* Leçon LOCAL (copie école du programme national, ou leçon custom).
* Référence principale depuis la migration SubjectLesson.
*/
#[ORM\ManyToOne(inversedBy: 'progresses')]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
private ?SubjectLesson $subjectLesson = null;
/**
* Le Subject réel : matière + classe + école + année.
*/
#[ORM\ManyToOne(inversedBy: 'lessonProgresses')]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private ?Subject $subject = null;
#[ORM\Column(length: 20)]
private string $status = self::STATUS_NOT_STARTED;
#[ORM\Column(type: 'datetime', nullable: true)]
private ?\DateTimeInterface $startedAt = null;
#[ORM\Column(type: 'datetime', nullable: true)]
private ?\DateTimeInterface $completedAt = null;
/** Prof qui a marqué la leçon comme terminée. */
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
private ?User $completedBy = null;
#[ORM\OneToMany(
mappedBy: 'lessonProgress',
targetEntity: LessonLog::class,
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
#[ORM\OrderBy(['date' => 'DESC'])]
private Collection $lessonLogs;
public function __construct()
{
$this->lessonLogs = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
// ── SubjectLesson (nouveau système) ────────────────────────────────────
public function getSubjectLesson(): ?SubjectLesson
{
return $this->subjectLesson;
}
public function setSubjectLesson(?SubjectLesson $subjectLesson): static
{
$this->subjectLesson = $subjectLesson;
return $this;
}
// ── Lesson (ancien système, deprecated) ─────────────────────────────────
/** @deprecated Utiliser getSubjectLesson() */
public function getLesson(): ?Lesson
{
return $this->lesson;
}
/** @deprecated Utiliser setSubjectLesson() */
public function setLesson(?Lesson $lesson): static
{
$this->lesson = $lesson;
return $this;
}
// ── Helper titre compatible ancien + nouveau système ─────────────────────
/**
* Retourne le titre de la leçon quelle que soit la version du système.
* À utiliser dans les templates à la place de
* lessonProgress.lesson.title.
*/
public function getLessonTitle(): string
{
if ($this->subjectLesson !== null) {
return $this->subjectLesson->getTitle() ?? '';
}
return $this->lesson?->getTitle() ?? '';
}
// ── Subject ──────────────────────────────────────────────────────────────
public function getSubject(): ?Subject
{
return $this->subject;
}
public function setSubject(?Subject $subject): static
{
$this->subject = $subject;
return $this;
}
// ── Statut ───────────────────────────────────────────────────────────────
public function getStatus(): string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function isNotStarted(): bool
{
return $this->status === self::STATUS_NOT_STARTED;
}
public function isInProgress(): bool
{
return $this->status === self::STATUS_IN_PROGRESS;
}
public function isDone(): bool
{
return $this->status === self::STATUS_DONE;
}
// ── Dates ────────────────────────────────────────────────────────────────
public function getStartedAt(): ?\DateTimeInterface
{
return $this->startedAt;
}
public function setStartedAt(?\DateTimeInterface $startedAt): static
{
$this->startedAt = $startedAt;
return $this;
}
public function getCompletedAt(): ?\DateTimeInterface
{
return $this->completedAt;
}
public function setCompletedAt(?\DateTimeInterface $completedAt): static
{
$this->completedAt = $completedAt;
return $this;
}
public function getCompletedBy(): ?User
{
return $this->completedBy;
}
public function setCompletedBy(?User $completedBy): static
{
$this->completedBy = $completedBy;
return $this;
}
// ── LessonLogs ───────────────────────────────────────────────────────────
/** @return Collection<int, LessonLog> */
public function getLessonLogs(): Collection
{
return $this->lessonLogs;
}
public function addLessonLog(LessonLog $lessonLog): static
{
if (!$this->lessonLogs->contains($lessonLog)) {
$this->lessonLogs->add($lessonLog);
$lessonLog->setLessonProgress($this);
}
return $this;
}
public function removeLessonLog(LessonLog $lessonLog): static
{
if ($this->lessonLogs->removeElement($lessonLog)) {
if ($lessonLog->getLessonProgress() === $this) {
$lessonLog->setLessonProgress(null);
}
}
return $this;
}
/**
* Durée totale (en heures) enregistrée dans le cahier de texte
* pour cette leçon.
*/
public function getTotalLoggedHours(): float
{
$total = 0.0;
foreach ($this->lessonLogs as $log) {
$total += $log->getDuration() ?? 0.0;
}
return $total;
}
}