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

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