<?php
namespace App\Entity;
use App\Repository\SubjectReferenceRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\Traits\Timestampable;
/**
* Référentiel national d'une matière pour une ClassOption donnée,
* pour une "version du programme" (SchoolYear) donnée.
*
* Exemple : "Mathématiques" pour la ClassOption "3ème", coef 4,
* version programme 2025-2026 → 1 SubjectReference.
*
* Reprend volontairement les mêmes propriétés que Subject (name, nameEn,
* coef, year, subjectGroup) à l'exception de tout ce qui rattache Subject
* à une instance concrète (school, classe, prof, notes...).
*
* Le superadmin crée ces référentiels et leurs Lesson associés.
* Chaque Subject réel "hérite" de la progression via
* SubjectReferenceRepository::findForSubject().
*/
#[ORM\HasLifecycleCallbacks]
#[ORM\Entity(repositoryClass: SubjectReferenceRepository::class)]
class SubjectReference
{
use Timestampable;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $nameEn = null;
/**
* Coefficient de référence de la matière pour cette ClassOption.
* Sert d'indication / valeur par défaut ; chaque Subject réel garde
* son propre coef (qui peut différer selon l'école).
*/
#[ORM\Column(nullable: true)]
private ?float $coef = null;
/**
* Horaire hebdomadaire de référence (nombre d'heures de cours par
* semaine) pour cette matière du programme national, facultatif.
*/
#[ORM\Column(nullable: true)]
private ?float $horaire = null;
#[ORM\ManyToOne(inversedBy: 'subjectReferences')]
#[ORM\JoinColumn(nullable: false)]
private ?ClassOption $classOption = null;
/**
* Groupe de matières national (équivalent national de SubjectGroup).
*/
#[ORM\ManyToOne(inversedBy: 'subjectReferences')]
private ?SubjectGroupReference $subjectGroupReference = null;
/**
* "Version du programme national" : permet de faire évoluer le
* programme d'une année à l'autre sans perdre l'historique.
* Ex : SubjectReference "Maths - 3ème" version 2025-2026
* vs "Maths - 3ème" version 2026-2027.
*/
#[ORM\ManyToOne(inversedBy: 'subjectReferences')]
#[ORM\JoinColumn(nullable: false)]
private ?SchoolYear $year = null;
#[ORM\OneToMany(mappedBy: 'subjectReference', targetEntity: Lesson::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['position' => 'ASC'])]
private Collection $lessons;
#[ORM\OneToMany(mappedBy: 'subjectReference', targetEntity: Module::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['position' => 'ASC'])]
private Collection $modules;
#[ORM\OneToMany(mappedBy: 'subjectReference', targetEntity: LearningUnit::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['position' => 'ASC'])]
private Collection $learningUnits;
#[ORM\OneToMany(mappedBy: 'subjectReference', targetEntity: CompetenceReference::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['quarterNumber' => 'ASC', 'position' => 'ASC'])]
private Collection $competenceReferences;
/**
* Sous-matières du programme national (écoles primaires/maternelles) —
* voir SubjectComponentReference.
*/
#[ORM\OneToMany(mappedBy: 'subjectReference', targetEntity: SubjectComponentReference::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['position' => 'ASC'])]
private Collection $subjectComponentReferences;
#[ORM\ManyToOne]
private ?User $author = null;
#[ORM\OneToMany(mappedBy: 'reference', targetEntity: Subject::class)]
private Collection $subjects;
public function __construct()
{
$this->lessons = new ArrayCollection();
$this->subjects = new ArrayCollection();
$this->competenceReferences = new ArrayCollection();
$this->subjectComponentReferences = new ArrayCollection();
$this->modules = new ArrayCollection();
$this->learningUnits = new ArrayCollection();
}
public function __toString(): string
{
return $this->name . ' (' . ($this->classOption?->getName() ?? '') . ')';
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getNameEn(): ?string
{
return $this->nameEn;
}
public function setNameEn(?string $nameEn): static
{
$this->nameEn = $nameEn;
return $this;
}
public function getCoef(): ?float
{
return $this->coef;
}
public function setCoef(?float $coef): static
{
$this->coef = $coef;
return $this;
}
public function getHoraire(): ?float
{
return $this->horaire;
}
public function setHoraire(?float $horaire): static
{
$this->horaire = $horaire;
return $this;
}
public function getClassOption(): ?ClassOption
{
return $this->classOption;
}
public function setClassOption(?ClassOption $classOption): static
{
$this->classOption = $classOption;
return $this;
}
public function getSubjectGroupReference(): ?SubjectGroupReference
{
return $this->subjectGroupReference;
}
public function setSubjectGroupReference(?SubjectGroupReference $subjectGroupReference): static
{
$this->subjectGroupReference = $subjectGroupReference;
return $this;
}
public function getYear(): ?SchoolYear
{
return $this->year;
}
public function setYear(?SchoolYear $year): static
{
$this->year = $year;
return $this;
}
/**
* @return Collection<int, Lesson>
*/
public function getLessons(): Collection
{
return $this->lessons;
}
public function addLesson(Lesson $lesson): static
{
if (!$this->lessons->contains($lesson)) {
$this->lessons->add($lesson);
$lesson->setSubjectReference($this);
}
return $this;
}
public function removeLesson(Lesson $lesson): static
{
if ($this->lessons->removeElement($lesson)) {
if ($lesson->getSubjectReference() === $this) {
$lesson->setSubjectReference(null);
}
}
return $this;
}
/**
* @return Collection<int, CompetenceReference>
*/
public function getCompetenceReferences(): Collection
{
return $this->competenceReferences;
}
public function addCompetenceReference(CompetenceReference $competenceReference): static
{
if (!$this->competenceReferences->contains($competenceReference)) {
$this->competenceReferences->add($competenceReference);
$competenceReference->setSubjectReference($this);
}
return $this;
}
public function removeCompetenceReference(CompetenceReference $competenceReference): static
{
if ($this->competenceReferences->removeElement($competenceReference)) {
if ($competenceReference->getSubjectReference() === $this) {
$competenceReference->setSubjectReference(null);
}
}
return $this;
}
/**
* @return Collection<int, SubjectComponentReference>
*/
public function getSubjectComponentReferences(): Collection
{
return $this->subjectComponentReferences;
}
public function addSubjectComponentReference(SubjectComponentReference $subjectComponentReference): static
{
if (!$this->subjectComponentReferences->contains($subjectComponentReference)) {
$this->subjectComponentReferences->add($subjectComponentReference);
$subjectComponentReference->setSubjectReference($this);
}
return $this;
}
public function removeSubjectComponentReference(SubjectComponentReference $subjectComponentReference): static
{
if ($this->subjectComponentReferences->removeElement($subjectComponentReference)) {
if ($subjectComponentReference->getSubjectReference() === $this) {
$subjectComponentReference->setSubjectReference(null);
}
}
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): static
{
$this->author = $author;
return $this;
}
/** @return Collection<int, Module> */
public function getModules(): Collection
{
return $this->modules;
}
/** @return Collection<int, LearningUnit> */
public function getLearningUnits(): Collection
{
return $this->learningUnits;
}
/**
* @return Collection<int, Subject>
*/
public function getSubjects(): Collection
{
return $this->subjects;
}
public function addSubject(Subject $subject): static
{
if (!$this->subjects->contains($subject)) {
$this->subjects->add($subject);
$subject->setReference($this);
}
return $this;
}
public function removeSubject(Subject $subject): static
{
if ($this->subjects->removeElement($subject)) {
// set the owning side to null (unless already changed)
if ($subject->getReference() === $this) {
$subject->setReference(null);
}
}
return $this;
}
}