src/Entity/Core/Quiz/QuizSession.php line 24

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Entity\Core\Quiz;
  4. use App\Entity\Core\Classroom\Classroom;
  5. use App\Entity\Core\ActivitySessionInterface;
  6. use App\Entity\Core\FolderAwareInterface;
  7. use App\Entity\Core\FolderAwareTrait;
  8. use App\Entity\Core\SelfStudy\SelfStudyExamQuiz;
  9. use App\Entity\Core\SelfStudy\SelfStudyTopic;
  10. use App\Entity\Core\SelfStudy\SelfStudyTypicalExamProblem;
  11. use App\Entity\Core\TemplateMathproblem;
  12. use App\Entity\User\User;
  13. use DateTime;
  14. use DateTimeZone;
  15. use Doctrine\Common\Collections\ArrayCollection;
  16. use Doctrine\ORM\Mapping as ORM;
  17. use Exception;
  18. use JsonSerializable;
  19. #[ORM\Table('quiz_session')]
  20. #[ORM\Entity(repositoryClass: QuizSessionRepository::class)]
  21. class QuizSession implements JsonSerializable, FolderAwareInterface, ActivitySessionInterface
  22. {
  23. use FolderAwareTrait;
  24. private const FOLDER_ACTIVITY_TYPE = 'quiz';
  25. /**
  26. * @var int
  27. */
  28. #[ORM\Column(name: 'id', type: 'integer')]
  29. #[ORM\Id]
  30. #[ORM\GeneratedValue(strategy: 'AUTO')]
  31. private int $id;
  32. /**
  33. * @var Quiz
  34. */
  35. #[ORM\JoinColumn(name: 'quiz', referencedColumnName: 'id', onDelete: 'CASCADE', nullable: true)]
  36. #[ORM\ManyToOne(targetEntity: Quiz::class, inversedBy: 'quizSessions')]
  37. private ?Quiz $quiz;
  38. /**
  39. * @var User
  40. */
  41. #[ORM\JoinColumn(name: 'created_by', referencedColumnName: 'id')]
  42. #[ORM\ManyToOne(targetEntity: User::class)]
  43. private ?User $createdBy;
  44. /**
  45. * @var Classroom
  46. */
  47. #[ORM\JoinColumn(name: 'classroom', referencedColumnName: 'id', onDelete: 'CASCADE')]
  48. #[ORM\ManyToOne(targetEntity: Classroom::class, inversedBy: 'quizSessions')]
  49. private ?Classroom $classroom;
  50. /**
  51. * @var bool
  52. */
  53. #[ORM\Column(name: 'dormant', type: 'boolean', nullable: true)]
  54. private ?bool $dormant;
  55. /**
  56. * @var int
  57. */
  58. #[ORM\Column(type: 'smallint', nullable: true)]
  59. private ?int $duration;
  60. /**
  61. * @var DateTime|null
  62. */
  63. #[ORM\Column(name: 'startTime', type: 'datetime', nullable: true)]
  64. private ?DateTime $startTime;
  65. #[ORM\Column(type: 'datetime', nullable: true)]
  66. private ?DateTime $deadline;
  67. #[ORM\Column(type: 'string', length: 255, nullable: true)]
  68. private ?string $name;
  69. /**
  70. * @var DateTime
  71. */
  72. #[ORM\Column(name: 'createdAt', type: 'datetime', nullable: false)]
  73. private DateTime $createdAt;
  74. /**
  75. * @var integer
  76. * [0 - created, in phase of editing; 1 - ready to start, if it's dormant ; 2 - startTime set]
  77. */
  78. #[ORM\Column(type: 'integer', nullable: false, options: ['default' => 0])]
  79. private int $status = 0;
  80. /**
  81. * @var integer
  82. */
  83. #[ORM\Column(type: 'integer', nullable: false, options: ['default' => 1])]
  84. private int $isEnabled = 1;
  85. #[ORM\Column(type: 'boolean', nullable: true, options: ['default' => false])]
  86. private ?bool $deleted = false;
  87. /**
  88. * @var QuizUnit[]
  89. */
  90. #[ORM\OneToMany(targetEntity: QuizUnit::class, mappedBy: 'quizSession', cascade: ['persist'])]
  91. private $quizUnits;
  92. /**
  93. * @var bool
  94. */
  95. #[ORM\Column(type: 'boolean', nullable: true)]
  96. private ?bool $durationIgnored;
  97. /**
  98. * @var bool
  99. */
  100. #[ORM\Column(name: 'hints_available', type: 'boolean', nullable: true)]
  101. private ?bool $hintsAvailable;
  102. #[ORM\Column(name: 'results_available_before_deadline', type: 'boolean', nullable: true)]
  103. private ?bool $resultsAvailableBeforeDeadline;
  104. /**
  105. * @var string|null
  106. */
  107. #[ORM\Column(name: 'isbn', type: 'string', length: 255, nullable: true)]
  108. private ?string $isbn;
  109. /**
  110. * @var DateTime
  111. */
  112. #[ORM\Column(name: 'updated_at', type: 'datetime', nullable: true)]
  113. private DateTime $updatedAt;
  114. /**
  115. * @var User
  116. */
  117. #[ORM\JoinColumn(name: 'updated_by', referencedColumnName: 'id')]
  118. #[ORM\ManyToOne(targetEntity: User::class)]
  119. private User $updatedBy;
  120. /**
  121. * @var string|null
  122. */
  123. #[ORM\Column(name: 'description', type: 'text', nullable: true)]
  124. private ?string $description;
  125. /**
  126. * @var DateTime
  127. */
  128. #[ORM\Column(name: 'result_view_open_at', type: 'datetime', nullable: true)]
  129. private ?DateTime $resultViewOpenAt;
  130. /**
  131. * @var ?bool
  132. */
  133. #[ORM\Column(name: 'extra_teachers', type: 'boolean', nullable: true)]
  134. private ?bool $extraTeachers = null;
  135. /**
  136. * possible values: 'self_study_exam', 'self_study_topic', 'self_study_typical_problem'
  137. * If it is null then it is a regular quiz
  138. */
  139. #[ORM\Column(name: 'type', type: 'string', length: 255, nullable: true, options: ['default' => ''])]
  140. private ?string $type = '';
  141. /**
  142. * @var SelfStudyTopic
  143. */
  144. #[ORM\JoinColumn(name: 'self_study_topic', referencedColumnName: 'id')]
  145. #[ORM\ManyToOne(targetEntity: SelfStudyTopic::class)]
  146. private $selfStudyTopic = null;
  147. /**
  148. * @var SelfStudyTypicalExamProblem
  149. */
  150. #[ORM\JoinColumn(name: 'self_study_typical_exam_problem', referencedColumnName: 'id')]
  151. #[ORM\ManyToOne(targetEntity: SelfStudyTypicalExamProblem::class)]
  152. private $selfStudyTypicalExamProblem = null;
  153. /**
  154. * @var SelfStudyExamQuiz
  155. */
  156. #[ORM\JoinColumn(name: 'self_study_exam', referencedColumnName: 'id')]
  157. #[ORM\ManyToOne(targetEntity: SelfStudyExamQuiz::class)]
  158. private $selfStudyExam = null;
  159. /**
  160. * @var bool
  161. */
  162. #[ORM\Column(name: 'deactivated_questions', type: 'boolean', nullable: true)]
  163. private ?bool $deactivatedProblems = null;
  164. /**
  165. * @var bool
  166. */
  167. #[ORM\Column(name: 'is_archived', type: 'boolean', nullable: true)]
  168. private ?bool $isArchived = null;
  169. /**
  170. * @var int|null
  171. */
  172. #[ORM\Column(name: 'copy_of', type: 'integer', nullable: true)]
  173. private ?int $copyOfSession = null;
  174. /**
  175. * @var bool|null
  176. */
  177. #[ORM\Column(name: 'is_shared_quiz', type: 'boolean', nullable: true)]
  178. private ?bool $isSharedQuiz = null;
  179. /**
  180. * @var bool|null
  181. */
  182. #[ORM\Column(name: 'is_pinned', type: 'boolean', nullable: true)]
  183. private ?bool $isPinned = null;
  184. #[ORM\Column(name: 'can_pause', type: 'boolean', options: ['default' => false])]
  185. private bool $canPause = false;
  186. /**
  187. */
  188. public function __construct(?int $duration)
  189. {
  190. $this->createdAt = new DateTime('now', new DateTimeZone('Europe/Copenhagen'));
  191. $this->updatedAt = new DateTime('now', new DateTimeZone('Europe/Copenhagen'));
  192. $this->quizUnits = new ArrayCollection();
  193. $this->duration = $duration;
  194. }
  195. public function getCopyOfSession(): ?int
  196. {
  197. return $this->copyOfSession;
  198. }
  199. public function setCopyOfSession(?int $copyOfSession): void
  200. {
  201. $this->copyOfSession = $copyOfSession;
  202. }
  203. public function getId(): int
  204. {
  205. return $this->id;
  206. }
  207. /**
  208. * @return Quiz
  209. */
  210. public function getQuiz(): ?Quiz
  211. {
  212. return $this->quiz;
  213. }
  214. /**
  215. * @param Quiz $quiz
  216. * @return $this
  217. */
  218. public function setQuiz(?Quiz $quiz): static
  219. {
  220. $this->quiz = $quiz;
  221. return $this;
  222. }
  223. /**
  224. * @return User
  225. */
  226. public function getCreatedBy(): ?User
  227. {
  228. return $this->createdBy;
  229. }
  230. /**
  231. * @param User $createdBy
  232. * @return $this
  233. */
  234. public function setCreatedBy(?User $createdBy): static
  235. {
  236. $this->createdBy = $createdBy;
  237. return $this;
  238. }
  239. /**
  240. * @return Classroom
  241. */
  242. public function getClassroom(): ?Classroom
  243. {
  244. return $this->classroom;
  245. }
  246. /**
  247. * @param Classroom $classroom
  248. * @return $this
  249. */
  250. public function setClassroom(?Classroom $classroom)
  251. {
  252. $this->classroom = $classroom;
  253. return $this;
  254. }
  255. /**
  256. * @return boolean
  257. */
  258. public function isDormant(): ?bool
  259. {
  260. return $this->dormant;
  261. }
  262. /**
  263. * @param boolean $dormant
  264. * @return $this
  265. */
  266. public function setDormant(?bool $dormant)
  267. {
  268. $this->dormant = $dormant;
  269. return $this;
  270. }
  271. /**
  272. * @return DateTime
  273. */
  274. public function getStartTime(): ?DateTime
  275. {
  276. return $this->startTime;
  277. }
  278. /**
  279. * @param DateTime $startTime
  280. * @return $this
  281. */
  282. public function setStartTime(?DateTime $startTime)
  283. {
  284. $this->startTime = $startTime;
  285. return $this;
  286. }
  287. public function getCreatedAt(): DateTime
  288. {
  289. return $this->createdAt;
  290. }
  291. public function setCreatedAt(DateTime $createdAt): void
  292. {
  293. $this->createdAt = $createdAt;
  294. }
  295. public function getStatus(): int
  296. {
  297. return $this->status;
  298. }
  299. /**
  300. * @return $this
  301. */
  302. public function setStatus(int $status): static
  303. {
  304. $this->status = $status;
  305. return $this;
  306. }
  307. /**
  308. * @return QuizUnit[]
  309. */
  310. public function getQuizUnits()
  311. {
  312. return $this->quizUnits;
  313. }
  314. /**
  315. * @param QuizUnit[] $quizUnits
  316. * @return $this
  317. */
  318. public function setQuizUnits($quizUnits)
  319. {
  320. $this->quizUnits = $quizUnits;
  321. return $this;
  322. }
  323. /**
  324. * @return $this
  325. */
  326. public function addQuizUnit(QuizUnit $quizUnit)
  327. {
  328. $quizUnit->setQuizSession($this);
  329. $this->quizUnits->add($quizUnit);
  330. return $this;
  331. }
  332. public function getEndTime()
  333. {
  334. if ($this->getDeadline() !== null) {
  335. return $this->getDeadline();
  336. }
  337. $endTime = clone $this->startTime;
  338. return $endTime->modify(sprintf('+%d minutes', $this->getDuration()));
  339. }
  340. public function setIsEnabled(int $isEnabled): void
  341. {
  342. $this->isEnabled = $isEnabled;
  343. }
  344. public function getIsEnabled(): int
  345. {
  346. return $this->isEnabled;
  347. }
  348. public function isDeleted(): ?bool
  349. {
  350. return $this->deleted;
  351. }
  352. public function setDeleted(bool $deleted): void
  353. {
  354. $this->deleted = $deleted;
  355. }
  356. public function getDeadline(): ?DateTime
  357. {
  358. return $this->deadline;
  359. }
  360. public function setDeadline(?DateTime $deadline = null): void
  361. {
  362. $this->deadline = $deadline;
  363. }
  364. public function isDurationIgnored(): ?bool
  365. {
  366. return $this->durationIgnored;
  367. }
  368. public function setDurationIgnored(bool $durationIgnored): void
  369. {
  370. $this->durationIgnored = $durationIgnored;
  371. }
  372. public function getDuration(): ?int
  373. {
  374. return $this->duration;
  375. }
  376. public function setDuration(?int $duration): void
  377. {
  378. $this->duration = $duration;
  379. }
  380. public function isHintsAvailable(): ?bool
  381. {
  382. return $this->hintsAvailable;
  383. }
  384. public function setHintsAvailable(bool $hintsAvailable): void
  385. {
  386. $this->hintsAvailable = $hintsAvailable;
  387. }
  388. public function areResultsAvailableBeforeDeadline(): bool
  389. {
  390. return (bool)$this->resultsAvailableBeforeDeadline;
  391. }
  392. public function setResultsAvailableBeforeDeadline(?bool $resultsAvailableBeforeDeadline): void
  393. {
  394. $this->resultsAvailableBeforeDeadline = $resultsAvailableBeforeDeadline;
  395. }
  396. public function getName(): ?string
  397. {
  398. return $this->name;
  399. }
  400. public function setName(?string $name): void
  401. {
  402. $this->name = $name;
  403. }
  404. public function isHomework(): bool
  405. {
  406. return (bool)$this->deadline;
  407. }
  408. public function getType(): string
  409. {
  410. return $this->type;
  411. }
  412. public function isSelfStudyExamQuiz(): bool
  413. {
  414. return $this->type === 'self_study_exam';
  415. }
  416. public function isSelfStudyTopicQuiz(): bool
  417. {
  418. return $this->type === 'self_study_topic';
  419. }
  420. public function isSelfStudyTypicalProblemQuiz(): bool
  421. {
  422. return $this->type === 'self_study_typical_exam_problem';
  423. }
  424. public function isSelfStudyQuiz(): bool
  425. {
  426. return $this->isSelfStudyExamQuiz() || $this->isSelfStudyTopicQuiz() || $this->isSelfStudyTypicalProblemQuiz();
  427. }
  428. public function setTypeToSelfStudyExamQuiz(): void
  429. {
  430. $this->type = 'self_study_exam';
  431. }
  432. public function setTypeToSelfStudyTopicQuiz(): void
  433. {
  434. $this->type = 'self_study_topic';
  435. }
  436. public function setTypeToSelfStudyTypicalProblemQuiz(): void
  437. {
  438. $this->type = 'self_study_typical_problem';
  439. }
  440. public function setType(?string $type): void
  441. {
  442. $this->type = $type;
  443. }
  444. public function getSelfStudyTopic(): ?SelfStudyTopic
  445. {
  446. return $this->selfStudyTopic;
  447. }
  448. public function setSelfStudyTopic(?SelfStudyTopic $selfStudyTopic): void
  449. {
  450. $this->selfStudyTopic = $selfStudyTopic;
  451. }
  452. public function getSelfStudyTypicalExamProblem(): ?SelfStudyTypicalExamProblem
  453. {
  454. return $this->selfStudyTypicalExamProblem;
  455. }
  456. public function setSelfStudyTypicalExamProblem(?SelfStudyTypicalExamProblem $selfStudyTypicalExamProblem): void
  457. {
  458. $this->selfStudyTypicalExamProblem = $selfStudyTypicalExamProblem;
  459. }
  460. public function getSelfStudyExam(): ?SelfStudyExamQuiz
  461. {
  462. return $this->selfStudyExam;
  463. }
  464. public function setSelfStudyExam(?SelfStudyExamQuiz $selfStudyExam): void
  465. {
  466. $this->selfStudyExam = $selfStudyExam;
  467. }
  468. /**
  469. * @throws Exception
  470. */
  471. public function jsonSerialize(): mixed
  472. {
  473. $topics = [];
  474. $quiz = $this->getQuiz();
  475. if ($quiz) {
  476. foreach ($quiz->getSortedMathproblems() as $problem) {
  477. $template = $problem->getTemplate();
  478. if (!$template) {
  479. continue;
  480. }
  481. $this->getUniqueTopics($template, $topics);
  482. }
  483. $topics = array_values($topics);
  484. }
  485. return [
  486. "duration" => $this->getDuration(),
  487. "id" => $this->getId(),
  488. "name" => $this->prefixNameWithFolderSortOrder($this->getName(), self::FOLDER_ACTIVITY_TYPE, $this->getQuiz()?->getId()),
  489. "startTime" => $this->getStartTime(),
  490. 'deadline' => $this->getDeadline() ?? $this->getEndTime(),
  491. 'isHomework' => $this->isHomework(),
  492. 'secondsUntilDeadline' => $this->getSecondsUntilDeadline(),
  493. 'durationIgnored' => $this->isDurationIgnored(),
  494. 'session_type' => basename(str_replace('\\', '/', __CLASS__)),
  495. 'activity_type' => 'quiz',
  496. 'start' => $this->getStartTime()->getTimestamp(),
  497. 'topics' => $topics
  498. ];
  499. }
  500. public function getSortOrderInFolder(): ?int
  501. {
  502. return $this->getFolderSortOrder(self::FOLDER_ACTIVITY_TYPE, $this->getQuiz()?->getId());
  503. }
  504. public function setISBN(?string $isbn = null): void
  505. {
  506. $this->isbn = $isbn;
  507. }
  508. public function getISBN(): ?string
  509. {
  510. return $this->isbn;
  511. }
  512. public function getUpdatedAt(): DateTime
  513. {
  514. return $this->updatedAt;
  515. }
  516. public function setUpdatedAt(DateTime $updatedAt): void
  517. {
  518. $this->updatedAt = $updatedAt;
  519. }
  520. public function getUpdatedBy(): User
  521. {
  522. return $this->updatedBy;
  523. }
  524. public function setUpdatedBy(User $updatedBy): void
  525. {
  526. $this->updatedBy = $updatedBy;
  527. }
  528. public function getDescription(): string
  529. {
  530. return $this->description;
  531. }
  532. public function setDescription(string $description): void
  533. {
  534. $this->description = $description;
  535. }
  536. public function getResultViewOpenAt(): ?DateTime
  537. {
  538. return $this->resultViewOpenAt;
  539. }
  540. public function setResultViewOpenAt(?DateTime $resultViewOpenAt): void
  541. {
  542. $this->resultViewOpenAt = $resultViewOpenAt;
  543. }
  544. public function hasExtraTeachers(): ?bool
  545. {
  546. return $this->extraTeachers;
  547. }
  548. public function setExtraTeachers(?bool $extraTeachers): void
  549. {
  550. $this->extraTeachers = $extraTeachers;
  551. }
  552. public function hasDeactivatedProblems(): ?bool
  553. {
  554. return $this->deactivatedProblems;
  555. }
  556. public function setDeactivatedProblems(?bool $deactivatedProblems): void
  557. {
  558. $this->deactivatedProblems = $deactivatedProblems;
  559. }
  560. public function isArchived(): ?bool
  561. {
  562. return $this->isArchived;
  563. }
  564. public function setIsArchived(?bool $isArchived): void
  565. {
  566. $this->isArchived = $isArchived;
  567. }
  568. public function isSharedQuiz(): ?bool
  569. {
  570. return $this->isSharedQuiz;
  571. }
  572. public function setIsSharedQuiz(bool $isSharedQuiz): void
  573. {
  574. $this->isSharedQuiz = $isSharedQuiz;
  575. }
  576. public function getIsPinned(): ?bool
  577. {
  578. return $this->isPinned;
  579. }
  580. public function setIsPinned(?bool $isPinned): void
  581. {
  582. $this->isPinned = $isPinned;
  583. }
  584. public function getNameOrDefaultToQuizName(): ?string
  585. {
  586. return trim($this->getName() ?? '') === '' ? $this->getQuiz()->getName() : $this->getName();
  587. }
  588. public function getCanPause(): bool
  589. {
  590. return $this->canPause;
  591. }
  592. public function canPause(): bool
  593. {
  594. return $this->canPause;
  595. }
  596. /**
  597. * @param bool $canPause
  598. */
  599. public function setCanPause(?bool $canPause): void
  600. {
  601. $this->canPause = $canPause;
  602. }
  603. /**
  604. * @throws Exception
  605. */
  606. public function getSecondsUntilDeadline():int
  607. {
  608. if($this->getDeadline() === null){
  609. return 0;
  610. }
  611. $now = new DateTime('now', new DateTimeZone('Europe/Copenhagen'));
  612. $interval = $now->diff($this->getDeadline());
  613. $seconds = ($interval->days * 24 * 60 * 60) + ($interval->h * 60 * 60) + ($interval->i * 60) + $interval->s;
  614. if($interval->invert){
  615. return 0;
  616. }
  617. return $seconds;
  618. }
  619. public function getProblemCount(){
  620. return $this->quiz->getProblemCount();
  621. }
  622. private function getUniqueTopics(TemplateMathproblem $template, array &$topics): void
  623. {
  624. if($topic = $template->getTopic()){
  625. $topics[$topic->getId()] = $topic->jsonSerialize();
  626. }
  627. }
  628. }