Exercises: Fix question creation errors after update from 1.11.x

pull/3706/head
Julio Montoya 5 years ago
parent ac2f372b3f
commit 89804fd30e
  1. 2
      public/main/exercise/TestCategory.php
  2. 15
      public/main/exercise/UniqueAnswerImage.php
  3. 12
      public/main/exercise/answer.class.php
  4. 8
      public/main/exercise/fill_blanks.class.php
  5. 23
      public/main/exercise/hotspot.class.php
  6. 41
      public/main/exercise/hotspot_actionscript.as.php
  7. 20
      public/main/exercise/hotspot_actionscript_admin.as.php
  8. 47
      public/main/exercise/hotspot_admin.inc.php
  9. 20
      public/main/exercise/hotspot_answers.as.php
  10. 2
      public/main/exercise/multiple_answer_true_false.class.php
  11. 8
      public/main/exercise/unique_answer.class.php
  12. 8
      public/main/exercise/unique_answer_no_option.class.php
  13. 9
      src/CoreBundle/Traits/ControllerTrait.php

@ -485,7 +485,7 @@ class TestCategory
$courseId = api_get_course_int_id(); $courseId = api_get_course_int_id();
} }
$categories = self::getCategoryListInfo('', $courseId); $categories = self::getCategoryListInfo('', $courseId);
$result = ['0' => get_lang('NoCategorySelected')]; $result = ['0' => get_lang('No category selected')];
for ($i = 0; $i < count($categories); $i++) { for ($i = 0; $i < count($categories); $i++) {
$result[$categories[$i]->id] = $categories[$i]->name; $result[$categories[$i]->id] = $categories[$i]->name;
} }

