diff --git a/main/exercice/exercice.php b/main/exercice/exercice.php
index b3ce7661bc..37b797e2ab 100644
--- a/main/exercice/exercice.php
+++ b/main/exercice/exercice.php
@@ -698,6 +698,13 @@ if (!empty($exercise_list)) {
}*/
}
+ if ($app['security']->isGranted('ROLE_SESSION_MANAGER')) {
+ $actions .= Display::url(
+ Display::return_icon('admin_star.png', get_lang('Distribution'), '', ICON_SIZE_SMALL),
+ $app['url_generator']->generate('exercise_distribution.controller:indexAction', array('exerciseId' => $exercise_id))
+ );
+ }
+
// Number of questions
/*
$random_label = null;
diff --git a/main/exercice/question.class.php b/main/exercice/question.class.php
index 6192b3fbf4..9c1643ebc9 100644
--- a/main/exercice/question.class.php
+++ b/main/exercice/question.class.php
@@ -137,7 +137,7 @@ abstract class Question
* @param int $course_id
* @param Exercise
*
- * @return boolean - true if question exists, otherwise false
+ * @return Question
*/
public static function read($id, $course_id = null, Exercise $exercise = null)
{
diff --git a/main/exercice/testcategory.class.php b/main/exercice/testcategory.class.php
index fa2af193ea..f095d93626 100644
--- a/main/exercice/testcategory.class.php
+++ b/main/exercice/testcategory.class.php
@@ -722,6 +722,39 @@ class Testcategory
return $newCategoryList;
}
+ /**
+ * Returns an array of question ids for each category
+ * $categories[1][30] = 10, array with category id = 1 and question_id = 10
+ * A question has "n" categories
+ * @param int exercise
+ * @param array check question list
+ * @param string order by
+ * @return array
+ */
+ static function getQuestionsByCategory($categoryId) {
+ $tableQuestion = Database::get_course_table(TABLE_QUIZ_QUESTION);
+ $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
+ $TBL_QUESTION_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
+ $categoryTable = Database::get_course_table(TABLE_QUIZ_CATEGORY);
+ $categoryId = intval($categoryId);
+
+ $sql = "SELECT DISTINCT qrc.question_id, qrc.category_id
+ FROM $TBL_QUESTION_REL_CATEGORY qrc INNER JOIN $TBL_EXERCICE_QUESTION eq
+ ON (eq.question_id = qrc.question_id)
+ INNER JOIN $categoryTable c
+ ON (c.iid = qrc.category_id)
+ INNER JOIN $tableQuestion q
+ ON (q.iid = qrc.question_id )
+ WHERE qrc.category_id = $categoryId ";
+
+ $res = Database::query($sql);
+ $newCategoryList = array();
+ while ($data = Database::fetch_array($res)) {
+ $newCategoryList[] = $data['question_id'];
+ }
+ return $newCategoryList;
+ }
+
/**
* Return an array of X elements of an array
* @param array $array
diff --git a/main/inc/Entity/CQuizDistribution.php b/main/inc/Entity/CQuizDistribution.php
index 522168f7ce..e2d645e862 100644
--- a/main/inc/Entity/CQuizDistribution.php
+++ b/main/inc/Entity/CQuizDistribution.php
@@ -23,6 +23,14 @@ class CQuizDistribution
*/
private $id;
+ /**
+ * @var string
+ *
+ * @ORM\Column(name="title", type="string", length=250, precision=0, scale=0, nullable=true, unique=false)
+ */
+ private $title;
+
+
/**
* @var integer
*
@@ -58,6 +66,32 @@ class CQuizDistribution
*/
private $lastGenerationDate;
+ /**
+ * @ORM\OneToMany(targetEntity="CQuizDistributionQuestions", mappedBy="distribution", cascade={"persist", "remove"} )
+ */
+ private $questions;
+
+ public function __construct()
+ {
+ $this->lastGenerationDate = new \DateTime();
+ $this->questions = new ArrayCollection();
+ }
+
+ public function getQuestions()
+ {
+ return $this->questions;
+ }
+
+ public function setQuestions($questions)
+ {
+ $this->questions = $questions;
+ return $this;
+ }
+
+ public function setQuestion(CQuizDistributionQuestions $questions)
+ {
+ $this->questions->add($questions);
+ }
/**
* Get id
@@ -82,6 +116,29 @@ class CQuizDistribution
return $this;
}
+ /**
+ * Set title
+ *
+ * @param string $title
+ * @return CQuizDistribution
+ */
+ public function setTitle($title)
+ {
+ $this->title = $title;
+
+ return $this;
+ }
+
+ /**
+ * Get title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
/**
* Get exerciseId
*
diff --git a/main/inc/Entity/CQuizDistributionQuestions.php b/main/inc/Entity/CQuizDistributionQuestions.php
index 97ea1eeae2..09e5650f17 100644
--- a/main/inc/Entity/CQuizDistributionQuestions.php
+++ b/main/inc/Entity/CQuizDistributionQuestions.php
@@ -45,6 +45,17 @@ class CQuizDistributionQuestions
*/
private $questionId;
+ /**
+ * @ORM\ManyToOne(targetEntity="CQuizDistribution")
+ * @ORM\JoinColumn(name="quiz_distribution_id", referencedColumnName="id", nullable=true)
+ */
+ private $distribution;
+
+
+ public function setDistribution($distribution)
+ {
+ $this->distribution = $distribution;
+ }
/**
* Get id
diff --git a/main/inc/routes.php b/main/inc/routes.php
index 99be98f73a..41468ca7d1 100644
--- a/main/inc/routes.php
+++ b/main/inc/routes.php
@@ -668,5 +668,7 @@ if ($alreadyInstalled) {
$app->mount('/admin/director', new ChamiloLMS\Provider\ReflectionControllerProvider('branch_director.controller'));
$app->mount('/admin/jury_president', new ChamiloLMS\Provider\ReflectionControllerProvider('jury_president.controller'));
$app->mount('/admin/jury_member', new ChamiloLMS\Provider\ReflectionControllerProvider('jury_member.controller'));
+
+ $app->mount('/admin/question_manager/exercise_distribution', new ChamiloLMS\Provider\ReflectionControllerProvider('exercise_distribution.controller'));
}
diff --git a/main/inc/services.php b/main/inc/services.php
index 4cd9e8bd88..be4817a471 100644
--- a/main/inc/services.php
+++ b/main/inc/services.php
@@ -762,4 +762,8 @@ $app['jury_member.controller'] = $app->share(
}
);
-
+$app['exercise_distribution.controller'] = $app->share(
+ function () use ($app) {
+ return new ChamiloLMS\Controller\Admin\QuestionManager\ExerciseDistributionController($app);
+ }
+);
diff --git a/main/install/1.10.0/update.sql b/main/install/1.10.0/update.sql
index 29ece0c83a..ad9305a43f 100644
--- a/main/install/1.10.0/update.sql
+++ b/main/install/1.10.0/update.sql
@@ -55,10 +55,11 @@ RENAME TABLE branch_sync_log TO branch_transaction_log;
UPDATE settings_current SET selected_value = 'minedu' WHERE variable = 'template';
UPDATE settings_current SET selected_value = 'digedd' WHERE variable = 'stylesheets';
-
+DROP TABLE c_quiz_distribution;
CREATE TABLE c_quiz_distribution (
id int unsigned not null primary key AUTO_INCREMENT,
exercise_id int unsigned not null,
+ title varchar(255) not null,
-- the list of questions id that the student will have to go through for this form, split by ","
-- (as in track_e_exercices - this will avoid 60 more queries to the next table once the exam is taking place)
data_tracking text not null default '',
diff --git a/main/template/minedu/admin/questionmanager/exercise_distribution/add.tpl b/main/template/minedu/admin/questionmanager/exercise_distribution/add.tpl
new file mode 100644
index 0000000000..24b40d4488
--- /dev/null
+++ b/main/template/minedu/admin/questionmanager/exercise_distribution/add.tpl
@@ -0,0 +1,11 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+
+
+ {{ 'List' |trans }}
+
+
+
+{% endblock %}
diff --git a/main/template/minedu/admin/questionmanager/exercise_distribution/edit.tpl b/main/template/minedu/admin/questionmanager/exercise_distribution/edit.tpl
new file mode 100644
index 0000000000..17e1e1c99c
--- /dev/null
+++ b/main/template/minedu/admin/questionmanager/exercise_distribution/edit.tpl
@@ -0,0 +1,11 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+
+
+ {{ 'List' |trans }}
+
+
+
+{% endblock %}
diff --git a/main/template/minedu/admin/questionmanager/exercise_distribution/list.tpl b/main/template/minedu/admin/questionmanager/exercise_distribution/list.tpl
new file mode 100644
index 0000000000..e46d8e8a31
--- /dev/null
+++ b/main/template/minedu/admin/questionmanager/exercise_distribution/list.tpl
@@ -0,0 +1,31 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+
+ {{ 'Add' |trans }}
+
+
+{% endblock %}
diff --git a/main/template/minedu/admin/questionmanager/exercise_distribution/read.tpl b/main/template/minedu/admin/questionmanager/exercise_distribution/read.tpl
new file mode 100644
index 0000000000..6527886742
--- /dev/null
+++ b/main/template/minedu/admin/questionmanager/exercise_distribution/read.tpl
@@ -0,0 +1,31 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+
+ List
+
+
+ #{{ item.id }} {{ item.branchName }}
+
+ {% if item.getUsers %}
+
+ {{ 'Users' | trans }}
+
+ Add users
+ {% for branchUsers in item.getUsers %}
+
+ {{ branchUsers.user.getCompleteName }} - {{ branchUsers.role.name }}
+
+ Remove
+
+
+ {% endfor %}
+ {% endif %}
+
+
+{% endblock %}
diff --git a/src/ChamiloLMS/Controller/Admin/QuestionManager/ExerciseDistributionController.php b/src/ChamiloLMS/Controller/Admin/QuestionManager/ExerciseDistributionController.php
new file mode 100644
index 0000000000..79a19e2f7f
--- /dev/null
+++ b/src/ChamiloLMS/Controller/Admin/QuestionManager/ExerciseDistributionController.php
@@ -0,0 +1,343 @@
+
+ */
+class ExerciseDistributionController extends CommonController
+{
+ public $exerciseId = null;
+
+ /**
+ * @Route("/{exerciseId}/distribution/list")
+ * @Method({"GET"})
+ */
+ public function indexAction($exerciseId)
+ {
+ $criteria = array('exerciseId' => $exerciseId);
+ $items = $this->getRepository()->findBy($criteria);
+
+ $template = $this->get('template');
+ $template->assign('exerciseId', $exerciseId);
+ $template->assign('items', $items);
+ $template->assign('links', $this->generateLinks());
+ $response = $template->render_template($this->getTemplatePath().'list.tpl');
+ return new Response($response, 200, array());
+ }
+
+ /**
+ *
+ * @Route("/{exerciseId}/distribution/{id}", requirements={"id" = "\d+"})
+ * @Method({"GET"})
+ */
+ public function readAction($id)
+ {
+ return parent::readAction($id);
+ }
+
+ /**
+ *
+ * @Route("/{exerciseId}/distribution/{id}/toggle_visibility", requirements={"id" = "\d+"})
+ * @Method({"GET"})
+ */
+ public function toogleVisibilityAction($exerciseId, $id)
+ {
+ $criteria = array('exerciseId' => $exerciseId, 'id' => $id);
+ /** @var Entity\CQuizDistribution $distribution */
+ $distribution = $this->getRepository()->findOneBy($criteria);
+
+ $distribution->setActive(!$distribution->getActive());
+
+ $this->getManager()->persist($distribution);
+ $this->getManager()->flush();
+
+ $this->get('session')->getFlashBag()->add('success', "Visibility changed");
+ $url = $this->createUrl('list_link');
+ return $this->redirect($url);
+ }
+
+ /**
+ * @Route("/{exerciseId}/distribution/{id}/apply")
+ * @Method({"GET"})
+ */
+ public function applyDistributionAction($exerciseId, $id)
+ {
+ $em = $this->getManager();
+ $criteria = array('exerciseId' => $exerciseId);
+ $distributionRelSession = $em->getRepository('Entity\CQuizDistributionRelSession')->findOneBy($criteria);
+
+ if ($distributionRelSession) {
+ $em->remove($distributionRelSession);
+ $em->flush();
+ }
+
+ $distributionRelSession = new Entity\CQuizDistributionRelSession();
+ /*$distributionRelSession->setCId($this->getCourse()->getId());
+ $distributionRelSession->setSessionId($this->getSession()->getId());*/
+
+ $distributionRelSession->setCId(api_get_course_int_id());
+ $distributionRelSession->setSessionId(api_get_session_id());
+
+ $distributionRelSession->setQuizDistributionId($id);
+ $distributionRelSession->setExerciseId($exerciseId);
+ $em->persist($distributionRelSession);
+ $em->flush();
+
+ $this->get('session')->getFlashBag()->add('success', "Distribution applied");
+ $url = $this->createUrl('list_link');
+ return $this->redirect($url);
+ }
+
+ /**
+ * @Route("/{exerciseId}/distribution/add")
+ * @Method({"GET"})
+ */
+ public function addDistributionAction($exerciseId)
+ {
+ $template = $this->get('template');
+ $em = $this->getManager();
+ $this->exerciseId = $exerciseId;
+ $template->assign('exerciseId', $exerciseId);
+
+ $request = $this->getRequest();
+ $distribution = $this->getDefaultEntity();
+ $form = $this->createForm($this->getFormType(), $distribution);
+
+ $form->handleRequest($request);
+
+ if ($form->isValid()) {
+
+ $exercise = new \Exercise();
+ $exercise->read($exerciseId);
+ $questionList = $exercise->getQuestionList();
+ $exercise->get_categories_in_exercise();
+
+ /** @var Entity\CQuizDistribution $distribution */
+ $distribution = $form->getData();
+
+ $distribution->setDataTracking(implode(',', $questionList));
+ $distribution->setAuthorUserId($this->getUser()->getUserId());
+
+ $em->persist($distribution);
+ // Registering quiz distribution + quiz distribution questions
+ if ($distribution) {
+ foreach ($questionList as $questionId) {
+ $distributionQuestion = new Entity\CQuizDistributionQuestions();
+
+ $questionObj = \Question::read($questionId);
+ $categories = $questionObj->get_categories_from_question();
+ if (!empty($categories)) {
+ $categoryId = current($categories);
+ $distributionQuestion->setCategoryId($categoryId);
+ }
+ $distributionQuestion->setQuestionId($questionId);
+ $distributionQuestion->setDistribution($distribution);
+ $em->persist($distributionQuestion);
+ }
+ }
+
+ // Checking from all distributions
+ $em->flush();
+
+ $categoriesInExercise = $exercise->get_categories_in_exercise();
+
+ $questionsPerCategory = array();
+ foreach ($categoriesInExercise as $categoryInfo) {
+ $categoryId = $categoryInfo['category_id'];
+ $questions = \Testcategory::getQuestionsByCategory($categoryId);
+ $questionsPerCategory[$categoryId] = $questions;
+ }
+
+ $criteria = array('quizDistributionId' => $distribution->getId());
+ $currentDistributionQuestions = $this->getManager()->getRepository('Entity\CQuizDistributionQuestions')->findBy($criteria);
+
+ /** @var Entity\CQuizDistributionQuestions $question */
+ foreach ($currentDistributionQuestions as $question) {
+ $criteria = array('categoryId' => $question->getCategoryId(), 'questionId' => $question->getQuestionId());
+ $result = $this->getManager()->getRepository('Entity\CQuizDistributionQuestions')->findBy($criteria);
+
+ // doubles found !
+ if (count($result) > 1) {
+
+ // Question list of this category
+ $questionList = $questionsPerCategory[$question->getCategoryId()];
+
+ // Checking if there are questions that are not added yet
+ $qb = $this->getManager()->getRepository('Entity\CQuizDistributionQuestions')->createQueryBuilder('e');
+ $qb->where('e.categoryId = :categoryId')
+ ->andWhere($qb->expr()->notIn('e.questionId', $questionList))
+ ->setParameters(array('categoryId' => $question->getCategoryId()));
+
+ $result = $qb->getQuery()->getArrayResult();
+ // Found some questions
+ if (count($result) > 0) {
+ shuffle($result);
+ $selected = current($result);
+ } else {
+ // Nothing found take one question
+ shuffle($questionList);
+ $selected = current($questionList);
+ }
+ // $selected contains the new question id
+ if (!empty($selected)) {
+ //remove the old and create a new one
+ $newQuestionDistribution = $question;
+ $em->remove($question);
+ $newQuestionDistribution->setQuestionId($selected);
+ $em->persist($newQuestionDistribution);
+ $em->flush();
+ }
+ }
+ }
+
+ $currentDistributionQuestions = $this->getManager()->getRepository('Entity\CQuizDistributionQuestions')->findBy($criteria);
+ $questionList = array();
+ foreach($currentDistributionQuestions as $question) {
+ $questionList[] = $question->getQuestionId();
+ }
+
+ // Rebuild question list
+ $distribution->setDataTracking(implode(',', $questionList));
+ $em->persist($distribution);
+ $em->flush();
+
+ $this->get('session')->getFlashBag()->add('success', "Added");
+ $url = $this->createUrl('list_link');
+ return $this->redirect($url);
+ }
+
+ $template = $this->get('template');
+ $template->assign('links', $this->generateLinks());
+ $template->assign('form', $form->createView());
+ $response = $template->render_template($this->getTemplatePath().'add.tpl');
+ return new Response($response, 200, array());
+ }
+
+
+ /**
+ *
+ * @Route("/{exerciseId}/distribution/{id}/edit", requirements={"id" = "\d+"})
+ * @Method({"GET"})
+ */
+ public function editDistributionAction($exerciseId, $id)
+ {
+ $repo = $this->getRepository();
+ $request = $this->getRequest();
+ $item = $repo->findOneById($id);
+
+ $this->exerciseId = $exerciseId;
+ $template = $this->get('template');
+ $template->assign('exerciseId', $exerciseId);
+ $template->assign('id', $id);
+
+ if ($item) {
+
+ $form = $this->createForm($this->getFormType(), $item);
+
+ $form->handleRequest($request);
+
+ if ($form->isValid()) {
+ $data = $form->getData();
+ $this->updateAction($data);
+ $this->get('session')->getFlashBag()->add('success', "Updated");
+ $url = $this->createUrl('list_link');
+ return $this->redirect($url);
+ }
+
+ $template->assign('item', $item);
+ $template->assign('form', $form->createView());
+ $template->assign('links', $this->generateLinks());
+ $response = $template->render_template($this->getTemplatePath().'edit.tpl');
+ return new Response($response, 200, array());
+ } else {
+ return $this->createNotFoundException();
+ }
+ }
+
+ /**
+ *
+ * @Route("/{exerciseId}/distribution/{id}/delete", requirements={"id" = "\d+"})
+ * @Method({"GET"})
+ */
+ public function deleteDistributionAction($exerciseId, $id)
+ {
+ $this->exerciseId = $exerciseId;
+ $template = $this->get('template');
+ $template->assign('exerciseId', $exerciseId);
+
+ $result = $this->removeEntity($id);
+ if ($result) {
+ $url = $this->createUrl('list_link');
+ $this->get('session')->getFlashBag()->add('success', "Deleted");
+
+ return $this->redirect($url);
+ }
+ }
+
+
+
+
+
+ protected function getExtraParameters()
+ {
+ return array('exerciseId');
+ }
+
+ protected function getControllerAlias()
+ {
+ return 'exercise_distribution.controller';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getTemplatePath()
+ {
+ return 'admin/questionmanager/exercise_distribution/';
+ }
+
+ /**
+ * @return \Entity\Repository\JuryRepository
+ */
+ protected function getRepository()
+ {
+ return $this->get('orm.em')->getRepository('Entity\CQuizDistribution');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getNewEntity()
+ {
+ return new Entity\CQuizDistribution();
+ }
+
+ protected function getDefaultEntity()
+ {
+ $dist = new Entity\CQuizDistribution();
+ $dist ->setExerciseId($this->exerciseId);
+ return $dist;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getFormType()
+ {
+ return new CQuizDistributionType();
+ }
+}
diff --git a/src/ChamiloLMS/Controller/BaseController.php b/src/ChamiloLMS/Controller/BaseController.php
index fe7d9a7321..19a1079701 100644
--- a/src/ChamiloLMS/Controller/BaseController.php
+++ b/src/ChamiloLMS/Controller/BaseController.php
@@ -141,6 +141,21 @@ abstract class BaseController extends FlintController
if (!empty($session)) {
$parameters['id_session'] = $session->getId();
}
+
+ $extraParams = $this->getExtraParameters();
+
+ if (!empty($extraParams)) {
+ $request = $this->getRequest();
+ $dynamicParams = array();
+ foreach ($extraParams as $param) {
+ $value = $request->get($param);
+ if (!empty($value)) {
+ $dynamicParams[$param] = $value;
+ }
+ }
+ $parameters = array_merge($parameters, $dynamicParams);
+ }
+
if (isset($links) && is_array($links) && isset($links[$label])) {
$url = $this->generateUrl($links[$label], $parameters);
return $url;
@@ -148,6 +163,11 @@ abstract class BaseController extends FlintController
return $url = $this->generateUrl($links['list_link']);
}
+ protected function addParameters()
+ {
+ return array();
+ }
+
/**
* @see Symfony\Component\Routing\RouterInterface::generate()
*/
@@ -191,16 +211,14 @@ abstract class BaseController extends FlintController
$request = $this->getRequest();
$form = $this->createForm($this->getFormType(), $this->getDefaultEntity());
- if ($request->getMethod() == 'POST') {
- $form->bind($request);
+ $form->handleRequest($request);
- if ($form->isValid()) {
- $item = $form->getData();
- $this->createAction($item);
- $this->get('session')->getFlashBag()->add('success', "Added");
- $url = $this->createUrl('list_link');
- return $this->redirect($url);
- }
+ if ($form->isValid()) {
+ $item = $form->getData();
+ $this->createAction($item);
+ $this->get('session')->getFlashBag()->add('success', "Added");
+ $url = $this->createUrl('list_link');
+ return $this->redirect($url);
}
$template = $this->get('template');
@@ -237,15 +255,14 @@ abstract class BaseController extends FlintController
$form = $this->createForm($this->getFormType(), $item);
- if ($request->getMethod() == 'POST') {
- $form->bind($this->getRequest());
- if ($form->isValid()) {
- $data = $form->getData();
- $this->updateAction($data);
- $this->get('session')->getFlashBag()->add('success', "Updated");
- $url = $this->createUrl('list_link');
- return $this->redirect($url);
- }
+ $form->handleRequest($request);
+
+ if ($form->isValid()) {
+ $data = $form->getData();
+ $this->updateAction($data);
+ $this->get('session')->getFlashBag()->add('success', "Updated");
+ $url = $this->createUrl('list_link');
+ return $this->redirect($url);
}
$template = $this->get('template');
diff --git a/src/ChamiloLMS/Form/CQuizDistributionType.php b/src/ChamiloLMS/Form/CQuizDistributionType.php
new file mode 100644
index 0000000000..50892a722c
--- /dev/null
+++ b/src/ChamiloLMS/Form/CQuizDistributionType.php
@@ -0,0 +1,33 @@
+add('title', 'text');
+ $builder->add('active', 'checkbox', array('required' => false));
+ $builder->add('exerciseId', 'hidden');
+ $builder->add('submit', 'submit');
+ }
+
+ public function setDefaultOptions(OptionsResolverInterface $resolver)
+ {
+ $resolver->setDefaults(
+ array(
+ 'data_class' => 'Entity\CQuizDistribution'
+ )
+ );
+ }
+
+ public function getName()
+ {
+ return 'quiz_distribution';
+ }
+}