���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home3/cpr76684/public_html/customfields.tar
���ѧ٧ѧ�
db/access.php 0000644 00000003600 15152206134 0007101 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Plugin capabilities are defined here. * * @package qbank_customfields * @category access * @copyright 2021 Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $capabilities = [ // Controls if a user can can change the value of a locked custom field. 'qbank/customfields:changelockedcustomfields' => [ 'riskbitmask' => RISK_SPAM, 'captype' => 'write', 'contextlevel' => CONTEXT_COURSE, 'archetypes' => [ 'manager' => CAP_ALLOW ], ], // Controls if a user can configure question custom fields. 'qbank/customfields:configurecustomfields' => [ 'riskbitmask' => RISK_SPAM, 'captype' => 'write', 'contextlevel' => CONTEXT_SYSTEM, 'clonepermissionsfrom' => 'moodle/site:config' ], // Controls if a user can view the content of hidden custom fields. 'qbank/customfields:viewhiddencustomfields' => [ 'captype' => 'read', 'contextlevel' => CONTEXT_COURSE, 'archetypes' => [ 'editingteacher' => CAP_ALLOW, 'manager' => CAP_ALLOW ], ], ]; tests/question_handler_test.php 0000644 00000014461 15152206134 0013027 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields; /** * Class qbank_customfields_question_handler_testcase * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class question_handler_test extends \advanced_testcase { /** * Question setup helper method. * * @return int The question id. * @throws coding_exception */ protected function setup_question(): int { $category = $this->getDataGenerator()->create_category(); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $context = \context_coursecat::instance($category->id); $questioncategory = $questiongenerator->create_question_category(['contextid' => $context->id]); $questiondata = ['category' => $questioncategory->id, 'idnumber' => 'q1']; $question = $questiongenerator->create_question('shortanswer', null, $questiondata); return $question->id; } /** * Test custom field data. */ public function test_get_field_data(): void { $this->resetAfterTest(); $fieldgenerator = $this->getDataGenerator()->get_plugin_generator('core_customfield'); $instanceid = $this->setup_question(); $fieldvalue = 'test field text'; $categorydata = new \stdClass(); $categorydata->component = 'qbank_customfields'; $categorydata->area = 'question'; $categorydata->name = 'test category'; $customfieldcatid = $fieldgenerator->create_category($categorydata)->get('id'); $field = $fieldgenerator->create_field(['categoryid' => $customfieldcatid, 'type' => 'text', 'shortname' => 'f1']); $fieldgenerator->add_instance_data($field, $instanceid, $fieldvalue); // Get the field data. $customfieldhandler = customfield\question_handler::create(); $fieldinstancedata = $customfieldhandler->get_field_data($field, $instanceid); $this->assertEquals($categorydata->name, $fieldinstancedata->get_field()->get_category()->get('name')); $this->assertEquals($fieldvalue, $fieldinstancedata->get_value()); } /** * Test getting custom field data for table display. */ public function test_display_custom_field_table(): void { $this->resetAfterTest(); $fieldgenerator = $this->getDataGenerator()->get_plugin_generator('core_customfield'); $instanceid = $this->setup_question(); $fieldvalue = 'test field text'; $categorydata = new \stdClass(); $categorydata->component = 'qbank_customfields'; $categorydata->area = 'question'; $categorydata->name = 'test category'; $customfieldcatid = $fieldgenerator->create_category($categorydata)->get('id'); $field = $fieldgenerator->create_field(['categoryid' => $customfieldcatid, 'type' => 'text', 'shortname' => 'f1']); $fieldgenerator->add_instance_data($field, $instanceid, $fieldvalue); // Get the field data. $customfieldhandler = customfield\question_handler::create(); $fieldinstancedata = $customfieldhandler->get_field_data($field, $instanceid); $output = $customfieldhandler->display_custom_field_table($fieldinstancedata); $this->assertStringContainsString($fieldvalue, $output); } /** * Test getting categories and field data for a specific instance. */ public function test_get_categories_fields_data(): void { $this->resetAfterTest(); $fieldgenerator = $this->getDataGenerator()->get_plugin_generator('core_customfield'); $instanceid = $this->setup_question(); $field1value = 'first field text'; $field2value = 'second field text'; $field3value = 'third field text'; $categorydata = new \stdClass(); $categorydata->component = 'qbank_customfields'; $categorydata->area = 'question'; $categorydata->name = 'test category'; $customfieldcat1id = $fieldgenerator->create_category($categorydata)->get('id'); $categorydata->name = 'test category two'; $customfieldcat2id = $fieldgenerator->create_category($categorydata)->get('id'); $field1 = $fieldgenerator->create_field(['categoryid' => $customfieldcat1id, 'type' => 'text', 'shortname' => 'f1']); $fieldgenerator->add_instance_data($field1, $instanceid, $field1value); $field2 = $fieldgenerator->create_field(['categoryid' => $customfieldcat1id, 'type' => 'text', 'shortname' => 'f2']); $fieldgenerator->add_instance_data($field2, $instanceid, $field2value); $field3 = $fieldgenerator->create_field(['categoryid' => $customfieldcat2id, 'type' => 'text', 'shortname' => 'f3']); $fieldgenerator->add_instance_data($field3, $instanceid, $field3value); // Get the field data. $customfieldhandler = customfield\question_handler::create(); $outputdata = $customfieldhandler->get_categories_fields_data($instanceid); $this->assertEquals($field1value, $outputdata['test category'][0]['value']); $this->assertEquals($field2value, $outputdata['test category'][1]['value']); $this->assertEquals($field3value, $outputdata['test category two'][0]['value']); // While we're here, lets test the rendering of this data. $outputhtml = $customfieldhandler->display_custom_categories_fields($outputdata); $this->assertStringContainsString($field1value, $outputhtml); $this->assertStringContainsString($field2value, $outputhtml); $this->assertStringContainsString($field3value, $outputhtml); } } tests/behat/customfield_question.feature 0000644 00000005745 15152206134 0014625 0 ustar 00 @core @core_question @core_customfield @qbank_customfields @javascript Feature: A teacher can edit question with custom fields In order to improve my questions As a teacher I need to be able to edit questions and add extra metadata via custom fields Background: Given the following "users" exist: | username | firstname | lastname | email | | teacher1 | Teacher | 1 | teacher1@example.com | And the following "courses" exist: | fullname | shortname | format | | Course 1 | C1 | weeks | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | And the following "custom field categories" exist: | name | component | area | itemid | | Category for test | qbank_customfields | question | 0 | And the following "custom fields" exist: | name | category | type | shortname | | Field 1 | Category for test | text | f1 | And the following "activity" exists: | activity | quiz | | course | C1 | | idnumber | 00001 | | name | Test quiz name | | intro | Test quiz description | | section | 1 | | grade | 10 | And I log in as "teacher1" And I am on "Course 1" course homepage with editing mode on And I add a "True/False" question to the "Test quiz name" quiz with: | Question name | First question | | Question text | Answer the first question | | General feedback | Thank you, this is the general feedback | | Correct answer | False | | Feedback for the response 'True'. | So you think it is true | | Feedback for the response 'False'. | So you think it is false | And I am on the "Test quiz name" "mod_quiz > question bank" page Scenario: Edit a previously created question and see the custom field in the overview table and in the question preview. When I choose "Edit question" action for "First question" in the question bank And I should see "Category for test" And I click on "Expand all" "link" And I should see "Field 1" And I set the following fields to these values: | Field 1 | custom field text | And I press "id_submitbutton" And I should see "First question" And I should see "custom field text" And I choose "Preview" action for "First question" in the question bank And I should see "Field 1" Then I should see "custom field text" Scenario: Preview a previously created question with custom fields set with empty values When I choose "Preview" action for "First question" in the question bank And I should see "Field 1" Then I should not see "custom field text" tests/behat/customfield_question_visbility.feature 0000644 00000006536 15152206134 0016722 0 ustar 00 @core @core_quiz @core_customfield @qbank_customfields @javascript Feature: The visibility of question custom fields control where they are displayed In order to display custom fields in a quiz Background: Given the following "users" exist: | username | firstname | lastname | email | | teacher1 | Terry1 | Teacher1 | teacher1@example.com | And the following "courses" exist: | fullname | shortname | format | | Course 1 | C1 | weeks | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | And the following "custom field categories" exist: | name | component | area | itemid | | Category for test | qbank_customfields | question | 0 | And the following "custom fields" exist: | name | category | type | shortname | configdata | | Field 1 | Category for test | text | f1 | {"visibility":"2"} | | Field 2 | Category for test | text | f2 | {"visibility":"2"} | | Field 3 | Category for test | text | f3 | {"visibility":"2","defaultvalue":"secret"} | And the following "activity" exists: | activity | quiz | | course | C1 | | idnumber | 00001 | | name | Test quiz name | | intro | Test quiz description | | section | 1 | | grade | 10 | When I log in as "teacher1" And I am on "Course 1" course homepage with editing mode on And I add a "True/False" question to the "Test quiz name" quiz with: | Question name | First question | | Question text | Answer the first question | | General feedback | Thank you, this is the general feedback | | Correct answer | False | | Feedback for the response 'True'. | So you think it is true | | Feedback for the response 'False'. | So you think it is false | And I am on the "Test quiz name" "mod_quiz > question bank" page @javascript Scenario: Display custom question fields to teachers based on their visibility. When I choose "Edit question" action for "First question" in the question bank And I should see "Category for test" And I click on "Expand all" "link" And I should see "Field 1" And I should see "Field 2" And I should see "Field 3" And I set the following fields to these values: | Field 1 | custom field text one| | Field 2 | custom field text two| And I press "id_submitbutton" And I should see "Field 1" And I should see "custom field text one" And I should see "Field 2" And I should see "custom field text two" And I should see "Field 3" And I should see "secret" And I choose "Preview" action for "First question" in the question bank And I should see "Field 1" And I should see "custom field text one" And I should see "Field 2" And I should see "custom field text two" And I should see "Field 3" Then I should see "secret" tests/behat/customfield_question_setup.feature 0000644 00000013137 15152206134 0016037 0 ustar 00 @core @core_question @core_customfield @qbank_customfields @javascript Feature: Site administrators can manage categories for question custom fields In order to have additional data in questions As a site site administrator I need to create, edit, remove and sort question custom field categories Scenario: Create a category for custom question fields Given I log in as "admin" When I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration And I press "Add a new category" And I wait until the page is ready Then I should see "Other fields" in the "#customfield_catlist" "css_element" Scenario: Edit a category name for custom question fields Given the following "custom field categories" exist: | name | component | area | itemid | | Category for test | qbank_customfields | question | 0 | And I log in as "admin" And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration And I set the field "Edit category name" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element" to "Good fields" Then I should not see "Category for test" in the "#customfield_catlist" "css_element" And "New value for Category for test" "field" should not exist And I should see "Good fields" in the "#customfield_catlist" "css_element" Scenario: Delete a category for custom question fields Given the following "custom field categories" exist: | name | component | area | itemid | | Category for test | qbank_customfields | question | 0 | And the following "custom fields" exist: | name | category | type | shortname | | Field 1 | Category for test | text | f1 | And I log in as "admin" And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration And I click on "[data-role='deletecategory']" "css_element" And I click on "Yes" "button" in the "Confirm" "dialogue" And I wait until the page is ready And I wait until "Test category" "text" does not exist Then I should not see "Test category" in the "#customfield_catlist" "css_element" Scenario: Move field in the question custom fields to another category Given the following "custom field categories" exist: | name | component | area | itemid | | Category1 | qbank_customfields | question | 0 | | Category2 | qbank_customfields | question | 0 | | Category3 | qbank_customfields | question | 0 | And the following "custom fields" exist: | name | category | type | shortname | | Field1 | Category1 | text | f1 | | Field2 | Category2 | text | f2 | When I log in as "admin" And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration Then "Field1" "text" should appear after "Category1" "text" And "Category2" "text" should appear after "Field1" "text" And "Field2" "text" should appear after "Category2" "text" And "Category3" "text" should appear after "Field2" "text" And I press "Move \"Field1\"" And I follow "To the top of category Category2" And "Category2" "text" should appear after "Category1" "text" And "Field1" "text" should appear after "Category2" "text" And "Field2" "text" should appear after "Field1" "text" And "Category3" "text" should appear after "Field2" "text" And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration And "Category2" "text" should appear after "Category1" "text" And "Field1" "text" should appear after "Category2" "text" And "Field2" "text" should appear after "Field1" "text" And "Category3" "text" should appear after "Field2" "text" And I press "Move \"Field1\"" And I follow "After field Field2" And "Field1" "text" should appear after "Field2" "text" Scenario: Reorder question custom field categories Given the following "custom field categories" exist: | name | component | area | itemid | | Category1 | qbank_customfields | question | 0 | | Category2 | qbank_customfields | question | 0 | | Category3 | qbank_customfields | question | 0 | And the following "custom fields" exist: | name | category | type | shortname | | Field1 | Category1 | text | f1 | When I log in as "admin" And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration Then "Field1" "text" should appear after "Category1" "text" And "Category2" "text" should appear after "Field1" "text" And "Category3" "text" should appear after "Category2" "text" And I press "Move \"Category2\"" And I follow "After \"Category3\"" And "Field1" "text" should appear after "Category1" "text" And "Category3" "text" should appear after "Field1" "text" And "Category2" "text" should appear after "Category3" "text" And I navigate to "Plugins > Question bank plugins > Question custom fields" in site administration And "Field1" "text" should appear after "Category1" "text" And "Category3" "text" should appear after "Field1" "text" And "Category2" "text" should appear after "Category3" "text" And I press "Move \"Category2\"" And I follow "After \"Category1\"" And "Field1" "text" should appear after "Category1" "text" And "Category2" "text" should appear after "Field1" "text" And "Category3" "text" should appear after "Category2" "text" tests/customfield_test.php 0000644 00000032300 15152206134 0011771 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); /** * Class qbank_customfields_customfield_testcase * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class customfield_test extends \advanced_testcase { /** * @var array Data object for generating a question. */ protected $question1data; /** * @var array Data object for generating a question. */ protected $question2data; /** * @var component_generator_base Question Generator. */ protected $qgen; /** * @var core_course_category Course category. */ protected $category; /** * @var stdClass Course object. */ protected $course; /** * @var int Timestamp to use in tests. */ protected $testnow = 1632278491; /** * Helper to assist with setting up custom fields. * This is creating custom field category and the fields, not adding instance field data. */ protected function setup_custom_fields(): void { $dg = self::getDataGenerator(); $data = new \stdClass(); $data->component = 'qbank_customfields'; $data->area = 'question'; $catid = $dg->create_custom_field_category($data)->get('id'); $dg->create_custom_field(['categoryid' => $catid, 'type' => 'text', 'shortname' => 'f1']); $dg->create_custom_field(['categoryid' => $catid, 'type' => 'checkbox', 'shortname' => 'f2']); $dg->create_custom_field(['categoryid' => $catid, 'type' => 'date', 'shortname' => 'f3', 'configdata' => ['startyear' => 2000, 'endyear' => 3000, 'includetime' => 1]]); $dg->create_custom_field(['categoryid' => $catid, 'type' => 'select', 'shortname' => 'f4', 'configdata' => ['options' => "a\nb\nc"]]); $dg->create_custom_field(['categoryid' => $catid, 'type' => 'textarea', 'shortname' => 'f5']); } /** * Helper to assist with setting up questions used in tests. */ protected function setup_questions(): void { // Question initial set up. $this->category = $this->getDataGenerator()->create_category(); $this->course = $this->getDataGenerator()->create_course(['category' => $this->category->id]); $context = \context_coursecat::instance($this->category->id); $this->qgen = $this->getDataGenerator()->get_plugin_generator('core_question'); $qcat = $this->qgen->create_question_category(['contextid' => $context->id]); $this->question1data = [ 'category' => $qcat->id, 'idnumber' => 'q1', 'customfield_f1' => 'some text', 'customfield_f2' => 1, 'customfield_f3' => $this->testnow, 'customfield_f4' => 2, 'customfield_f5_editor' => ['text' => 'test', 'format' => FORMAT_HTML]]; $this->question2data = [ 'category' => $qcat->id, 'idnumber' => 'q2', 'customfield_f1' => 'some more text', 'customfield_f2' => 0, 'customfield_f3' => $this->testnow, 'customfield_f4' => 1, 'customfield_f5_editor' => ['text' => 'test text', 'format' => FORMAT_HTML]]; } /** * Makes a backup of the course. * * @param \stdClass $course The course object. * @return string Unique identifier for this backup. */ protected function backup_course(\stdClass $course): string { global $CFG, $USER; // Turn off file logging, otherwise it can't delete the file (Windows). $CFG->backup_file_logger_level = \backup::LOG_NONE; // Do backup with default settings. MODE_IMPORT means it will just // create the directory and not zip it. $bc = new \backup_controller(\backup::TYPE_1COURSE, $course->id, \backup::FORMAT_MOODLE, \backup::INTERACTIVE_NO, \backup::MODE_IMPORT, $USER->id); $backupid = $bc->get_backupid(); $bc->execute_plan(); $bc->destroy(); return $backupid; } /** * Restores a backup that has been made earlier. * * @param string $backupid The unique identifier of the backup. * @param string $fullname Full name of the new course that is going to be created. * @param string $shortname Short name of the new course that is going to be created. * @param int $categoryid The course category the backup is going to be restored in. * @return int The new course id. */ protected function restore_course(string $backupid, string $fullname, string $shortname, int $categoryid): int { global $CFG, $USER; // Turn off file logging, otherwise it can't delete the file (Windows). $CFG->backup_file_logger_level = \backup::LOG_NONE; // Do restore to new course with default settings. $newcourseid = \restore_dbops::create_new_course($fullname, $shortname, $categoryid); $rc = new \restore_controller($backupid, $newcourseid, \backup::INTERACTIVE_NO, \backup::MODE_GENERAL, $USER->id, \backup::TARGET_NEW_COURSE); $rc->execute_precheck(); $rc->execute_plan(); $rc->destroy(); return $newcourseid; } /** * Test creating questions with custom fields. */ public function test_create_question(): void { $this->resetAfterTest(); $this->setAdminUser(); $this->setup_custom_fields(); $this->setup_questions(); // Create 2 questions. $question1 = $this->qgen->create_question('shortanswer', null, $this->question1data); $question2 = $this->qgen->create_question('shortanswer', null, $this->question2data); // Explicitly save the custom field data for the questions, like a form would. $customfieldhandler = \qbank_customfields\customfield\question_handler::create(); $this->question1data['id'] = $question1->id; $this->question2data['id'] = $question2->id; $customfieldhandler->instance_form_save((object)$this->question1data); $customfieldhandler->instance_form_save((object)$this->question2data); // Get the custom field data associated with these question ids. $q1cfdata = $customfieldhandler->export_instance_data_object($question1->id); $q2cfdata = $customfieldhandler->export_instance_data_object($question2->id); $this->assertEquals('some text', $q1cfdata->f1); $this->assertEquals('Yes', $q1cfdata->f2); $this->assertEquals(userdate($this->testnow, get_string('strftimedaydatetime')), $q1cfdata->f3); $this->assertEquals('b', $q1cfdata->f4); $this->assertEquals('test', $q1cfdata->f5); $this->assertEquals('some more text', $q2cfdata->f1); $this->assertEquals('No', $q2cfdata->f2); $this->assertEquals(userdate($this->testnow, get_string('strftimedaydatetime')), $q2cfdata->f3); $this->assertEquals('a', $q2cfdata->f4); $this->assertEquals('test text', $q2cfdata->f5); } /** * Test deleting questions with custom fields. */ public function test_delete_question(): void { $this->resetAfterTest(); $this->setAdminUser(); $this->setup_custom_fields(); $this->setup_questions(); // Create 2 questions. $question1 = $this->qgen->create_question('shortanswer', null, $this->question1data); $question2 = $this->qgen->create_question('shortanswer', null, $this->question2data); // Explicitly save the custom field data for the questions, like a form would. $customfieldhandler = \qbank_customfields\customfield\question_handler::create(); $this->question1data['id'] = $question1->id; $this->question2data['id'] = $question2->id; $customfieldhandler->instance_form_save((object)$this->question1data); $customfieldhandler->instance_form_save((object)$this->question2data); // Get the custom field data associated with these question ids. $q1cfdata = $customfieldhandler->export_instance_data_object($question1->id); $q2cfdata = $customfieldhandler->export_instance_data_object($question2->id); // Quick check that we have data for the custom fields. $this->assertEquals('some text', $q1cfdata->f1); $this->assertEquals('some more text', $q2cfdata->f1); // Delete the questions. question_delete_question($question1->id); question_delete_question($question2->id); // Check the custom field data for the questions has also gone. $q1cfdata = $customfieldhandler->export_instance_data_object($question1->id); $q2cfdata = $customfieldhandler->export_instance_data_object($question2->id); $this->assertEmpty($q1cfdata->f1); $this->assertEmpty($q2cfdata->f1); } /** * Test custom fields attached to questions persist * across the backup and restore process. */ public function test_backup_restore(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $this->setup_custom_fields(); $this->setup_questions(); $courseshortname = $this->course->shortname; $coursefullname = $this->course->fullname; // Create 2 questions. $question1 = $this->qgen->create_question('shortanswer', null, $this->question1data); $question2 = $this->qgen->create_question('shortanswer', null, $this->question2data); // Explicitly save the custom field data for the questions, like a form would. $customfieldhandler = \qbank_customfields\customfield\question_handler::create(); $this->question1data['id'] = $question1->id; $this->question2data['id'] = $question2->id; $customfieldhandler->instance_form_save((object)$this->question1data); $customfieldhandler->instance_form_save((object)$this->question2data); // Create a quiz and the questions to that. $quiz = $this->getDataGenerator()->create_module( 'quiz', ['course' => $this->course->id, 'name' => 'restored_quiz']); quiz_add_quiz_question($question1->id, $quiz); quiz_add_quiz_question($question2->id, $quiz); // Backup the course. $backupid = $this->backup_course($this->course); // Now delete everything. delete_course($this->course, false); question_delete_question($question1->id); question_delete_question($question2->id); // Check the custom field data for the questions has also gone. $q1cfdata = $customfieldhandler->export_instance_data_object($question1->id); $q2cfdata = $customfieldhandler->export_instance_data_object($question2->id); $this->assertEmpty($q1cfdata->f1); $this->assertEmpty($q2cfdata->f1); // Restore the backup we had made earlier into a new course. $newcategory = $this->getDataGenerator()->create_category(); $this->restore_course($backupid, $coursefullname, $courseshortname . '_2', $newcategory->id); // The questions and their associated custom fields should have been restored. $sql = 'SELECT q.* FROM {question} q JOIN {question_versions} qv ON qv.questionid = q.id JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid WHERE qbe.idnumber = ?'; $newquestion1 = $DB->get_record_sql($sql, ['q1']); $newquestion1cfdata = $customfieldhandler->export_instance_data_object($newquestion1->id); $this->assertEquals('some text', $newquestion1cfdata->f1); $this->assertEquals('Yes', $newquestion1cfdata->f2); $this->assertEquals(userdate($this->testnow, get_string('strftimedaydatetime')), $newquestion1cfdata->f3); $this->assertEquals('b', $newquestion1cfdata->f4); $this->assertEquals('test', $newquestion1cfdata->f5); $newquestion2 = $DB->get_record_sql($sql, ['q2']); $newquestion2cfdata = $customfieldhandler->export_instance_data_object($newquestion2->id); $this->assertEquals('some more text', $newquestion2cfdata->f1); $this->assertEquals('No', $newquestion2cfdata->f2); $this->assertEquals(userdate($this->testnow, get_string('strftimedaydatetime')), $newquestion2cfdata->f3); $this->assertEquals('a', $newquestion2cfdata->f4); $this->assertEquals('test text', $newquestion2cfdata->f5); } } templates/table_display.mustache 0000644 00000002022 15152206134 0013104 0 ustar 00 {{! This file is part of Moodle - http://moodle.org/ Moodle is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Moodle is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Moodle. If not, see <http://www.gnu.org/licenses/>. }} {{! @template qbank_customfields/table_display Example context (json): { "ftype" : "text", "shortname" : "nickname", "value" : "Star Lord" } }} {{#hasvalue}} <div class="customfield customfield_{{type}} customfield_{{shortname}}"> <span class="customfieldvalue">{{{value}}}</span> </div> {{/hasvalue}} templates/preview_display.mustache 0000644 00000002576 15152206134 0013514 0 ustar 00 {{! This file is part of Moodle - http://moodle.org/ Moodle is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Moodle is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Moodle. If not, see <http://www.gnu.org/licenses/>. }} {{! @template qbank_customfields/preview_display Example context (json): {"categories":[ { "catname":"Other fields", "fields":[ {"name":"checkit", "value":"No"}, {"name":"datetime", "value":"1 October 2021"} ] } ]} }} <h3>{{#str}} customfield, qbank_customfields {{/str}}</h3> {{#categories}} <h4>{{catname}}</h4> {{#fields}} <div class="customfield customfield_{{type}} customfield_{{shortname}}"> <span class="customfieldname">{{{name}}}</span><span class="customfieldseparator">: </span><span class="customfieldvalue">{{{value}}}</span> </div> {{/fields}} {{/categories}} backup/moodle2/restore_qbank_customfields_plugin.class.php 0000644 00000005027 15152206134 0020170 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Restore plugin class that provides the necessary information needed to restore comments for questions. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_qbank_customfields_plugin extends restore_qbank_plugin { /** * Returns the paths to be handled by the plugin at question level. * * @return restore_path_element[] The restore path element array. */ protected function define_question_plugin_structure(): array { return [new restore_path_element('customfield', $this->get_pathfor('/customfields/customfield'))]; } /** * Process the question custom field element. * * @param array $data The custom field data to restore. */ public function process_customfield(array $data) { global $DB; $newquestion = $this->get_new_parentid('question'); if (!empty($data->contextid) && $newcontextid = $this->get_mappingid('context', $data->contextid)) { $fieldcontextid = $newcontextid; } else { // Get the category, so we can then later get the context. $categoryid = $this->get_new_parentid('question_category'); if (empty($this->cachedcategory) || $this->cachedcategory->id != $categoryid) { $this->cachedcategory = $DB->get_record('question_categories', ['id' => $categoryid]); } $fieldcontextid = $this->cachedcategory->contextid; } $data['newquestion'] = $newquestion; $data['fieldcontextid'] = $fieldcontextid; $customfieldhandler = qbank_customfields\customfield\question_handler::create(); $customfieldhandler->restore_instance_data_from_backup($this->task, $data); } } backup/moodle2/backup_qbank_customfields_plugin.class.php 0000644 00000005204 15152206134 0017747 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Provides the information to backup question custom field. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class backup_qbank_customfields_plugin extends \backup_qbank_plugin { /** * Returns the comment information to attach to question element. * * @return backup_plugin_element The backup plugin element */ protected function define_question_plugin_structure(): backup_plugin_element { // Define the virtual plugin element with the condition to fulfill. $plugin = $this->get_plugin_element(); // Create one standard named plugin element (the visible container). $pluginwrapper = new backup_nested_element($this->get_recommended_name()); // Connect the visible container ASAP. $plugin->add_child($pluginwrapper); $customfields = new backup_nested_element('customfields'); $customfield = new backup_nested_element('customfield', ['id'], ['shortname', 'type', 'value', 'valueformat']); $pluginwrapper->add_child($customfields); $customfields->add_child($customfield); $customfield->set_source_sql("SELECT cfd.id, cff.shortname, cff.type, cfd.value, cfd.valueformat FROM {customfield_data} cfd JOIN {customfield_field} cff ON cff.id = cfd.fieldid JOIN {customfield_category} cfc ON cfc.id = cff.categoryid WHERE cfc.component = 'qbank_customfields' AND cfc.area = 'question' AND cfd.instanceid = ?", [ backup::VAR_PARENTID ]); // Don't need to annotate ids nor files. return $plugin; } } settings.php 0000644 00000002617 15152206134 0007122 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Plugin administration pages are defined here. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); if ($hassiteconfig) { // Settings for question custom fields. $settings = null; $ADMIN->add('qbanksettings', new admin_externalpage('qbank_customfields', new lang_string('pluginname', 'qbank_customfields'), $CFG->wwwroot . '/question/bank/customfields/customfield.php', ['qbank/customfields:configurecustomfields'] ) ); } customfield.php 0000644 00000002647 15152206134 0007603 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Manage question custom fields * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once('../../..//config.php'); require_once($CFG->libdir.'/adminlib.php'); admin_externalpage_setup('qbank_customfields'); $output = $PAGE->get_renderer('core_customfield'); $customfieldhandler = qbank_customfields\customfield\question_handler::create(); $outputpage = new \core_customfield\output\management($customfieldhandler); echo $output->header(), $output->heading(new lang_string('pluginname', 'qbank_customfields')), $output->render($outputpage), $output->footer(); lib.php 0000644 00000002737 15152206134 0006033 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Helper functions and callbacks. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Safat Shahin <safatshahin@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Comment content for callbacks. * * @param question_definition $question * @param int $courseid * @return string */ function qbank_customfields_preview_display(question_definition $question, int $courseid): string { // Prepare custom fields data. $customfieldhandler = qbank_customfields\customfield\question_handler::create(); $catfielddata = $customfieldhandler->get_categories_fields_data($question->id); return $customfieldhandler->display_custom_categories_fields($catfielddata); } version.php 0000644 00000002172 15152206134 0006743 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Version information for qbank_customfields. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'qbank_customfields'; $plugin->version = 2022112800; $plugin->requires = 2022111800; $plugin->maturity = MATURITY_STABLE; classes/output/renderer.php 0000644 00000003716 15152206134 0012066 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields\output; /** * Class renderer. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-ca.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class renderer extends \plugin_renderer_base { /** * Render custom field data for table display. * * @param object $fielddata The field data to display. * @return string The rendered HTML. */ public function render_for_table(object $fielddata): string { $context = $fielddata->export_for_template($this); return $this->render_from_template('qbank_customfields/table_display', $context); } /** * Render custom filed data for table display. * * @param array $catfielddata The category and field data. * @return string The rendered HTML. */ public function render_for_preview(array $catfielddata): string { $context = ['categories' => []]; foreach ($catfielddata as $key => $value) { $context['categories'][] = [ 'catname' => $key, 'fields' => $value ]; } return $this->render_from_template('qbank_customfields/preview_display', $context); } } classes/privacy/provider.php 0000644 00000002516 15152206134 0012224 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields\privacy; /** * Privacy Subsystem for qbank_customfields implementing null_provider. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\null_provider { /** * Get the language string identifier with the component's language * file to explain why this plugin stores no data. * * @return string */ public static function get_reason(): string { return 'privacy:metadata'; } } classes/plugin_feature.php 0000644 00000004272 15152206134 0011727 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields; use core_question\local\bank\plugin_features_base; use core_question\local\bank\view; use qbank_customfields\customfield\question_handler; /** * Class plugin_feature is the entrypoint for the columns. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class plugin_feature extends plugin_features_base { /** * This method will return the array of objects to be rendered as a prt of question bank columns/actions. * * @param view $qbank * @return array */ public function get_question_columns(view $qbank): array { // We make a column for each custom field and load the data into it. $columns = []; // First get all the available question custom fields. $customfieldhandler = question_handler::create(); $fields = $customfieldhandler->get_fields(); $context = $qbank->get_most_specific_context(); // Iterate through the fields initialising a column for each. // We don't need to know the values that questions have at this stage. foreach ($fields as $field) { if ($customfieldhandler->can_view_type($field, $context)) { $customfieldcolumn = new custom_field_column($qbank, $field); $columns[] = $customfieldcolumn; } } return $columns; } } classes/customfield/question_handler.php 0000644 00000030272 15152206134 0014577 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields\customfield; use core_customfield\api; use core_customfield\field_controller; use core_customfield\output\field_data; /** * Question handler for custom fields. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class question_handler extends \core_customfield\handler { /** * @var question_handler */ static protected $singleton; /** * @var \context */ protected $parentcontext; /** @var int Field is displayed in the question display and question preview, visible to everybody */ const VISIBLETOALL = 2; /** @var int Field is displayed in the question display and question preview but only for "teachers" */ const VISIBLETOTEACHERS = 1; /** @var int Field is not displayed in the question display and question preview */ const NOTVISIBLE = 0; /** * Creates the custom field handler and returns a singleton. * Itemid is always zero as the custom fields are the same * for every question across the system. * * @param int $itemid Always zero. * @return \qbank_customfields\customfield\question_handler */ public static function create(int $itemid = 0) : \core_customfield\handler { if (static::$singleton === null) { self::$singleton = new static(0); } return self::$singleton; } /** * Run reset code after unit tests to reset the singleton usage. */ public static function reset_caches(): void { if (!PHPUNIT_TEST) { throw new \coding_exception('This feature is only intended for use in unit tests'); } static::$singleton = null; } /** * The current user can configure custom fields on this component. * * @return bool true if the current can configure custom fields, false otherwise */ public function can_configure() : bool { return has_capability('qbank/customfields:configurecustomfields', $this->get_configuration_context()); } /** * The current user can edit custom fields for the given question. * * @param field_controller $field * @param int $instanceid id of the question to test edit permission * @return bool true if the current can edit custom fields, false otherwise */ public function can_edit(field_controller $field, int $instanceid = 0) : bool { if ($instanceid) { $context = $this->get_instance_context($instanceid); } else { $context = $this->get_parent_context(); } return (!$field->get_configdata_property('locked') || has_capability('qbank/customfields:changelockedcustomfields', $context)); } /** * The current user can view custom fields for the given question. * * @param field_controller $field * @param int $instanceid id of the question to test edit permission * @return bool true if the current can edit custom fields, false otherwise */ public function can_view(field_controller $field, int $instanceid) : bool { $visibility = $field->get_configdata_property('visibility'); if ($visibility == self::NOTVISIBLE) { return false; } else if ($visibility == self::VISIBLETOTEACHERS) { return has_capability('qbank/customfields:viewhiddencustomfields', $this->get_instance_context($instanceid)); } else { return true; } } /** * Determine if the current user can view custom field in their given context. * This determines if the user can see the field at all not just the field for * a particular instance. * Used primarily in showing or not the field in the question bank table. * * @param field_controller $field The field trying to be viewed. * @param context $context The context the field is being displayed in. * @return bool true if the current can edit custom fields, false otherwise. */ public function can_view_type(field_controller $field, \context $context) : bool { $visibility = $field->get_configdata_property('visibility'); if ($visibility == self::NOTVISIBLE) { return false; } else if ($visibility == self::VISIBLETOTEACHERS) { return has_capability('qbank/customfields:viewhiddencustomfields', $context); } else { return true; } } /** * Sets parent context for the question. * * This may be needed when question is being created, there is no question context but we need to check capabilities * * @param \context $context */ public function set_parent_context(\context $context): void { $this->parentcontext = $context; } /** * Returns the parent context for the question. * * @return \context */ protected function get_parent_context() : \context { if ($this->parentcontext) { return $this->parentcontext; } else { return \context_system::instance(); } } /** * Context that should be used for new categories created by this handler. * * @return \context the context for configuration */ public function get_configuration_context() : \context { return \context_system::instance(); } /** * URL for configuration page for the fields for the question custom fields. * * @return \moodle_url The URL to configure custom fields for this component */ public function get_configuration_url() : \moodle_url { return new \moodle_url('/question/customfield.php'); } /** * Returns the context for the data associated with the given instanceid. * * @param int $instanceid id of the record to get the context for * @return \context the context for the given record * @throws \coding_exception */ public function get_instance_context(int $instanceid = 0) : \context { if ($instanceid > 0) { $questiondata = \question_bank::load_question_data($instanceid); $contextid = $questiondata->contextid; $context = \context::instance_by_id($contextid); return $context; } else { throw new \coding_exception('Instance id must be provided.'); } } /** * Given a field and instance id get all the filed data. * * @param field_controller $field The field to get the data for. * @param int $instanceid The instance id to get the data for. * @return \core_customfield\data_controller The fetched data. */ public function get_field_data(\core_customfield\field_controller $field, int $instanceid): \core_customfield\data_controller { $fields = [$field->get('id') => $field]; $fieldsdata = api::get_instance_fields_data($fields, $instanceid); return $fieldsdata[$field->get('id')]; } /** * For a given instance id (question id) get the categories and the * fields with any data. Return an array of categories containing an * array of field names and values that is ready to be passed to a renderer. * * @param int $instanceid The instance id to get the data for. * @return array $cfdata The fetched data */ public function get_categories_fields_data(int $instanceid): array { // Prepare custom fields data. $instancedata = $this->get_instance_data($instanceid); $cfdata = []; foreach ($instancedata as $instance) { $field = $instance->get_field(); if ($this->can_view($field, $instanceid)) { $category = $instance->get_field()->get_category()->get('name'); $fieldname = $field->get_formatted_name(); $fieldvalue = $this->get_field_data($field, $instanceid)->export_value(); $cfdata[$category][] = ['name' => $fieldname, 'value' => $fieldvalue]; } } return $cfdata; } /** * Get the custom data for the given field * and render HTML ready for display in question table. * * @param object $fielddata The field data used for display. * @return string The HTML to display in the table column. */ public function display_custom_field_table(object $fielddata) : string { global $PAGE; $output = $PAGE->get_renderer('qbank_customfields'); $outputdata = new field_data($fielddata); return $output->render_for_table($outputdata); } /** * Render the custom field category and filed data as HTML ready for display. * * @param array $catfielddata Array of categories and field names and values. * @return string The HTML to display. */ public function display_custom_categories_fields(array $catfielddata) : string { global $PAGE; $output = $PAGE->get_renderer('qbank_customfields'); return $output->render_for_preview($catfielddata); } /** * Add custom controls to the field configuration form that will be saved. * * @param \MoodleQuickForm $mform The form to add the custom fields to. */ public function config_form_definition(\MoodleQuickForm $mform): void { $mform->addElement('header', 'question_handler_header', get_string('customfieldsettings', 'qbank_customfields')); $mform->setExpanded('question_handler_header', true); // If field is locked. $mform->addElement('selectyesno', 'configdata[locked]', get_string('customfield_islocked', 'qbank_customfields')); $mform->addHelpButton('configdata[locked]', 'customfield_islocked', 'qbank_customfields'); // Field data visibility. $visibilityoptions = [ self::VISIBLETOALL => get_string('customfield_visibletoall', 'qbank_customfields'), self::VISIBLETOTEACHERS => get_string('customfield_visibletoteachers', 'qbank_customfields'), self::NOTVISIBLE => get_string('customfield_notvisible', 'qbank_customfields') ]; $mform->addElement('select', 'configdata[visibility]', get_string('customfield_visibility', 'qbank_customfields'), $visibilityoptions); $mform->addHelpButton( 'configdata[visibility]', 'customfield_visibility', 'qbank_customfields'); } /** * Creates or updates the question custom field data when restoring from a backup. * * @param \restore_task $task * @param array $data */ public function restore_instance_data_from_backup(\restore_task $task, array $data): void { $editablefields = $this->get_editable_fields($data['newquestion']); $records = api::get_instance_fields_data($editablefields, $data['newquestion']); $target = $task->get_target(); $override = ($target != \backup::TARGET_CURRENT_ADDING && $target != \backup::TARGET_EXISTING_ADDING); foreach ($records as $d) { $field = $d->get_field(); if ($field->get('shortname') === $data['shortname'] && $field->get('type') === $data['type']) { if (!$d->get('id') || $override) { $d->set($d->datafield(), $data['value']); $d->set('value', $data['value']); $d->set('valueformat', $data['valueformat']); $d->set('contextid', $data['fieldcontextid']); $d->save(); } return; } } } } classes/custom_field_column.php 0000644 00000006255 15152206134 0012753 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace qbank_customfields; use core_question\local\bank\column_base; /** * A column type for the name of the question creator. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class custom_field_column extends column_base { /** @var \core_customfield\field_controller The custom field this column is displaying. */ protected $field; /** * Constructor. * * @param view $qbank the question bank view we are helping to render. * @param \core_customfield\field_controller $field The custom field this column is displaying. */ public function __construct(\core_question\local\bank\view $qbank, \core_customfield\field_controller $field) { parent::__construct($qbank); $this->field = $field; } /** * Get the internal name for this column. Used as a CSS class name, * and to store information about the current sort. Must match PARAM_ALPHA. * * @return string column name. */ public function get_name(): string { return 'customfield'; } /** * Get the name of this column. This must be unique. * When using the inherited class to make many columns from one parent, * ensure each instance returns a unique value. * * @return string The unique name; */ public function get_column_name(): string { return 'custom_field_column\\' . $this->field->get('shortname'); } /** * Title for this column. Not used if is_sortable returns an array. * * @return string */ public function get_title(): string { return $this->field->get_formatted_name(); } /** * Output the contents of this column. * * @param object $question the row from the $question table, augmented with extra information. * @param string $rowclasses CSS class names that should be applied to this row of output. */ protected function display_content($question, $rowclasses): void { $fieldhandler = $this->field->get_handler(); if ($fieldhandler->can_view($this->field, $question->id)) { $fielddata = $fieldhandler->get_field_data($this->field, $question->id); echo $fieldhandler->display_custom_field_table($fielddata); } else { echo ''; } } public function get_extra_classes(): array { return ['pr-3']; } } lang/en/qbank_customfields.php 0000644 00000003764 15152206134 0012466 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Strings for component qbank_customfields, language 'en'. * * @package qbank_customfields * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Matt Porritt <mattp@catalyst-au.net> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['pluginname'] = 'Question custom fields'; $string['privacy:metadata'] = 'The Question custom fields question bank plugin does not store any personal data.'; $string['customfield'] = 'Question custom fields'; $string['customfield_islocked'] = 'Locked'; $string['customfield_islocked_help'] = 'If the field is locked, only users with the capability to change locked custom fields will be able to change it in the question settings.'; $string['customfield_notvisible'] = 'Nobody'; $string['customfield_visibility'] = 'Visible to'; $string['customfield_visibility_help'] = 'This setting determines who can view the custom field name and value.'; $string['customfield_visibletoall'] = 'Everyone'; $string['customfield_visibletoteachers'] = 'Teachers'; $string['customfieldsettings'] = 'Common question custom fields settings'; $string['customfields:changelockedcustomfields'] = 'Change locked custom fields'; $string['customfields:configurecustomfields'] = 'Configure custom fields'; $string['customfields:viewhiddencustomfields'] = 'View hidden custom fields';
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | ���֧ߧ֧�ѧ�ڧ� ����ѧߧڧ��: 0 |
proxy
|
phpinfo
|
���ѧ����ۧܧ