View source
<?php
namespace Drupal\quiz\Form;
use Drupal;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\quiz\Entity\Quiz;
use const QUIZ_QUESTION_ALWAYS;
use const QUIZ_QUESTION_RANDOM;
use function _quiz_update_items;
use function db_select;
use function db_update;
use function quiz_get_question_types;
use function render;
class QuizQuestionsForm extends FormBase {
function _quiz_add_fields_for_creating_questions(&$form, &$types, Quiz $quiz) {
$form['additional_questions'] = array(
'#type' => 'fieldset',
'#title' => t('Create new question'),
);
$create_question = FALSE;
$entity_manager = Drupal::entityTypeManager();
$access_handler = $entity_manager
->getAccessControlHandler('quiz_question');
foreach ($types as $type => $info) {
$options = array(
'query' => [
'qid' => $quiz
->id(),
'vid' => $quiz
->getRevisionId(),
],
'attributes' => [
'class' => 'use-ajax',
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'width' => 800,
]),
],
);
$access = $access_handler
->createAccess($type);
if ($access) {
$create_question = TRUE;
}
$url = Url::fromRoute('entity.quiz_question.add_form', [
'quiz_question_type' => $type,
], $options);
$form['additional_questions'][$type] = array(
'#markup' => '<div class="add-questions">' . Link::fromTextAndUrl($info['label'], $url)
->toString() . '</div>',
'#access' => $access,
);
}
if (!$create_question) {
$form['additional_questions']['create'] = array(
'#type' => 'markup',
'#markup' => t('You have not enabled any question type module or no has permission been given to create any question.'),
);
}
}
public function buildForm(array $form, FormStateInterface $form_state) {
$types = quiz_get_question_types();
$quiz = $form_state
->getBuildInfo()['args'][0];
$this
->_quiz_add_fields_for_creating_questions($form, $types, $quiz);
$header = [
'Question',
'Type',
'Max score',
'Auto max score',
];
if ($quiz
->get('randomization')
->getString() == 2) {
$header[] = 'Required';
}
$header = array_merge($header, [
'Revision',
'Operations',
'Weight',
'Parent',
]);
$form['question_list'] = [
'#type' => 'table',
'#title' => t('Questions in this @quiz', array(
'@quiz' => _quiz_get_quiz_name(),
)),
'#type' => 'table',
'#header' => $header,
'#empty' => t('There are currently no questions in this @quiz. Assign existing questions by using the question browser below. You can also use the links above to create new questions.', array(
'@quiz' => _quiz_get_quiz_name(),
)),
'#tabledrag' => [
[
'action' => 'match',
'relationship' => 'parent',
'group' => 'qqr-pid',
'source' => 'qqr-id',
'hidden' => TRUE,
'limit' => 1,
],
[
'action' => 'order',
'relationship' => 'sibling',
'group' => 'table-sort-weight',
],
],
];
$all_questions = $quiz
->getQuestions();
uasort($all_questions, [
'self',
'sortQuestions',
]);
$questions = [];
foreach ($all_questions as $qqr_id => $question) {
if (!$question
->get('qqr_pid')
->getString()) {
$questions[$qqr_id] = $question;
$questions += $this
->getSubQuestions($question, $all_questions);
}
}
$this
->_quiz_add_questions_to_form($form, $questions, $quiz, $types);
$always_count = isset($form['question_list']['titles']) ? count($form['question_list']['titles']) : 0;
$form['timestamp'] = array(
'#type' => 'hidden',
'#default_value' => \Drupal::time()
->getRequestTime(),
);
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
$this
->_quiz_add_revision_checkbox($form, $quiz);
return $form;
}
function getSubQuestions($root_question, $all_questions) {
$append = [];
foreach ($all_questions as $sub_question) {
if ($root_question
->id() == $sub_question
->get('qqr_pid')
->getString()) {
$append[$sub_question
->id()] = $sub_question;
}
}
return $append;
}
function sortQuestions($a, $b) {
$aw = $a
->get('weight')
->getString();
$bw = $b
->get('weight')
->getString();
if ($aw == $bw) {
return 0;
}
return $aw < $bw ? -1 : 1;
}
public function getFormId() : string {
return 'quiz_questions_form';
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$question_list = $form_state
->getValue('question_list');
foreach ($question_list as $qqr_id => $row) {
$qqr = \Drupal\quiz\Entity\QuizQuestionRelationship::load($qqr_id);
foreach ($row as $name => $value) {
if ($name == 'qqr_pid' && empty($value)) {
$value = NULL;
}
$qqr
->set($name, $value);
}
$qqr
->save();
}
\Drupal::messenger()
->addMessage(t('Questions updated successfully.'));
return;
$quiz = $form_state['build_info']['args'][0];
if (\Drupal::config('quiz.settings')
->get('auto_revisioning', 1)) {
$is_new_revision = $quiz
->hasAttempts();
}
else {
$is_new_revision = !empty($form_state['values']['new_revision']);
}
$num_random = isset($form_state['values']['num_random_questions']) ? $form_state['values']['num_random_questions'] : 0;
$quiz->max_score_for_random = isset($form_state['values']['max_score_for_random']) ? $form_state['values']['max_score_for_random'] : 1;
$questions = _quiz_update_items($quiz, $weight_map, $max_scores, $auto_update_max_scores, $is_new_revision, $refreshes, $stayers, $qnr_ids_map, $qqr_pids_map, $compulsories);
$assigned_random = 0;
foreach ($questions as $question) {
if ($question->question_status == QUIZ_QUESTION_RANDOM) {
++$assigned_random;
}
}
if ($num_random > $assigned_random) {
$num_random = $assigned_random;
\Drupal::messenger()
->addWarning(t('The number of random questions for this @quiz have been lowered to %anum to match the number of questions you assigned.', array(
'@quiz' => _quiz_get_quiz_name(),
'%anum' => $assigned_random,
)));
}
if ($quiz->type == 'quiz') {
db_update('quiz_node_properties')
->fields(array(
'number_of_random_questions' => $num_random ? $num_random : 0,
'max_score_for_random' => $quiz->max_score_for_random,
))
->condition('vid', $quiz->vid)
->condition('nid', $quiz->nid)
->execute();
$query = db_select('quiz_node_relationship', 'qnr');
$query
->addExpression('SUM(max_score)', 'sum');
$query
->condition('parent_vid', $quiz->vid);
$query
->condition('question_status', QUIZ_QUESTION_ALWAYS);
$score = $query
->execute()
->fetchAssoc();
db_update('quiz_node_properties')
->expression('max_score', 'max_score_for_random * number_of_random_questions + :sum', array(
':sum' => (int) $score['sum'],
))
->condition('vid', $quiz->vid)
->execute();
}
}
function _quiz_add_revision_checkbox(&$form, $quiz) {
$config = $this
->config('quiz.settings');
if ($quiz
->hasAttempts()) {
$results_url = Url::fromRoute('view.quiz_results.list', [
'quiz' => $quiz
->id(),
])
->toString();
$quiz_url = Url::fromRoute('entity.quiz.edit_form', [
'quiz' => $quiz
->id(),
], [
'query' => \Drupal::destination()
->getAsArray(),
])
->toString();
$form['revision_help'] = [
'#markup' => t('This quiz has been answered. To make changes to the quiz you must either <a href="@results_url">delete all results</a> or <a href="@quiz_url">create a new revision</a>.', [
'@results_url' => $results_url,
'@quiz_url' => $quiz_url,
]),
];
$form['actions']['submit']['#access'] = FALSE;
}
}
function _quiz_add_questions_to_form(&$form, &$questions, &$quiz, &$question_types) {
foreach ($questions as $id => $question_relationship) {
$question_vid = $question_relationship
->get('question_vid')
->getString();
$quiz_question = Drupal::entityTypeManager()
->getStorage('quiz_question')
->loadRevision($question_vid);
$table =& $form['question_list'];
$view_url = Url::fromRoute('entity.quiz_question.canonical', [
'quiz_question' => $quiz_question
->id(),
], [
'attributes' => [
'class' => 'use-ajax',
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'width' => 800,
]),
],
'query' => \Drupal::destination()
->getAsArray(),
]);
$edit_url = Url::fromRoute('entity.quiz_question.edit_form', [
'quiz_question' => $quiz_question
->id(),
], [
'attributes' => [
'class' => 'use-ajax',
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'width' => 800,
]),
],
'query' => \Drupal::destination()
->getAsArray(),
]);
$remove_url = Url::fromRoute('entity.quiz_question_relationship.delete_form', [
'quiz_question_relationship' => $question_relationship
->id(),
], [
'attributes' => [
'class' => 'use-ajax',
'data-dialog-type' => 'modal',
],
'query' => \Drupal::destination()
->getAsArray(),
]);
if ($quiz_question
->access('view')) {
$question_titles = [
'#markup' => Link::fromTextAndUrl($quiz_question
->get('title')
->getString(), $view_url)
->toString(),
];
}
else {
$question_titles = [
'#plain_text' => $quiz_question
->get('title')
->getString(),
];
}
$table[$id]['#attributes']['class'][] = 'draggable';
if ($quiz_question
->bundle() != 'page') {
$table[$id]['#attributes']['class'][] = 'tabledrag-leaf';
}
$table[$id]['title'] = $question_titles;
if ($question_relationship
->get('qqr_pid')
->getString()) {
$indentation = [
'#theme' => 'indentation',
'#size' => 1,
];
$table[$id]['title']['#prefix'] = render($indentation);
}
$table[$id]['type'] = array(
'#markup' => $quiz_question
->bundle(),
);
$table[$id]['max_score'] = array(
'#type' => $quiz_question
->isGraded() ? 'textfield' : 'hidden',
'#size' => 2,
'#disabled' => (bool) $question_relationship
->get('auto_update_max_score')
->getString(),
'#default_value' => $question_relationship
->get('max_score')
->getString(),
'#states' => array(
'disabled' => array(
"#edit-question-list-{$id}-auto-update-max-score" => array(
'checked' => TRUE,
),
),
),
);
$table[$id]['auto_update_max_score'] = array(
'#type' => $quiz_question
->isGraded() ? 'checkbox' : 'hidden',
'#default_value' => $question_relationship
->get('auto_update_max_score')
->getString() ? $question_relationship
->get('auto_update_max_score')
->getString() : 0,
);
if ($quiz
->get('randomization')
->getString() == 2) {
$table[$id]['question_status'] = array(
'#type' => 'checkbox',
'#default_value' => $question_relationship
->get('question_status')
->getString(),
);
}
$entity_manager = Drupal::entityTypeManager();
$access_handler = $entity_manager
->getAccessControlHandler('quiz_question');
$latest_quiz_question = Drupal::entityTypeManager()
->getStorage('quiz_question')
->load($quiz_question
->id());
if ($question_relationship
->get('question_vid')->value == $latest_quiz_question
->getRevisionId()) {
$update_cell = array(
'#markup' => t('<em>Up to date</em>'),
);
}
else {
$revisions_url = Url::fromRoute('entity.quiz_question.edit_form', [
'quiz_question' => $quiz_question
->id(),
]);
$update_cell = array(
'#type' => 'checkbox',
'#return_value' => $latest_quiz_question
->getRevisionId(),
'#title' => t('Update to latest'),
);
}
$table[$id]['question_vid'] = $update_cell;
$update_question = $access_handler
->access($quiz_question, 'update');
$table[$id]['operations'] = array(
'#type' => 'operations',
'#links' => [
[
'title' => t('Edit'),
'url' => $edit_url,
],
[
'title' => t('Remove'),
'url' => $remove_url,
],
],
);
$table[$id]['#weight'] = (int) $question_relationship
->get('weight')
->getString();
$table[$id]['weight'] = array(
'#title_display' => 'invisible',
'#title' => $this
->t('Weight for ID @id', [
'@id' => $id,
]),
'#type' => 'number',
'#default_value' => (int) $question_relationship
->get('weight')
->getString(),
'#attributes' => [
'class' => [
'table-sort-weight',
],
],
);
$table[$id]['parent']['qqr_id'] = array(
'#title' => t('Relationship ID'),
'#type' => 'hidden',
'#default_value' => $question_relationship
->get('qqr_id')
->getString(),
'#attributes' => [
'class' => [
'qqr-id',
],
],
'#parents' => [
'question_list',
$id,
'qqr_id',
],
);
$table[$id]['parent']['qqr_pid'] = array(
'#title' => t('Parent ID'),
'#title_display' => 'invisible',
'#type' => 'number',
'#size' => 3,
'#min' => 0,
'#default_value' => $question_relationship
->get('qqr_pid')
->getString(),
'#attributes' => [
'class' => [
'qqr-pid',
],
],
'#parents' => [
'question_list',
$id,
'qqr_pid',
],
);
}
}
}