Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2023-01-16 AC: Adds more OOP extensibility to mod_questionnaire. #457

Open
wants to merge 2 commits into
base: MOODLE_311_STABLE
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions classes/question/question.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,20 +181,39 @@ public function __construct($id = 0, $question = null, $context = null, $params
}

/**
* Short name for this question type - no spaces, etc..
* Short name for this question type - no spaces, etc.
* @return string
*/
abstract public function helpname();

/**
* Build a question from data.
* Build a question from id.
* @param int $qtype
* @param int|array $qdata
* @param \stdClass $context
* @return mixed
*/
public static function question_builder($qtype, $qdata = null, $context = null) {
$qclassname = '\\mod_questionnaire\\question\\'.self::qtypename($qtype);
$qclassname = '\\mod_questionnaire\\question\\' . self::qtypename($qtype);
$qid = 0;
if (!empty($qdata) && is_array($qdata)) {
$qdata = (object)$qdata;
} else if (!empty($qdata) && is_int($qdata)) {
$qid = $qdata;
}
return new $qclassname($qid, $qdata, $context, ['type_id' => $qtype]);
}

/**
* Build a question from FQCN.
* @param string $qtypefqcn
* @param int $qtype
* @param int|array $qdata
* @param \stdClass $context
* @return mixed
*/
public static function question_builder_fqcn($qtypefqcn, $qtype, $qdata = null, $context = null) {
$qclassname = (string) $qtypefqcn;
$qid = 0;
if (!empty($qdata) && is_array($qdata)) {
$qdata = (object)$qdata;
Expand Down
11 changes: 11 additions & 0 deletions db/install.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,76 +35,87 @@ function xmldb_questionnaire_install() {
$questiontype->type = 'Yes/No';
$questiontype->has_choices = 'n';
$questiontype->response_table = 'response_bool';
$questiontype->fqcn = '\\mod_questionnaire\\question\\yesno';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 2;
$questiontype->type = 'Text Box';
$questiontype->has_choices = 'n';
$questiontype->response_table = 'response_text';
$questiontype->fqcn = '\\mod_questionnaire\\question\\text';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 3;
$questiontype->type = 'Essay Box';
$questiontype->has_choices = 'n';
$questiontype->response_table = 'response_text';
$questiontype->fqcn = '\\mod_questionnaire\\question\\essay';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 4;
$questiontype->type = 'Radio Buttons';
$questiontype->has_choices = 'y';
$questiontype->response_table = 'resp_single';
$questiontype->fqcn = '\\mod_questionnaire\\question\\radio';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 5;
$questiontype->type = 'Check Boxes';
$questiontype->has_choices = 'y';
$questiontype->response_table = 'resp_multiple';
$questiontype->fqcn = '\\mod_questionnaire\\question\\check';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 6;
$questiontype->type = 'Dropdown Box';
$questiontype->has_choices = 'y';
$questiontype->response_table = 'resp_single';
$questiontype->fqcn = '\\mod_questionnaire\\question\\drop';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 8;
$questiontype->type = 'Rate (scale 1..5)';
$questiontype->has_choices = 'y';
$questiontype->response_table = 'response_rank';
$questiontype->fqcn = '\\mod_questionnaire\\question\\rate';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 9;
$questiontype->type = 'Date';
$questiontype->has_choices = 'n';
$questiontype->response_table = 'response_date';
$questiontype->fqcn = '\\mod_questionnaire\\question\\date';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 10;
$questiontype->type = 'Numeric';
$questiontype->has_choices = 'n';
$questiontype->response_table = 'response_text';
$questiontype->fqcn = '\\mod_questionnaire\\question\\numerical';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 99;
$questiontype->type = 'Page Break';
$questiontype->has_choices = 'n';
$questiontype->response_table = '';
$questiontype->fqcn = '\\mod_questionnaire\\question\\pagebreak';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

$questiontype = new stdClass();
$questiontype->typeid = 100;
$questiontype->type = 'Section Text';
$questiontype->has_choices = 'n';
$questiontype->response_table = '';
$questiontype->fqcn = '\\mod_questionnaire\\question\\sectiontext';
$id = $DB->insert_record('questionnaire_question_type', $questiontype);

}
1 change: 1 addition & 0 deletions db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
<FIELD NAME="type" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="has_choices" TYPE="char" LENGTH="1" NOTNULL="true" DEFAULT="y" SEQUENCE="false"/>
<FIELD NAME="response_table" TYPE="char" LENGTH="32" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="fqcn" TYPE="char" LENGTH="256" NOTNULL="true" SEQUENCE="false" DEFAULT="fqcn"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
Expand Down
61 changes: 61 additions & 0 deletions db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,67 @@ function xmldb_questionnaire_upgrade($oldversion=0) {
upgrade_mod_savepoint(true, 2020062301, 'questionnaire');
}

if ($oldversion < 2022121501) {
// Add new FQCN configuration for question types.
$table = new xmldb_table('questionnaire_question_type');
$field = new xmldb_field('fqcn', XMLDB_TYPE_CHAR, '256', null, XMLDB_NOTNULL, null, 'fqcn', null);

// Conditionally launch add field.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}

$qtypes = $DB->get_recordset('questionnaire_question_type', null);

foreach ($qtypes as $questiontype) {
$questiontype->fqcn = '\\mod_questionnaire\\question\\';
switch ($questiontype->typeid) {
case 1:
$questiontype->fqcn .= 'yesno';
break;
case 2:
$questiontype->fqcn .= 'text';
break;
case 3:
$questiontype->fqcn .= 'essay';
break;
case 4:
$questiontype->fqcn .= 'radio';
break;
case 5:
$questiontype->fqcn .= 'check';
break;
case 6:
$questiontype->fqcn .= 'drop';
break;
case 8:
$questiontype->fqcn .= 'rate';
break;
case 9:
$questiontype->fqcn .= 'date';
break;
case 10:
$questiontype->fqcn .= 'numerical';
break;
case 99:
$questiontype->fqcn .= 'pagebreak';
break;
case 100:
$questiontype->fqcn .= 'sectiontext';
break;
default:
$unknowntype = true;
}

if (!$unknowntype) {
$DB->update_record('questionnaire_question_type', $questiontype);
}
}

// Questionnaire savepoint reached.
upgrade_mod_savepoint(true, 2022121501, 'questionnaire');
}

return $result;
}

Expand Down
3 changes: 3 additions & 0 deletions lang/en/questionnaire.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
$string['downloadtextformat_link'] = 'mod/questionnaire/report#Download_in_text_format';
$string['downloadtypes'] = 'Report type';
$string['dropdown'] = 'Dropdown Box';
$string['dropdownbox'] = 'Dropdown Box';
$string['dropdown_help'] = 'There is no real advantage to using the Dropdown Box over using the Radio Buttons
except perhaps for longish lists of options, to save screen space.';
$string['dropdown_link'] = 'mod/questionnaire/questions#Dropdown_Box';
Expand Down Expand Up @@ -386,6 +387,8 @@
$string['overviewnumrespvw1'] = 'response';
$string['owner'] = 'Owner';
$string['page'] = 'Page';
$string['pagebreak'] = '----- Page Break -----';
$string['pagebreak_help'] = '----- Page Break -----';
$string['pageof'] = 'Page {$a->page} of {$a->totpages}';
$string['parent'] = 'Parent';
$string['participant'] = 'Participant';
Expand Down
85 changes: 57 additions & 28 deletions locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -466,34 +466,62 @@ function questionnaire_get_survey_select($courseid=0, $type='') {
* @param int $id
* @return lang_string|mixed|string
* @throws coding_exception
* @deprecated Please use questionnaire_get_type_name() instead.
*/
function questionnaire_get_type ($id) {
switch ($id) {
case 1:
return get_string('yesno', 'questionnaire');
case 2:
return get_string('textbox', 'questionnaire');
case 3:
return get_string('essaybox', 'questionnaire');
case 4:
return get_string('radiobuttons', 'questionnaire');
case 5:
return get_string('checkboxes', 'questionnaire');
case 6:
return get_string('dropdown', 'questionnaire');
case 8:
return get_string('ratescale', 'questionnaire');
case 9:
return get_string('date', 'questionnaire');
case 10:
return get_string('numeric', 'questionnaire');
case 100:
return get_string('sectiontext', 'questionnaire');
case 99:
return get_string('sectionbreak', 'questionnaire');
default:
return $id;
function questionnaire_get_type($id) {
return questionnaire_get_type_name($id);
}

/**
* Return the language string for the specified question type.
* @param int $id
* @return lang_string|mixed|string
* @throws coding_exception
*/
function questionnaire_get_type_name($id) {
global $DB;

if ($qtypeobject = $DB->get_record('questionnaire_question_type', ['typeid' => $id], '*', MUST_EXIST)) {
$qtype = preg_replace("/[^a-zA-Z]+/", "", strtolower($qtypeobject->type));

$qtypeobjectnamespace = explode('\\', questionnaire_get_question_type_object($id)->fqcn)[1];

return get_string($qtype, $qtypeobjectnamespace);
} else {
return '';
}
}

/**
* Return the language string for all question types.
* @return array
* @throws coding_exception
*/
function questionnaire_get_all_question_types() {
global $DB;

$qtypes = $DB->get_records('questionnaire_question_type', [], 'typeid',
'typeid, type, has_choices, response_table');

foreach ($qtypes as $qtype) {
$qtypenames[$qtype->typeid] = $qtype->type;
}

return $qtypenames;
}

/**
* Return an object of the specified question type.
* @param int $id
* @return stdClass
* @throws coding_exception
*/
function questionnaire_get_question_type_object($id) {
global $DB;

$qtypeobject = $DB->get_record('questionnaire_question_type', ['typeid' => $id], '*', MUST_EXIST);

return $qtypeobject;
}

/**
Expand Down Expand Up @@ -876,7 +904,8 @@ function questionnaire_prep_for_questionform($questionnaire, $qid, $qtype) {
}
}
} else {
$question = \mod_questionnaire\question\question::question_builder($qtype);
$question = questionnaire_get_question_type_object($qtype);
$question = \mod_questionnaire\question\question::question_builder_fqcn($question->fqcn, $qtype);
$question->sid = $questionnaire->survey->id;
$question->id = $questionnaire->cm->id;
$question->type_id = $qtype;
Expand All @@ -890,7 +919,7 @@ function questionnaire_prep_for_questionform($questionnaire, $qid, $qtype) {
}

/**
* Get the standard page contructs and check for validity.
* Get the standard page constructs and check for validity.
* @param int $id The coursemodule id.
* @param int $a The module instance id.
* @return array An array with the $cm, $course, and $questionnaire records in that order.
Expand Down
9 changes: 5 additions & 4 deletions questionnaire.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ public function add_questions($sid = false) {
$sec = 1;
$isbreak = false;
foreach ($records as $record) {

$this->questions[$record->id] = \mod_questionnaire\question\question::question_builder($record->type_id,
$record, $this->context);
$qtypeobject = questionnaire_get_question_type_object($record->type_id);
$this->questions[$record->id] = \mod_questionnaire\question\question::question_builder_fqcn($qtypeobject->fqcn,
$record->type_id, $record, $this->context);

if ($record->type_id != QUESPAGEBREAK) {
$this->questionsbysec[$sec][] = $record->id;
Expand Down Expand Up @@ -3020,7 +3020,8 @@ protected function get_survey_all_responses($rid = '', $userid = '', $groupid =
}

foreach ($uniquetypes as $type) {
$question = \mod_questionnaire\question\question::question_builder($type);
$qtypeobject = questionnaire_get_question_type_object($type);
$question = \mod_questionnaire\question\question::question_builder_fqcn($qtypeobject->fqcn, $type);
if (!isset($question->responsetype)) {
continue;
}
Expand Down
8 changes: 5 additions & 3 deletions questions.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@

// Log question deleted event.
$context = context_module::instance($questionnaire->cm->id);
$questiontype = \mod_questionnaire\question\question::qtypename($questionnaire->questions[$qid]->type_id);
$questiontype = questionnaire_get_all_question_types()[$questionnaire->questions[$qid]->type_id];
$params = array(
'context' => $context,
'courseid' => $questionnaire->course->id,
Expand Down Expand Up @@ -220,7 +220,8 @@
$questionrec->surveyid = $qformdata->sid;
$questionrec->type_id = QUESPAGEBREAK;
$questionrec->content = 'break';
$question = \mod_questionnaire\question\question::question_builder(QUESPAGEBREAK);
$qtypeobject = questionnaire_get_question_type_object(QUESPAGEBREAK);
$question = \mod_questionnaire\question\question::question_builder_fqcn($qtypeobject->fqcn, QUESPAGEBREAK);
$question->add($questionrec);
$reload = true;
} else {
Expand Down Expand Up @@ -296,7 +297,7 @@
// Log question created event.
if (isset($qformdata)) {
$context = context_module::instance($questionnaire->cm->id);
$questiontype = \mod_questionnaire\question\question::qtypename($qformdata->type_id);
$questiontype = questionnaire_get_all_question_types()[$qformdata->type_id];
$params = array(
'context' => $context,
'courseid' => $questionnaire->course->id,
Expand Down Expand Up @@ -413,5 +414,6 @@
} else {
$questionnaire->page->add_to_page('formarea', $questionsform->render());
}

echo $questionnaire->renderer->render($questionnaire->page);
echo $questionnaire->renderer->footer();