@ -60,7 +60,8 @@ class UniqueAnswerImage extends UniqueAnswer
} }
$html = '<div class="alert alert-success" role="alert">'. $html = '<div class="alert alert-success" role="alert">'.
get_lang('UniqueAnswerImagePreferredSize200x150').'</div>'; get_lang('Images will be resized (up or down) to 200x150 pixels. For a better rendering of the question, we recommend you upload only images of this size.')
.'</div>';
$zoomOptions = api_get_configuration_value('quiz_image_zoom'); $zoomOptions = api_get_configuration_value('quiz_image_zoom');
if (isset($zoomOptions['options'])) { if (isset($zoomOptions['options'])) {
@ -69,10 +70,8 @@ class UniqueAnswerImage extends UniqueAnswer
$html .= '<link rel="stylesheet" type="text/css" media="screen" $html .= '<link rel="stylesheet" type="text/css" media="screen"
href="'.$finderFolder.'css/elfinder.full.css">'; href="'.$finderFolder.'css/elfinder.full.css">';
$html .= '<link rel="stylesheet" type="text/css" media="screen" href="'.$finderFolder.'css/theme.css">'; $html .= '<link rel="stylesheet" type="text/css" media="screen" href="'.$finderFolder.'css/theme.css">';
$html .= '<!-- elFinder JS (REQUIRED) -->'; $html .= '<!-- elFinder JS (REQUIRED) -->';
$html .= '<script type="text/javascript" src="'.$finderFolder.'js/elfinder.full.js"></script>'; $html .= '<script type="text/javascript" src="'.$finderFolder.'js/elfinder.full.js"></script>';
$html .= '<!-- elFinder translation (OPTIONAL) -->'; $html .= '<!-- elFinder translation (OPTIONAL) -->';
$language = 'en'; $language = 'en';
$platformLanguage = api_get_interface_language(); $platformLanguage = api_get_interface_language();
@ -347,14 +346,12 @@ class UniqueAnswerImage extends UniqueAnswer
$weighting = trim($form->getSubmitValue('weighting['.$i.']')); $weighting = trim($form->getSubmitValue('weighting['.$i.']'));
$scenario = $form->getSubmitValue('scenario'); $scenario = $form->getSubmitValue('scenario');
//$listDestination = $form -> getSubmitValue('destination'.$i); //$listDestination = $form -> getSubmitValue('destination'.$i);
//$destinationStr = $form -> getSubmitValue('destination'.$i); //$destinationStr = $form -> getSubmitValue('destination'.$i);
$try = $scenario['try'.$i] ?? null;
$try = $scenario['try'.$i]; $lp = $scenario['lp'.$i] ?? null;
$lp = $scenario['lp'.$i]; $destination = $scenario['destination'.$i] ?? null;
$destination = $scenario['destination'.$i]; $url = trim($scenario['url'.$i] ?? null);
$url = trim($scenario['url'.$i]);
/* /*
How we are going to parse the destination value How we are going to parse the destination value

@ -812,15 +812,17 @@ class Answer
if (count($this->position) > $this->new_nbrAnswers) { if (count($this->position) > $this->new_nbrAnswers) {
$i = $this->new_nbrAnswers + 1; $i = $this->new_nbrAnswers + 1;
while ($this->position[$i]) { if (isset($this->position[$i])) {
$position = $this->position[$i]; while ($this->position[$i]) {
$sql = "DELETE FROM $answerTable $position = $this->position[$i];
$sql = "DELETE FROM $answerTable
WHERE WHERE
c_id = {$this->course_id} AND c_id = {$this->course_id} AND
question_id = '".$questionId."' AND question_id = '".$questionId."' AND
position ='$position'"; position ='$position'";
Database::query($sql); Database::query($sql);
$i++; $i++;
}
} }
} }

@ -323,7 +323,9 @@ class FillBlanks extends Question
// answer // answer
$form->addLabel( $form->addLabel(
null, null,
get_lang('Please type your text below').', '.get_lang('and').' '.get_lang('use square brackets [...] to define one or more blanks') get_lang('Please type your text below').', '.
get_lang('and').' '.
get_lang('use square brackets [...] to define one or more blanks')
); );
$form->addElement( $form->addElement(
'html_editor', 'html_editor',
@ -341,7 +343,7 @@ class FillBlanks extends Question
'select_separator', 'select_separator',
get_lang('Select a blanks marker'), get_lang('Select a blanks marker'),
self::getAllowedSeparatorForSelect(), self::getAllowedSeparatorForSelect(),
' id="select_separator" style="width:150px" class="selectpicker" onchange="changeBlankSeparator()" ' ' id="select_separator" style="width:150px" class="form-control" onchange="changeBlankSeparator()" '
); );
$form->addLabel( $form->addLabel(
null, null,
@ -553,7 +555,7 @@ class FillBlanks extends Question
$resultOptions, $resultOptions,
$selected, $selected,
[ [
'class' => 'selectpicker', 'class' => 'form-control',
'data-width' => $width, 'data-width' => $width,
'id' => $labelId, 'id' => $labelId,
], ],

@ -98,4 +98,27 @@ class HotSpot extends Question
return parent::return_header($exercise, $counter, $score) return parent::return_header($exercise, $counter, $score)
.'<table><tr><td><table class="table">'; .'<table><tr><td><table class="table">';
} }
public static function getLangVariables()
{
return [
'Square' => get_lang('Square'),
'Ellipse' => get_lang('Ellipse'),
'Polygon' => get_lang('Polygon'),
'HotspotStatus1' => get_lang('Draw a hotspot'),
'HotspotStatus2Polygon' => get_lang('Use right-click to close the polygon'),
'HotspotStatus2Other' => get_lang('Release the mousebutton to save the hotspot'),
'HotspotStatus3' => get_lang('Hotspot saved'),
'HotspotShowUserPoints' => get_lang('Show/Hide userclicks'),
'ShowHotspots' => get_lang('Show / Hide hotspots'),
'Triesleft' => get_lang('Attempts left'),
'HotspotExerciseFinished' => get_lang('Now click on the button below to validate your answers'),
'NextAnswer' => get_lang('Now click on:'),
'Delineation' => get_lang('Delineation'),
'CloseDelineation' => get_lang('Close delineation'),
'Oar' => get_lang('Area to avoid'),
'ClosePolygon' => get_lang('Close polygon'),
'DelineationStatus1' => get_lang('Use right-click to close the delineation'),
];
}
} }

@ -6,14 +6,9 @@ use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CourseBundle\Entity\CQuizQuestion; use Chamilo\CourseBundle\Entity\CQuizQuestion;
use ChamiloSession as Session; use ChamiloSession as Session;
/* /**
* This file generates the ActionScript variables code used by the HotSpot .swf. * This file generates the ActionScript variables code used by the HotSpot .swf.
*
* @package chamilo.exercise
*
* @author Toon Keppens * @author Toon Keppens
*
* @version $Id: admin.php 10680 2007-01-11 21:26:23Z pcool $
*/ */
session_cache_limiter('none'); session_cache_limiter('none');
@ -43,42 +38,24 @@ $course_id = api_get_course_int_id();
// Query db for answers // Query db for answers
if (HOT_SPOT_DELINEATION == $answer_type) { if (HOT_SPOT_DELINEATION == $answer_type) {
$sql = "SELECT iid, id, answer, hotspot_coordinates, hotspot_type, ponderation $sql = "SELECT iid, id, answer, hotspot_coordinates, hotspot_type, ponderation
FROM $TBL_ANSWERS FROM $TBL_ANSWERS
WHERE WHERE
c_id = $course_id AND c_id = $course_id AND
question_id = $questionId AND question_id = $questionId AND
hotspot_type = 'delineation' hotspot_type = 'delineation'
ORDER BY iid"; ORDER BY iid";
} else { } else {
$sql = "SELECT iid, id, answer, hotspot_coordinates, hotspot_type, ponderation $sql = "SELECT iid, id, answer, hotspot_coordinates, hotspot_type, ponderation
FROM $TBL_ANSWERS FROM $TBL_ANSWERS
WHERE c_id = $course_id AND question_id = $questionId WHERE c_id = $course_id AND question_id = $questionId
ORDER BY position"; ORDER BY position";
} }
$result = Database::query($sql); $result = Database::query($sql);
$data = []; $data = [];
$data['type'] = 'user'; $data['type'] = 'user';
$data['lang'] = [ $data['lang'] = HotSpot::getLangVariables();
'Square' => get_lang('Square'),
'Ellipse' => get_lang('Ellipse'),
'Polygon' => get_lang('Polygon'),
'HotspotStatus1' => get_lang('HotspotStatus1'),
'HotspotStatus2Polygon' => get_lang('HotspotStatus2Polygon'),
'HotspotStatus2Other' => get_lang('HotspotStatus2Other'),
'HotspotStatus3' => get_lang('HotspotStatus3'),
'HotspotShowUserPoints' => get_lang('HotspotShowUserPoints'),
'ShowHotspots' => get_lang('ShowHotspots'),
'Triesleft' => get_lang('Triesleft'),
'HotspotExerciseFinished' => get_lang('HotspotExerciseFinished'),
'NextAnswer' => get_lang('NextAnswer'),
'Delineation' => get_lang('Delineation'),
'CloseDelineation' => get_lang('CloseDelineation'),
'Oar' => get_lang('Oar'),
'ClosePolygon' => get_lang('ClosePolygon'),
'DelineationStatus1' => get_lang('DelineationStatus1'),
];
$data['image'] = $imagePath; $data['image'] = $imagePath;
$data['image_width'] = $pictureWidth; $data['image_width'] = $pictureWidth;
$data['image_height'] = $pictureHeight; $data['image_height'] = $pictureHeight;

@ -35,25 +35,7 @@ $imagePath = $questionRepo->getHotSpotImageUrl($objQuestion);
$data = []; $data = [];
$data['type'] = 'admin'; $data['type'] = 'admin';
$data['lang'] = [ $data['lang'] = HotSpot::getLangVariables();
'Square' => get_lang('Square'),
'Ellipse' => get_lang('Ellipse'),
'Polygon' => get_lang('Polygon'),
'HotspotStatus1' => get_lang('HotspotStatus1'),
'HotspotStatus2Polygon' => get_lang('HotspotStatus2Polygon'),
'HotspotStatus2Other' => get_lang('HotspotStatus2Other'),
'HotspotStatus3' => get_lang('HotspotStatus3'),
'HotspotShowUserPoints' => get_lang('HotspotShowUserPoints'),
'ShowHotspots' => get_lang('ShowHotspots'),
'Triesleft' => get_lang('Triesleft'),
'HotspotExerciseFinished' => get_lang('HotspotExerciseFinished'),
'NextAnswer' => get_lang('NextAnswer'),
'Delineation' => get_lang('Delineation'),
'CloseDelineation' => get_lang('CloseDelineation'),
'Oar' => get_lang('Oar'),
'ClosePolygon' => get_lang('ClosePolygon'),
'DelineationStatus1' => get_lang('DelineationStatus1'),
];
$data['image'] = $imagePath; $data['image'] = $imagePath;
$data['image_width'] = $pictureWidth; $data['image_width'] = $pictureWidth;
$data['image_height'] = $pictureHeight; $data['image_height'] = $pictureHeight;

@ -1,4 +1,5 @@
<?php <?php
/* For licensing terms, see /license.txt */ /* For licensing terms, see /license.txt */
use ChamiloSession as Session; use ChamiloSession as Session;
@ -19,6 +20,12 @@ $answerType = $objQuestion->selectType();
$debug = 0; $debug = 0;
$reponse = $_REQUEST['reponse'] ?? null;
$comment = $_REQUEST['comment'] ?? null;
$weighting = $_REQUEST['weighting'] ?? null;
$hotspot_coordinates = $_REQUEST['hotspot_coordinates'] ?? null;
$hotspot_type = $_REQUEST['hotspot_type'] ?? null;
// if we come from the warning box "this question is used in several exercises" // if we come from the warning box "this question is used in several exercises"
if ($modifyIn) { if ($modifyIn) {
if ($debug > 0) { if ($debug > 0) {
@ -75,12 +82,8 @@ if ($submitAnswers || $buttonBack) {
} }
$questionWeighting = $nbrGoodAnswers = 0; $questionWeighting = $nbrGoodAnswers = 0;
for ($i = 1; $i <= $nbrAnswers; $i++) { for ($i = 1; $i <= $nbrAnswers; $i++) {
if ($debug > 0) { $reponse[$i] = trim($reponse[$i] ?? null);
echo str_repeat('&nbsp;', 4).'$answerType is HOT_SPOT'."<br />\n"; $comment[$i] = trim($comment[$i] ?? null);
}
$reponse[$i] = trim($reponse[$i]);
$comment[$i] = trim($comment[$i]);
$weighting[$i] = $weighting[$i]; // it can be float $weighting[$i] = $weighting[$i]; // it can be float
// checks if field is empty // checks if field is empty
@ -101,7 +104,7 @@ if ($submitAnswers || $buttonBack) {
break; break;
} }
if ('0;0|0|0' == $hotspot_coordinates[$i] || empty($hotspot_coordinates[$i])) { if ('0;0|0|0' === $hotspot_coordinates[$i] || empty($hotspot_coordinates[$i])) {
$msgErr = get_lang('You haven\'t drawn all your hotspots yet'); $msgErr = get_lang('You haven\'t drawn all your hotspots yet');
// clears answers already recorded into the Answer object // clears answers already recorded into the Answer object
$objAnswer->cancel(); $objAnswer->cancel();
@ -116,9 +119,9 @@ if ($submitAnswers || $buttonBack) {
echo str_repeat('&nbsp;', 4).'$answerType is HOT_SPOT'."<br />\n"; echo str_repeat('&nbsp;', 4).'$answerType is HOT_SPOT'."<br />\n";
} }
$reponse[$i] = trim($reponse[$i]); $reponse[$i] = trim($reponse[$i] ?? null);
$comment[$i] = trim($comment[$i]); $comment[$i] = trim($comment[$i] ?? null);
$weighting[$i] = $weighting[$i]; // It can be float. $weighting[$i] = $weighting[$i] ?? null; // It can be float.
if ($weighting[$i]) { if ($weighting[$i]) {
$questionWeighting += $weighting[$i]; $questionWeighting += $weighting[$i];
@ -162,14 +165,14 @@ if ($submitAnswers || $buttonBack) {
$url = isset($_POST['url']) ? $_POST['url'] : ''; $url = isset($_POST['url']) ? $_POST['url'] : '';
$destination = []; $destination = [];
$threadhold1 = $_POST['threadhold1']; $threadhold1 = $_POST['threadhold1'] ?? null;
$threadhold2 = $_POST['threadhold2']; $threadhold2 = $_POST['threadhold2'] ?? null;
$threadhold3 = $_POST['threadhold3']; $threadhold3 = $_POST['threadhold3'] ?? null;
for ($i = 1; $i <= $nbrAnswers; $i++) { for ($i = 1; $i <= $nbrAnswers; $i++) {
$reponse[$i] = trim($reponse[$i]); $reponse[$i] = trim($reponse[$i] ?? null);
$comment[$i] = trim($comment[$i]); $comment[$i] = trim($comment[$i] ?? null);
$weighting[$i] = $weighting[$i]; $weighting[$i] = $weighting[$i] ?? null;
if (empty($threadhold1[$i])) { if (empty($threadhold1[$i])) {
$threadhold1_str = 0; $threadhold1_str = 0;
@ -191,7 +194,7 @@ if ($submitAnswers || $buttonBack) {
$threadhold_total = $threadhold1_str.';'.$threadhold2_str.';'.$threadhold3_str; $threadhold_total = $threadhold1_str.';'.$threadhold2_str.';'.$threadhold3_str;
if (isset($try[$i]) && 'on' == $try[$i]) { if (isset($try[$i]) && 'on' === $try[$i]) {
$try_str = 1; $try_str = 1;
} else { } else {
$try_str = 0; $try_str = 0;
@ -207,10 +210,8 @@ if ($submitAnswers || $buttonBack) {
if (isset($url[$i]) && !empty($url[$i])) { if (isset($url[$i]) && !empty($url[$i])) {
$url_str = $url[$i]; $url_str = $url[$i];
} }
$question_str = 0;
if ('' == $select_question[$i]) { if (isset($select_question[$i]) && !empty($select_question[$i])) {
$question_str = 0;
} else {
$question_str = $select_question[$i]; $question_str = $select_question[$i];
} }
@ -226,7 +227,7 @@ if ($submitAnswers || $buttonBack) {
break; break;
} }
if ($weighting[$i] <= 0 && 'oar' != $_SESSION['tmp_answers']['hotspot_type'][$i]) { if ($weighting[$i] <= 0 && 'oar' !== $_SESSION['tmp_answers']['hotspot_type'][$i]) {
$msgErr = get_lang('You must give a positive score for each hotspots'); $msgErr = get_lang('You must give a positive score for each hotspots');
// clears answers already recorded into the Answer object // clears answers already recorded into the Answer object
$objAnswer->cancel(); $objAnswer->cancel();
@ -234,7 +235,7 @@ if ($submitAnswers || $buttonBack) {
break; break;
} }
if ('0;0|0|0' == $hotspot_coordinates[$i] || empty($hotspot_coordinates[$i])) { if ('0;0|0|0' === $hotspot_coordinates[$i] || empty($hotspot_coordinates[$i])) {
$msgErr = get_lang('You haven\'t drawn all your hotspots yet'); $msgErr = get_lang('You haven\'t drawn all your hotspots yet');
// clears answers already recorded into the Answer object // clears answers already recorded into the Answer object
$objAnswer->cancel(); $objAnswer->cancel();

@ -72,25 +72,7 @@ $em = Database::getManager();
$data = []; $data = [];
$data['type'] = 'solution'; $data['type'] = 'solution';
$data['lang'] = [ $data['lang'] = HotSpot::getLangVariables();
'Square' => get_lang('Square'),
'Ellipse' => get_lang('Ellipse'),
'Polygon' => get_lang('Polygon'),
'HotspotStatus1' => get_lang('HotspotStatus1'),
'HotspotStatus2Polygon' => get_lang('HotspotStatus2Polygon'),
'HotspotStatus2Other' => get_lang('HotspotStatus2Other'),
'HotspotStatus3' => get_lang('HotspotStatus3'),
'HotspotShowUserPoints' => get_lang('HotspotShowUserPoints'),
'ShowHotspots' => get_lang('ShowHotspots'),
'Triesleft' => get_lang('Triesleft'),
'HotspotExerciseFinished' => get_lang('HotspotExerciseFinished'),
'NextAnswer' => get_lang('NextAnswer'),
'Delineation' => get_lang('Delineation'),
'CloseDelineation' => get_lang('CloseDelineation'),
'Oar' => get_lang('Oar'),
'ClosePolygon' => get_lang('ClosePolygon'),
'DelineationStatus1' => get_lang('DelineationStatus1'),
];
$data['image'] = $imagePath; $data['image'] = $imagePath;
$data['image_width'] = $pictureWidth; $data['image_width'] = $pictureWidth;
$data['image_height'] = $pictureHeight; $data['image_height'] = $pictureHeight;

@ -150,7 +150,7 @@ class MultipleAnswerTrueFalse extends Question
} }
// show comment when feedback is enable // show comment when feedback is enable
if (EXERCISE_FEEDBACK_TYPE_EXAM != $obj_ex->getFeedbackType()) { if (EXERCISE_FEEDBACK_TYPE_EXAM != $obj_ex->getFeedbackType()) {
$form->addElement( $txtComment = $form->addElement(
'html_editor', 'html_editor',
'comment['.$i.']', 'comment['.$i.']',
null, null,

@ -139,10 +139,10 @@ class UniqueAnswer extends Question
if (isset($answer->destination[$i])) { if (isset($answer->destination[$i])) {
$item_list = explode('@@', $answer->destination[$i]); $item_list = explode('@@', $answer->destination[$i]);
} }
$try = isset($item_list[0]) ? $item_list[0] : ''; $try = $item_list[0] ?? '';
$lp = isset($item_list[1]) ? $item_list[1] : ''; $lp = $item_list[1] ?? '';
$list_dest = isset($item_list[2]) ? $item_list[2] : ''; $list_dest = $item_list[2] ?? '';
$url = isset($item_list[3]) ? $item_list[3] : ''; $url = $item_list[3] ?? '';
if (0 == $try) { if (0 == $try) {
$try_result = 0; $try_result = 0;

@ -300,10 +300,10 @@ class UniqueAnswerNoOption extends Question
$comment = trim($form->getSubmitValue('comment['.$i.']')); $comment = trim($form->getSubmitValue('comment['.$i.']'));
$weighting = trim($form->getSubmitValue('weighting['.$i.']')); $weighting = trim($form->getSubmitValue('weighting['.$i.']'));
$scenario = $form->getSubmitValue('scenario'); $scenario = $form->getSubmitValue('scenario');
$try = $scenario['try'.$i]; $try = $scenario['try'.$i] ?? null;
$lp = $scenario['lp'.$i]; $lp = $scenario['lp'.$i] ?? null;
$destination = $scenario['destination'.$i]; $destination = $scenario['destination'.$i] ?? null;
$url = trim($scenario['url'.$i]); $url = trim($scenario['url'.$i] ?? null);
/* /*
How we are going to parse the destination value How we are going to parse the destination value

@ -12,6 +12,10 @@ use Chamilo\CourseBundle\Repository\CAnnouncementAttachmentRepository;
use Chamilo\CourseBundle\Repository\CAnnouncementRepository; use Chamilo\CourseBundle\Repository\CAnnouncementRepository;
use Chamilo\CourseBundle\Repository\CCalendarEventAttachmentRepository; use Chamilo\CourseBundle\Repository\CCalendarEventAttachmentRepository;
use Chamilo\CourseBundle\Repository\CDocumentRepository; use Chamilo\CourseBundle\Repository\CDocumentRepository;
use Chamilo\CourseBundle\Repository\CForumAttachmentRepository;
use Chamilo\CourseBundle\Repository\CForumForumRepository;
use Chamilo\CourseBundle\Repository\CQuizQuestionCategoryRepository;
use Chamilo\CourseBundle\Repository\CQuizQuestionRepository;
use Knp\Menu\FactoryInterface as MenuFactoryInterface; use Knp\Menu\FactoryInterface as MenuFactoryInterface;
use Sylius\Bundle\SettingsBundle\Form\Factory\SettingsFormFactory; use Sylius\Bundle\SettingsBundle\Form\Factory\SettingsFormFactory;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -35,6 +39,11 @@ trait ControllerTrait
$services[] = CAnnouncementRepository::class; $services[] = CAnnouncementRepository::class;
$services[] = CAnnouncementAttachmentRepository::class; $services[] = CAnnouncementAttachmentRepository::class;
$services[] = CCalendarEventAttachmentRepository::class; $services[] = CCalendarEventAttachmentRepository::class;
$services[] = CQuizQuestionRepository::class;
$services[] = CQuizQuestionCategoryRepository::class;
$services[] = CForumForumRepository::class;
$services[] = CForumAttachmentRepository::class;
/*$services[] = CAttendanceRepository::class; /*$services[] = CAttendanceRepository::class;
$services[] = CDocumentRepository::class; $services[] = CDocumentRepository::class;

Loading…
Cancel
Save