<?php
namespace App\Entity;
use App\Entity\Traits\Timestampable;
use App\Repository\ActivityRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
// Activité interactive auto-corrigée (QCM, vrai/faux, réponse courte,
// association, remise en ordre) portée par un CapsuleBlock de type
// `activity`. Association optionnelle à une LearningCompetency — PAS à
// App\Entity\Competence (système de notation trimestriel existant) : sur
// demande explicite, cette compétence-ci n'a aucun rapport avec le trimestre,
// elle sert seulement à suivre la progression continue de l'élève sur un
// savoir-faire au travers de plusieurs activités (voir StudentActivityAttempt).
#[ORM\HasLifecycleCallbacks]
#[ORM\Entity(repositoryClass: ActivityRepository::class)]
class Activity
{
use Timestampable;
public const TYPE_QCM = 'qcm';
public const TYPE_TRUE_FALSE = 'true_false';
public const TYPE_SHORT_ANSWER = 'short_answer';
public const TYPE_MATCHING = 'matching';
public const TYPE_ORDERING = 'ordering';
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 20)]
private ?string $type = null;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $instructions = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
private ?LearningCompetency $learningCompetency = null;
#[ORM\Column(nullable: true)]
private ?int $maxAttempts = null;
// Temps limite (en secondes) pour répondre à CETTE activité (quiz
// chronométré), indépendant de Capsule::timeLimitSeconds — les deux sont
// cumulables. Null = pas de limite propre à l'activité.
#[ORM\Column(nullable: true)]
private ?int $timeLimitSeconds = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $author = null;
#[ORM\ManyToOne]
private ?User $editor = null;
// Côté inverse de CapsuleBlock::$activity (qui porte la FK) — permet de
// remonter school/year/subject pour le scoping des endpoints de sync
// (Activity n'a pas de lien direct vers Subject/School/SchoolYear).
#[ORM\OneToOne(mappedBy: 'activity')]
private ?CapsuleBlock $block = null;
#[ORM\OneToMany(mappedBy: 'activity', targetEntity: Question::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['position' => 'ASC'])]
private Collection $questions;
public function __construct()
{
$this->questions = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
public function getInstructions(): ?string
{
return $this->instructions;
}
public function setInstructions(?string $instructions): static
{
$this->instructions = $instructions;
return $this;
}
public function getLearningCompetency(): ?LearningCompetency
{
return $this->learningCompetency;
}
public function setLearningCompetency(?LearningCompetency $learningCompetency): static
{
$this->learningCompetency = $learningCompetency;
return $this;
}
public function getMaxAttempts(): ?int
{
return $this->maxAttempts;
}
public function setMaxAttempts(?int $maxAttempts): static
{
$this->maxAttempts = $maxAttempts;
return $this;
}
public function getTimeLimitSeconds(): ?int
{
return $this->timeLimitSeconds;
}
public function setTimeLimitSeconds(?int $timeLimitSeconds): static
{
$this->timeLimitSeconds = $timeLimitSeconds;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): static
{
$this->author = $author;
return $this;
}
public function getEditor(): ?User
{
return $this->editor;
}
public function setEditor(?User $editor): static
{
$this->editor = $editor;
return $this;
}
public function getBlock(): ?CapsuleBlock
{
return $this->block;
}
/** @return Collection<int, Question> */
public function getQuestions(): Collection
{
return $this->questions;
}
public function addQuestion(Question $question): static
{
if (!$this->questions->contains($question)) {
$this->questions->add($question);
$question->setActivity($this);
}
return $this;
}
public function removeQuestion(Question $question): static
{
if ($this->questions->removeElement($question)) {
if ($question->getActivity() === $this) {
$question->setActivity(null);
}
}
return $this;
}
}