Adding distribution changes see #6718

skala
Julio Montoya 12 years ago
parent 30674e425a
commit ab3a81aa44
  1. 7
      main/exercice/exercice.php
  2. 2
      main/exercice/question.class.php
  3. 33
      main/exercice/testcategory.class.php
  4. 57
      main/inc/Entity/CQuizDistribution.php
  5. 11
      main/inc/Entity/CQuizDistributionQuestions.php
  6. 2
      main/inc/routes.php
  7. 6
      main/inc/services.php
  8. 3
      main/install/1.10.0/update.sql
  9. 11
      main/template/minedu/admin/questionmanager/exercise_distribution/add.tpl
  10. 11
      main/template/minedu/admin/questionmanager/exercise_distribution/edit.tpl
  11. 31
      main/template/minedu/admin/questionmanager/exercise_distribution/list.tpl
  12. 31
      main/template/minedu/admin/questionmanager/exercise_distribution/read.tpl
  13. 343
      src/ChamiloLMS/Controller/Admin/QuestionManager/ExerciseDistributionController.php
  14. 29
      src/ChamiloLMS/Controller/BaseController.php
  15. 33
      src/ChamiloLMS/Form/CQuizDistributionType.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;

@ -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)
{

@ -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

@ -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
*

@ -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

@ -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'));
}

@ -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);
}
);

@ -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 '',

@ -0,0 +1,11 @@
{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
{% block content %}
<a href="{{ url('exercise_distribution.controller:indexAction', {'exerciseId' : exerciseId }) }}">
{{ 'List' |trans }}
</a>
<hr />
<form action="{{ url('exercise_distribution.controller:addDistributionAction', {'exerciseId' : exerciseId }) }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
</form>
{% endblock %}

@ -0,0 +1,11 @@
{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
{% block content %}
<a href="{{ url('exercise_distribution.controller:indexAction', {'exerciseId' : exerciseId }) }}">
{{ 'List' |trans }}
</a>
<hr />
<form action="{{ url('exercise_distribution.controller:editDistributionAction', {'exerciseId' : exerciseId, 'id' : id }) }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
</form>
{% endblock %}

@ -0,0 +1,31 @@
{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
{% block content %}
<a href="{{ url('exercise_distribution.controller:addDistributionAction', {'exerciseId' : exerciseId }) }}">
{{ 'Add' |trans }}
</a>
<table class="table">
{% for item in items %}
<tr>
<td>
<a href="{{ url('exercise_distribution.controller:readAction', { 'exerciseId' : exerciseId, 'id' : item.id }) }}">
{{ item.title }}
</a>
</td>
<td>
{{ item.active }}
</td>
<td>
<a class="btn" href="{{ url('exercise_distribution.controller:editDistributionAction',
{ 'exerciseId' : exerciseId, id: item.id }) }}"> {{ 'Edit' |trans }}</a>
<a class="btn" href="{{ url('exercise_distribution.controller:toogleVisibilityAction',
{ 'exerciseId' : exerciseId, id: item.id }) }}"> {{ 'Visible' |trans }}</a>
<a class="btn" href="{{ url('exercise_distribution.controller:applyDistributionAction',
{ 'exerciseId' : exerciseId, id: item.id }) }}"> {{ 'Apply distribution' |trans }}</a>
<a class="btn" href="{{ url('exercise_distribution.controller:deleteDistributionAction',
{ 'exerciseId' : exerciseId, id: item.id }) }}"> {{ 'Delete' |trans }}</a>
</td>
</tr>
{% endfor %}
</table>
{% endblock %}

@ -0,0 +1,31 @@
{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
{% block content %}
<a href="{{ url(links.list_link) }}">
List
</a>
<h3>#{{ item.id }} {{ item.branchName }} </h3>
{% if item.getUsers %}
<hr />
<h4> {{ 'Users' | trans }} </h4>
<a class="btn" href="{{ url('branch.controller:addDirectorAction', { "id" : item.id }) }}"> Add users </a>
{% for branchUsers in item.getUsers %}
<li>
{{ branchUsers.user.getCompleteName }} - {{ branchUsers.role.name }}
<a class="btn btn-danger" href="{{ url('branch.controller:removeDirectorAction', { 'id': item.id, 'userId':branchUsers.user.userId }) }}">
Remove
</a>
</li>
{% endfor %}
{% endif %}
<hr />
<ul>
{% for subitem in subitems %}
<li>
<a href="{{ url(links.read_link, { id: subitem.id} ) }}">{{ subitem.branchName }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}

@ -0,0 +1,343 @@
<?php
/* For licensing terms, see /license.txt */
namespace ChamiloLMS\Controller\Admin\QuestionManager;
use Silex\Application;
use ChamiloLMS\Controller\CommonController;
use Entity;
use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use ChamiloLMS\Form\CQuizDistributionType;
use Doctrine\Common\Collections\Criteria;
/**
* Class DistributionController
* @package ChamiloLMS\Controller
* @author Julio Montoya <gugli100@gmail.com>
*/
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();
}
}

@ -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,8 +211,7 @@ 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();
@ -201,7 +220,6 @@ abstract class BaseController extends FlintController
$url = $this->createUrl('list_link');
return $this->redirect($url);
}
}
$template = $this->get('template');
$template->assign('links', $this->generateLinks());
@ -237,8 +255,8 @@ abstract class BaseController extends FlintController
$form = $this->createForm($this->getFormType(), $item);
if ($request->getMethod() == 'POST') {
$form->bind($this->getRequest());
$form->handleRequest($request);
if ($form->isValid()) {
$data = $form->getData();
$this->updateAction($data);
@ -246,7 +264,6 @@ abstract class BaseController extends FlintController
$url = $this->createUrl('list_link');
return $this->redirect($url);
}
}
$template = $this->get('template');
$template->assign('item', $item);

@ -0,0 +1,33 @@
<?php
namespace ChamiloLMS\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Entity;
class CQuizDistributionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->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';
}
}
Loading…
Cancel
Save