<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/401/en/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gustav</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/401/en/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gustav"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/Special:Contributions/Gustav"/>
	<updated>2026-04-15T15:17:31Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Cloze&amp;diff=6266</id>
		<title>Cloze</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Cloze&amp;diff=6266"/>
		<updated>2006-02-22T19:53:13Z</updated>

		<summary type="html">&lt;p&gt;Gustav: removed duplicate paragraph&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Embedded answers (Cloze)&#039;&#039;&#039; questions consist of a passage of text (in Moodle format) that has various answers embedded within it, including multiple choice, short answers and numerical answers.&lt;br /&gt;
&lt;br /&gt;
There is currently no graphical interface to create these questions - you need to specify the question format using the text box or by importing them from external files. &lt;br /&gt;
&lt;br /&gt;
Lots of people suggest that [http://hotpot.uvic.ca/ Hot Potatoes] software is the easiest way to create Embedded answer (Cloze) questions.  Once you have created your questions on your PC, you can then import them into into Moodle&#039;s quiz module.&lt;br /&gt;
&lt;br /&gt;
==Format==&lt;br /&gt;
&lt;br /&gt;
The Moodle [http://moodle.org/help.php?module=quiz&amp;amp;file=multianswer.html help documentation for Cloze questions] gives an example.  Peter Ruthven-Stuart advises, &amp;quot;I found the best way to learn how to make the Cloze type questions was to copy the example in the above link, and then make small changes to the example until I broke it.&amp;quot; &lt;br /&gt;
&lt;br /&gt;
The number appearing at the beginning of a &#039;blank&#039; indicates the weighting for the question, and is nothing to do with the question number. So, in the example below the blank has been given a weight of &#039;2&#039;. So, if the blanks all have an equal weight, you don&#039;t need to type any number.&lt;br /&gt;
&lt;br /&gt;
{2:SHORTANSWER:%100%CALL#Yes, that&#039;s it!~%0%?#What should I __ you? Either lower or UPPER case is OK.}&lt;br /&gt;
&lt;br /&gt;
NB: Be careful when copying a cloze type question into the WYSIWYG HTML editor, as line breaks tend to get added, which destroys the question.&lt;br /&gt;
&lt;br /&gt;
Joseph Rézeau provided the following examples and the detailed explanation of the syntax.&lt;br /&gt;
&lt;br /&gt;
Match the following cities with the correct state:&lt;br /&gt;
&lt;br /&gt;
* San Francisco: {1:MULTICHOICE:=California#OK~Arizona#Wrong}&lt;br /&gt;
* Tucson: {1:MULTICHOICE:California#Wrong~%100%Arizona#OK}&lt;br /&gt;
* Los Angeles: {1:MULTICHOICE:=California#OK~Arizona#Wrong}&lt;br /&gt;
* Phoenix: {1:MULTICHOICE:%0%California#Wrong~=Arizona#OK}&lt;br /&gt;
&lt;br /&gt;
The capital of France is {1:SHORTANSWER:=Paris#Congratulations!~%50%Marseille#No, that is the second largest city in France (after Paris).~.*#Wrong answer. The capital of France is Paris, of course.} Note! This example only works in Moodle 1.5.2, see the point 12 below.&lt;br /&gt;
&lt;br /&gt;
Please note that this does not cover the [[NUMERICAL]] type question.&lt;br /&gt;
&lt;br /&gt;
# all question items within a cloze-type question are coded inside curled braces { }&lt;br /&gt;
# the number which appears between the opening brace and the colon {1: is the weighting of that item; if it is set at 1 for all the items, it needs not be specified, so you can have {:&lt;br /&gt;
# after the colon we have the item type: MULTICHOICE, SHORTANSWER, NUMERICAL&lt;br /&gt;
# the syntax for MULTICHOICE and SHORTANSWER is the same; the only difference is in the displaying of the item to the student&lt;br /&gt;
# the order of the various answers is indifferent (except if you want a catch-all for wrong answers, see #12 below)&lt;br /&gt;
# a correct answer is preceded with the equal sign = or a percentage (usually %100%)&lt;br /&gt;
# a wrong answer is preceded with nothing or a percentage (usually %0%)&lt;br /&gt;
# you can allocate some points between 0 and 100 to some answers, if you put the appropriate percentage&lt;br /&gt;
# all answers except the first one are separated from one another by the tilde ~ sign&lt;br /&gt;
# answers can be followed by an optional feedback message, preceded with the # sign; if there is no feedback message, the # sign can be present or absent, it does not matter&lt;br /&gt;
# note that the feedback message is displayed in a small popup window (if and when feedback has been declared accessible to the students in the Quiz settings) upon mouse hovering&lt;br /&gt;
# in the SHORTANSWER type you may want to put a catch-all (wrong) answer in order to send a &amp;quot;wrong, try again&amp;quot; feedback; you can do this by inserting .* as a wrong answer; this does not work in Moodle 1.5, 1.5.3 and 1.6; it works in version 1.5.2 only; see my post here&lt;br /&gt;
# unfortunately in MULTICHOICE MODE it is not possible to get the answers to be scrambled&lt;br /&gt;
# unfortunately in SHORTANSWER mode it is not possible to make the answers case-sensitive (except by using a workaround which I will make explain in a further post in this thread)&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
This information was drawn from:&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36521 Is there a guide to using the cloze format?] forum discussion&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36430&amp;amp;parent=170308 Cloze-type question syntax] forum post&lt;br /&gt;
&lt;br /&gt;
[[Category:Teacher]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Backup_and_restore_FAQ&amp;diff=5447</id>
		<title>Backup and restore FAQ</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Backup_and_restore_FAQ&amp;diff=5447"/>
		<updated>2006-02-15T21:23:29Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* How do I backup my whole Moodle site? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;Site backups&lt;br /&gt;
:Site backups, as explained in [[Upgrading_Moodle#Backup_important_data|upgrading Moodle]], are recommended in order to have all data saved with the best confidence and the shortest recovery time.&lt;br /&gt;
&lt;br /&gt;
;Course backups&lt;br /&gt;
:Course backups, configured on the [[admin/backup|backup]] page, are more expensive in terms of time and CPU usage. The recovery time to have your site running again is longer. Course backups are useful for obtaining &amp;quot;fresh&amp;quot; copies of courses to be re-used or distributed individually, however they should never be used as a primary backup system (unless your hosting doesn&#039;t allow the preferred site backups). In order to make scheduled backups, you have to setup CRON to run periodically. Have a look at [[Installing Moodle#Set_up_cron|Set up cron]] for details.&lt;br /&gt;
&lt;br /&gt;
===How do I backup my whole Moodle site?===&lt;br /&gt;
&lt;br /&gt;
There are two main things you need to make a copy of - the database and the uploaded files. The Moodle scripts themselves are less important, since you can always download a fresh copy if you have to.&lt;br /&gt;
&lt;br /&gt;
There are many ways to do such backups. Here is an outline of a little script you can run on Unix to backup the database (it works well to have such a script run daily via a cron task):&lt;br /&gt;
&lt;br /&gt;
 cd /my/backup/directory&lt;br /&gt;
 mv moodle-database.sql.gz moodle-database-old.sql.gz&lt;br /&gt;
 mysqldump -h example.com -u myusername --password=mypassword -C -Q -e -a mydatabasename &amp;gt; moodle-database.sql&lt;br /&gt;
 gzip moodle-database.sql&lt;br /&gt;
&lt;br /&gt;
For the files, you can use rsync regularly to copy only the changed files to another host:&lt;br /&gt;
&lt;br /&gt;
 rsync -auvtz --delete -e ssh mysshusername@example.com:/my/server/directory /my/backup/directory/&lt;br /&gt;
&lt;br /&gt;
===What data is not contained in course backups?===&lt;br /&gt;
&lt;br /&gt;
By selecting all the options when setting up the backup you can include almost all the data in the course. However you should be aware of the fact that some things are not backed up:&lt;br /&gt;
* Quiz questions are only backed up if at least one question from their category has been added to a quiz.&lt;br /&gt;
* Scales are only backed up if they are used by at least one activity.&lt;br /&gt;
&lt;br /&gt;
===Error: An error occurred deleting old backup data===&lt;br /&gt;
&lt;br /&gt;
This part of the backup (or restore) procedure tries to delete old info, used in previous executions, performing the following tasks:&lt;br /&gt;
&lt;br /&gt;
* Delete old records from &amp;quot;backup_ids&amp;quot; table: Check the table exists, repair it and try again.&lt;br /&gt;
&lt;br /&gt;
* Delete old records from &amp;quot;backup_files&amp;quot; table: Check the table exists, repair it and try again.&lt;br /&gt;
&lt;br /&gt;
* Delete old files from &amp;quot;moodledata/temp/backup&amp;quot;: Delete the dir completely and try again.&lt;br /&gt;
&lt;br /&gt;
There are various ways of repairing tables, including using MySQL Admin.&lt;br /&gt;
&lt;br /&gt;
===XML error: not well-formed (invalid token) at line YYYY===&lt;br /&gt;
&lt;br /&gt;
This problem can appear at any point in the restore process. It&#039;s caused when the XML parser detects something incorrect in the backup file that prevent correct operation. Usually, it&#039;s caused by some &amp;quot;illegal&amp;quot; characters added in the original course due to some copy/paste of text containing them (control characters, or invalid sequences...).&lt;br /&gt;
&lt;br /&gt;
The best method to handle this issue is:&lt;br /&gt;
&lt;br /&gt;
* Unzip the problematic backup file under one empty folder.&lt;br /&gt;
&lt;br /&gt;
* Open the moodle.xml with Firefox. It will show you where (exact char) the problem is happening.&lt;br /&gt;
&lt;br /&gt;
* Edit the moodle.xml file with some UTF8-compatible editor and delete such characters. Save changes.&lt;br /&gt;
&lt;br /&gt;
* Test the moodle.xml file again with Firefox until no error was displayed.&lt;br /&gt;
&lt;br /&gt;
* Zip everything again (all the folder contents but the folder itself!).&lt;br /&gt;
&lt;br /&gt;
* Restore the course. It should work now.&lt;br /&gt;
&lt;br /&gt;
Also, if possible, it&#039;s highly recommended to solve those problems in the original course too from Moodle itself. Once &amp;quot;repaired&amp;quot; there, problems will be out if you create new backup files in the future.&lt;br /&gt;
&lt;br /&gt;
=== Some of your courses weren&#039;t saved!! ===&lt;br /&gt;
&lt;br /&gt;
There are two possible causes of this problem:&lt;br /&gt;
&lt;br /&gt;
1. Error - this happens when the backup procedure has found an error and so hasn&#039;t finished the backup of a particular course. These are &amp;quot;controlled&amp;quot; errors and the scheduled backup continues with the next course.&lt;br /&gt;
&lt;br /&gt;
2. Unfinished - this happens when the backup procedure dies without knowing why. When the cron is next executed it detects that the last execution went wrong, and continues skipping the problematic course. A possible solution would be to raise the PHP/Apache limit in your installation (memory, time of execution...). By taking a look to your log tables you should be able to see if the &amp;quot;crash&amp;quot; is happening at exact time intervals (usually a problem with the max_execution_time php&#039;s variable), or if there is some exact point were all the courses are breaking (generally internal zip libraries, try to switch to external executables instead).&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/mod/forum/view.php?f=128 Using Moodle: Backup and Restore]&lt;br /&gt;
*[http://download.moodle.org/modules/integrations.php Moodle Download: Integrations] - MySQL Admin for download&lt;br /&gt;
&lt;br /&gt;
== External links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.databasejournal.com/features/mysql/article.php/10897_3300511_2 Repairing Database Corruption in MySQL]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:FAQ]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5431</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5431"/>
		<updated>2006-02-15T20:18:34Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_question_instances */  explain problem with random questions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}&lt;br /&gt;
==Overview==&lt;br /&gt;
The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. This table can also be used to find all the questions assigned to a particular quiz. But note that this is not the same as the questions that are actually used because if the quiz contains random questions then these in turn choose other questions to be used when an attempt is started and these actually used questions are not stored in this table.&lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;uniqueid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Primary key since Moodle 1.6 used by [[Quiz database structure#quiz_states|quiz_states table]]. See [[Separating_questions_from_quizzes]] for details.&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module run-time code. This $state run-time object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A time stamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previous state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at run time. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the run-time state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true and must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indices are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_attempts|quiz_attempts]] table. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5361</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5361"/>
		<updated>2006-02-14T16:33:47Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Moved table of contents to the top&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}&lt;br /&gt;
==Overview==&lt;br /&gt;
The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;uniqueid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Primary key since Moodle 1.6 used by [[Quiz database structure#quiz_states|quiz_states table]]. See [[Separating_questions_from_quizzes]] for details.&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module run-time code. This $state run-time object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A time stamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previous state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at run time. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the run-time state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true and must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indices are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_attempts|quiz_attempts]] table. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Blocks&amp;diff=5339</id>
		<title>Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Blocks&amp;diff=5339"/>
		<updated>2006-02-14T10:51:47Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Improved image layouts&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Blocks.jpg|thumb|Example of blocks on a course page]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;Note for Contributors&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
This page should explain briefly what &#039;&#039;&#039;blocks&#039;&#039;&#039; are.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the left and right sides of the course homepage there are side blocks, which can be added, removed and moved around. &lt;br /&gt;
&lt;br /&gt;
To enable arranging blocks (as well as the content of the course), editing should be enabled (click the &amp;quot;Turn editing on&amp;quot; button located in the top right corner of the screen).&lt;br /&gt;
&lt;br /&gt;
[[Image:BlocksEdit.jpg|frame|none|Blocks with the editing icons showing]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
Developer documentation: [[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=admin/modules&amp;diff=5335</id>
		<title>admin/modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=admin/modules&amp;diff=5335"/>
		<updated>2006-02-13T22:33:22Z</updated>

		<summary type="html">&lt;p&gt;Gustav: fixed double redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#redirect [[Modules (administrator)]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Blocks&amp;diff=5302</id>
		<title>Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Blocks&amp;diff=5302"/>
		<updated>2006-02-13T19:03:20Z</updated>

		<summary type="html">&lt;p&gt;Gustav: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;Note for Contributors&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
This page should explain briefly what &#039;&#039;&#039;blocks&#039;&#039;&#039; are.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the left and right sides of the course homepage there are side blocks, which can be added, removed and moved around. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Blocks.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To enable arranging blocks (as well as the content of the course), editing should be enabled (click the &amp;quot;Turn editing on&amp;quot; button located in the top right corner of the screen).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:BlocksEdit.jpg]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
Developer documentation: [[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5277</id>
		<title>Development:Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5277"/>
		<updated>2006-02-13T15:54:26Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_match_sub */  added code field&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_match===&lt;br /&gt;
&lt;br /&gt;
This table is only used in the code for saving matching questions and can therefore be considered redundant.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;subquestions &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:a comma separated list of ids of the question-answer pairs used in this question. These ids refer to the id field of the quiz_match_sub table.&lt;br /&gt;
&lt;br /&gt;
;shuffleanswers :tinyint(4) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:a flag that determines whether the answers should be shuffled, provided the quiz settings allows this.&lt;br /&gt;
&lt;br /&gt;
===quiz_match_sub===&lt;br /&gt;
&lt;br /&gt;
The quiz_match_sub extends the quiz_questions table. It stores the pairs of questions and answers (as strings) that need to be matched for a correct solution. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;code&lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:This field is randomly set to a unique integer. This code will be used to identify the response. The reason we do not simply use the id is that that would make it possible for students to look at the page source and match the answers and questions with the same id.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;answertext &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The matching questiontype needs to store information about the order of its subquestions and the selected responses. Because each subquestion is identified by one record in the quiz_match_sub table, the ids of this table could be used to identify both the question and the response part. This is indeed how it was done until Moodle 1.5. This however had the drawback that students who looked at the page source could figure out which answer belonged to which question. Since Moodle 1.6 the response part is encoded with respect to the new &#039;code&#039; field in the quiz_match_sub table. The entry in the &#039;code&#039; field is randomly created with rand() when a subquestion is created.&lt;br /&gt;
&lt;br /&gt;
For each subquestion a &#039;-&#039;-separated pair is created, giving first the id of the record that provided the subquestion and then the code of the record that provided the selected response. E.g. 1-3 means that the answer of the third question was selected for the first subquestion. If no response is selected, the second entry in the pair is set to &#039;0&#039;. These pairs are then put into a comma separated list to allow each subquestion to store a response.&lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
The $questions-&amp;gt;options object has the properties&lt;br /&gt;
&lt;br /&gt;
;subquestions:an array of all the records from the quiz_match_sub table for this question, i.e., all the question-answer pairs, indexed by the ids.&lt;br /&gt;
;shuffleanswers:a flag that indicates whether the answers should be shuffled, provided this is enabled at the quiz level.&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
The $state-&amp;gt;options object has a single property &#039;&#039;&#039;&#039;subquestions&#039;&#039;&#039;&#039; which holds an array of objects representing the question-answer pairs, indexed by the ids. Each entry from the table is an object with the following properties:&lt;br /&gt;
;id&lt;br /&gt;
;question&lt;br /&gt;
;questiontext&lt;br /&gt;
;answertext&lt;br /&gt;
;options&lt;br /&gt;
The &#039;&#039;&#039;options&#039;&#039;&#039; property in turn is an object with a single property &#039;&#039;&#039;answers&#039;&#039;&#039; which is an array of objects with the following properties:&lt;br /&gt;
;id:the id of this subquestion&lt;br /&gt;
;answer:the answertext for this subquestion&lt;br /&gt;
;fraction:this is always set to 1 and has the effect that all subquestions carry the same weight.&lt;br /&gt;
&lt;br /&gt;
The reason this is done in such a complicated manner is that it makes it easier to reuse the code for the matching question type also for the random short-answer questiontype.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5276</id>
		<title>Development:Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5276"/>
		<updated>2006-02-13T15:50:21Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_match */  type&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_match===&lt;br /&gt;
&lt;br /&gt;
This table is only used in the code for saving matching questions and can therefore be considered redundant.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;subquestions &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:a comma separated list of ids of the question-answer pairs used in this question. These ids refer to the id field of the quiz_match_sub table.&lt;br /&gt;
&lt;br /&gt;
;shuffleanswers :tinyint(4) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:a flag that determines whether the answers should be shuffled, provided the quiz settings allows this.&lt;br /&gt;
&lt;br /&gt;
===quiz_match_sub===&lt;br /&gt;
&lt;br /&gt;
The quiz_match_sub extends the quiz_questions table. It stores the pairs of questions and answers (as strings) that need to be matched for a correct solution. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;answertext &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The matching questiontype needs to store information about the order of its subquestions and the selected responses. Because each subquestion is identified by one record in the quiz_match_sub table, the ids of this table could be used to identify both the question and the response part. This is indeed how it was done until Moodle 1.5. This however had the drawback that students who looked at the page source could figure out which answer belonged to which question. Since Moodle 1.6 the response part is encoded with respect to the new &#039;code&#039; field in the quiz_match_sub table. The entry in the &#039;code&#039; field is randomly created with rand() when a subquestion is created.&lt;br /&gt;
&lt;br /&gt;
For each subquestion a &#039;-&#039;-separated pair is created, giving first the id of the record that provided the subquestion and then the code of the record that provided the selected response. E.g. 1-3 means that the answer of the third question was selected for the first subquestion. If no response is selected, the second entry in the pair is set to &#039;0&#039;. These pairs are then put into a comma separated list to allow each subquestion to store a response.&lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
The $questions-&amp;gt;options object has the properties&lt;br /&gt;
&lt;br /&gt;
;subquestions:an array of all the records from the quiz_match_sub table for this question, i.e., all the question-answer pairs, indexed by the ids.&lt;br /&gt;
;shuffleanswers:a flag that indicates whether the answers should be shuffled, provided this is enabled at the quiz level.&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
The $state-&amp;gt;options object has a single property &#039;&#039;&#039;&#039;subquestions&#039;&#039;&#039;&#039; which holds an array of objects representing the question-answer pairs, indexed by the ids. Each entry from the table is an object with the following properties:&lt;br /&gt;
;id&lt;br /&gt;
;question&lt;br /&gt;
;questiontext&lt;br /&gt;
;answertext&lt;br /&gt;
;options&lt;br /&gt;
The &#039;&#039;&#039;options&#039;&#039;&#039; property in turn is an object with a single property &#039;&#039;&#039;answers&#039;&#039;&#039; which is an array of objects with the following properties:&lt;br /&gt;
;id:the id of this subquestion&lt;br /&gt;
;answer:the answertext for this subquestion&lt;br /&gt;
;fraction:this is always set to 1 and has the effect that all subquestions carry the same weight.&lt;br /&gt;
&lt;br /&gt;
The reason this is done in such a complicated manner is that it makes it easier to reuse the code for the matching question type also for the random short-answer questiontype.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Multiple_Choice_question_type&amp;diff=5275</id>
		<title>Development:Multiple Choice question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Multiple_Choice_question_type&amp;diff=5275"/>
		<updated>2006-02-13T15:49:41Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_multichoice table */  added shuffleanswers field&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
==quiz_multichoice table==&lt;br /&gt;
&lt;br /&gt;
The quiz_multichoice table is an extension of the [[Quiz database structure#quiz_questions|quiz_questions table]]. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field of the [[Quiz database structure#quiz_questions|quiz_questions table]] &lt;br /&gt;
&lt;br /&gt;
;layout &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:does not seem to be used&lt;br /&gt;
&lt;br /&gt;
;answers &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:stores the order of the answers. This should be superseded by the seq_number field in the quiz_answers table&lt;br /&gt;
&lt;br /&gt;
;single &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A flag signaling, whether only one option or multiple options can be chosen.&lt;br /&gt;
&lt;br /&gt;
;shuffleanswers :tinyint(4) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:a flag that determines whether the answers should be shuffled, provided the quiz settings allows this.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
What is stored in $state-&amp;gt;responses depends on whether only a single answer is allowed or whether multiple answers are allowed. For single answers the answer id is saved in $state-&amp;gt;responses[&#039;&#039;], whereas for the multiple answers case the $state-&amp;gt;responses array is indexed by the answer ids and the values are also the answer ids (i.e. key = value).&lt;br /&gt;
&lt;br /&gt;
The multichoice questiontype stores both the order of the choices and the selected choices in the answer field of the quiz_states table. Storing the order is optional (mainly to provide backward compatibility with previous versions of this questiontype). The order is stored as a comma separated list of answer ids (i.e. form the quiz_answers table). It is separated with a colon (&#039;:&#039;) from the selected responses, which are also stored as a comma separated list of answer ids. For example 1,3,2,4:2,4 means that the answers were shown in the order 1, 3, 2 and then 4 and the answers 2 and 4 were checked. Note that the list of selected responses is usually shorter (and often contains only one id) than the list that provides the order.&lt;br /&gt;
&lt;br /&gt;
Comment by [[User:Gustav]]: It is logically not very nice that the quiz_states table is used to store the order of answers in the multiple choice question. This is information that does not change in between states. It is really associated with the attempt and the question, not the state. Unfortunately we don&#039;t have a natural table to store such information. &lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
$question-&amp;gt;options is set to the object from the appropriate record in the quiz_multichoice table but with the &#039;answers&#039; field replaced by an array of answer objects from the [[Quiz database structure#quiz_answers|quiz_answers table]].&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
$state-&amp;gt;options has a single property &#039;&#039;&#039;order&#039;&#039;&#039; that is set to an array of answerids.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Random_Short-Answer_Matching_question_type&amp;diff=5274</id>
		<title>Development:Random Short-Answer Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Random_Short-Answer_Matching_question_type&amp;diff=5274"/>
		<updated>2006-02-13T15:49:14Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Database tables */  added shuffleanswers field&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The &#039;&#039;&#039;quiz_randomsamatch&#039;&#039;&#039; table is an extension of the quiz_questions table&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field of the quiz_questions table&lt;br /&gt;
;choose &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;4&#039;,&lt;br /&gt;
:The number of shortanswer questions should be randomly chosen to build this randomsamatch question.&lt;br /&gt;
&lt;br /&gt;
;shuffleanswers :tinyint(4) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:a flag that determines whether the answers should be shuffled, provided the quiz settings allows this.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
The random shortanswer matching questiontype reuses the save_session_and_responses method of the matching questiontype and therefore stores its responses in the same format. The difference is that the first id in the pair is the question id (quiz_questions) of the selected shortanswer and the second id is the id of the first correct answer that is found ofr that shortanswer question in the quiz_answers table.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5273</id>
		<title>Development:Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5273"/>
		<updated>2006-02-13T15:48:00Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_match */  added shuffleanswers field&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_match===&lt;br /&gt;
&lt;br /&gt;
This table is only used in the code for saving matching questions and can therefore be considered redundant.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;subquestions &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:a comma separated list of ids of the question-answer pairs used in this question. These ids refer to the id field of the quiz_match_sub table.&lt;br /&gt;
&lt;br /&gt;
;shuffleanswers :tinyint(4) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:a flag that determines whether the answers should be shuffled, provided the quiz settings allows this.&lt;br /&gt;
&lt;br /&gt;
===quiz_match_sub===&lt;br /&gt;
&lt;br /&gt;
The quiz_match_sub extends the quiz_questions table. It stores the pairs of questions and answers (as strings) that need to be matched for a correct solution. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;answertext &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The matching questiontype needs to store information about the order of its subquestions and the selected responses. Because each subquestion is identified by one record in the quiz_match_sub table, the ids of this table could be used to identify both the question and the response part. This is indeed how it was done until Moodle 1.5. This however had the drawback that students who looked at the page source could figure out which answer belonged to which question. Since Moodle 1.6 the response part is encoded with respect to the new &#039;code&#039; field in the quiz_match_sub table. The entry in the &#039;code&#039; field is randomly created with rand() when a subquestion is created.&lt;br /&gt;
&lt;br /&gt;
For each subquestion a &#039;-&#039;-separated pair is created, giving first the id of the record that provided the subquestion and then the code of the record that provided the selected response. E.g. 1-3 means that the answer of the third question was selected for the first subquestion. If no response is selected, the second entry in the pair is set to &#039;0&#039;. These pairs are then put into a comma separated list to allow each subquestion to store a response.&lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
The $questions-&amp;gt;options object has the properties&lt;br /&gt;
&lt;br /&gt;
;subquestions:an array of all the records from the quiz_match_sub table for this question, i.e., all the question-answer pairs, indexed by the ids.&lt;br /&gt;
;shuffleanswers:a flag that indicates whether the answers should be shuffled, provided this is enabled at the quiz level.&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
The $state-&amp;gt;options object has a single property &#039;&#039;&#039;&#039;subquestions&#039;&#039;&#039;&#039; which holds an array of objects representing the question-answer pairs, indexed by the ids. Each entry from the table is an object with the following properties:&lt;br /&gt;
;id&lt;br /&gt;
;question&lt;br /&gt;
;questiontext&lt;br /&gt;
;answertext&lt;br /&gt;
;options&lt;br /&gt;
The &#039;&#039;&#039;options&#039;&#039;&#039; property in turn is an object with a single property &#039;&#039;&#039;answers&#039;&#039;&#039; which is an array of objects with the following properties:&lt;br /&gt;
;id:the id of this subquestion&lt;br /&gt;
;answer:the answertext for this subquestion&lt;br /&gt;
;fraction:this is always set to 1 and has the effect that all subquestions carry the same weight.&lt;br /&gt;
&lt;br /&gt;
The reason this is done in such a complicated manner is that it makes it easier to reuse the code for the matching question type also for the random short-answer questiontype.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5272</id>
		<title>Development:Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5272"/>
		<updated>2006-02-13T15:45:05Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Response storage */  now using &amp;#039;code&amp;#039; field&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_match===&lt;br /&gt;
&lt;br /&gt;
This table is only used in the code for saving matching questions and can therefore be considered redundant.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;subquestions &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_match_sub===&lt;br /&gt;
&lt;br /&gt;
The quiz_match_sub extends the quiz_questions table. It stores the pairs of questions and answers (as strings) that need to be matched for a correct solution. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;answertext &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The matching questiontype needs to store information about the order of its subquestions and the selected responses. Because each subquestion is identified by one record in the quiz_match_sub table, the ids of this table could be used to identify both the question and the response part. This is indeed how it was done until Moodle 1.5. This however had the drawback that students who looked at the page source could figure out which answer belonged to which question. Since Moodle 1.6 the response part is encoded with respect to the new &#039;code&#039; field in the quiz_match_sub table. The entry in the &#039;code&#039; field is randomly created with rand() when a subquestion is created.&lt;br /&gt;
&lt;br /&gt;
For each subquestion a &#039;-&#039;-separated pair is created, giving first the id of the record that provided the subquestion and then the code of the record that provided the selected response. E.g. 1-3 means that the answer of the third question was selected for the first subquestion. If no response is selected, the second entry in the pair is set to &#039;0&#039;. These pairs are then put into a comma separated list to allow each subquestion to store a response.&lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
The $questions-&amp;gt;options object has the properties&lt;br /&gt;
&lt;br /&gt;
;subquestions:an array of all the records from the quiz_match_sub table for this question, i.e., all the question-answer pairs, indexed by the ids.&lt;br /&gt;
;shuffleanswers:a flag that indicates whether the answers should be shuffled, provided this is enabled at the quiz level.&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
The $state-&amp;gt;options object has a single property &#039;&#039;&#039;&#039;subquestions&#039;&#039;&#039;&#039; which holds an array of objects representing the question-answer pairs, indexed by the ids. Each entry from the table is an object with the following properties:&lt;br /&gt;
;id&lt;br /&gt;
;question&lt;br /&gt;
;questiontext&lt;br /&gt;
;answertext&lt;br /&gt;
;options&lt;br /&gt;
The &#039;&#039;&#039;options&#039;&#039;&#039; property in turn is an object with a single property &#039;&#039;&#039;answers&#039;&#039;&#039; which is an array of objects with the following properties:&lt;br /&gt;
;id:the id of this subquestion&lt;br /&gt;
;answer:the answertext for this subquestion&lt;br /&gt;
;fraction:this is always set to 1 and has the effect that all subquestions carry the same weight.&lt;br /&gt;
&lt;br /&gt;
The reason this is done in such a complicated manner is that it makes it easier to reuse the code for the matching question type also for the random short-answer questiontype.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5270</id>
		<title>Development:Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5270"/>
		<updated>2006-02-13T14:15:54Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* State options object */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_match===&lt;br /&gt;
&lt;br /&gt;
This table is only used in the code for saving matching questions and can therefore be considered redundant.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;subquestions &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_match_sub===&lt;br /&gt;
&lt;br /&gt;
The quiz_match_sub extends the quiz_questions table. It stores the pairs of questions and answers (as strings) that need to be matched for a correct solution. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;answertext &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The matching questiontype needs to store information about the order of its subquestions and the selected responses. Because each subquestion is identified by one record in the quiz_match_sub table, the ids of this table are used to identify both the question and the response part. For each subquestion a &#039;-&#039;-separated pair is created, giving first the id of the record that provided the subquestion and then the id of the record that provided the selected response. E.g. 1-3 means that the answer of the third question was selected for the first subquestion. Correct responses are always pairs of identical ids, e.g 2-2. If no response is selected, the second id in the pair is set to &#039;0&#039;. These pairs are then put into a comma separated list to allow each subquestion to store a response.&lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
The $questions-&amp;gt;options object has the properties&lt;br /&gt;
&lt;br /&gt;
;subquestions:an array of all the records from the quiz_match_sub table for this question, i.e., all the question-answer pairs, indexed by the ids.&lt;br /&gt;
;shuffleanswers:a flag that indicates whether the answers should be shuffled, provided this is enabled at the quiz level.&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
The $state-&amp;gt;options object has a single property &#039;&#039;&#039;&#039;subquestions&#039;&#039;&#039;&#039; which holds an array of objects representing the question-answer pairs, indexed by the ids. Each entry from the table is an object with the following properties:&lt;br /&gt;
;id&lt;br /&gt;
;question&lt;br /&gt;
;questiontext&lt;br /&gt;
;answertext&lt;br /&gt;
;options&lt;br /&gt;
The &#039;&#039;&#039;options&#039;&#039;&#039; property in turn is an object with a single property &#039;&#039;&#039;answers&#039;&#039;&#039; which is an array of objects with the following properties:&lt;br /&gt;
;id:the id of this subquestion&lt;br /&gt;
;answer:the answertext for this subquestion&lt;br /&gt;
;fraction:this is always set to 1 and has the effect that all subquestions carry the same weight.&lt;br /&gt;
&lt;br /&gt;
The reason this is done in such a complicated manner is that it makes it easier to reuse the code for the matching question type also for the random short-answer questiontype.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5269</id>
		<title>Development:Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Matching_question_type&amp;diff=5269"/>
		<updated>2006-02-13T14:01:44Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Question options object */  added shuffleanswers&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_match===&lt;br /&gt;
&lt;br /&gt;
This table is only used in the code for saving matching questions and can therefore be considered redundant.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;subquestions &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_match_sub===&lt;br /&gt;
&lt;br /&gt;
The quiz_match_sub extends the quiz_questions table. It stores the pairs of questions and answers (as strings) that need to be matched for a correct solution. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field in the [[Quiz database structure#quiz_questions|quiz_questions table]]&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;answertext &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The matching questiontype needs to store information about the order of its subquestions and the selected responses. Because each subquestion is identified by one record in the quiz_match_sub table, the ids of this table are used to identify both the question and the response part. For each subquestion a &#039;-&#039;-separated pair is created, giving first the id of the record that provided the subquestion and then the id of the record that provided the selected response. E.g. 1-3 means that the answer of the third question was selected for the first subquestion. Correct responses are always pairs of identical ids, e.g 2-2. If no response is selected, the second id in the pair is set to &#039;0&#039;. These pairs are then put into a comma separated list to allow each subquestion to store a response.&lt;br /&gt;
&lt;br /&gt;
==Question options object==&lt;br /&gt;
&lt;br /&gt;
The $questions-&amp;gt;options object has the properties&lt;br /&gt;
&lt;br /&gt;
;subquestions:an array of all the records from the quiz_match_sub table for this question, i.e., all the question-answer pairs, indexed by the ids.&lt;br /&gt;
;shuffleanswers:a flag that indicates whether the answers should be shuffled, provided this is enabled at the quiz level.&lt;br /&gt;
&lt;br /&gt;
==State options object==&lt;br /&gt;
&lt;br /&gt;
The $state-&amp;gt;options object has a single property &#039;&#039;&#039;&#039;subquestions&#039;&#039;&#039;&#039; which holds an array of objects representing the question-answer pairs, indexed by the ids. Each entry from the table is an object with the following properties:&lt;br /&gt;
;id&lt;br /&gt;
;question&lt;br /&gt;
;questiontext&lt;br /&gt;
;answertext&lt;br /&gt;
;options&lt;br /&gt;
The &#039;&#039;&#039;options&#039;&#039;&#039; property in turn is an object with a single property &#039;&#039;&#039;answers&#039;&#039;&#039; which is an array indexed by .... Oh, who made this so complicated?&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development_talk:Developer_documentation&amp;diff=5268</id>
		<title>Development talk:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development_talk:Developer_documentation&amp;diff=5268"/>
		<updated>2006-02-13T12:39:52Z</updated>

		<summary type="html">&lt;p&gt;Gustav: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;After discussions with Helen I think that this page should have a section &amp;quot;Current development projects&amp;quot; which should have the links that are currently on the [[Developer notes]] page. That page should then simply be redirected to [[Developer documentation]]. I find it important to be able to have an overview over everything on this main page. I am not worried about this page being long, the table of contents at the top allows one to easily jump to the section of interest. --[[User:Gustav|Gustav]] 20:39, 13 February 2006 (WST)&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5263</id>
		<title>Development:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5263"/>
		<updated>2006-02-13T10:36:12Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Guides for developers */  moved link to previous section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
The M in Moodle stands for &#039;Modular&#039;. There are many different types of components that you can contribute that can be plugged into Moodle to provide additional funtionality. Even if you are not a programmer there are things you can change or help with.&lt;br /&gt;
*[[Activity modules]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Text filters]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Question types]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Guides for developers==&lt;br /&gt;
*[[Moodle architecture]]&lt;br /&gt;
*[[Coding|Coding guidelines]]&lt;br /&gt;
*[[Interface_guidelines]]&lt;br /&gt;
*[[CVS|Moodle CVS for developers]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
Ideas for and details of planned future features of Moodle are initially discussed on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course at moodle.org. That developer discussions are intermixed with user discussions in the same forums may seem strange at first but is one of the reasons for the success of Moodle. It is important that both end-users and developers discuss the future features together.&lt;br /&gt;
&lt;br /&gt;
Once ideas begin to crystalize on the forums they can be summarized in this wiki, either as part of the [[Roadmap]] or in the form of [[Developer notes]]. These pages then form the basis for further discussion in the forums.&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for core components==&lt;br /&gt;
This section is for documentation of specific components of the existing core Moodle code. Discussion of components that are under discussion or in development can be found in the [[Developer notes]] or on the [[Roadmap]].&lt;br /&gt;
&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for contributed code==&lt;br /&gt;
Many Moodle users contribute code for the benefit of other Moodle users. This can take the form of new activity modules, blocks, themes, resource plug-ins, assignment plug-ins, question type plug-ins, question import/export formats, quiz report plug-ins, course formats, ... This code is initially posted on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course and then often go into the [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/ contrib branch] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&lt;br /&gt;
* .&lt;br /&gt;
&lt;br /&gt;
== Developer resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/bugs/ Moodle bug tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code]&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://moodle.org/mod/resource/view.php?id=1267 Core API]&lt;br /&gt;
*[http://moodle.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference]&lt;br /&gt;
*[[Unmerged files|1.4 and 1.5 un-merged files]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
*[[Presentations]]&lt;br /&gt;
*[[Moodle manuals]]&lt;br /&gt;
*[[Using Moodle book]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5262</id>
		<title>Development:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5262"/>
		<updated>2006-02-13T10:33:01Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* How you can contribute */  extended the list of ways to contribute&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
The M in Moodle stands for &#039;Modular&#039;. There are many different types of components that you can contribute that can be plugged into Moodle to provide additional funtionality. Even if you are not a programmer there are things you can change or help with.&lt;br /&gt;
*[[Activity modules]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Text filters]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Question types]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Guides for developers==&lt;br /&gt;
*[[Moodle architecture]]&lt;br /&gt;
*[[Coding|Coding guidelines]]&lt;br /&gt;
*[[Interface_guidelines]]&lt;br /&gt;
*[[CVS|Moodle CVS for developers]]&lt;br /&gt;
*[[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
Ideas for and details of planned future features of Moodle are initially discussed on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course at moodle.org. That developer discussions are intermixed with user discussions in the same forums may seem strange at first but is one of the reasons for the success of Moodle. It is important that both end-users and developers discuss the future features together.&lt;br /&gt;
&lt;br /&gt;
Once ideas begin to crystalize on the forums they can be summarized in this wiki, either as part of the [[Roadmap]] or in the form of [[Developer notes]]. These pages then form the basis for further discussion in the forums.&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for core components==&lt;br /&gt;
This section is for documentation of specific components of the existing core Moodle code. Discussion of components that are under discussion or in development can be found in the [[Developer notes]] or on the [[Roadmap]].&lt;br /&gt;
&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for contributed code==&lt;br /&gt;
Many Moodle users contribute code for the benefit of other Moodle users. This can take the form of new activity modules, blocks, themes, resource plug-ins, assignment plug-ins, question type plug-ins, question import/export formats, quiz report plug-ins, course formats, ... This code is initially posted on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course and then often go into the [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/ contrib branch] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&lt;br /&gt;
* .&lt;br /&gt;
&lt;br /&gt;
== Developer resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/bugs/ Moodle bug tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code]&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://moodle.org/mod/resource/view.php?id=1267 Core API]&lt;br /&gt;
*[http://moodle.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference]&lt;br /&gt;
*[[Unmerged files|1.4 and 1.5 un-merged files]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
*[[Presentations]]&lt;br /&gt;
*[[Moodle manuals]]&lt;br /&gt;
*[[Using Moodle book]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5261</id>
		<title>Development:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5261"/>
		<updated>2006-02-13T10:09:30Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Section for contributed code&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
Even if you are not a programmer there are things you can change or help with.&lt;br /&gt;
*[[Activity modules]]&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Guides for developers==&lt;br /&gt;
*[[Moodle architecture]]&lt;br /&gt;
*[[Coding|Coding guidelines]]&lt;br /&gt;
*[[Interface_guidelines]]&lt;br /&gt;
*[[CVS|Moodle CVS for developers]]&lt;br /&gt;
*[[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
Ideas for and details of planned future features of Moodle are initially discussed on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course at moodle.org. That developer discussions are intermixed with user discussions in the same forums may seem strange at first but is one of the reasons for the success of Moodle. It is important that both end-users and developers discuss the future features together.&lt;br /&gt;
&lt;br /&gt;
Once ideas begin to crystalize on the forums they can be summarized in this wiki, either as part of the [[Roadmap]] or in the form of [[Developer notes]]. These pages then form the basis for further discussion in the forums.&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for core components==&lt;br /&gt;
This section is for documentation of specific components of the existing core Moodle code. Discussion of components that are under discussion or in development can be found in the [[Developer notes]] or on the [[Roadmap]].&lt;br /&gt;
&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for contributed code==&lt;br /&gt;
Many Moodle users contribute code for the benefit of other Moodle users. This can take the form of new activity modules, blocks, themes, resource plug-ins, assignment plug-ins, question type plug-ins, question import/export formats, quiz report plug-ins, course formats, ... This code is initially posted on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course and then often go into the [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/ contrib branch] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&lt;br /&gt;
* .&lt;br /&gt;
&lt;br /&gt;
== Developer resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/bugs/ Moodle bug tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code]&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://moodle.org/mod/resource/view.php?id=1267 Core API]&lt;br /&gt;
*[http://moodle.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference]&lt;br /&gt;
*[[Unmerged files|1.4 and 1.5 un-merged files]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
*[[Presentations]]&lt;br /&gt;
*[[Moodle manuals]]&lt;br /&gt;
*[[Using Moodle book]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5260</id>
		<title>Development:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5260"/>
		<updated>2006-02-13T09:52:10Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Plans for the future */  stress importance of forum discussions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
Even if you are not a programmer there are things you can change or help with.&lt;br /&gt;
*[[Activity modules]]&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Guides for developers==&lt;br /&gt;
*[[Moodle architecture]]&lt;br /&gt;
*[[Coding|Coding guidelines]]&lt;br /&gt;
*[[Interface_guidelines]]&lt;br /&gt;
*[[CVS|Moodle CVS for developers]]&lt;br /&gt;
*[[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
Ideas for and details of planned future features of Moodle are initially discussed on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course at moodle.org. That developer discussions are intermixed with user discussions in the same forums may seem strange at first but is one of the reasons for the success of Moodle. It is important that both end-users and developers discuss the future features together.&lt;br /&gt;
&lt;br /&gt;
Once ideas begin to crystalize on the forums they can be summarized in this wiki, either as part of the [[Roadmap]] or in the form of [[Developer notes]]. These pages then form the basis for further discussion in the forums.&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for specific components==&lt;br /&gt;
This section is for documentation of specific components of the existing core Moodle code. Discussion of components that are under discussion or in development can be found in the [[Developer notes]] or on the [[Roadmap]].&lt;br /&gt;
&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
&lt;br /&gt;
== Developer resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/bugs/ Moodle bug tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code]&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://moodle.org/mod/resource/view.php?id=1267 Core API]&lt;br /&gt;
*[http://moodle.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference]&lt;br /&gt;
*[[Unmerged files|1.4 and 1.5 un-merged files]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
*[[Presentations]]&lt;br /&gt;
*[[Moodle manuals]]&lt;br /&gt;
*[[Using Moodle book]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5259</id>
		<title>Development:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5259"/>
		<updated>2006-02-13T09:45:56Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Documentation for specific components */  now for existing code only&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
Even if you are not a programmer there are things you can change or help with.&lt;br /&gt;
*[[Activity modules]]&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Guides for developers==&lt;br /&gt;
*[[Moodle architecture]]&lt;br /&gt;
*[[Coding|Coding guidelines]]&lt;br /&gt;
*[[Interface_guidelines]]&lt;br /&gt;
*[[CVS|Moodle CVS for developers]]&lt;br /&gt;
*[[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for specific components==&lt;br /&gt;
This section is for documentation of specific components of the existing core Moodle code. Discussion of components that are under discussion or in development can be found in the [[Developer notes]] or on the [[Roadmap]].&lt;br /&gt;
&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
&lt;br /&gt;
== Developer resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/bugs/ Moodle bug tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code]&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://moodle.org/mod/resource/view.php?id=1267 Core API]&lt;br /&gt;
*[http://moodle.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference]&lt;br /&gt;
*[[Unmerged files|1.4 and 1.5 un-merged files]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
*[[Presentations]]&lt;br /&gt;
*[[Moodle manuals]]&lt;br /&gt;
*[[Using Moodle book]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_notes&amp;diff=5224</id>
		<title>Development:Developer notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_notes&amp;diff=5224"/>
		<updated>2006-02-12T15:00:42Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Moved some stuff to the main Developer documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt; &#039;&#039;&#039;Note for contributors:&#039;&#039;&#039; This area is for developers to work on various bits of code and documentation as necessary. Once material has matured it should be linked to from the main [[Developer documentation]] page.&lt;br /&gt;
Initial text has been taken from [http://moodle.org/course/view.php?id=5 Using Moodle] Developer Wiki. If you find any text missing, please email docs AT moodle DOT org.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[[Forum development|Forum functional upgrade]]&lt;br /&gt;
*[[Other lang issues|Language issues]] &lt;br /&gt;
*[[MoodleDocs development]]&lt;br /&gt;
*[[Usability]]&lt;br /&gt;
*[[Blogs and forums|Blogs, forums and the nature of discussion]]&lt;br /&gt;
*[[Document Management API]]&lt;br /&gt;
*[[Filters schema]]&lt;br /&gt;
*[[Filterall support]]&lt;br /&gt;
*[[Application/session variables]]&lt;br /&gt;
*[[Wiki development|Wiki module development]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5223</id>
		<title>Development:Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Developer_documentation&amp;diff=5223"/>
		<updated>2006-02-12T14:56:23Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Reorganised and extended&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
Even if you are not a programmer there are things you can change or help with.&lt;br /&gt;
*[[Activity modules]]&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Guides for developers==&lt;br /&gt;
*[[Moodle architecture]]&lt;br /&gt;
*[[Coding|Coding guidelines]]&lt;br /&gt;
*[[Interface_guidelines]]&lt;br /&gt;
*[[CVS|Moodle CVS for developers]]&lt;br /&gt;
*[[Blocks Howto|A Step-by-step Guide To Creating Blocks]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for specific components==&lt;br /&gt;
&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
&lt;br /&gt;
== Developer resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[http://moodle.org/bugs/ Moodle bug tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code]&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://moodle.org/mod/resource/view.php?id=1267 Core API]&lt;br /&gt;
*[http://moodle.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference]&lt;br /&gt;
*[[Unmerged files|1.4 and 1.5 un-merged files]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
*[[Presentations]]&lt;br /&gt;
*[[Moodle manuals]]&lt;br /&gt;
*[[Using Moodle book]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5217</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5217"/>
		<updated>2006-02-12T14:15:53Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_newest_states */  about uniqueid&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;uniqueid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Primary key since Moodle 1.6 used by [[Quiz database structure#quiz_states|quiz_states table]]. See [[Separating_questions_from_quizzes]] for details.&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module run-time code. This $state run-time object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A time stamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previous state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at run time. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the run-time state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true and must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indices are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_attempts|quiz_attempts]] table. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key referring to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5216</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5216"/>
		<updated>2006-02-12T14:14:16Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_states */  fixing some typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;uniqueid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Primary key since Moodle 1.6 used by [[Quiz database structure#quiz_states|quiz_states table]]. See [[Separating_questions_from_quizzes]] for details.&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module run-time code. This $state run-time object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A time stamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previous state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at run time. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the run-time state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true and must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indices are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_attempts|quiz_attempts]] table&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5215</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5215"/>
		<updated>2006-02-12T14:09:16Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_states */  about uniqueid&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;uniqueid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Primary key since Moodle 1.6 used by [[Quiz database structure#quiz_states|quiz_states table]]. See [[Separating_questions_from_quizzes]] for details.&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module runtime code. This $state runtime object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]. In Moodle 1.5 it referred to the id field of that table, since Moodle 1.6 it refers to the uniqueid field. This change was done while [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A timestamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previouse state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at runtime. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the runtime state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true amd must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indicies are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_attempts|quiz_attempts]] table&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5214</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=5214"/>
		<updated>2006-02-12T14:06:38Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_attempts */  added uniqueid&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;uniqueid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Primary key since Moodle 1.6 used by [[Quiz database structure#quiz_states|quiz_states table]]. See [[Separating_questions_from_quizzes]] for details.&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module runtime code. This $state runtime object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A timestamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previouse state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at runtime. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the runtime state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true amd must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indicies are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_attempts|quiz_attempts]] table&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=5164</id>
		<title>Development:Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=5164"/>
		<updated>2006-02-11T13:57:55Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Code documentation */  editlib.php&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module with its own modular structure to allow question type plug-ins. The module has grown organically and in spite of a lot of rewriting for Moodle 1.5 the code is not very simple to understand. This page aims to collect useful documentation on how the module works. &lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the quiz module there are certain terms that can cause confusion because they can be used with different meanings. In Moodle we have adopted a certain terminology that will be explained below.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;question&#039;&#039;&#039; in the context of the quiz module is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it is much more than what one would in everyday language understand under a question and which in Moodle is just on field (the questiontext field) of the question object.&lt;br /&gt;
&lt;br /&gt;
What in Moodle we refer to as a &#039;question&#039; is what in the terminology of the QTI specification ismore appropriately called an &#039;&#039;&#039;assessment item&#039;&#039;&#039; or just &#039;item&#039; for short. &lt;br /&gt;
&lt;br /&gt;
There are different types of questions, like for example multiple-choice questions or numerical questions. These are referred to as &#039;&#039;&#039;[[Quiz developer docs#Question types|question types]]&#039;&#039;&#039; in Moodle.&lt;br /&gt;
&lt;br /&gt;
Since version 1.5 Moodle is able to handle so-called &#039;&#039;&#039;[[Adaptive questions]]&#039;&#039;&#039;, also known as &#039;adaptive items&#039; in QTI speak. These are qustions that walk the user through a directed graph of question states depending on the user&#039;s responses. For example a complicated mathematical question that is answered incorrectly, but is likely to be incorrect because of a common mistake, could provide the user with a hint towards this mistake, apply a penalty and allow a second attempt at this question. Quizzes can be run in &#039;adaptive mode&#039;, which provides buttons to mark each question individually.&lt;br /&gt;
&lt;br /&gt;
===Answers===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;answer&#039;&#039;&#039;&#039; is used exclusively for the &#039;&#039;&#039;teacher-defined answers&#039;&#039;&#039; of a question. When talking about the quiz module it is easy to get confused between these teacher-defined answers and the answers that the students actually give. We have therefore adopted the convention to refer to the student-supplied answers as &#039;responses&#039; and to reserve the term &#039;answers&#039; to apply to teacher-defined answers. In question types that rely on teacher-supplied answers these are used in the grading process by comparing them with the student responses. Of course not all question types use teacher-defined answers but use some more intelligent way to process the student responses. &lt;br /&gt;
&lt;br /&gt;
Perhaps one should also stress that &#039;answer&#039; is not always used in the sense of &#039;correct answer&#039;. For example every choice in a multiple-choice question is referred to as an answer. Other systems use the term &#039;distractor&#039; for wrong answers. &lt;br /&gt;
&lt;br /&gt;
In Moodle we always use the term &#039;&#039;&#039;&#039;responses&#039;&#039;&#039;&#039; to refer to the students&#039; responses to a question because term &#039;answers&#039; that one might also be tempted to use for this is already used to refer to the teacher-defined answers, see above. This term is always used in plural, although for some questiontypes there is only one possible response.&lt;br /&gt;
&lt;br /&gt;
There is unfortunately, for historical reasons, one exception to the above rule: The [[Quiz database structure#quiz_states|quiz_states table]] has a field &#039;answer&#039; whose purpose it actually is to hold the student&#039;s responses.&lt;br /&gt;
&lt;br /&gt;
===Attempts===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;attempt&#039;&#039;&#039;&#039; is used in the sense of &amp;quot;Attempt at the quiz&amp;quot;. Depending on the quiz settings, a student may be allowed several attempts at a quiz. An attempt is finished when the student clicks on the corresponding button on the attempt page. Students do not have to complete an attempt in one visit. They can navigate away from the quiz page and return later to continue the same attempt.&lt;br /&gt;
&lt;br /&gt;
Within one and the same quiz attempt a student may make several attempts at answering a particular question, at least if the questiontype allows it and the quiz is set up in adaptive mode. These will always be referred to as &#039;&#039;&#039;&#039;attempts at a question&#039;&#039;&#039;&#039;, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
Because a student can have several attempts at a question within the same attempt at the quiz, there is a lot of data that needs to be stored as the student takes the question through several &#039;&#039;&#039;&#039;states&#039;&#039;&#039;&#039; by repeated interactions with the question. A state object holds the most recent state of the question and whenever a student submits a response or a similar &#039;&#039;&#039;&#039;event&#039;&#039;&#039;&#039; occurs, the question goes to a new state. The complete history of question states that the question is taken through is saved and this is referred to as the question &#039;&#039;&#039;&#039;session&#039;&#039;&#039;&#039;. Usually only the most recent state and the last graded state are of interest though.&lt;br /&gt;
&lt;br /&gt;
==Code documentation==&lt;br /&gt;
&lt;br /&gt;
The code is documented according to phpdoc conventions. The explanations here in the wiki are meant to complement this.&lt;br /&gt;
&lt;br /&gt;
Inline comments should be used liberally in the code. The following conventions make it easier to search for comments with special meaning:&lt;br /&gt;
* use TODO in comments about things that need to be done&lt;br /&gt;
* use ??? in comments that are questions about the code&lt;br /&gt;
&lt;br /&gt;
There are three function libraries:&lt;br /&gt;
&lt;br /&gt;
;questionlib.php&lt;br /&gt;
:All functions that need to be available to any module wanting to use questions. This is New in Moodle 1.6, in Moodle 1.5 this was part of locallib.php. This instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core. This loads constants from &#039;&#039;&#039;constants.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;editlib.php&lt;br /&gt;
:Functions that are used by the edit page edit.php. This loads locallib.php&lt;br /&gt;
&lt;br /&gt;
;locallib.php&lt;br /&gt;
:All functions that are used only by the quiz module. This loads lib.php and questionlib.php&lt;br /&gt;
&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;questiontypes/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in locallib.php). The individual questiontypes extend this class in their own questiontype.php file. For documentation of the questiontype classes one should often look at the documentation of the default question type because much of the documentation that is in the default class is not repeated in the other questiontype classes&lt;br /&gt;
&lt;br /&gt;
Constants are defined in &#039;&#039;&#039;constants.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
While questiontypes are realized as classes, the quiz module is not written in a truly object-oriented way. Instead it follows the Moodle model of using objects mostly only as alternatives to arrays to hold database records. So none of the quiz, question, attempt, and state objects that play a central role in the module have any methods. Only the questiontype objects have methods. Strangely enough the quiz module instantiates on object of each questiontype class at the start and then reuses their methods for the different questions. If one is used to the Moodle way of programming then this is easy enough to handle.&lt;br /&gt;
&lt;br /&gt;
==Objects and data structures==&lt;br /&gt;
&lt;br /&gt;
Key to understanding how the quiz module works is to understand the different kinds of object work together. The most important ones are:&lt;br /&gt;
&lt;br /&gt;
*Quizzes&lt;br /&gt;
*Questions&lt;br /&gt;
*Attempts&lt;br /&gt;
*States&lt;br /&gt;
&lt;br /&gt;
Quizzes and Questions are data created by the teacher when setting up and editing a quiz. Attempts and States are data created by the student when interacting with a quiz. &lt;br /&gt;
&lt;br /&gt;
Moodle allows students to make several attempts at a quiz. Data about such an attempt is stored in an attempt object. This holds for example how the quiz was randomized for this attempt and the ordering of the questions and answers. So attempts are indexed by user id and quiz id.&lt;br /&gt;
&lt;br /&gt;
Moodle allows students to interact repeatedly with a single question. So for example the student might initially just save an answer, later mark it, then correct it if it was marked incorrect. Each time the student interacts with a particular question inside a particular attempt at a quiz a new state is created. So states are indexed by user id, attempt id and question id.&lt;br /&gt;
&lt;br /&gt;
===Database structure===&lt;br /&gt;
All this data needs to be kept in Moodle&#039;s database. How this is achieved is explained on a separate page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;, which also contains a useful diagram.&lt;br /&gt;
&lt;br /&gt;
As is customary in Moodle, most runtime objects simply represent the data from a particular database record. So for example a $quiz object has fields corresponding to all the fields in the [[Quiz database structure#quiz|quiz table]]. In some cases the objects have some additional fields that are added at runtime. This is particularly the case for $question and $state objects. These additional fields are also described on the page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;. Many functions that are used to process these objects make use of the additional fields and it is therefore necessary to use the correct functions for creating these objects.&lt;br /&gt;
&lt;br /&gt;
===Runtime objects===&lt;br /&gt;
Some objects used by the quiz module are purely runtime object and do not correspond to a database table. The structure of these objects is explained in detail on a separate page about the &#039;&#039;&#039;[[Quiz runtime objects]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The main script of the quiz module is attempt.php which will have to deal with all these objects. Studying the &#039;&#039;&#039;[[Quiz attempt|explanation of attempt.php]]&#039;&#039;&#039; is therefore a good way to start to study the quiz module code.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The student&#039;s responses to a question are stored in &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt;. Questiontypes are completely free to implement the storage mechanism of their responses (and other state information) the way they want. Still, the standard questiontypes all follow a similar model. The default storage model and the questiontype specific variations are explained below.&lt;br /&gt;
&lt;br /&gt;
The flexibility for the questiontypes to choose their response storage mechanism freely and to convert from the storage model to the runtime model is provided by a set of three functions, which allow to initialise the runtime &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field, to convert from the runtime to the storage model and vice versa:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;create_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Initializes the $state object, in particular the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Loads the question type specific session data from the database into the &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; object, in particular it loads the responses that have been saved for the given &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; into the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Saves the question type specific session data from the $state object to the database. In particular, for most questiontypes, it saves the responses from the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; to the database.&lt;br /&gt;
&lt;br /&gt;
The generic quiz module code saves the contents form the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; field to the answer field in the [[Quiz database structure#quiz_states|quiz_states table]] and also automatically restores the contents of this field to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This means that any questiontype, which only expects a single value as its response can skip the implementation of the three methods described above. All questiontypes that have multiple value responses need to implement these methods. &lt;br /&gt;
&lt;br /&gt;
The default questiontypes handle this problem by serializing/de-serializing the responses to/from the answer field in the quiz_states table. However, it is also possible (and may be better practice) to extend the quiz_states table with a questiontype specific table, i.e. take the id of the quiz_states record as a foreign key in the questiontype specific table. Because the value of &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is set to the value of the answer field, questiontypes that serialize their response need to overwrite (in &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;) whatever value the generic code set this field to with their serialized value (usually achieved with a simple set_field). &lt;br /&gt;
&lt;br /&gt;
In the method &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; the serialized value can be read from &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; because this is where the value from answer field of the quiz_states table has been moved. Care needs to be taken that this array value is then unset or the whole array overwritten, so that the array does not accidentally contain a value with the empty string index.&lt;br /&gt;
&lt;br /&gt;
==Response processing==&lt;br /&gt;
&lt;br /&gt;
The runtime model for responses dictates the structure of the $state-&amp;gt;responses array. Starting with the names of the form elements this section goes through the relevant processing steps and thus attempts to clarify why the keys of the $state-&amp;gt;responses array can differ for different questiontypes; even more, it explains how the array keys are chosen and set.&lt;br /&gt;
&lt;br /&gt;
Although it may initially seem strange to start with the naming convention of the form fields, the reason for this will become clear later on. The controls (i.e. the form fields) of a question get printed by the method &amp;lt;code&amp;gt;print_question_formulation_and_controls()&amp;lt;/code&amp;gt;. The convention only dictates that the name of the control element(s) must begin with the value of &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt; is a string starting with &amp;quot;resp&amp;quot; followed by the question id and an underscore, e.g. &amp;lt;code&amp;gt;resp56_&amp;lt;/code&amp;gt;. In the default case, when there is only a single control element (this includes the case of a list of equally named radio buttons), no postfix is appended to the name prefix. For questiontypes that allow or require multiple form elements, an arbitrary string can be appended to the name prefix to form the name of these form elements. The postfix must not include any relational data (i.e. ids of records in the quiz_answers table), because this can lead to problems with regrading of versioned questions.&lt;br /&gt;
&lt;br /&gt;
After the printing of the question the server only sees it again when it is submitted. So the submitted data will contain several values indexed by strings starting with &amp;lt;code&amp;gt;respXX_&amp;lt;/code&amp;gt;. Upon submission, the function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; is called, which assigns the submitted responses to the state of the question with id XX, using the postfix (i.e. everything after the underscore) as array keys. In the default case with only one control element the name only consists of the name prefix. This explains why the default index of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array is the empty string. The value of each array element is obviously the value that was submitted by the form, basically a raw response.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; in turn calls the questiontype specific method &amp;lt;code&amp;gt;grade_responses()&amp;lt;/code&amp;gt; to assign a grade to the submitted responses and &amp;lt;code&amp;gt;compare_responses()&amp;lt;/code&amp;gt; to determine whether the response was identical to the previous submission and to avoid regrading the same responses repeatedly. These questiontype specific functions need to be aware of the expected keys of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
Finally, the methods &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt; also need to know the questiontype specific layout of the &amp;lt;code&amp;gt;$state-&amp;gt;responses array&amp;lt;/code&amp;gt; and restore or save the information, e.g. by converting from or to the data representation.&lt;br /&gt;
&lt;br /&gt;
==Question types==&lt;br /&gt;
{{Questiontype developer docs}}&lt;br /&gt;
The quiz module is itself modular and allows question type plug-ins. For each question type there should be a page, accessible via the menu at the right, which provides at least the dtails about&lt;br /&gt;
*Database tables&lt;br /&gt;
*Response storage&lt;br /&gt;
*Question options object&lt;br /&gt;
*State options object&lt;br /&gt;
&lt;br /&gt;
It is hoped that Moodlers will contribute a lot of non-core question types in the future. For this it would be good to start a [[Guide to question type plugins]].&lt;br /&gt;
&lt;br /&gt;
==Grades==&lt;br /&gt;
&lt;br /&gt;
The handling of grades is a bit complicated because there are so many different grades around that get rescaled and combined in various ways. This section should summarize how this is done and why.&lt;br /&gt;
&lt;br /&gt;
The following grade fields are being used:&lt;br /&gt;
*$question-&amp;gt;defaultgrade&lt;br /&gt;
::This is the default value for the maximum grade for this question. This is set up when the teacher creates the question and it is stored in an int(10) field in the [[Quiz database structure#quiz_questions|quiz_questions]] table. However when the question is actually used in a particular quiz the teacher can overrule this default and this is stored in:&lt;br /&gt;
*$question-&amp;gt;maxgrade&lt;br /&gt;
::This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in an int(10) field in the [[Quiz database structure#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
*$question-&amp;gt;penalty&lt;br /&gt;
&lt;br /&gt;
*$state-&amp;gt;raw_grade&lt;br /&gt;
*$state-&amp;gt;grade&lt;br /&gt;
*$state-&amp;gt;penalty&lt;br /&gt;
*$state-&amp;gt;sumpenalty&lt;br /&gt;
&lt;br /&gt;
*$attempt-&amp;gt;sumgrades&lt;br /&gt;
&lt;br /&gt;
The maximum grades set by the teacher, $question-&amp;gt;defaultgrade and $question-&amp;gt;maxgrade, are integers. All student-obtained grades are in principle floating point numbers. For historical reasons they are stored in the database as varchar(10) fields. Care has to be taken when writing to the database to make sure all grades are correctly rounded and squeezed into a string of no more than 10 characters, otherwise the writing to database will fail, see bug 4220.&lt;br /&gt;
&lt;br /&gt;
The final outcome of the calculation of the grade for a user at a particular quiz is stored in the &#039;grade&#039; field of the [[Quiz database structure#quiz_grades|quiz_grades table]]. This field has type double.&lt;br /&gt;
&lt;br /&gt;
==Penalty mechanism==&lt;br /&gt;
&lt;br /&gt;
===What it is for===&lt;br /&gt;
&lt;br /&gt;
When the quiz is run in adaptive mode the student can interact with a question repeatedly. So in particular the student can try again when he gets a wrong answer. Clearly the final mark for the question must reflect the fact that the student did not get it right originally. Therefore a penalty is subtracted from the final mark.&lt;br /&gt;
&lt;br /&gt;
===How the penalty is determined===&lt;br /&gt;
&lt;br /&gt;
First of all penalties are relevant only if a quiz is run in adaptive mode. Only in this case can a student have a second attempt and therefore only in this mode can there be any occasion to subtract a penalty.&lt;br /&gt;
&lt;br /&gt;
Even in adaptive mode the penalty mechanism is only used when it is selected in the quiz options. If &amp;quot;Apply penalties&amp;quot; is set to &amp;quot;No&amp;quot; then the final mark for the question is the mark for the last graded response.&lt;br /&gt;
&lt;br /&gt;
Each question has a &#039;penalty&#039; field (which should really be called &#039;penaltyfactor&#039;) which is a number between 0 and 1. The penalty for a wrong response is calculated as the product ($quiz-&amp;gt;penalty * $quiz-&amp;gt;grade), i.e., as the product of the penaltyfactor with the maximum achievable grade for the question. This product is stored in $state-&amp;gt;penalty. So $quiz-&amp;gt;penalty is the fraction of the maximum grade that is subtracted as a penalty for each wrong response.&lt;br /&gt;
&lt;br /&gt;
The $quiz-&amp;gt;penalty field has a default value of 0.1, both in the database and in mod/quiz/defaults.php. This default can of course be overwritten by the admin on the quiz configuration page. This admin-selected default is (as usual for admin defaults) stored in $CFG-&amp;gt;quiz_penalty. The teacher can choose a different penalty factor for each individual question when adding or editing a question.&lt;br /&gt;
&lt;br /&gt;
Now if a student makes repeated wrong attempts (or partially correct attempts) the penalties for all these attempts are added up in $state-&amp;gt;sumpenalties. The mark for the question is then calculated as the mark for the last graded response minus the sum of the penalties.&lt;br /&gt;
&lt;br /&gt;
One curious fact about $state-&amp;gt;sumpenalties is that, for efficiency reasons, it is not stored in the quiz_states table but instead in the &#039;sumpenalty&#039; field of the quiz_newest_states table. That way it only has to be stored once per attempt rather than once per response.&lt;br /&gt;
&lt;br /&gt;
===Where it is done in the code===&lt;br /&gt;
&lt;br /&gt;
The function quiz_apply_penalty_and_timelimit() subtracts the penalty in $state-&amp;gt;sumpenalty from the raw grade in $state-&amp;gt;raw_grade to obtain $state-&amp;gt;grade for the response. However it is ensured that the grade of a new attempt at the question never falls below the previously achieved grade. This function also increases $state-&amp;gt;sumpenalty by the amount in $state-&amp;gt;penalty. The assumption is that $state-&amp;gt;penalty has just been set appropriately by the code calling this function, e.g., quiz_process_responses.&lt;br /&gt;
&lt;br /&gt;
==Time limit==&lt;br /&gt;
&lt;br /&gt;
A quiz can have a time limit. This is stored in minutes in $quiz-&amp;gt;timelimit. So before using this in time calculations it always has to be multiplied by 60 to turn it into seconds like all other timestamps in moodle and php. If $quiz-&amp;gt;timelimit is zero it means there is no timelimit.&lt;br /&gt;
&lt;br /&gt;
If a student asks to start an attempt on view.php for a quiz with a timelimit then he is shown a javascript message alerting him to the timelimit and is asked to confirm.&lt;br /&gt;
&lt;br /&gt;
For quizzes with timelimit attempt.php shows a javascript timer that counts down and automatically submits and closes the attempt when the time is up.&lt;br /&gt;
&lt;br /&gt;
Confusingly there are two javascript timers in the quiz module. jsclock.php provides a countdown in the title bar that counts down to the quiz closing time if this is less than a day away. This has nothing to do with the timelimit. jstimer.php provides the countdown timer that implements the timelimit. It in turn uses timer.js.&lt;br /&gt;
&lt;br /&gt;
The time a response was submitted by the student is recorded by attempt.php right at the top of the page and is then passed on to quiz_process_responses in $action-&amp;gt;timestamp. This puts it into $state-&amp;gt;timestamp. Finally, after the responses have been graded, the function quiz_apply_penalty_and_timelimit() checks that the responses are within the timelimit to within 5% and if not it sets the grade to zero (or the previously obtained grade, if that is higher).&lt;br /&gt;
&lt;br /&gt;
==Pagination==&lt;br /&gt;
&lt;br /&gt;
Quiz attempts can be paginated, i.e., spread over several pages. The student can navigate between the pages using the standard Moodle paging bar. When the student navigates to a different quiz page the answers on the current page are automatically submitted for saving (but not grading).&lt;br /&gt;
&lt;br /&gt;
To do this automatic submission the paging bar needs some javascript. It is therefore not produced with Moodle&#039;s standard print_paging_bar() function from weblib.php but with quiz_print_navigation_panel() which is defined in mod/quiz/locallib.php and produces something that looks the same.&lt;br /&gt;
&lt;br /&gt;
The teacher has complete control via the edit interface on edit.php over where the page breaks should occur. He can repaginate the quiz with any chosen number of questions per page. He can also move the page-breaks up and down using the arrows.&lt;br /&gt;
&lt;br /&gt;
Internally page breaks are stored in the $quiz-&amp;gt;questions field (which now should really be called $quiz-&amp;gt;layout). This field contains a comma separated list of questionids and pagebreaks where the pagebreaks are represented by the id 0. For example 23,12,0,11, 0 means that the two questions with ids 23 and 12 are on the first page and the question with id 11 is on the second page. The last page break is invisible and Moodle sometimes puts it there itself for its own convenience.&lt;br /&gt;
&lt;br /&gt;
Because the quiz has an option $quiz-&amp;gt;shufflequestions to shuffle questions the layout that the student sees in a particular attempt does not necessarily have to be the same as that stored in $quiz-&amp;gt;questions. Therefore each attempt has its own $attemp-&amp;gt;layout field. If $quiz-&amp;gt;shufflequestions is false then this just contains a copy of $quiz-&amp;gt;questions but if it is true then during the creation of a new attempt by quiz_create_attempt() the function quiz_repaginate() is used to produce a layout with $quiz-&amp;gt;questionsperpage number of questions per page that are randomly ordered.&lt;br /&gt;
&lt;br /&gt;
Both attempt.php and review.php use the $attempt-&amp;gt;layout field to determine what questions to show on a particular page. That way we can guarantee that the student will, for a particular attempt, always see the questions in the same order and with the same pagination, both while attempting and during review. Also a teacher when reviewing a student&#039;s attempt sees the pages the same way they were shown to the student. However the teacher is also given the option to see all questions on one page.&lt;br /&gt;
&lt;br /&gt;
There are some functions in locallib.php dedicated to handling the layout fields: quiz_questions_on_page(), quiz_questions_in_quiz(), quiz_number_of_pages(), quiz_first_questionnumber(), quiz_repaginate(). They are very short functions. The function quiz_first_questionnumber() that determines the number of the first question on a particular page makes use of the $question-&amp;gt;length field. To allow this calculation to be fast is the main reason why that field is in the question table even though it could also be determined easily from the question type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Question versioning==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Question versioning is currently disabled until it is re-developed to fix all reported issues.&lt;br /&gt;
&lt;br /&gt;
When questions that were already attempted by a student are edited, it can be important to keep a copy of the question as it was before editing in order to reconstruct the quiz as it was seen by the student. To provide this functionality a question versioning mechanism was implemented.&lt;br /&gt;
&lt;br /&gt;
The first goal, namely keeping around old questions, is easily achieved. They are just not deleted any more. However, this is not enough; it is also necessary to store which questions are versions of others. To achieve this goal, there is an additional table, which stores the versioning information: quiz_question_versions.&lt;br /&gt;
&lt;br /&gt;
When a question is replaced for which there are already student attempts then all the attempt data gets associated to the new version of the question and is re-graded. This requires the question ids in the quiz_attempts, quiz_states and quiz_newest_states tables to be replaced by the new id. However we do also want to be able to reconstruct the quiz the way the student saw it when he gave his answers. For that purpose the id of the original question is always preserved in the &#039;originalquestion&#039; field of the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
If all old versions of questions are kept around this could horribly clutter the editing interface. Therefore a field called hidden was added to the quiz_questions table and all old versions of edited questions are automatically hidden. When this flag is set to 1 the question is not displayed in the list of available questions, unless the user chooses to show them.&lt;br /&gt;
&lt;br /&gt;
While the mechanism above should work as described, there is some additional complexity in order to minimise the number of versions created. If a question is created and has not been attempted by a student yet (this excludes teacher previews of the individual question and the quiz!), the database record will be reused (i.e. overwritten) and no new version will be created. This is especially important when the question is created and the first 2 or 3 mistakes are only noticed during preview.&lt;br /&gt;
&lt;br /&gt;
On the editing screen for questions an additional set of options was introduced (see image).&lt;br /&gt;
Replacement Options&lt;br /&gt;
It shows which quizzes use the edited question and how many students have attempted it in a particular quiz. Based on this information it is then possible to choose in which quizzes the new version of the question should be used and in which ones the old one should remain.&lt;br /&gt;
&lt;br /&gt;
By default the &#039;replace&#039; checkbox for all quizzes that don&#039;t have any students&#039; attempts are checked and in addition, if the question is edited out of a quiz context (i.e. not in the category question list), the &#039;replace&#039; option is checked for that quiz as well.&lt;br /&gt;
&lt;br /&gt;
===Database===&lt;br /&gt;
&lt;br /&gt;
The changes to the database structure are limited to an added field (hidden) in the quiz_questions table and an additional table called quiz_question_versions. However, dealing with the quiz_questions table has become slightly more complicated.&lt;br /&gt;
&lt;br /&gt;
The hidden field in the quiz_questions table has no implications for the core functionality. It is only used to determine, as the name implies, whether the question is shown in the category list or not.&lt;br /&gt;
&lt;br /&gt;
The table quiz_question_versions stores information about the actual change. This information includes the ids of the old question and the new question, the id of the user who did the change and a timestamp. Quite importantly, the id of the quiz, in which the question was replaced is also stored. This means that the versions table provides a history of the different states the quiz went through until it was edited to be at the current state. The information allows to recreate a quiz as it was at any point in time (from a data perspective - this possibility is not used extensively by the code).&lt;br /&gt;
&lt;br /&gt;
===Adjustments to the Data===&lt;br /&gt;
&lt;br /&gt;
When a question is replaced by a newer version, database records are updated in the order shown below (compare with question.php):&lt;br /&gt;
&lt;br /&gt;
* First a new record is inserted into the quiz_question_versions table for each affected quiz (i.e. each quiz in which the question was replaced).&lt;br /&gt;
* Then, for each affected quiz, the comma separated list of question ids in the question field is updated by replacing the old question id with the new one.&lt;br /&gt;
* In the quiz_question_instances table the record that links the old question to the quiz is also updated to point to the new question.&lt;br /&gt;
* In all attempts belonging to the old question the comma-separated list of question ids in the layout field are changed by replacing the old id by the new one.&lt;br /&gt;
* All states belonging to the old question are made to belong to the new version by changing the id in the &#039;question&#039; field. However if we are replacing the original question then the id of this original version is stored in the originalquestion field.&lt;br /&gt;
* We have to change the questionid field in quiz_newest_states.&lt;br /&gt;
* Finally we have to do any question-type specific changes. For example question types that store student responses by storing the id of the answer in the quiz_answers table will have to recode these ids in all the states to point to the corresponding answers in the new version. This is handled by the function replace_question_in_attempts() in the question type class.&lt;br /&gt;
&lt;br /&gt;
===Affected Code and Functionality===&lt;br /&gt;
&lt;br /&gt;
Note: This section should still be considered under construction until the question mark behind bug #3311 is taken off.&lt;br /&gt;
&lt;br /&gt;
In the file review.php and potentially also in the file attempt.php, if a question is edited during a student&#039;s attempt, the data from quiz_question_versions needs to be taken into account. If a student has attempted a quiz and a question was changed afterwards (i.e. a new version of that question was created), the question id of the old version remains in the comma separated list inside the attempt-&amp;gt;layout field. However, since the records in the quiz_question_instances table get updated, we need to go forward in the question history, by looping through entries from the quiz_question_versions table, to find out the id of the question version that is currently used in the quiz.&lt;br /&gt;
&lt;br /&gt;
Suggestion: With a fairly simple change to the convention of what is stored in the quiz_question_versions table we could get rid of the requirement of looping through all the versions. If in the newquestion field we store the id of the question that is currently used in the quiz, it would be possible to get the complete history for a question quite simply by selecting by quiz id and newquestion.&lt;br /&gt;
&lt;br /&gt;
It should be fairly simple to write an upgrade script for this change. Additionally, another set_field would need to be added to question.php to change the newquestion field to the new question id. The benefits would be a much simpler handling of the question history, resulting in more efficient code than the current fix for bug #3311 in review.php.&lt;br /&gt;
&lt;br /&gt;
The place where all the versioning actually takes place is question.php. Here the changes described in Adjustments to the Data are carried out.&lt;br /&gt;
&lt;br /&gt;
Obviously the backup and restore scripts also take quiz_question_versions into account, however, they don&#039;t need to be concerned with the ways the data is used.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.5: adaptive questions==&lt;br /&gt;
&lt;br /&gt;
During the first half of 2005 the quiz module code has undergone a considerable rewrite to allow for adaptive questions in which a question session can consist of several sequential student responses. The question can adapt itself to the student answers. For example in response to certain answers the question could provide feedback or hints and then ask the student to answer again or give the student a simpler or related question.&lt;br /&gt;
&lt;br /&gt;
Unfortunately many changes had to be made to the question type methods. This has however resulted in improved efficiency and has made the writing of question types easier. It also allows question types with more powerful features and has fixed some bugs / annoying behaviour. &lt;br /&gt;
&lt;br /&gt;
For details see:&lt;br /&gt;
*[[Quiz rewrite|Quiz module rewrite]]&lt;br /&gt;
*[[Quiz conversion|How to convert existing question types]]&lt;br /&gt;
&lt;br /&gt;
Of course there were countless other changes to the quiz module going from Moodle 1.4 to 1.5, especially to the teacher interface. However in spite of the fact that these changes are a lot more visible they were much less drastic from the point of view of the code. Here is a very incomplete list of changes:&lt;br /&gt;
&lt;br /&gt;
* New quiz results overview page&lt;br /&gt;
* Reform of the quiz edit page: Changes on the quiz edit page are saved straightaway, not only after Save button is pressed.&lt;br /&gt;
* Copying questions: The teacher can create a new question using a previous one as template.&lt;br /&gt;
* Moving questions: The teacher can now move selected questions to a different category.&lt;br /&gt;
* Re-marking after question editing: if a teacher corrects a question that students have already attempted the teacher can request a remark.&lt;br /&gt;
* Teacher preview tab.&lt;br /&gt;
* Detailed teacher control over what students can see during review.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.6: separating questions from quizzes==&lt;br /&gt;
&lt;br /&gt;
The quiz module is not the only activity module in Moodle that uses questions. The lesson does too and potentially questions could be useful in many modules. Therefore we have started to rewrite some  of the quiz module functions and move them from locallib.php to questionlib.php so that eventually they could be moved into a central library and be used by other modules. &lt;br /&gt;
&lt;br /&gt;
Module developers who want to use the &lt;br /&gt;
quiz module questions in their own module should take a look at the simple questiondemo module that you can find in CVS at [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/questiondemo contrib/questiondemo]. The idea is that it will be simpler&lt;br /&gt;
to understand this demonstration module than the code in the quiz module which&lt;br /&gt;
is very complicated due to the many options and features. The interesting code in the questiondemo module is in view.php. There you can see how to&lt;br /&gt;
both render and score questions. This module requires the version of the quiz module from Moodle 1.6dev or later.&lt;br /&gt;
&lt;br /&gt;
The details of the changes are explained on the page [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
==Future plans==&lt;br /&gt;
&lt;br /&gt;
The features below are in no particular order:&lt;br /&gt;
&lt;br /&gt;
* Editing questions: This is about editing questions after students have already attempted them. There needs to be a mechanism to keep the old versions of the question around for auditing purposes.&lt;br /&gt;
* New quiz statistics pages?: These pages should be built by using functions defined by the individual question types.&lt;br /&gt;
* Manual grade override: Teachers should be able to override the automatically calculated grades and should be able to make comments.&lt;br /&gt;
* Off-line questions: The answers to these are handed in off-line in the conventional way (e.g., on paper) and teachers enter marks on Moodle.&lt;br /&gt;
* Batch printing of quiz sheets: We want to be able to hand out question sheets to students so they can start working on the questions before going to the computer.&lt;br /&gt;
* Question preview from question edit page: so the teacher can try the question already before saving the changes.&lt;br /&gt;
* Show table of questions on view.php: gives teachers and students a bit of an overview of the quiz.&lt;br /&gt;
* Extending deadlines for individual students: for example when a student misses a deadline for good reasons.&lt;br /&gt;
* Filtering questions by quiz and by search: More ways to restrict which questions are shown on the quiz editing page.&lt;br /&gt;
* Re-open quizzes for revision: After the due date has passed the quiz could allow practice attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Help:Editing&amp;diff=5163</id>
		<title>Help:Editing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Help:Editing&amp;diff=5163"/>
		<updated>2006-02-11T13:48:29Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* External links */  HTML to MediaWiki converter&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Editing ==&lt;br /&gt;
&lt;br /&gt;
Every wiki page has an &amp;quot;edit&amp;quot; tab at the top plus edit links at the side. These links lets you do exactly what they say i.e. edit the page you&#039;re looking at. Please try it in the [[sandbox]]!&lt;br /&gt;
&lt;br /&gt;
=== Show preview ===&lt;br /&gt;
This lets you see what the page will look like after your edit, before you actually save.  We all make mistakes; this feature lets you catch them immediately.  Using Show preview before saving also lets you try format changes and other edits without cluttering up the page history, and has a number of other advantages.  Don&#039;t forget to save your edits after previewing, though!&lt;br /&gt;
&lt;br /&gt;
=== Edit summary ===&lt;br /&gt;
Before saving the page, it&#039;s considered good practice to enter a very brief summary of your changes in the summary box below the edit-box.&lt;br /&gt;
&lt;br /&gt;
== Formatting ==&lt;br /&gt;
&lt;br /&gt;
Most &#039;&#039;&#039;formatting&#039;&#039;&#039; is usually done with Wiki markup - you don&#039;t have to learn HTML!&lt;br /&gt;
&lt;br /&gt;
=== Bold and italics ===&lt;br /&gt;
&#039;&#039;&#039;Bolding&#039;&#039;&#039; and &#039;&#039;italicizing&#039;&#039; is done by surrounding a word or phrase with multiple apostrophes (&amp;lt;tt&amp;gt;&#039;&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&#039;&#039;italics&#039;&#039;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; appears as &#039;&#039;italics&#039;&#039;. (2 apostrophes on both sides)&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;bold&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; appears as &#039;&#039;&#039;bold&#039;&#039;&#039;. (3 apostrophes on both sides)&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;bolded italics&#039;&#039;&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; appears as &#039;&#039;&#039;&#039;&#039;bolded italics&#039;&#039;&#039;&#039;&#039;.  (5 apostrophes on both sides)&lt;br /&gt;
&lt;br /&gt;
=== Headings and subheadings ===&lt;br /&gt;
Headings and subheadings are an easy way to improve the organization of an article. &lt;br /&gt;
&lt;br /&gt;
Headings can be created like this:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;==Top level heading==&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; (2 equals signs)&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;===Subheading===&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; (3 equals signs)&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;====Another level down====&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; (4 equals signs)&lt;br /&gt;
&lt;br /&gt;
If an article has at least four headings, a table of contents will automatically be generated.&lt;br /&gt;
&lt;br /&gt;
=== Indentations ===&lt;br /&gt;
The simplest way of indenting is to place a colon (&amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt;) at the beginning of a line. The more colons you put, the further indented the text will be. A newline marks the end of the indented paragraph e.g.&lt;br /&gt;
:&amp;lt;code&amp;gt;This is aligned all the way to the left.&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;This is indented slightly.&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;::&amp;lt;/nowiki&amp;gt;This is indented more.&amp;lt;/code&amp;gt;&lt;br /&gt;
is shown as&lt;br /&gt;
:This is aligned all the way to the left.&lt;br /&gt;
::This is indented slightly.&lt;br /&gt;
:::This is indented more.&lt;br /&gt;
&lt;br /&gt;
=== Lists ===&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!What it looks like&lt;br /&gt;
!What you type&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
* &#039;&#039;Unordered lists&#039;&#039; are easy to do:&lt;br /&gt;
** start every line with a star&lt;br /&gt;
*** more stars means deeper levels&lt;br /&gt;
*A newline&lt;br /&gt;
*in a list  &lt;br /&gt;
marks the end of the list.&lt;br /&gt;
&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;* Unordered Lists are easy to do:&lt;br /&gt;
** start every line with a star&lt;br /&gt;
*** more stars means deeper levels&lt;br /&gt;
*A newline&lt;br /&gt;
*in a list  &lt;br /&gt;
marks the end of the list.&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
# Numbered lists are also good&lt;br /&gt;
## very organized&lt;br /&gt;
## easy to follow&lt;br /&gt;
#A newline&lt;br /&gt;
#in a list  &lt;br /&gt;
marks the end of the list.&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;# Numbered lists are also good&lt;br /&gt;
## very organized&lt;br /&gt;
## easy to follow&lt;br /&gt;
#A newline&lt;br /&gt;
#in a list  &lt;br /&gt;
marks the end of the list.&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Preserving formatting ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!What it looks like&lt;br /&gt;
!What you type&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
Leading spaces are another way to preserve formatting.&lt;br /&gt;
&lt;br /&gt;
 Putting a space at the beginning of each line&lt;br /&gt;
 stops the text from being reformatted. &lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Leading spaces are another way to preserve formatting.&lt;br /&gt;
&lt;br /&gt;
 Putting a space at the beginning of each line&lt;br /&gt;
 stops the text from being reformatted.&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Wiki links ===&lt;br /&gt;
To make a wiki link, simply put the word in double square brackets, like this: &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[Sandbox]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to use words other than the article title as the text of the link, you can do so by adding the pipe &amp;quot;|&amp;quot; divider (SHIFT + BACKSLASH on English-layout and other keyboards) followed by the alternative name.&lt;br /&gt;
&lt;br /&gt;
For example, if you wanted to make a link to the [[sandbox]], but wanted it to say &amp;quot;my text&amp;quot; you would write it as: &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[sandbox|my text]]&amp;lt;/nowiki&amp;gt;...&amp;lt;/code&amp;gt; It would appear as: [[sandbox|my text]]... but would link to the sandbox.&lt;br /&gt;
&lt;br /&gt;
=== External links ===&lt;br /&gt;
&lt;br /&gt;
The easiest way to make an external link is to simply type in the full URL for the page you want to link to e.g. http://www.google.com.&lt;br /&gt;
&lt;br /&gt;
To make the link display something other than the URL, use one square bracket at each end. If you want to make a link to Google, type &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[http://www.google.com/]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
This will display the link as a number in brackets, like this: [http://www.google.com/].&lt;br /&gt;
&lt;br /&gt;
If you want the link to appear with text that you specify, add an alternative title after the address separated by a &#039;&#039;&#039;space&#039;&#039;&#039; (&#039;&#039;not&#039;&#039; a pipe). So if you want the link to appear as [http://www.google.com Google search engine], just type &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[http://www.google.com Google search engine]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Categories===&lt;br /&gt;
&lt;br /&gt;
To put a page in a category, just type &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[Category:]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, and put the name of the category between the colon and the brackets.&lt;br /&gt;
&lt;br /&gt;
==External links==&lt;br /&gt;
*[http://meta.wikimedia.org/wiki/Help:Editing MediaWiki Help:Editing]&lt;br /&gt;
*[http://meta.wikimedia.org/wiki/Help:Image MediaWiki Help:Images and other uploaded files]&lt;br /&gt;
*[http://meta.wikimedia.org/wiki/Help:HTML_in_wikitext Help:HTML in wikitext]&lt;br /&gt;
*[http://diberri.dyndns.org/html2wiki.html HTML to MediaWiki converter]&lt;br /&gt;
*[http://wikipedia.mozdev.org/ Firefox Wikipedia extension] - The Wikipedia extension makes editing of  wiki pages easier by adding a new toolbar to your browser and by providing new menu items in the context menu (right mouse key).&lt;br /&gt;
&lt;br /&gt;
[[Category:MoodleDocs]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Blocks&amp;diff=5162</id>
		<title>Development:Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Blocks&amp;diff=5162"/>
		<updated>2006-02-11T13:34:27Z</updated>

		<summary type="html">&lt;p&gt;Gustav: I sent Jon&amp;#039;s page through a html to mediawiki converter&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039; A Step-by-step Guide To Creating Blocks &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Original Author: Jon Papaioannou (pj@uom.gr)&lt;br /&gt;
&lt;br /&gt;
The present document serves as a guide to developers who want to create their own blocks for use in Moodle. It applies to the 1.5 development version of Moodle (and any newer) &#039;&#039;&#039;only&#039;&#039;&#039;, as the blocks subsystem was rewritten and expanded for the 1.5 release. However, you can also find it useful if you want to modify blocks written for Moodle 1.3 and 1.4 to work with the latest versions (look at [[Blocks_Howto#appendix_b| Appendix B]]).&lt;br /&gt;
The guide is written as an interactive course which aims to develop a configurable, multi-purpose block that displays arbitrary HTML. It&#039;s targeted mainly at people with little experience with Moodle or programming in general and aims to show how easy it is to create new blocks for Moodle. A certain small amount of PHP programming knowledge is still required, though. Experienced developers and those who just want a reference text should refer to [[Blocks_Howto#appendix_a| Appendix A]] because the main guide has a rather low concentration of pure information in the text.&lt;br /&gt;
&lt;br /&gt;
== Basic Concepts ==&lt;br /&gt;
Through this guide, we will be following the creation of an &amp;quot;HTML&amp;quot; block from scratch in order to demonstrate most of the block features at our disposal. Our block will be named &amp;quot;SimpleHTML&amp;quot;. This does not constrain us regarding the name of the actual directory on the server where the files for our block will be stored, but for consistency we will follow the practice of using the lowercased form &amp;quot;simplehtml&amp;quot; in any case where such a name is required. Whenever we refer to a file or directory name which contains &amp;quot;simplehtml&amp;quot;, it&#039;s important to remember that &#039;&#039;only&#039;&#039; the &amp;quot;simplehtml&amp;quot; part is up to us to change; the rest is standardized and essential for Moodle to work correctly.&lt;br /&gt;
Whenever a file&#039;s path is mentioned in this guide, it will always start with a slash. This refers to the Moodle home directory; all files and directories will be referred to with respect to that directory.&lt;br /&gt;
&lt;br /&gt;
== Ready, Set, Go! ==&lt;br /&gt;
To define a &amp;quot;block&amp;quot; in Moodle, in the most basic case we need to provide just one source code file. We start by creating the directory &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/&amp;lt;/span&amp;gt; and creating a file named &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/block_simplehtml.php&amp;lt;/span&amp;gt; which will hold our code. We then begin coding the block:&lt;br /&gt;
 class block_simplehtml extends block_base {&lt;br /&gt;
     function init() {&lt;br /&gt;
         $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
         $this-&amp;gt;version = 2004111200;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
The first line is our block class definition; it must be named exactly in the manner shown. Again, only the &amp;quot;simplehtml&amp;quot; part can (and indeed must) change; everything else is standardized.&lt;br /&gt;
Our class is then given a small method: [[Blocks_Howto#method_init| init]]. This is essential for all blocks, and its purpose is to set the two class member variables listed inside it. But what do these values actually mean? Here&#039;s a more detailed description.&lt;br /&gt;
[[Blocks_Howto#variable_title| $this-&amp;gt;title]] is the title displayed in the header of our block. We can set it to whatever we like; in this case it&#039;s set to read the actual title from a language file we are presumably distributing together with the block. I &#039;ll skip ahead a bit here and say that if you want your block to display &#039;&#039;&#039;no&#039;&#039;&#039; title at all, then you should set this to any descriptive value you want (but &#039;&#039;&#039;not&#039;&#039;&#039; make it an empty string). We will later see [[Blocks_Howto#section_eye_candy| how to disable the title&#039;s display]].&lt;br /&gt;
[[Blocks_Howto#variable_version| $this-&amp;gt;version]] is the version of our block. This actually would only make a difference if your block wanted to keep its own data in special tables in the database (i.e. for very complex blocks). In that case the version number is used exactly as it&#039;s used in activities; an upgrade script uses it to incrementally upgrade an &amp;quot;old&amp;quot; version of the block&#039;s data to the latest. We will outline this process further ahead, since blocks tend to be relatively simple and not hold their own private data. In our example, &lt;br /&gt;
this is certainly the case so we just set [[Blocks_Howto#variable_version| $this-&amp;gt;version]] to &#039;&#039;&#039;YYYYMMDD00&#039;&#039;&#039; and forget about it.&lt;br /&gt;
&#039;&#039;&#039;UPDATING:&#039;&#039;&#039; Prior to version 1.5, the basic structure of each block class was slightly different. Refer to [[Blocks_Howto#appendix_b| Appendix B]] for more information on the changes that old blocks have to make to conform to the new standard.&lt;br /&gt;
== I Just Hear Static ==&lt;br /&gt;
In order to get our block to actually display something on screen, we need to add one more method to our class (before the final closing brace in our file). The new code is:&lt;br /&gt;
 function get_content() {&lt;br /&gt;
     if ($this-&amp;gt;content !== NULL) {&lt;br /&gt;
         return $this-&amp;gt;content;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     $this-&amp;gt;content = new stdClass;&lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;text = &#039;The content of our SimpleHTML block!&#039;;&lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
     return $this-&amp;gt;content;&lt;br /&gt;
 }&lt;br /&gt;
It can&#039;t get any simpler than that, can it? Let&#039;s dissect this method to see what&#039;s going on...&lt;br /&gt;
First of all, there is a check that returns the current value of [[Blocks_Howto#variable_content| $this-&amp;gt;content]] if it&#039;s not NULL; otherwise we proceed with &amp;quot;computing&amp;quot; it. Since the computation is potentially a time-consuming operation and it &#039;&#039;&#039;will&#039;&#039;&#039; be called several times for each block (Moodle works that way internally), we take a precaution and include this time-saver.&lt;br /&gt;
Supposing the content had not been computed before (it was NULL), we then define it from scratch. The code speaks for itself there, so there isn&#039;t much to say. Just keep in mind that we can use HTML both in the text &#039;&#039;&#039;and&#039;&#039;&#039; in the footer, if we want to.&lt;br /&gt;
At this point our block should be capable of being automatically installed in Moodle and added to courses; visit your administration page to install it and after seeing it in action come back to continue our tutorial.&lt;br /&gt;
== Configure That Out ==&lt;br /&gt;
The current version of our block doesn&#039;t really do much; it just displays a fixed message, which is not very useful. What we &#039;d really like to do is allow the teachers to customize what goes into the block. This, in block-speak, is called &amp;quot;instance configuration&amp;quot;. So let&#039;s give our block some instance configuration...&lt;br /&gt;
First of all, we need to tell Moodle that we want it to provide instance-specific configuration amenities to our block. That&#039;s as simple as adding one more method to our block class:&lt;br /&gt;
 function instance_allow_config() {&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
This small change is enough to make Moodle display an &amp;quot;Edit...&amp;quot; icon in our block&#039;s header when we turn editing mode on in any course. However, if you try to click on that icon you will be presented with a notice that complains about the block&#039;s configuration not being implemented correctly. Try it, it&#039;s harmless.&lt;br /&gt;
Moodle&#039;s complaints do make sense. We told it that we want to have configuration, but we didn&#039;t say &#039;&#039;what&#039;&#039; kind of configuration we want, or how it should be displayed. To do that, we need to create one more file: &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/config_instance.html&amp;lt;/span&amp;gt; (which has to be named exactly like that). For the moment, copy paste the following into it and save:&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;table cellpadding=&amp;quot;9&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;?php print_string(&#039;configcontent&#039;, &#039;block_simplehtml&#039;); ?&amp;gt;:&lt;br /&gt;
     &amp;lt;/td&amp;gt;&lt;br /&gt;
     &amp;lt;td&amp;gt;&lt;br /&gt;
         &amp;lt;?php print_textarea(true, 10, 50, 0, 0, &#039;text&#039;, $this-&amp;gt;config-&amp;gt;text); ?&amp;gt;&lt;br /&gt;
     &amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
     &amp;lt;td colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&amp;lt;?php print_string(&#039;savechanges&#039;) ?&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
     &amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;/table&amp;gt;&lt;br /&gt;
 &amp;lt;?php use_html_editor(); ?&amp;gt;&lt;br /&gt;
It isn&#039;t difficult to see that the above code just provides us with a wysiwyg-editor-enabled textarea to write our block&#039;s desired content in and a submit button to save. But... what&#039;s $this-&amp;gt;config-&amp;gt;text? Well...&lt;br /&gt;
Moodle goes a long way to make things easier for block developers. Did you notice that the textarea is actually named &amp;quot;text&amp;quot;? When the submit button is pressed, Moodle saves each and every field it can find in our &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config_instance.html&amp;lt;/span&amp;gt; file as instance configuration data. We can then access that data as &#039;&#039;&#039;$this-&amp;gt;config-&amp;gt;&#039;&#039;variablename&#039;&#039;&#039;&#039;&#039;, where &#039;&#039;variablename&#039;&#039; is the actual name we used for our field; in this case, &amp;quot;text&amp;quot;. So in essence, the above form just pre-populates the textarea with the current content of the block (as indeed it should) and then allows us to change it.&lt;br /&gt;
You also might be surprised by the presence of a submit button and the absence of any &amp;lt;form&amp;gt; element at the same time. But the truth is, we don&#039;t need to worry about that at all; Moodle goes a really long way to make things easier for developers! We just print the configuration options we want, in any format we want; include a submit button, and Moodle will handle all the rest itself. The instance configuration variables are automatically at our disposal to access from any of the class methods &#039;&#039;except&#039;&#039; [[Blocks_Howto#method_init| init]].&lt;br /&gt;
In the event where the default behavior is not satisfactory, we can still override it. However, this requires advanced modifications to our block class and will not be covered here; refer to [[Blocks_Howto#appendix_a| Appendix A]] for more details.&lt;br /&gt;
Having now the ability to refer to this instance configuration data through [[Blocks_Howto#variable_config| $this-&amp;gt;config]], the final twist is to tell our block to actually &#039;&#039;display&#039;&#039; what is saved in is configuration data. To do that, find this snippet in &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/block_simplehtml.php&amp;lt;/span&amp;gt;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 $this-&amp;gt;content = new stdClass;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;text = &#039;The content of our SimpleHTML block!&#039;;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
and change it to:&lt;br /&gt;
 &lt;br /&gt;
 $this-&amp;gt;content = new stdClass;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;text = $this-&amp;gt;config-&amp;gt;text;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
Oh, and since the footer isn&#039;t really exciting at this point, we remove it from our block because it doesn&#039;t contribute anything. We could just as easily have decided to make the footer configurable in the above way, too. So for our latest code, the snippet becomes:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 $this-&amp;gt;content = new stdClass;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;text = $this-&amp;gt;config-&amp;gt;text;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;footer = &#039;&#039;;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
After this discussion, our block is ready for prime time! Indeed, if you now visit any course with a SimpleHTML block, you will see that modifying its contents is now a snap.&lt;br /&gt;
== The Specialists ==&lt;br /&gt;
Implementing instance configuration for the block&#039;s contents was good enough to whet our apetite, but who wants to stop there? Why not customize the block&#039;s title, too?&lt;br /&gt;
Why not, indeed. Well, our first attempt to achieve this is natural enough: let&#039;s add another field to &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/config_instance.html&amp;lt;/span&amp;gt;. Here goes:&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;&amp;lt;p&amp;gt;&amp;lt;?php print_string(&#039;configtitle&#039;, &#039;block_simplehtml&#039;); ?&amp;gt;:&amp;lt;/td&amp;gt;&lt;br /&gt;
     &amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;title&amp;quot; size=&amp;quot;30&amp;quot; value=&amp;quot;&amp;lt;?php echo $this-&amp;gt;config-&amp;gt;title; ?&amp;gt;&amp;quot; /&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
We save the edited file, go to a course, edit the title of the block and... nothing happens! The instance configuration is saved correctly, all right (editing it once more proves that) but it&#039;s not being displayed. All we get is just the simple &amp;quot;SimpleHTML&amp;quot; title.&lt;br /&gt;
That&#039;s not too wierd, if we think back a bit. Do you remember that [[Blocks_Howto#method_init| init]] method, where we set [[Blocks_Howto#variable_title| $this-&amp;gt;title]]? We didn&#039;t actually change its value from then, and [[Blocks_Howto#variable_title| $this-&amp;gt;title]] is definitely not the same as $this-&amp;gt;config-&amp;gt;title (to Moodle, at least). What we need is a way to update [[Blocks_Howto#variable_title| $this-&amp;gt;title]] with the value in the instance configuration. But as we said a bit earlier, we can use [[Blocks_Howto#variable_config| $this-&amp;gt;config]] in all methods &#039;&#039;except&#039;&#039; [[Blocks_Howto#method_init| init]]&amp;lt;nowiki&amp;gt;! So what can we do?&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Let&#039;s pull out another ace from our sleeve, and add this small method to our block class:&lt;br /&gt;
 &lt;br /&gt;
 function specialization() {&lt;br /&gt;
     $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;title;&lt;br /&gt;
 }&lt;br /&gt;
Aha, here&#039;s what we wanted to do all along! But what&#039;s going on with the [[Blocks_Howto#method_specialization| specialization]] method?&lt;br /&gt;
This &amp;quot;magic&amp;quot; method has actually a very nice property: it&#039;s &#039;&#039;guaranteed&#039;&#039; to be automatically called by Moodle as soon as our instance configuration is loaded and available (that is, immediately after [[Blocks_Howto#method_init| init]] is called). That means before the block&#039;s content is computed for the first time, and indeed before &#039;&#039;anything&#039;&#039; else is done with the block. Thus, providing a [[Blocks_Howto#method_specialization| specialization]] method is the natural choice for any configuration data that needs to be acted upon &amp;quot;as soon as possible&amp;quot;, as in this case.&lt;br /&gt;
== Now You See Me, Now You Don&#039;t ==&lt;br /&gt;
Now would be a good time to mention another nifty technique that can be used in blocks, and which comes in handy quite often. Specifically, it may be the case that our block will have something interesting to display some of the time; but in some other cases, it won&#039;t have anything useful to say. (An example here would be the &amp;quot;Recent Activity&amp;quot; block, in the case where no recent activity in fact exists. However in that case the block chooses to explicitly inform you of the lack of said activity, which is arguably useful). It would be nice, then, to be able to have our block &amp;quot;disappear&amp;quot; if it&#039;s not needed to display it.&lt;br /&gt;
This is indeed possible, and the way to do it is to make sure that after the [[Blocks_Howto#method_get_content| get_content]]&amp;lt;nowiki&amp;gt; method is called, the block is completely void of content. Specifically, &amp;quot;void of content&amp;quot; means that both $this-&amp;gt;content-&amp;gt;text and $this-&amp;gt;content-&amp;gt;footer are each equal to the empty string (&#039;&#039;). Moodle performs this check by calling the block&#039;s &amp;lt;/nowiki&amp;gt;[[Blocks_Howto#method_is_empty| is_empty()]] method, and if the block is indeed empty then it is not displayed at all.&lt;br /&gt;
Note that the exact value of the block&#039;s title and the presence or absence of a [[Blocks_Howto#method_hide_header| hide_header]] method do &#039;&#039;not&#039;&#039; affect this behavior. A block is considered empty if it has no content, irrespective of anything else.&lt;br /&gt;
== We Are Legion ==&lt;br /&gt;
Right now our block is fully configurable, both in title and content. It&#039;s so versatile, in fact, that we could make pretty much anything out of it. It would be really nice to be able to add multiple blocks of this type to a single course. And, as you might have guessed, doing that is as simple as adding another small method to our block class:&lt;br /&gt;
 &lt;br /&gt;
 function instance_allow_multiple() {&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
This tells Moodle that it should allow any number of instances of the SimpleHTML block in any course. After saving the changes to our file, Moodle immediately allows us to add multiple copies of the block without further ado!&lt;br /&gt;
There are a couple more of interesting points to note here. First of all, even if a block itself allows multiple instances in the same page, the administrator still has the option of disallowing such behavior. This setting can be set separately for each block from the Administration / Configuration / Blocks page.&lt;br /&gt;
And finally, a nice detail is that as soon as we defined an [[Blocks_Howto#method_instance_allow_multiple| instance_allow_multiple]] method, the method [[Blocks_Howto#method_instance_allow_config| instance_allow_config]] that was already defined became obsolete. Moodle assumes that if a block allows multiple instances of itself, those instances will want to be configured (what is the point of same multiple instances in the same page if they are identical?) and thus automatically provides an &amp;quot;Edit&amp;quot; icon. So, we can also remove the whole [[Blocks_Howto#method_instance_allow_config| instance_allow_config]] method now without harm. We had only needed it when multiple instances of the block were not allowed.&lt;br /&gt;
== The Effects of Globalization ==&lt;br /&gt;
Configuring each block instance with its own personal data is cool enough, but sometimes administrators need some way to &amp;quot;touch&amp;quot; all instances of a specific block at the same time. In the case of our SimpleHTML block, a few settings that would make sense to apply to all instances aren&#039;t that hard to come up with. For example, we might want to limit the contents of each block to only so many characters, or we might have a setting that filters HTML out of the block&#039;s contents, only allowing pure text in. Granted, such a feature wouldn&#039;t win us any awards for naming our block &amp;quot;SimpleHTML&amp;quot; but some tormented administrator somewhere might actually find it useful.&lt;br /&gt;
This kind of configuration is called &amp;quot;global configuration&amp;quot; and applies only to a specific block type (all instances of that block type are affected, however). Implementing such configuration for our block is quite similar to implementing the instance configuration. We will now see how to implement the second example, having a setting that only allows text and not HTML in the block&#039;s contents.&lt;br /&gt;
First of all, we need to tell Moodle that we want our block to provide global configuration by, what a surprise, adding a small method to our block class:&lt;br /&gt;
 &lt;br /&gt;
 function has_config() {&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
Then, we need to create a HTML file that actually prints out the configuration screen. In our case, we &#039;ll just print out a checkbox saying &amp;quot;Do not allow HTML in the content&amp;quot; and a &amp;quot;submit&amp;quot; button. Let&#039;s create the file &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/config_global.html&amp;lt;/span&amp;gt; which again must be named just so, and copy paste the following into it:&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;block_simplehtml_strict&amp;quot; value=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;block_simplehtml_strict&amp;quot; value=&amp;quot;1&amp;quot;&lt;br /&gt;
   &amp;lt;?php if(!empty($CFG-&amp;gt;block_simplehtml_strict)) echo &#039;checked=&amp;quot;checked&amp;quot;&#039;; ?&amp;gt; /&amp;gt;&lt;br /&gt;
 &amp;lt;?php print_string(&#039;donotallowhtml&#039;, &#039;block_simplehtml&#039;); ?&amp;gt;&lt;br /&gt;
 &amp;lt;p&amp;gt;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&amp;lt;?php print_string(&#039;savechanges&#039;); ?&amp;gt;&amp;quot; /&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
 &amp;lt;/div&amp;gt;&lt;br /&gt;
True to our block&#039;s name, this looks simple enough. What it does is that it displays a checkbox named &amp;quot;block_simplehtml_strict&amp;quot; and if the Moodle configuration variable with the same name (i.e., $CFG-&amp;gt;block_simplehtml_strict) is set and not empty (that means it&#039;s not equal to an empty string, to zero, or to boolean false) it displays the box as pre-checked (reflecting the current status). Why does it check the configuration setting with the same name? Because the default implementation of the global configuration saving code takes all the variables we have in our form and saves them as Moodle configuration options with the same name. Thus, it&#039;s good practice to use a descriptive name and also one that won&#039;t possibly conflict with the name of another setting. &amp;quot;block_simplehtml_strict&amp;quot; clearly satisfies both requirements.&lt;br /&gt;
The astute reader may have noticed that we actually have &#039;&#039;two&#039;&#039; input fields named &amp;quot;block_simplehtml_strict&amp;quot; in our configuration file. One is hidden and its value is always 0; the other is the checkbox and its value is 1. What gives? Why have them both there?&lt;br /&gt;
Actually, this is a small trick we use to make our job as simple as possible. HTML forms work this way: if a checkbox in a form is not checked, its name does not appear at all in the variables passed to PHP when the form is submitted. That effectively means that, when we uncheck the box and click submit, the variable is not passed to PHP at all. Thus, PHP does not know to update its value to &amp;quot;0&amp;quot;, and our &amp;quot;strict&amp;quot; setting cannot be turned off at all once we turn it on for the first time. Not the behavior we want, surely.&lt;br /&gt;
However, when PHP handles received variables from a form, the variables are processed in the order in which they appear in the form. If a variable comes up having the same name with an already-processed variable, the new value overwrites the old one. Taking advantage of this, our logic runs as follows: the variable &amp;quot;block_simplehtml_strict&amp;quot; is first unconditionally set to &amp;quot;0&amp;quot;. Then, &#039;&#039;if&#039;&#039; the box is checked, it is set to &amp;quot;1&amp;quot;, overwriting the previous value as discussed. The net result is that our configuration setting behaves as it should.&lt;br /&gt;
To round our bag of tricks up, notice that the use of if(!empty($CFG-&amp;gt;block_simplehtml_strict)) in the test for &amp;quot;should the box be checked by default?&amp;quot; is quite deliberate. The first time this script runs, the variable $CFG-&amp;gt;block_simplehtml_strict will not exist at all. After it&#039;s set for the first time, its value can be either &amp;quot;0&amp;quot; or &amp;quot;1&amp;quot;. Given that both &amp;quot;not set&amp;quot; and the string &amp;quot;0&amp;quot; evaluate as empty while the sting &amp;quot;1&amp;quot; does not, we manage to avoid any warnings from PHP regarding the variable not being set at all, &#039;&#039;and&#039;&#039; have a nice human-readable representation for its two possible values (&amp;quot;0&amp;quot; and &amp;quot;1&amp;quot;).&lt;br /&gt;
Now that we have managed to cram a respectable amount of tricks into a few lines of HTML, we might as well discuss the alternative in case that tricks are not enough for a specific configuration setup we have in mind. Saving the data is done in the method [[Blocks_Howto#method_config_save| config_save]], the default implementation of which is as follows:&lt;br /&gt;
 &lt;br /&gt;
 function config_save($data) {&lt;br /&gt;
     // Default behavior: save all variables as $CFG properties&lt;br /&gt;
     foreach ($data as $name =&amp;gt; $value) {&lt;br /&gt;
         set_config($name, $value);&lt;br /&gt;
     }&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
As can be clearly seen, Moodle passes this method an associative array $data which contains all the variables coming in from our configuration screen. If we wanted to do the job without the &amp;quot;hidden variable with the same name&amp;quot; trick we used above, one way to do it would be by overriding this method with the following:&lt;br /&gt;
 &lt;br /&gt;
 function config_save($data) {&lt;br /&gt;
     if(isset($data[&#039;block_simplehtml_strict&#039;])) {&lt;br /&gt;
         set_config(&#039;block_simplehtml_strict&#039;, &#039;1&#039;);&lt;br /&gt;
     }&lt;br /&gt;
     else {&lt;br /&gt;
         set_config(&#039;block_simplehtml_strict&#039;, &#039;0&#039;);&lt;br /&gt;
     }&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
Quite straightfoward: if the variable &amp;quot;block_simplehtml_strict&amp;quot; is passed to us, then it can only mean that the user has checked it, so set the configuration variable with the same name to &amp;quot;1&amp;quot;. Otherwise, set it to &amp;quot;0&amp;quot;. Of course, this version would need to be updated if we add more configuration options because it doesn&#039;t respond to them as the default implementation does. Still, it&#039;s useful to know how we can override the default implementation if it does not fit our needs (for example, we might not want to save the variable as part of the Moodle configuration but do something else with it).&lt;br /&gt;
So, we are now at the point where we know if the block should allow HTML tags in its content or not. How do we get the block to actually respect that setting?&lt;br /&gt;
We could decide to do one of two things: either have the block &amp;quot;clean&amp;quot; HTML out from the input before saving it in the instance configuration and then display it as-is (the &amp;quot;eager&amp;quot; approach); or have it save the data &amp;quot;as is&amp;quot; and then clean it up each time just before displaying it (the &amp;quot;lazy&amp;quot; approach). The eager approach involves doing work once when saving the configuration; the lazy approach means doing work each time the block is displayed and thus it promises to be worse performance-wise. We shall hence go with the eager approach.&lt;br /&gt;
Much as we did just before with overriding [[Blocks_Howto#method_config_save| config_save]], what is needed here is overriding the method [[Blocks_Howto#method_instance_config_save| instance_config_save]] which handles the instance configuration. The default implementation is as follows:&lt;br /&gt;
 &lt;br /&gt;
 function instance_config_save($data) {&lt;br /&gt;
     $data = stripslashes_recursive($data);&lt;br /&gt;
     $this-&amp;gt;config = $data;&lt;br /&gt;
     return set_field(&#039;block_instance&#039;, &#039;configdata&#039;, base64_encode(serialize($data)),&lt;br /&gt;
                      &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
 }&lt;br /&gt;
This may look intimidating at first (what&#039;s all this stripslashes_recursive() and base64_encode() and serialize() stuff?) but do not despair; we won&#039;t have to touch any of it. We will only add some extra validation code in the beginning and then instruct Moodle to additionally call this default implementation to do the actual storing of the data. Specifically, we will add a method to our class which goes like this:&lt;br /&gt;
 &lt;br /&gt;
 function instance_config_save($data) {&lt;br /&gt;
     // Clean the data if we have to&lt;br /&gt;
     global $CFG;&lt;br /&gt;
     if(!empty($CFG-&amp;gt;block_simplehtml_strict)) {&lt;br /&gt;
         $data[&#039;text&#039;] = strip_tags($data[&#039;text&#039;]);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // And now forward to the default implementation defined in the parent class&lt;br /&gt;
     return parent::instance_config_save($data);&lt;br /&gt;
 }&lt;br /&gt;
At last! Now the administrator has absolute power of life and death over what type of content is allowed in our &amp;quot;SimpleHTML&amp;quot; block! Absolute? Well... not exactly. In fact, if we think about it for a while, it will become apparent that if at some point in time HTML is allowed and some blocks have saved their content with HTML included, and afterwards the administrator changes the setting to &amp;quot;off&amp;quot;, this will only prevent subsequent content changes from including HTML. Blocks which already had HTML in their content would continue to display it!&lt;br /&gt;
Following that train of thought, the next stop is realizing that we wouldn&#039;t have this problem if we had chosen the lazy approach a while back, because in that case we would &amp;quot;sanitize&amp;quot; each block&#039;s content just before it was displayed. The only thing we can do with the eager approach is strip all the tags from the content of all SimpleHTML instances as soon as the admin setting is changed to &amp;quot;HTML off&amp;quot;; but even then, turning the setting back to &amp;quot;HTML on&amp;quot; won&#039;t bring back the tags we stripped away. On the other hand, the lazy approach might be slower, but it&#039;s more versatile; we can choose whether to strip or keep the HTML before displaying the content, and we won&#039;t lose it at all if the admin toggles the setting off and on again. Isn&#039;t the life of a developer simple and wonderful?&lt;br /&gt;
We will let this part of the tutorial come to a close with the obligatory excercise for the reader: in order to have the SimpleHTML block work &amp;quot;correctly&amp;quot;, find out how to strengthen the eager approach to strip out all tags from the existing configuration of all instances of our block, &#039;&#039;&#039;or&#039;&#039;&#039; go back and implement the lazy approach instead. (Hint: do that in the [[Blocks_Howto#method_get_content| get_content]] method)&lt;br /&gt;
&#039;&#039;&#039;UPDATING&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;: Prior to version 1.5, the file &amp;lt;/nowiki&amp;gt;&amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config_global.html&amp;lt;/span&amp;gt; was named simply &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config.html&amp;lt;/span&amp;gt;. Also, the methods [[Blocks_Howto#method_config_save| config_save]] and [[Blocks_Howto#method_config_print| config_print]] were named &#039;&#039;&#039;handle_config&#039;&#039;&#039; and &#039;&#039;&#039;print_config&#039;&#039;&#039; respectively. Upgrading a block to work with Moodle 1.5 involves updating these aspects; refer to [[Blocks_Howto#appendix_b| Appendix B]] for more information.&lt;br /&gt;
== Eye Candy ==&lt;br /&gt;
Our block is just about complete functionally, so now let&#039;s take a look at some of the tricks we can use to make its behavior customized in a few more useful ways.&lt;br /&gt;
First of all, there are a couple of ways we can adjust the visual aspects of our block. For starters, it might be useful to create a block that doesn&#039;t display a header (title) at all. You can see this effect in action in the Course Description block that comes with Moodle. This behavior is achieved by, you guessed it, adding one more method to our block class:&lt;br /&gt;
 &lt;br /&gt;
 function hide_header() {&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
One more note here: we cannot just set an empty title inside the block&#039;s [[Blocks_Howto#method_init| init]] method; it&#039;s necessary for each block to have a unique, non-empty title after [[Blocks_Howto#method_init| init]] is called so that Moodle can use those titles to differentiate between all of the installed blocks.&lt;br /&gt;
Another adjustment we might want to do is instruct our block to take up a certain amount of width on screen. Moodle handles this as a two-part process: first, it queries each block about its preferred width and takes the maximum number as the desired value. Then, the page that&#039;s being displayed can choose to use this value or, more probably, bring it within some specific range of values if it isn&#039;t already. That means that the width setting is a best-effort settlement; your block can &#039;&#039;request&#039;&#039; a certain width and Moodle will &#039;&#039;try&#039;&#039; to provide it, but there&#039;s no guarantee whatsoever about the end result. As a concrete example, all standard Moodle course formats will deliver any requested width between 180 and 210 pixels, inclusive.&lt;br /&gt;
To instruct Moodle about our block&#039;s preferred width, we add one more method to the block class:&lt;br /&gt;
 &lt;br /&gt;
 function preferred_width() {&lt;br /&gt;
     // The preferred value is in pixels&lt;br /&gt;
     return 200;&lt;br /&gt;
 }&lt;br /&gt;
This will make our block (and all the other blocks displayed at the same side of the page) a bit wider than standard.&lt;br /&gt;
Finally, we can also affect some properties of the actual HTML that will be used to print our block. Each block is fully contained within a &amp;lt;table&amp;gt; element, inside which all the HTML for that block is printed. We can instruct Moodle to add HTML attributes with specific values to that container. This would be done to either a) directly affect the end result (if we say, assign bgcolor=&amp;quot;black&amp;quot;), or b) give us freedom to customize the end result using CSS (this is in fact done by default as we &#039;ll see below).&lt;br /&gt;
The default behavior of this feature in our case will assign to our block&#039;s container the class HTML attribute with the value &amp;quot;sideblock block_simplehtml&amp;quot; (the prefix &amp;quot;block_&amp;quot; followed by the name of our block, lowercased). We can then use that class to make CSS selectors in our theme to alter this block&#039;s visual style (for example, &amp;quot;.sideblock.block_simplehtml { border: 1px black solid}&amp;quot;).&lt;br /&gt;
To change the default behavior, we will need to define a method which returns an associative array of attribute names and values. For example, the version&lt;br /&gt;
 &lt;br /&gt;
 function html_attributes() {&lt;br /&gt;
     return array(&lt;br /&gt;
         &#039;class&#039;       =&amp;gt; &#039;sideblock block_&#039;. $this-&amp;gt;name(),&lt;br /&gt;
         &#039;onmouseover&#039; =&amp;gt; &#039;alert(&amp;quot;Mouseover on our block!&amp;quot;);&#039;&lt;br /&gt;
     );&lt;br /&gt;
 }&lt;br /&gt;
will result in a mouseover event being added to our block using JavaScript, just as if we had written the onmouseover=&amp;quot;alert(...)&amp;quot; part ourselves in HTML. Note that we actually duplicate the part which sets the class attribute (we want to keep that, and since we override the default behavior it&#039;s our responsibility to emulate it if required). And the final elegant touch is that we don&#039;t set the class to the hard-coded value &amp;quot;block_simplehtml&amp;quot; but instead use the [[Blocks_Howto#method_name| name]] method to make it dynamically match our block&#039;s name.&lt;br /&gt;
== Authorized Personnel Only ==&lt;br /&gt;
It&#039;s not difficult to imagine a block which is very useful in some circumstances but it simply cannot be made meaningful in others. An example of this would be the &amp;quot;Social Activities&amp;quot; block which is indeed useful in a course with the social format, but doesn&#039;t do anything useful in a course with the weeks format. There should be some way of allowing the use of such blocks only where they are indeed meaningful, and not letting them confuse users if they are not.&lt;br /&gt;
Moodle allows us to declare which course formats each block is allowed to be displayed in, and enforces these restrictions as set by the block developers at all times. The information is given to Moodle as a standard associative array, with each key corresponding to a page format and defining a boolean value (true/false) that declares whether the block should be allowed to appear in that page format.&lt;br /&gt;
Notice the deliberate use of the term &#039;&#039;page&#039;&#039; instead of &#039;&#039;course&#039;&#039; in the above paragraph. This is because in Moodle 1.5 and onwards, blocks can be displayed in any page that supports them. The best example of such pages are the course pages, but we are not restricted to them. For instance, the quiz view page (the first one we see when we click on the name of the quiz) also supports blocks.&lt;br /&gt;
The format names we can use for the pages derive from the name of the script which is actually used to display that page. For example, when we are looking at a course, the script is &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/course/view.php&amp;lt;/span&amp;gt; (this is evident from the browser&#039;s address line). Thus, the format name of that page is &#039;&#039;&#039;course-view&#039;&#039;&#039;. It follows easily that the format name for a quiz view page is &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039;. This rule of thumb does have a few exceptions, however:&lt;br /&gt;
#* The format name for the front page of Moodle is &#039;&#039;&#039;site-index&#039;&#039;&#039;.&lt;br /&gt;
#* The format name for courses is actually not just &#039;&#039;&#039;course-view&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; it is &amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;course-view-weeks&#039;&#039;&#039;, &#039;&#039;&#039;course-view-topics&#039;&#039;&#039;, etc.&lt;br /&gt;
#* Even though there is no such page, the format name &#039;&#039;&#039;all&#039;&#039;&#039; can be used as a catch-all option.&lt;br /&gt;
We can include as many format names as we want in our definition of the applicable formats. Each format can be allowed or disallowed, and there are also three more rules that help resolve the question &amp;quot;is this block allowed into this page or not?&amp;quot;:&lt;br /&gt;
#* Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
#* The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
#* The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
#* The order that the format names appear does not make any difference.&lt;br /&gt;
All of the above are enough to make the situation sound complex, so let&#039;s look at some specific examples. First of all, to have our block appear &#039;&#039;&#039;only&#039;&#039;&#039; in the site front page, we would use:&lt;br /&gt;
 &lt;br /&gt;
 function applicable_formats() {&lt;br /&gt;
     return array(&#039;site&#039; =&amp;gt; true);&lt;br /&gt;
 }&lt;br /&gt;
Since &#039;&#039;&#039;all&#039;&#039;&#039; is missing, the block is disallowed from appearing in &#039;&#039;any&#039;&#039; course format; but then &#039;&#039;&#039;site&#039;&#039;&#039; is set to true, so it&#039;s explicitly allowed to appear in the site front page (remember that &#039;&#039;&#039;site&#039;&#039;&#039; matches &#039;&#039;&#039;site-index&#039;&#039;&#039; because it&#039;s a prefix).&lt;br /&gt;
For another example, if we wanted to allow the block to appear in all course formats &#039;&#039;except&#039;&#039; social, and also to &#039;&#039;not&#039;&#039; be allowed anywhere but in courses, we would use:&lt;br /&gt;
 &lt;br /&gt;
 function applicable_formats() {&lt;br /&gt;
     return array(&#039;course-view&#039; =&amp;gt; true, &#039;course-view-social&#039; =&amp;gt; false);&lt;br /&gt;
 }&lt;br /&gt;
This time, we first allow the block to appear in all courses and then we explicitly disallow the social format.&lt;br /&gt;
For our final, most complicated example, suppose that a block can be displayed in the site front page, in courses (but not social courses) and also when we are viewing any activity module, &#039;&#039;except&#039;&#039; quiz. This would be:&lt;br /&gt;
 &lt;br /&gt;
 function applicable_formats() {&lt;br /&gt;
     return array(&#039;site-index&#039; =&amp;gt; true,&lt;br /&gt;
                  &#039;course-view&#039; =&amp;gt; true, &#039;course-view-social&#039; =&amp;gt; false,&lt;br /&gt;
                  &#039;mod&#039; =&amp;gt; true, &#039;mod-quiz&#039; =&amp;gt; false);&lt;br /&gt;
 }&lt;br /&gt;
It is not difficult to realize that the above accomplishes the objective if we remember that there is a &amp;quot;best match&amp;quot; policy to determine the end result.&lt;br /&gt;
&#039;&#039;&#039;UPDATING:&#039;&#039;&#039; Prior to version 1.5, blocks were only allowed in courses (and in Moodle 1.4, in the site front page). Also, the keywords used to describe the valid course formats at the time were slightly different and had to be changed in order to allow for a more open architecture. Refer to [[Blocks_Howto#appendix_b| Appendix B]] for more information on the changes that old blocks have to make to conform to the new standard.&lt;br /&gt;
== Lists and Icons ==&lt;br /&gt;
In this final part of the guide we will briefly discuss an additional capability of Moodle&#039;s block system, namely the ability to very easily create blocks that display a list of choices to the user. This list is displayed with one item per line, and an optional image (icon) next to the item. An example of such a &#039;&#039;list block&#039;&#039; is the standard Moodle &amp;quot;admin&amp;quot; block, which illustrates all the points discussed in this section.&lt;br /&gt;
As we have seen so far, blocks of use two properties of [[Blocks_Howto#variable_content| $this-&amp;gt;content]]&amp;lt;nowiki&amp;gt;: &amp;quot;text&amp;quot; and &amp;quot;footer&amp;quot;. The text is displayed as-is as the block content, and the footer is displayed below the content in a smaller font size. List blocks use $this-&amp;gt;content-&amp;gt;footer in the exact same way, but they ignore $this-&amp;gt;content-&amp;gt;text.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Instead, Moodle expects such blocks to set two other properties when the [[Blocks_Howto#method_get_content| get_content]] method is called: $this-&amp;gt;content-&amp;gt;items and $this-&amp;gt;content-&amp;gt;icons. $this-&amp;gt;content-&amp;gt;items should be a numerically indexed array containing elements that represent the HTML for each item in the list that is going to be displayed. Usually these items will be HTML anchor tags which provide links to some page. $this-&amp;gt;content-&amp;gt;icons should also be a numerically indexed array, with exactly as many items as $this-&amp;gt;content-&amp;gt;items has. Each of these items should be a fully qualified HTML &amp;lt;img&amp;gt; tag, with &amp;quot;src&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;width&amp;quot; and &amp;quot;alt&amp;quot; attributes. Obviously, it makes sense to keep the images small and of a uniform size.&lt;br /&gt;
In order to tell Moodle that we want to have a list block instead of the standard text block, we need to make a small change to our block class declaration. Instead of extending class &#039;&#039;&#039;block_base&#039;&#039;&#039;, our block will extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;. For example:&lt;br /&gt;
 &lt;br /&gt;
 class block_my_menu extends block_list {&lt;br /&gt;
     // The init() method does not need to change at all&lt;br /&gt;
 }&lt;br /&gt;
In addition to making this change, we must of course also modify the [[Blocks_Howto#method_get_content| get_content]] method to construct the [[Blocks_Howto#variable_content| $this-&amp;gt;content]] variable as discussed above:&lt;br /&gt;
 &lt;br /&gt;
 function get_content() {&lt;br /&gt;
     if ($this-&amp;gt;content !== NULL) {&lt;br /&gt;
         return $this-&amp;gt;content;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     $this-&amp;gt;content = new stdClass;&lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;items = array();&lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;icons = array();&lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;items[] = &#039;&amp;lt;a href=&amp;quot;some_file.php&amp;quot;&amp;gt;Menu Option 1&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
     $this-&amp;gt;content-&amp;gt;icons[] = &#039;&amp;lt;img src=&amp;quot;images/icons/1.gif&amp;quot; width=&amp;quot;16&amp;quot; height=&amp;quot;16&amp;quot; alt=&amp;quot;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
 &lt;br /&gt;
     // Add more list items here&lt;br /&gt;
 &lt;br /&gt;
     return $this-&amp;gt;content;&lt;br /&gt;
 }&lt;br /&gt;
To summarize, if we want to create a list block instead of a text block, we just need to change the block class declaration and the [[Blocks_Howto#method_get_content| get_content]] method. Adding the mandatory [[Blocks_Howto#method_init| init]] method as discussed earlier will then give us our first list block in no time!&lt;br /&gt;
&lt;br /&gt;
== Appendix A: Reference ==&lt;br /&gt;
&lt;br /&gt;
This Appendix will discuss the base class &#039;&#039;&#039;block_base&#039;&#039;&#039; from which all other block classes derive, and present each and every method that can be overridden by block developers in detail. Methods that should &#039;&#039;&#039;not&#039;&#039;&#039; be overridden are explicitly referred to as such. After reading this Appendix, you will have a clear understanding of every method which you should or could override to implement functionality for your block.&lt;br /&gt;
&lt;br /&gt;
The methods are divided into three categories: those you may use and override in your block, those that you may &#039;&#039;&#039;not&#039;&#039;&#039; override but might want to use, and those internal methods that should &#039;&#039;&#039;neither&#039;&#039;&#039; be used &#039;&#039;&#039;nor&#039;&#039;&#039; overridden. In each category, methods are presented in alphabetical order.&lt;br /&gt;
&lt;br /&gt;
=== Methods you can freely use and override: ===&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;applicable_formats&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function applicable_formats() {&lt;br /&gt;
     // Default case: the block can be used in courses and site index, but not in activities&lt;br /&gt;
     return array(&#039;all&#039; =&amp;gt; true, &#039;mod&#039; =&amp;gt; false);&lt;br /&gt;
 }&lt;br /&gt;
This method allows you to control which pages your block can be added to. Page formats are formulated from the full path of the script that is used to display that page. You should return an array with the keys being page format names and the values being booleans (true or false). Your block is only allowed to appear in those formats where the value is true.&lt;br /&gt;
Example format names are: &#039;&#039;&#039;course-view&#039;&#039;&#039;, &#039;&#039;&#039;site-index&#039;&#039;&#039; (this is an exception, referring front page of the Moodle site), &#039;&#039;&#039;course-format-weeks&#039;&#039;&#039; (referring to a specific course format), &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; (referring to the quiz module) and &#039;&#039;&#039;all&#039;&#039;&#039; (this will be used for those formats you have not explicitly allowed or disallowed).&lt;br /&gt;
The full matching rules are:&lt;br /&gt;
*** Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
*** The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
*** The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
*** The order that the format names appear does not make any difference.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;config_print&amp;lt;/div&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 function config_print() {&lt;br /&gt;
     // Default behavior: print the config_global.html file&lt;br /&gt;
     // You don&#039;t need to override this if you&#039;re satisfied with the above&lt;br /&gt;
     if (!$this-&amp;gt;has_config()) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     global $CFG, $THEME;&lt;br /&gt;
     print_simple_box_start(&#039;center&#039;, &#039;&#039;, $THEME-&amp;gt;cellheading);&lt;br /&gt;
     include($CFG-&amp;gt;dirroot.&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_global.html&#039;);&lt;br /&gt;
     print_simple_box_end();&lt;br /&gt;
     return true;&lt;br /&gt;
 }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
This method allows you to choose how to display the global configuration screen for your block. This is the screen that the administrator is presented with when he chooses &amp;quot;Settings...&amp;quot; for a specific block. Override it if you need something much more complex than the default implementation allows you to do. However, keep these points in mind:&lt;br /&gt;
**# If you save your configuration options in $CFG, you will probably need to use global $CFG; before including any HTML configuration screens.&lt;br /&gt;
**# The HTML &amp;lt;input&amp;gt; elements that you include in your method&#039;s output will be automatically enclosed in a &amp;lt;form&amp;gt; element. You do not need to worry about where and how that form is submitted; however, you &#039;&#039;&#039;must&#039;&#039;&#039; provide a way to submit it (i.e., an &amp;lt;input type=&amp;quot;submit&amp;quot; /&amp;gt;.&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;config_save&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function config_save($data) {&lt;br /&gt;
     // Default behavior: save all variables as $CFG properties&lt;br /&gt;
     // You don&#039;t need to override this if you &#039;re satisfied with the above&lt;br /&gt;
     foreach ($data as $name =&amp;gt; $value) {&lt;br /&gt;
         set_config($name, $value);&lt;br /&gt;
     }&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
This method allows you to override the storage mechanism for your global configuration data. The received argument is an associative array, with the keys being setting names and the values being setting values. The default implementation saves everything as Moodle $CFG variables.&lt;br /&gt;
Note that $data does not hold all of the submitted POST data because Moodle adds some hidden fields to the form in order to be able to process it. However, before calling this method it strips the hidden fields from the received data and so when this method is called only the &amp;quot;real&amp;quot; configuration data remain.&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;get_content&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function get_content() {&lt;br /&gt;
     // This should be implemented by the derived class.&lt;br /&gt;
     return NULL;&lt;br /&gt;
 }&lt;br /&gt;
This method should, when called, populate the [[Blocks_Howto#variable_content| $this-&amp;gt;content]] variable of your block. Populating the variable means:&lt;br /&gt;
&#039;&#039;&#039;EITHER&#039;&#039;&#039;&amp;lt;br /&amp;gt;defining $this-&amp;gt;content-&amp;gt;text and $this-&amp;gt;content-&amp;gt;footer if your block derives from &#039;&#039;&#039;block_base&#039;&#039;&#039;. Both of these should be strings, and can contain arbitrary HTML.&lt;br /&gt;
&#039;&#039;&#039;OR&#039;&#039;&#039;&amp;lt;br /&amp;gt;defining $this-&amp;gt;content-&amp;gt;items, $this-&amp;gt;content-&amp;gt;icons and $this-&amp;gt;content-&amp;gt;footer if your block derives from &#039;&#039;&#039;block_list&#039;&#039;&#039;. The first two should be numerically indexed arrays having the exact same number of elements. $this-&amp;gt;content-&amp;gt;items is an array of strings that can contain arbitrary HTML while $this-&amp;gt;content-&amp;gt;icons also contains should strings, but those must be fully-qualified HTML &amp;lt;img&amp;gt; tags &#039;&#039;&#039;and nothing else&#039;&#039;&#039;. $this-&amp;gt;content-&amp;gt;footer is a string, as above.&lt;br /&gt;
If you set &#039;&#039;all&#039;&#039; of these variables to their default &amp;quot;empty&amp;quot; values (empty arrays for the arrays and empty strings for the strings), the block will &#039;&#039;&#039;not&#039;&#039;&#039; be displayed at all except to editing users. This is a good way of having your block hide itself to unclutter the screen if there is no reason to have it displayed.&lt;br /&gt;
Before starting to populate [[Blocks_Howto#variable_content| $this-&amp;gt;content]], you should also include a simple caching check. If [[Blocks_Howto#variable_content| $this-&amp;gt;content]] is exactly equal to NULL then proceed as normally, while if it is not, return the existing value instead of calculating it once more. If you fail to do this, Moodle will suffer a performance hit.&lt;br /&gt;
In any case, your method should return the fully constructed [[Blocks_Howto#variable_content| $this-&amp;gt;content]] variable.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;has_config&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function has_config() {&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
This method should return a boolean value that denotes whether your block wants to present a configuration interface to site admins or not. The configuration that this interface offers will impact all instances of the block equally.&lt;br /&gt;
To actually implement the configuration interface, you will either need to rely on the default [[Blocks_Howto#method_instance_config_print| config_print]] method or override it. The full guide contains [[Blocks_Howto#section_effects_of_globalization| more information on this]].&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;hide_header&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function hide_header() {&lt;br /&gt;
     //Default, false--&amp;gt; the header is shown&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
This method should return a boolean value that denotes whether your block wants to hide its header (or title). Thus, if you override it to return true, your block will not display a title unless the current user is in editing mode.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;html_attributes&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function html_attributes() {&lt;br /&gt;
     // Default case: an id with the instance and a class with our name in it&lt;br /&gt;
     return array(&#039;id&#039; =&amp;gt; &#039;inst&#039;.$this-&amp;gt;instance-&amp;gt;id, &#039;class&#039; =&amp;gt; &#039;block_&#039;. $this-&amp;gt;name());&lt;br /&gt;
 }&lt;br /&gt;
This method should return an associative array of HTML attributes that will be given to your block&#039;s container element when Moodle constructs the output HTML. No sanitization will be performed in these elements at all.&lt;br /&gt;
If you intend to override this method, you should return the default attributes as well as those you add yourself. The recommended way to do this is:&lt;br /&gt;
 &lt;br /&gt;
 function html_attributes() {&lt;br /&gt;
     $attrs = parent::html_attributes();&lt;br /&gt;
     // Add your own attributes here, e.g.&lt;br /&gt;
     // $attrs[&#039;width&#039;] = &#039;50%&#039;;&lt;br /&gt;
     return $attrs;&lt;br /&gt;
 }&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;init&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function init() {&lt;br /&gt;
     $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
     $this-&amp;gt;version = 2004111200;&lt;br /&gt;
 }&lt;br /&gt;
This method must be implemented for all blocks. It has to assign meaningful values to the object variables [[Blocks_Howto#variable_title| $this-&amp;gt;title]] and [[Blocks_Howto#variable_version| $this-&amp;gt;version]] (which is used by Moodle for performing automatic updates when available).&lt;br /&gt;
No return value is expected from this method.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;instance_allow_config&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function instance_allow_config() {&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
This method should return a boolean value. True indicates that your block wants to have per-instance configuration, while false means it does not. If you do want to implement instance configuration, you will need to take some additional steps apart from overriding this method; refer to the full guide for [[Blocks_Howto#section_configure_that_out| more information]].&lt;br /&gt;
This method&#039;s return value is irrelevant if [[Blocks_Howto#method_instance_allow_multiple| instance_allow_multiple]] returns true; it is assumed that if you want multiple instances then each instance needs its own configuration.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;instance_allow_multiple&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function instance_allow_multiple() {&lt;br /&gt;
     // Are you going to allow multiple instances of each block?&lt;br /&gt;
     // If yes, then it is assumed that the block WILL USE per-instance configuration&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
This method should return a boolean value, indicating whether you want to allow multiple instances of this block in the same page or not. If you do allow multiple instances, it is assumed that you will also be providing per-instance configuration for the block. Thus, you will need to take some additional steps apart from overriding this method; refer to the full guide for [[Blocks_Howto#section_configure_that_out| more information]].&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;instance_config_print&amp;lt;/div&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 function instance_config_print() {&lt;br /&gt;
     // Default behavior: print the config_instance.html file&lt;br /&gt;
     // You don&#039;t need to override this if you&#039;re satisfied with the above&lt;br /&gt;
     if (!$this-&amp;gt;instance_allow_multiple() &amp;amp;&amp;amp; !$this-&amp;gt;instance_allow_config()) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     global $CFG, $THEME;&lt;br /&gt;
 &lt;br /&gt;
     if (is_file($CFG-&amp;gt;dirroot .&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_instance.html&#039;)) {&lt;br /&gt;
         print_simple_box_start(&#039;center&#039;, &#039;&#039;, $THEME-&amp;gt;cellheading);&lt;br /&gt;
         include($CFG-&amp;gt;dirroot .&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_instance.html&#039;);&lt;br /&gt;
         print_simple_box_end();&lt;br /&gt;
     } else {&lt;br /&gt;
         notice(get_string(&#039;blockconfigbad&#039;),&lt;br /&gt;
                str_replace(&#039;blockaction=&#039;, &#039;dummy=&#039;, qualified_me()));&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return true;&lt;br /&gt;
 }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
This method allows you to choose how to display the instance configuration screen for your block. Override it if you need something much more complex than the default implementation allows you to do. Keep in mind that whatever you do output from [[Blocks_Howto#method_instance_config_print| config_print]], it will be enclosed in a HTML form automatically. You only need to provide a way to submit that form.&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;instance_config_save&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function instance_config_save($data) {&lt;br /&gt;
     $data = stripslashes_recursive($data);&lt;br /&gt;
     $this-&amp;gt;config = $data;&lt;br /&gt;
     return set_field(&#039;block_instance&#039;, &#039;configdata&#039;, base64_encode(serialize($data)),&lt;br /&gt;
                      &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
 }&lt;br /&gt;
This method allows you to override the storage mechanism for your instance configuration data. The received argument is an associative array, with the keys being setting names and the values being setting values.&lt;br /&gt;
The configuration must be stored in the &amp;quot;configdata&amp;quot; field of your instance record in the database so that Moodle can auto-load it when your block is constructed. However, you may still want to override this method if you need to take some additional action apart from saving the data. In that case, you really should do what data processing you want and then call parent::instance_config_save($data) with your new $data array. This will keep your block from becoming broken if the default implementation of instance_config_save changes in the future.&lt;br /&gt;
Note that $data does not hold all of the submitted POST data because Moodle adds some hidden fields to the form in order to be able to process it. However, before calling this method it strips the hidden fields from the received data and so when this method is called only the &amp;quot;real&amp;quot; configuration data remain.&lt;br /&gt;
If you want to update the stored copy of the configuration data at run time (for example to persist some changes you made programmatically), you should not use this method. The correct procedure for that purpose is to call [[Blocks_Howto#method_instance_config_commit| instance_config_commit]].&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;preferred_width&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function preferred_width() {&lt;br /&gt;
     // Default case: the block wants to be 180 pixels wide&lt;br /&gt;
     return 180;&lt;br /&gt;
 }&lt;br /&gt;
This method should return an integer value, which is the number of pixels of width your block wants to take up when displayed. Moodle will try to honor your request, but this is actually up to the implementation of the format of the page your block is being displayed in and therefore no guarantee is given. You might get exactly what you want or any other width the format decides to give you, although obviously an effort to accomodate your block will be made.&lt;br /&gt;
Most display logic at this point allocates the maximum width requested by the blocks that are going to be displayed, bounding it both downwards and upwards to avoid having a bad-behaving block break the format.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;refresh_content&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function refresh_content() {&lt;br /&gt;
     // Nothing special here, depends on content()&lt;br /&gt;
     $this-&amp;gt;content = NULL;&lt;br /&gt;
     return $this-&amp;gt;get_content();&lt;br /&gt;
 }&lt;br /&gt;
This method should cause your block to recalculate its content immediately. If you follow the guidelines for [[Blocks_Howto#get_content| get_content]], which say to respect the current content value unless it is NULL, then the default implementation will do the job just fine.&lt;br /&gt;
You should return the new value of [[Blocks_Howto#variable_content| $this-&amp;gt;content]] after refreshing it.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;specialization&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function specialization() {&lt;br /&gt;
     // Just to make sure that this method exists.&lt;br /&gt;
 }&lt;br /&gt;
This method is automatically called by the framework immediately after your instance data (which includes the page type and id and all instance configuration data) is loaded from the database. If there is some action that you need to take as soon as this data becomes available and which cannot be taken earlier, you should override this method.&lt;br /&gt;
The instance data will be available in the variables [[Blocks_Howto#variable_instance| $this-&amp;gt;instance]] and [[Blocks_Howto#variable_config| $this-&amp;gt;config]].&lt;br /&gt;
This method should not return anything at all.&lt;br /&gt;
=== Methods which you should &#039;&#039;not&#039;&#039; override but may want to use: ===&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;instance_config_commit&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function instance_config_commit() {&lt;br /&gt;
     return set_field(&#039;block_instance&#039;,&lt;br /&gt;
                      &#039;configdata&#039;, base64_encode(serialize($this-&amp;gt;config)),&lt;br /&gt;
                      &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
 }&lt;br /&gt;
This method saves the current contents of [[Blocks_Howto#variable_config| $this-&amp;gt;config]] to the database. If you need to make a change to the configuration settings of a block instance at run time (and not through the usual avenue of letting the user change it), just make the changes you want to [[Blocks_Howto#variable_config| $this-&amp;gt;config]] and then call this method.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;get_content_type&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function get_content_type() {&lt;br /&gt;
     return $this-&amp;gt;content_type;&lt;br /&gt;
 }&lt;br /&gt;
This method returns the value of [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;get_title&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function get_title() {&lt;br /&gt;
     return $this-&amp;gt;title;&lt;br /&gt;
 }&lt;br /&gt;
This method returns the value of [[Blocks_Howto#variable_title| $this-&amp;gt;title]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;get_version&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function get_version() {&lt;br /&gt;
     return $this-&amp;gt;version;&lt;br /&gt;
 }&lt;br /&gt;
This method returns the value of [[Blocks_Howto#variable_version| $this-&amp;gt;version]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;is_empty&amp;lt;/div&amp;gt;&lt;br /&gt;
For blocks that extend class &#039;&#039;&#039;block_base&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function is_empty() {&lt;br /&gt;
     $this-&amp;gt;get_content();&lt;br /&gt;
     return(empty($this-&amp;gt;content-&amp;gt;text) &amp;amp;&amp;amp; empty($this-&amp;gt;content-&amp;gt;footer));&lt;br /&gt;
 }&lt;br /&gt;
For blocks that extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function is_empty() {&lt;br /&gt;
     $this-&amp;gt;get_content();&lt;br /&gt;
     return (empty($this-&amp;gt;content-&amp;gt;items) &amp;amp;&amp;amp; empty($this-&amp;gt;content-&amp;gt;footer));&lt;br /&gt;
 }&lt;br /&gt;
This method returns the a boolean true/false value, depending on whether the block has any content at all to display. Blocks without content are not displayed by the framework.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;name&amp;lt;/div&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 function name() {&lt;br /&gt;
     static $myname;&lt;br /&gt;
     if ($myname === NULL) {&lt;br /&gt;
         $myname = strtolower(get_class($this));&lt;br /&gt;
         $myname = substr($myname, strpos($myname, &#039;_&#039;) + 1);&lt;br /&gt;
     }&lt;br /&gt;
     return $myname;&lt;br /&gt;
 }&lt;br /&gt;
This method returns the internal name of your block inside Moodle, without the &#039;&#039;&#039;block_&#039;&#039;&#039; prefix. Obtaining the name of a block object is sometimes useful because it can be used to write code that is agnostic to the actual block&#039;s name (and thus more generic and reusable). For an example of this technique, see the [[Blocks_Howto#method_config_print| config_print]] method.&lt;br /&gt;
=== Methods which you should &#039;&#039;not&#039;&#039; override and &#039;&#039;not&#039;&#039; use at all: ===&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;_self_test&amp;lt;/div&amp;gt;&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;_add_edit_controls&amp;lt;/div&amp;gt;&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;_load_instance&amp;lt;/div&amp;gt;&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;_print_block&amp;lt;/div&amp;gt;&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
** &amp;lt;div class=&amp;quot;function_title&amp;quot;&amp;gt;_print_shadow&amp;lt;/div&amp;gt;&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;block_base&#039;&#039;&#039; also has a few standard member variables which its methods manipulate. These variables, the purpose of each and the type of data they are expected to hold is explained in the next section of this Appendix.&lt;br /&gt;
&lt;br /&gt;
=== Class variables: ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;div class=&amp;quot;variable_title&amp;quot;&amp;gt;$this-&amp;gt;config&amp;lt;/div&amp;gt;&lt;br /&gt;
This variable holds all the specialized instance configuration data that have been provided for this specific block instance (object). It is an object of type stdClass, with member variables directly corresponding to the HTML &amp;lt;input&amp;gt; elements in the block&#039;s &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config_instance.html&amp;lt;/span&amp;gt; file.&lt;br /&gt;
The variable is initialized just after the block object is constructed, immediately before [[Blocks_Howto#method_specialization| specialization]] is called for the object. It is possible that the block has no instance configuration, in which case the variable will be NULL.&lt;br /&gt;
It is obvious that there is a direct relationship between this variable and the configdata field in the mdl_block_instance table. However, it is &#039;&#039;strongly&#039;&#039; advised that you refrain from accessing the configdata field yourself. If you absolutely must update its value at any time, it is recommended that you call the method [[Blocks_Howto#method_instance_config_commit| instance_config_commit]] to do the actual work.&lt;br /&gt;
* &amp;lt;div class=&amp;quot;variable_title&amp;quot;&amp;gt;$this-&amp;gt;content_type&amp;lt;/div&amp;gt;&lt;br /&gt;
This variable instructs Moodle on what type of content it should assume the block has, and is used to differentiate text blocks from list blocks. It is essential that it has a meaningful value, as Moodle depends on this for correctly displaying the block on screen. Consequently, this variable is closely tied with the variable [[Blocks_Howto#variable_content| $this-&amp;gt;content]]. The variable is expected to have a valid value after the framework calls the [[Blocks_Howto#method_init| init]] method for each block.&lt;br /&gt;
The only valid values for this variable are the two named constants [[Blocks_Howto#constant_block_type_text| BLOCK_TYPE_TEXT]] and [[Blocks_Howto#constant_block_type_list| BLOCK_TYPE_LIST]].&lt;br /&gt;
* &amp;lt;div class=&amp;quot;variable_title&amp;quot;&amp;gt;$this-&amp;gt;content&amp;lt;/div&amp;gt;&lt;br /&gt;
This variable holds all the actual content that is displayed inside each block. Valid values for it are either NULL or an object of class stdClass, which must have specific member variables set as explained below. Normally, it begins life with a value of NULL and it becomes fully constructed (i.e., an object) when [[Blocks_Howto#method_get_content| get_content]] is called.&lt;br /&gt;
After it is fully constructed, this object is expected to have certain properties, depending on the value of [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]]. Specifically:&lt;br /&gt;
** If [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] is [[Blocks_Howto#constant_block_type_text| BLOCK_TYPE_TEXT]], then [[Blocks_Howto#variable_content| $this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
*** &amp;lt;div&amp;gt;&#039;&#039;&#039;text&#039;&#039;&#039;&amp;lt;/div&amp;gt;This is a string of arbitrary length and content. It is displayed inside the main area of the block, and can contain HTML.&lt;br /&gt;
*** &amp;lt;div&amp;gt;&#039;&#039;&#039;footer&#039;&#039;&#039;&amp;lt;/div&amp;gt;This is a string of arbitrary length and contents. It is displayed below the text, using a smaller font size. It can also contain HTML.&lt;br /&gt;
** If [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] is [[Blocks_Howto#constant_block_type_list| BLOCK_TYPE_LIST]], then [[Blocks_Howto#variable_content| $this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
*** &amp;lt;div&amp;gt;&#039;&#039;&#039;items&#039;&#039;&#039;&amp;lt;/div&amp;gt;This is a numerically indexed array of strings which holds the title for each item in the list that will be displayed in the block&#039;s area. Since usually such lists function like menus, the title for each item is normally a fully qualified HTML &amp;lt;a&amp;gt; tag.&lt;br /&gt;
*** &amp;lt;div&amp;gt;&#039;&#039;&#039;icons&#039;&#039;&#039;&amp;lt;/div&amp;gt;This is a numerically indexed array of strings which represent the images displayed before each item of the list. It therefore follows that it should have the exact number of elements as the items member variable. Each item in this array should be a fully qualified HTML &amp;lt;img&amp;gt; tag.&lt;br /&gt;
*** &amp;lt;div&amp;gt;&#039;&#039;&#039;footer&#039;&#039;&#039;&amp;lt;/div&amp;gt;This is a string of arbitrary length and contents. It is displayed below the text, using a smaller font size. It can also contain HTML.&lt;br /&gt;
* &amp;lt;div class=&amp;quot;variable_title&amp;quot;&amp;gt;$this-&amp;gt;instance&amp;lt;/div&amp;gt;&lt;br /&gt;
This member variable holds all the specific information that differentiates one block instance (i.e., the PHP object that embodies it) from another. It is an object of type stdClass retrieved by calling get_record on the table mdl_block_instance. Its member variables, then, directly correspond to the fields of that table. It is initialized immediately after the block object itself is constructed.&lt;br /&gt;
* &amp;lt;div class=&amp;quot;variable_title&amp;quot;&amp;gt;$this-&amp;gt;title&amp;lt;/div&amp;gt;&lt;br /&gt;
This variable is a string that contains the human-readable name of the block. It is used to refer to blocks of that type throughout Moodle, for example in the administrator&#039;s block configuration screen and in the editing teacher&#039;s add block menu. It is also the title that is printed when the block is displayed on screen, although blocks can specifically change this title to something else if they wish (see below). The variable is expected to have a valid value after the framework calls the [[Blocks_Howto#method_init| init]] method for each object.&lt;br /&gt;
In the case of blocks which may want to configure their title dynamically through instance configuration, it is still essential to provide a valid title inside [[Blocks_Howto#method_init| init]]. This title may then be overridden when the [[Blocks_Howto#method_specialization| specialization]] method is called by the framework:&lt;br /&gt;
 &lt;br /&gt;
 function specialization() {&lt;br /&gt;
     // At this point, $this-&amp;gt;instance and $this-&amp;gt;config are available&lt;br /&gt;
     // for use. We can now change the title to whatever we want.&lt;br /&gt;
     $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;variable_holding_the_title;&lt;br /&gt;
 }&lt;br /&gt;
* &amp;lt;div class=&amp;quot;variable_title&amp;quot;&amp;gt;$this-&amp;gt;version&amp;lt;/div&amp;gt;&lt;br /&gt;
This variable should hold each block&#039;s version number in the form &#039;&#039;&#039;YYYYMMDDXX&#039;&#039;&#039;, as per the convention throughout Moodle. The version number is used by Moodle to detect when a block has been upgraded and it consequently needs to run the block&#039;s upgrade code to bring the &amp;quot;old&amp;quot; version of the block&#039;s data up to date. The variable is expected to have a valid value after the framework calls the [[Blocks_Howto#method_init| init]] method for each block.&lt;br /&gt;
Most blocks do not keep complex data of their own in the database the way that modules do, so in most cases nothing actually happens during a block version upgrade. However, the version number is displayed in the administration interface for blocks. It is good practice therefore to change your block&#039;s version number when it gains new functionality or receives important bug fixes, to enable site administrators to easily identify the exact version of the block they are working with.&lt;br /&gt;
&lt;br /&gt;
Appearing throughout the code related to the Blocks API, there is a number of predefined constants that are utilized to avoid the use of &amp;quot;magic numbers&amp;quot; in the code. These constants are:&lt;br /&gt;
&lt;br /&gt;
=== Named constants: ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;div class=&amp;quot;named_constant&amp;quot;&amp;gt;BLOCK_TYPE_LIST&amp;lt;/div&amp;gt;&lt;br /&gt;
This is one of the two valid values for the [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[Blocks_Howto#variable_content| $this-&amp;gt;content]].&lt;br /&gt;
* &amp;lt;div class=&amp;quot;named_constant&amp;quot;&amp;gt;BLOCK_TYPE_TEXT&amp;lt;/div&amp;gt;&lt;br /&gt;
This is one of the two valid values for the [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[Blocks_Howto#variable_content| $this-&amp;gt;content]].&lt;br /&gt;
&lt;br /&gt;
== Appendix B: Differences in the Blocks API for Moodle versions prior to 1.5 ==&lt;br /&gt;
&lt;br /&gt;
This Appendix will discuss what changes in the Blocks API were introduced by Moodle 1.5 and what steps developers need to take to update their blocks to be fully compatible with Moodle 1.5. Unfortunately, with these changes backward compatibility is broken; this means that blocks from Moodle 1.4 will never work with 1.5 and vice versa.&lt;br /&gt;
&lt;br /&gt;
=== Class naming conventions changed ===&lt;br /&gt;
In Moodle 1.4, all block classes were required to have a name like &#039;&#039;&#039;CourseBlock_something&#039;&#039;&#039; and the base class from which the derived was &#039;&#039;&#039;MoodleBlock&#039;&#039;&#039;. This has changed in Moodle 1.5, to bring the naming conventions in line with other object-oriented aspects of Moodle (for example there are classes enrolment_base, resource_base etc). The new block classes should instead be named like &#039;&#039;&#039;block_something&#039;&#039;&#039; and derive from &#039;&#039;&#039;block_base&#039;&#039;&#039;. This means that in order to make a block compatible with Moodle 1.5, you need to change the class definition&lt;br /&gt;
 &lt;br /&gt;
 class CourseBlock_online_users extends MoodleBlock { ... }&lt;br /&gt;
to&lt;br /&gt;
 &lt;br /&gt;
 class block_online_users extends block_base { ... }&lt;br /&gt;
An exception to the above is the special case where the block is intended to display a list of items instead of arbitrary text; in this case the block class must derive from class &#039;&#039;&#039;block_list&#039;&#039;&#039; instead, like this:&lt;br /&gt;
 &lt;br /&gt;
 class block_admin extends block_list { ... }&lt;br /&gt;
&lt;br /&gt;
=== Constructor versus init() ===&lt;br /&gt;
&lt;br /&gt;
In Moodle 1.4, in each block class it was mandatory to define a constructor which accepted a course data record as an argument (the example is from the actual Online Users block):&lt;br /&gt;
 &lt;br /&gt;
     function CourseBlock_online_users ($course) {&lt;br /&gt;
         $this-&amp;gt;title = get_string(&#039;blockname&#039;,&#039;block_online_users&#039;);&lt;br /&gt;
         $this-&amp;gt;content_type = BLOCK_TYPE_TEXT;&lt;br /&gt;
         $this-&amp;gt;course = $course;&lt;br /&gt;
         $this-&amp;gt;version = 2004052700;&lt;br /&gt;
     }&lt;br /&gt;
In contrast, Moodle 1.5 does away with the constructor and instead requires you to define an init() method that takes no arguments:&lt;br /&gt;
 &lt;br /&gt;
     function init() {&lt;br /&gt;
         $this-&amp;gt;title = get_string(&#039;blockname&#039;,&#039;block_online_users&#039;);&lt;br /&gt;
         $this-&amp;gt;version = 2004111600;&lt;br /&gt;
     }&lt;br /&gt;
Of course, this leaves you without access to the $course object, which you might actually need. Since that&#039;s probably going to be needed inside [[Blocks_Howto#method_get_content| get_content]], the way to retrieve it is by using this code:&lt;br /&gt;
 &lt;br /&gt;
     $course = get_record(&#039;course&#039;, &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;pageid);&lt;br /&gt;
If you are going to need access to $course from inside other methods in addition to [[Blocks_Howto#method_get_content| get_content]], you might fetch the $course object inside the [[Blocks_Howto#method_specialization| specialization]] method and save it as a class variable for later use, in order to avoid executing the same query multiple times:&lt;br /&gt;
 &lt;br /&gt;
     function specialization() {&lt;br /&gt;
         $this-&amp;gt;course = get_record(&#039;course&#039;, &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;pageid);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
=== Blocks with configuration ===&lt;br /&gt;
In Moodle 1.4, blocks could only have what are now (in Moodle 1.5) called &amp;quot;global configuration&amp;quot; options, to differentiate from the new &amp;quot;instance configuration&amp;quot; options. If your block has support for configuration, you will need to take these steps:&lt;br /&gt;
## Rename your &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config.html&amp;lt;/span&amp;gt; file to &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config_global.html&amp;lt;/span&amp;gt;.&lt;br /&gt;
## Edit the newly renamed file and completely remove the &amp;lt;form&amp;gt; tag (Moodle now wraps your configuration in a form automatically).&lt;br /&gt;
## If you are using any HTML &amp;lt;input&amp;gt; tags other than those that directly affect your configuration (for example, &amp;quot;sesskey&amp;quot;), REMOVE those too (Moodle will add them automatically as required).&lt;br /&gt;
## If you have overridden &#039;&#039;&#039;print_config&#039;&#039;&#039;, rename your method to &#039;&#039;&#039;config_print&#039;&#039;&#039;.&lt;br /&gt;
## If you have overridden &#039;&#039;&#039;handle_config&#039;&#039;&#039;, rename your method to &#039;&#039;&#039;config_save&#039;&#039;&#039;.&lt;br /&gt;
=== Blocks with customized applicable formats ===&lt;br /&gt;
The correct way to specify the formats you want to allow or disallow your block to exist has been reworked for Moodle 1.5 to take account of the fact that blocks are no longer restricted to just courses. To have a block retain its intended behavior, you must change these format names (array keys in the return value of [[Blocks_Howto#method_applicable_formats| applicable_formats]]) if they are used in your block:&lt;br /&gt;
#* &#039;&#039;&#039;social&#039;&#039;&#039; should become &#039;&#039;&#039;course-view-social&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;topics&#039;&#039;&#039; should become &#039;&#039;&#039;course-view-topics&#039;&#039;&#039;&lt;br /&gt;
#* &#039;&#039;&#039;weeks&#039;&#039;&#039; should become &#039;&#039;&#039;course-view-weeks&#039;&#039;&#039;&lt;br /&gt;
You should also keep in mind that there is now the possibility of blocks being displayed in other pages too, like the introductory page that users see when they enter an activity module. You might therefore need to make the specification for applicable formats more restrictive to keep your block out of pages it is not supposed to be shown in. Also, there are subtle changes to the way that the final decision to allow or disallow a block is made. For the technical details refer to the definition of [[Blocks_Howto#method_applicable_formats| applicable_formats]], and for a more extended example read [[Blocks_Howto#section_authorized_personnel_only| the section dedicated to this subject]].&lt;br /&gt;
That&#039;s everything; your block will now be ready for use in Moodle 1.5!&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Question_type_plugin_how_to&amp;diff=5053</id>
		<title>Development:Question type plugin how to</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Question_type_plugin_how_to&amp;diff=5053"/>
		<updated>2006-02-08T19:46:45Z</updated>

		<summary type="html">&lt;p&gt;Gustav: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}&lt;br /&gt;
There is no Guide yet. The code is the only documentation. The quickest way we are going to get a Guide is if everyone who gains some experience with the questiontypes shares this experience here as they go along. After a while we will be able to assemble the combined wisdom into a guide.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4986</id>
		<title>Development:Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4986"/>
		<updated>2006-02-08T00:34:16Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Code documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module with its own modular structure to allow question type plug-ins. The module has grown organically and in spite of a lot of rewriting for Moodle 1.5 the code is not very simple to understand. This page aims to collect useful documentation on how the module works. &lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the quiz module there are certain terms that can cause confusion because they can be used with different meanings. In Moodle we have adopted a certain terminology that will be explained below.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;question&#039;&#039;&#039; in the context of the quiz module is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it is much more than what one would in everyday language understand under a question and which in Moodle is just on field (the questiontext field) of the question object.&lt;br /&gt;
&lt;br /&gt;
What in Moodle we refer to as a &#039;question&#039; is what in the terminology of the QTI specification ismore appropriately called an &#039;&#039;&#039;assessment item&#039;&#039;&#039; or just &#039;item&#039; for short. &lt;br /&gt;
&lt;br /&gt;
There are different types of questions, like for example multiple-choice questions or numerical questions. These are referred to as &#039;&#039;&#039;[[Quiz developer docs#Question types|question types]]&#039;&#039;&#039; in Moodle.&lt;br /&gt;
&lt;br /&gt;
Since version 1.5 Moodle is able to handle so-called &#039;&#039;&#039;[[Adaptive questions]]&#039;&#039;&#039;, also known as &#039;adaptive items&#039; in QTI speak. These are qustions that walk the user through a directed graph of question states depending on the user&#039;s responses. For example a complicated mathematical question that is answered incorrectly, but is likely to be incorrect because of a common mistake, could provide the user with a hint towards this mistake, apply a penalty and allow a second attempt at this question. Quizzes can be run in &#039;adaptive mode&#039;, which provides buttons to mark each question individually.&lt;br /&gt;
&lt;br /&gt;
===Answers===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;answer&#039;&#039;&#039;&#039; is used exclusively for the &#039;&#039;&#039;teacher-defined answers&#039;&#039;&#039; of a question. When talking about the quiz module it is easy to get confused between these teacher-defined answers and the answers that the students actually give. We have therefore adopted the convention to refer to the student-supplied answers as &#039;responses&#039; and to reserve the term &#039;answers&#039; to apply to teacher-defined answers. In question types that rely on teacher-supplied answers these are used in the grading process by comparing them with the student responses. Of course not all question types use teacher-defined answers but use some more intelligent way to process the student responses. &lt;br /&gt;
&lt;br /&gt;
Perhaps one should also stress that &#039;answer&#039; is not always used in the sense of &#039;correct answer&#039;. For example every choice in a multiple-choice question is referred to as an answer. Other systems use the term &#039;distractor&#039; for wrong answers. &lt;br /&gt;
&lt;br /&gt;
In Moodle we always use the term &#039;&#039;&#039;&#039;responses&#039;&#039;&#039;&#039; to refer to the students&#039; responses to a question because term &#039;answers&#039; that one might also be tempted to use for this is already used to refer to the teacher-defined answers, see above. This term is always used in plural, although for some questiontypes there is only one possible response.&lt;br /&gt;
&lt;br /&gt;
There is unfortunately, for historical reasons, one exception to the above rule: The [[Quiz database structure#quiz_states|quiz_states table]] has a field &#039;answer&#039; whose purpose it actually is to hold the student&#039;s responses.&lt;br /&gt;
&lt;br /&gt;
===Attempts===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;attempt&#039;&#039;&#039;&#039; is used in the sense of &amp;quot;Attempt at the quiz&amp;quot;. Depending on the quiz settings, a student may be allowed several attempts at a quiz. An attempt is finished when the student clicks on the corresponding button on the attempt page. Students do not have to complete an attempt in one visit. They can navigate away from the quiz page and return later to continue the same attempt.&lt;br /&gt;
&lt;br /&gt;
Within one and the same quiz attempt a student may make several attempts at answering a particular question, at least if the questiontype allows it and the quiz is set up in adaptive mode. These will always be referred to as &#039;&#039;&#039;&#039;attempts at a question&#039;&#039;&#039;&#039;, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
Because a student can have several attempts at a question within the same attempt at the quiz, there is a lot of data that needs to be stored as the student takes the question through several &#039;&#039;&#039;&#039;states&#039;&#039;&#039;&#039; by repeated interactions with the question. A state object holds the most recent state of the question and whenever a student submits a response or a similar &#039;&#039;&#039;&#039;event&#039;&#039;&#039;&#039; occurs, the question goes to a new state. The complete history of question states that the question is taken through is saved and this is referred to as the question &#039;&#039;&#039;&#039;session&#039;&#039;&#039;&#039;. Usually only the most recent state and the last graded state are of interest though.&lt;br /&gt;
&lt;br /&gt;
==Code documentation==&lt;br /&gt;
&lt;br /&gt;
The code is documented according to phpdoc conventions. The explanations here in the wiki are meant to complement this.&lt;br /&gt;
&lt;br /&gt;
Inline comments should be used liberally in the code. The following conventions make it easier to search for comments with special meaning:&lt;br /&gt;
* use TODO in comments about things that need to be done&lt;br /&gt;
* use ??? in comments that are questions about the code&lt;br /&gt;
&lt;br /&gt;
There are three function libraries:&lt;br /&gt;
&lt;br /&gt;
;questionlib.php&lt;br /&gt;
:All functions that need to be available to any module wanting to use questions. This is New in Moodle 1.6, in Moodle 1.5 this was part of locallib.php. This instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core. This loads constants from &#039;&#039;&#039;constants.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;locallib.php&lt;br /&gt;
:All functions that are used only by the quiz module. This loads lib.php and questionlib.php&lt;br /&gt;
&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;questiontypes/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in locallib.php). The individual questiontypes extend this class in their own questiontype.php file. For documentation of the questiontype classes one should often look at the documentation of the default question type because much of the documentation that is in the default class is not repeated in the other questiontype classes&lt;br /&gt;
&lt;br /&gt;
Constants are defined in &#039;&#039;&#039;constants.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
While questiontypes are realized as classes, the quiz module is not written in a truly object-oriented way. Instead it follows the Moodle model of using objects mostly only as alternatives to arrays to hold database records. So none of the quiz, question, attempt, and state objects that play a central role in the module have any methods. Only the questiontype objects have methods. Strangely enough the quiz module instantiates on object of each questiontype class at the start and then reuses their methods for the different questions. If one is used to the Moodle way of programming then this is easy enough to handle.&lt;br /&gt;
&lt;br /&gt;
==Objects and data structures==&lt;br /&gt;
&lt;br /&gt;
Key to understanding how the quiz module works is to understand the different kinds of object work together. The most important ones are:&lt;br /&gt;
&lt;br /&gt;
*Quizzes&lt;br /&gt;
*Questions&lt;br /&gt;
*Attempts&lt;br /&gt;
*States&lt;br /&gt;
&lt;br /&gt;
Quizzes and Questions are data created by the teacher when setting up and editing a quiz. Attempts and States are data created by the student when interacting with a quiz. &lt;br /&gt;
&lt;br /&gt;
Moodle allows students to make several attempts at a quiz. Data about such an attempt is stored in an attempt object. This holds for example how the quiz was randomized for this attempt and the ordering of the questions and answers. So attempts are indexed by user id and quiz id.&lt;br /&gt;
&lt;br /&gt;
Moodle allows students to interact repeatedly with a single question. So for example the student might initially just save an answer, later mark it, then correct it if it was marked incorrect. Each time the student interacts with a particular question inside a particular attempt at a quiz a new state is created. So states are indexed by user id, attempt id and question id.&lt;br /&gt;
&lt;br /&gt;
===Database structure===&lt;br /&gt;
All this data needs to be kept in Moodle&#039;s database. How this is achieved is explained on a separate page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;, which also contains a useful diagram.&lt;br /&gt;
&lt;br /&gt;
As is customary in Moodle, most runtime objects simply represent the data from a particular database record. So for example a $quiz object has fields corresponding to all the fields in the [[Quiz database structure#quiz|quiz table]]. In some cases the objects have some additional fields that are added at runtime. This is particularly the case for $question and $state objects. These additional fields are also described on the page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;. Many functions that are used to process these objects make use of the additional fields and it is therefore necessary to use the correct functions for creating these objects.&lt;br /&gt;
&lt;br /&gt;
===Runtime objects===&lt;br /&gt;
Some objects used by the quiz module are purely runtime object and do not correspond to a database table. The structure of these objects is explained in detail on a separate page about the &#039;&#039;&#039;[[Quiz runtime objects]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The main script of the quiz module is attempt.php which will have to deal with all these objects. Studying the &#039;&#039;&#039;[[Quiz attempt|explanation of attempt.php]]&#039;&#039;&#039; is therefore a good way to start to study the quiz module code.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The student&#039;s responses to a question are stored in &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt;. Questiontypes are completely free to implement the storage mechanism of their responses (and other state information) the way they want. Still, the standard questiontypes all follow a similar model. The default storage model and the questiontype specific variations are explained below.&lt;br /&gt;
&lt;br /&gt;
The flexibility for the questiontypes to choose their response storage mechanism freely and to convert from the storage model to the runtime model is provided by a set of three functions, which allow to initialise the runtime &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field, to convert from the runtime to the storage model and vice versa:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;create_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Initializes the $state object, in particular the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Loads the question type specific session data from the database into the &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; object, in particular it loads the responses that have been saved for the given &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; into the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Saves the question type specific session data from the $state object to the database. In particular, for most questiontypes, it saves the responses from the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; to the database.&lt;br /&gt;
&lt;br /&gt;
The generic quiz module code saves the contents form the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; field to the answer field in the [[Quiz database structure#quiz_states|quiz_states table]] and also automatically restores the contents of this field to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This means that any questiontype, which only expects a single value as its response can skip the implementation of the three methods described above. All questiontypes that have multiple value responses need to implement these methods. &lt;br /&gt;
&lt;br /&gt;
The default questiontypes handle this problem by serializing/de-serializing the responses to/from the answer field in the quiz_states table. However, it is also possible (and may be better practice) to extend the quiz_states table with a questiontype specific table, i.e. take the id of the quiz_states record as a foreign key in the questiontype specific table. Because the value of &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is set to the value of the answer field, questiontypes that serialize their response need to overwrite (in &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;) whatever value the generic code set this field to with their serialized value (usually achieved with a simple set_field). &lt;br /&gt;
&lt;br /&gt;
In the method &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; the serialized value can be read from &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; because this is where the value from answer field of the quiz_states table has been moved. Care needs to be taken that this array value is then unset or the whole array overwritten, so that the array does not accidentally contain a value with the empty string index.&lt;br /&gt;
&lt;br /&gt;
==Response processing==&lt;br /&gt;
&lt;br /&gt;
The runtime model for responses dictates the structure of the $state-&amp;gt;responses array. Starting with the names of the form elements this section goes through the relevant processing steps and thus attempts to clarify why the keys of the $state-&amp;gt;responses array can differ for different questiontypes; even more, it explains how the array keys are chosen and set.&lt;br /&gt;
&lt;br /&gt;
Although it may initially seem strange to start with the naming convention of the form fields, the reason for this will become clear later on. The controls (i.e. the form fields) of a question get printed by the method &amp;lt;code&amp;gt;print_question_formulation_and_controls()&amp;lt;/code&amp;gt;. The convention only dictates that the name of the control element(s) must begin with the value of &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt; is a string starting with &amp;quot;resp&amp;quot; followed by the question id and an underscore, e.g. &amp;lt;code&amp;gt;resp56_&amp;lt;/code&amp;gt;. In the default case, when there is only a single control element (this includes the case of a list of equally named radio buttons), no postfix is appended to the name prefix. For questiontypes that allow or require multiple form elements, an arbitrary string can be appended to the name prefix to form the name of these form elements. The postfix must not include any relational data (i.e. ids of records in the quiz_answers table), because this can lead to problems with regrading of versioned questions.&lt;br /&gt;
&lt;br /&gt;
After the printing of the question the server only sees it again when it is submitted. So the submitted data will contain several values indexed by strings starting with &amp;lt;code&amp;gt;respXX_&amp;lt;/code&amp;gt;. Upon submission, the function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; is called, which assigns the submitted responses to the state of the question with id XX, using the postfix (i.e. everything after the underscore) as array keys. In the default case with only one control element the name only consists of the name prefix. This explains why the default index of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array is the empty string. The value of each array element is obviously the value that was submitted by the form, basically a raw response.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; in turn calls the questiontype specific method &amp;lt;code&amp;gt;grade_responses()&amp;lt;/code&amp;gt; to assign a grade to the submitted responses and &amp;lt;code&amp;gt;compare_responses()&amp;lt;/code&amp;gt; to determine whether the response was identical to the previous submission and to avoid regrading the same responses repeatedly. These questiontype specific functions need to be aware of the expected keys of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
Finally, the methods &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt; also need to know the questiontype specific layout of the &amp;lt;code&amp;gt;$state-&amp;gt;responses array&amp;lt;/code&amp;gt; and restore or save the information, e.g. by converting from or to the data representation.&lt;br /&gt;
&lt;br /&gt;
==Question types==&lt;br /&gt;
{{Questiontype developer docs}}&lt;br /&gt;
The quiz module is itself modular and allows question type plug-ins. For each question type there should be a page, accessible via the menu at the right, which provides at least the dtails about&lt;br /&gt;
*Database tables&lt;br /&gt;
*Response storage&lt;br /&gt;
*Question options object&lt;br /&gt;
*State options object&lt;br /&gt;
&lt;br /&gt;
It is hoped that Moodlers will contribute a lot of non-core question types in the future. For this it would be good to start a [[Guide to question type plugins]].&lt;br /&gt;
&lt;br /&gt;
==Grades==&lt;br /&gt;
&lt;br /&gt;
The handling of grades is a bit complicated because there are so many different grades around that get rescaled and combined in various ways. This section should summarize how this is done and why.&lt;br /&gt;
&lt;br /&gt;
The following grade fields are being used:&lt;br /&gt;
*$question-&amp;gt;defaultgrade&lt;br /&gt;
::This is the default value for the maximum grade for this question. This is set up when the teacher creates the question and it is stored in an int(10) field in the [[Quiz database structure#quiz_questions|quiz_questions]] table. However when the question is actually used in a particular quiz the teacher can overrule this default and this is stored in:&lt;br /&gt;
*$question-&amp;gt;maxgrade&lt;br /&gt;
::This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in an int(10) field in the [[Quiz database structure#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
*$question-&amp;gt;penalty&lt;br /&gt;
&lt;br /&gt;
*$state-&amp;gt;raw_grade&lt;br /&gt;
*$state-&amp;gt;grade&lt;br /&gt;
*$state-&amp;gt;penalty&lt;br /&gt;
*$state-&amp;gt;sumpenalty&lt;br /&gt;
&lt;br /&gt;
*$attempt-&amp;gt;sumgrades&lt;br /&gt;
&lt;br /&gt;
The maximum grades set by the teacher, $question-&amp;gt;defaultgrade and $question-&amp;gt;maxgrade, are integers. All student-obtained grades are in principle floating point numbers. For historical reasons they are stored in the database as varchar(10) fields. Care has to be taken when writing to the database to make sure all grades are correctly rounded and squeezed into a string of no more than 10 characters, otherwise the writing to database will fail, see bug 4220.&lt;br /&gt;
&lt;br /&gt;
The final outcome of the calculation of the grade for a user at a particular quiz is stored in the &#039;grade&#039; field of the [[Quiz database structure#quiz_grades|quiz_grades table]]. This field has type double.&lt;br /&gt;
&lt;br /&gt;
==Penalty mechanism==&lt;br /&gt;
&lt;br /&gt;
===What it is for===&lt;br /&gt;
&lt;br /&gt;
When the quiz is run in adaptive mode the student can interact with a question repeatedly. So in particular the student can try again when he gets a wrong answer. Clearly the final mark for the question must reflect the fact that the student did not get it right originally. Therefore a penalty is subtracted from the final mark.&lt;br /&gt;
&lt;br /&gt;
===How the penalty is determined===&lt;br /&gt;
&lt;br /&gt;
First of all penalties are relevant only if a quiz is run in adaptive mode. Only in this case can a student have a second attempt and therefore only in this mode can there be any occasion to subtract a penalty.&lt;br /&gt;
&lt;br /&gt;
Even in adaptive mode the penalty mechanism is only used when it is selected in the quiz options. If &amp;quot;Apply penalties&amp;quot; is set to &amp;quot;No&amp;quot; then the final mark for the question is the mark for the last graded response.&lt;br /&gt;
&lt;br /&gt;
Each question has a &#039;penalty&#039; field (which should really be called &#039;penaltyfactor&#039;) which is a number between 0 and 1. The penalty for a wrong response is calculated as the product ($quiz-&amp;gt;penalty * $quiz-&amp;gt;grade), i.e., as the product of the penaltyfactor with the maximum achievable grade for the question. This product is stored in $state-&amp;gt;penalty. So $quiz-&amp;gt;penalty is the fraction of the maximum grade that is subtracted as a penalty for each wrong response.&lt;br /&gt;
&lt;br /&gt;
The $quiz-&amp;gt;penalty field has a default value of 0.1, both in the database and in mod/quiz/defaults.php. This default can of course be overwritten by the admin on the quiz configuration page. This admin-selected default is (as usual for admin defaults) stored in $CFG-&amp;gt;quiz_penalty. The teacher can choose a different penalty factor for each individual question when adding or editing a question.&lt;br /&gt;
&lt;br /&gt;
Now if a student makes repeated wrong attempts (or partially correct attempts) the penalties for all these attempts are added up in $state-&amp;gt;sumpenalties. The mark for the question is then calculated as the mark for the last graded response minus the sum of the penalties.&lt;br /&gt;
&lt;br /&gt;
One curious fact about $state-&amp;gt;sumpenalties is that, for efficiency reasons, it is not stored in the quiz_states table but instead in the &#039;sumpenalty&#039; field of the quiz_newest_states table. That way it only has to be stored once per attempt rather than once per response.&lt;br /&gt;
&lt;br /&gt;
===Where it is done in the code===&lt;br /&gt;
&lt;br /&gt;
The function quiz_apply_penalty_and_timelimit() subtracts the penalty in $state-&amp;gt;sumpenalty from the raw grade in $state-&amp;gt;raw_grade to obtain $state-&amp;gt;grade for the response. However it is ensured that the grade of a new attempt at the question never falls below the previously achieved grade. This function also increases $state-&amp;gt;sumpenalty by the amount in $state-&amp;gt;penalty. The assumption is that $state-&amp;gt;penalty has just been set appropriately by the code calling this function, e.g., quiz_process_responses.&lt;br /&gt;
&lt;br /&gt;
==Time limit==&lt;br /&gt;
&lt;br /&gt;
A quiz can have a time limit. This is stored in minutes in $quiz-&amp;gt;timelimit. So before using this in time calculations it always has to be multiplied by 60 to turn it into seconds like all other timestamps in moodle and php. If $quiz-&amp;gt;timelimit is zero it means there is no timelimit.&lt;br /&gt;
&lt;br /&gt;
If a student asks to start an attempt on view.php for a quiz with a timelimit then he is shown a javascript message alerting him to the timelimit and is asked to confirm.&lt;br /&gt;
&lt;br /&gt;
For quizzes with timelimit attempt.php shows a javascript timer that counts down and automatically submits and closes the attempt when the time is up.&lt;br /&gt;
&lt;br /&gt;
Confusingly there are two javascript timers in the quiz module. jsclock.php provides a countdown in the title bar that counts down to the quiz closing time if this is less than a day away. This has nothing to do with the timelimit. jstimer.php provides the countdown timer that implements the timelimit. It in turn uses timer.js.&lt;br /&gt;
&lt;br /&gt;
The time a response was submitted by the student is recorded by attempt.php right at the top of the page and is then passed on to quiz_process_responses in $action-&amp;gt;timestamp. This puts it into $state-&amp;gt;timestamp. Finally, after the responses have been graded, the function quiz_apply_penalty_and_timelimit() checks that the responses are within the timelimit to within 5% and if not it sets the grade to zero (or the previously obtained grade, if that is higher).&lt;br /&gt;
&lt;br /&gt;
==Pagination==&lt;br /&gt;
&lt;br /&gt;
Quiz attempts can be paginated, i.e., spread over several pages. The student can navigate between the pages using the standard Moodle paging bar. When the student navigates to a different quiz page the answers on the current page are automatically submitted for saving (but not grading).&lt;br /&gt;
&lt;br /&gt;
To do this automatic submission the paging bar needs some javascript. It is therefore not produced with Moodle&#039;s standard print_paging_bar() function from weblib.php but with quiz_print_navigation_panel() which is defined in mod/quiz/locallib.php and produces something that looks the same.&lt;br /&gt;
&lt;br /&gt;
The teacher has complete control via the edit interface on edit.php over where the page breaks should occur. He can repaginate the quiz with any chosen number of questions per page. He can also move the page-breaks up and down using the arrows.&lt;br /&gt;
&lt;br /&gt;
Internally page breaks are stored in the $quiz-&amp;gt;questions field (which now should really be called $quiz-&amp;gt;layout). This field contains a comma separated list of questionids and pagebreaks where the pagebreaks are represented by the id 0. For example 23,12,0,11, 0 means that the two questions with ids 23 and 12 are on the first page and the question with id 11 is on the second page. The last page break is invisible and Moodle sometimes puts it there itself for its own convenience.&lt;br /&gt;
&lt;br /&gt;
Because the quiz has an option $quiz-&amp;gt;shufflequestions to shuffle questions the layout that the student sees in a particular attempt does not necessarily have to be the same as that stored in $quiz-&amp;gt;questions. Therefore each attempt has its own $attemp-&amp;gt;layout field. If $quiz-&amp;gt;shufflequestions is false then this just contains a copy of $quiz-&amp;gt;questions but if it is true then during the creation of a new attempt by quiz_create_attempt() the function quiz_repaginate() is used to produce a layout with $quiz-&amp;gt;questionsperpage number of questions per page that are randomly ordered.&lt;br /&gt;
&lt;br /&gt;
Both attempt.php and review.php use the $attempt-&amp;gt;layout field to determine what questions to show on a particular page. That way we can guarantee that the student will, for a particular attempt, always see the questions in the same order and with the same pagination, both while attempting and during review. Also a teacher when reviewing a student&#039;s attempt sees the pages the same way they were shown to the student. However the teacher is also given the option to see all questions on one page.&lt;br /&gt;
&lt;br /&gt;
There are some functions in locallib.php dedicated to handling the layout fields: quiz_questions_on_page(), quiz_questions_in_quiz(), quiz_number_of_pages(), quiz_first_questionnumber(), quiz_repaginate(). They are very short functions. The function quiz_first_questionnumber() that determines the number of the first question on a particular page makes use of the $question-&amp;gt;length field. To allow this calculation to be fast is the main reason why that field is in the question table even though it could also be determined easily from the question type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Question versioning==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Question versioning is currently disabled until it is re-developed to fix all reported issues.&lt;br /&gt;
&lt;br /&gt;
When questions that were already attempted by a student are edited, it can be important to keep a copy of the question as it was before editing in order to reconstruct the quiz as it was seen by the student. To provide this functionality a question versioning mechanism was implemented.&lt;br /&gt;
&lt;br /&gt;
The first goal, namely keeping around old questions, is easily achieved. They are just not deleted any more. However, this is not enough; it is also necessary to store which questions are versions of others. To achieve this goal, there is an additional table, which stores the versioning information: quiz_question_versions.&lt;br /&gt;
&lt;br /&gt;
When a question is replaced for which there are already student attempts then all the attempt data gets associated to the new version of the question and is re-graded. This requires the question ids in the quiz_attempts, quiz_states and quiz_newest_states tables to be replaced by the new id. However we do also want to be able to reconstruct the quiz the way the student saw it when he gave his answers. For that purpose the id of the original question is always preserved in the &#039;originalquestion&#039; field of the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
If all old versions of questions are kept around this could horribly clutter the editing interface. Therefore a field called hidden was added to the quiz_questions table and all old versions of edited questions are automatically hidden. When this flag is set to 1 the question is not displayed in the list of available questions, unless the user chooses to show them.&lt;br /&gt;
&lt;br /&gt;
While the mechanism above should work as described, there is some additional complexity in order to minimise the number of versions created. If a question is created and has not been attempted by a student yet (this excludes teacher previews of the individual question and the quiz!), the database record will be reused (i.e. overwritten) and no new version will be created. This is especially important when the question is created and the first 2 or 3 mistakes are only noticed during preview.&lt;br /&gt;
&lt;br /&gt;
On the editing screen for questions an additional set of options was introduced (see image).&lt;br /&gt;
Replacement Options&lt;br /&gt;
It shows which quizzes use the edited question and how many students have attempted it in a particular quiz. Based on this information it is then possible to choose in which quizzes the new version of the question should be used and in which ones the old one should remain.&lt;br /&gt;
&lt;br /&gt;
By default the &#039;replace&#039; checkbox for all quizzes that don&#039;t have any students&#039; attempts are checked and in addition, if the question is edited out of a quiz context (i.e. not in the category question list), the &#039;replace&#039; option is checked for that quiz as well.&lt;br /&gt;
&lt;br /&gt;
===Database===&lt;br /&gt;
&lt;br /&gt;
The changes to the database structure are limited to an added field (hidden) in the quiz_questions table and an additional table called quiz_question_versions. However, dealing with the quiz_questions table has become slightly more complicated.&lt;br /&gt;
&lt;br /&gt;
The hidden field in the quiz_questions table has no implications for the core functionality. It is only used to determine, as the name implies, whether the question is shown in the category list or not.&lt;br /&gt;
&lt;br /&gt;
The table quiz_question_versions stores information about the actual change. This information includes the ids of the old question and the new question, the id of the user who did the change and a timestamp. Quite importantly, the id of the quiz, in which the question was replaced is also stored. This means that the versions table provides a history of the different states the quiz went through until it was edited to be at the current state. The information allows to recreate a quiz as it was at any point in time (from a data perspective - this possibility is not used extensively by the code).&lt;br /&gt;
&lt;br /&gt;
===Adjustments to the Data===&lt;br /&gt;
&lt;br /&gt;
When a question is replaced by a newer version, database records are updated in the order shown below (compare with question.php):&lt;br /&gt;
&lt;br /&gt;
* First a new record is inserted into the quiz_question_versions table for each affected quiz (i.e. each quiz in which the question was replaced).&lt;br /&gt;
* Then, for each affected quiz, the comma separated list of question ids in the question field is updated by replacing the old question id with the new one.&lt;br /&gt;
* In the quiz_question_instances table the record that links the old question to the quiz is also updated to point to the new question.&lt;br /&gt;
* In all attempts belonging to the old question the comma-separated list of question ids in the layout field are changed by replacing the old id by the new one.&lt;br /&gt;
* All states belonging to the old question are made to belong to the new version by changing the id in the &#039;question&#039; field. However if we are replacing the original question then the id of this original version is stored in the originalquestion field.&lt;br /&gt;
* We have to change the questionid field in quiz_newest_states.&lt;br /&gt;
* Finally we have to do any question-type specific changes. For example question types that store student responses by storing the id of the answer in the quiz_answers table will have to recode these ids in all the states to point to the corresponding answers in the new version. This is handled by the function replace_question_in_attempts() in the question type class.&lt;br /&gt;
&lt;br /&gt;
===Affected Code and Functionality===&lt;br /&gt;
&lt;br /&gt;
Note: This section should still be considered under construction until the question mark behind bug #3311 is taken off.&lt;br /&gt;
&lt;br /&gt;
In the file review.php and potentially also in the file attempt.php, if a question is edited during a student&#039;s attempt, the data from quiz_question_versions needs to be taken into account. If a student has attempted a quiz and a question was changed afterwards (i.e. a new version of that question was created), the question id of the old version remains in the comma separated list inside the attempt-&amp;gt;layout field. However, since the records in the quiz_question_instances table get updated, we need to go forward in the question history, by looping through entries from the quiz_question_versions table, to find out the id of the question version that is currently used in the quiz.&lt;br /&gt;
&lt;br /&gt;
Suggestion: With a fairly simple change to the convention of what is stored in the quiz_question_versions table we could get rid of the requirement of looping through all the versions. If in the newquestion field we store the id of the question that is currently used in the quiz, it would be possible to get the complete history for a question quite simply by selecting by quiz id and newquestion.&lt;br /&gt;
&lt;br /&gt;
It should be fairly simple to write an upgrade script for this change. Additionally, another set_field would need to be added to question.php to change the newquestion field to the new question id. The benefits would be a much simpler handling of the question history, resulting in more efficient code than the current fix for bug #3311 in review.php.&lt;br /&gt;
&lt;br /&gt;
The place where all the versioning actually takes place is question.php. Here the changes described in Adjustments to the Data are carried out.&lt;br /&gt;
&lt;br /&gt;
Obviously the backup and restore scripts also take quiz_question_versions into account, however, they don&#039;t need to be concerned with the ways the data is used.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.5: adaptive questions==&lt;br /&gt;
&lt;br /&gt;
During the first half of 2005 the quiz module code has undergone a considerable rewrite to allow for adaptive questions in which a question session can consist of several sequential student responses. The question can adapt itself to the student answers. For example in response to certain answers the question could provide feedback or hints and then ask the student to answer again or give the student a simpler or related question.&lt;br /&gt;
&lt;br /&gt;
Unfortunately many changes had to be made to the question type methods. This has however resulted in improved efficiency and has made the writing of question types easier. It also allows question types with more powerful features and has fixed some bugs / annoying behaviour. &lt;br /&gt;
&lt;br /&gt;
For details see:&lt;br /&gt;
*[[Quiz rewrite|Quiz module rewrite]]&lt;br /&gt;
*[[Quiz conversion|How to convert existing question types]]&lt;br /&gt;
&lt;br /&gt;
Of course there were countless other changes to the quiz module going from Moodle 1.4 to 1.5, especially to the teacher interface. However in spite of the fact that these changes are a lot more visible they were much less drastic from the point of view of the code. Here is a very incomplete list of changes:&lt;br /&gt;
&lt;br /&gt;
* New quiz results overview page&lt;br /&gt;
* Reform of the quiz edit page: Changes on the quiz edit page are saved straightaway, not only after Save button is pressed.&lt;br /&gt;
* Copying questions: The teacher can create a new question using a previous one as template.&lt;br /&gt;
* Moving questions: The teacher can now move selected questions to a different category.&lt;br /&gt;
* Re-marking after question editing: if a teacher corrects a question that students have already attempted the teacher can request a remark.&lt;br /&gt;
* Teacher preview tab.&lt;br /&gt;
* Detailed teacher control over what students can see during review.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.6: separating questions from quizzes==&lt;br /&gt;
&lt;br /&gt;
The quiz module is not the only activity module in Moodle that uses questions. The lesson does too and potentially questions could be useful in many modules. Therefore we have started to rewrite some  of the quiz module functions and move them from locallib.php to questionlib.php so that eventually they could be moved into a central library and be used by other modules. &lt;br /&gt;
&lt;br /&gt;
Module developers who want to use the &lt;br /&gt;
quiz module questions in their own module should take a look at the simple questiondemo module that you can find in CVS at [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/questiondemo contrib/questiondemo]. The idea is that it will be simpler&lt;br /&gt;
to understand this demonstration module than the code in the quiz module which&lt;br /&gt;
is very complicated due to the many options and features. The interesting code in the questiondemo module is in view.php. There you can see how to&lt;br /&gt;
both render and score questions. This module requires the version of the quiz module from Moodle 1.6dev or later.&lt;br /&gt;
&lt;br /&gt;
The details of the changes are explained on the page [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
==Future plans==&lt;br /&gt;
&lt;br /&gt;
The features below are in no particular order:&lt;br /&gt;
&lt;br /&gt;
* Editing questions: This is about editing questions after students have already attempted them. There needs to be a mechanism to keep the old versions of the question around for auditing purposes.&lt;br /&gt;
* New quiz statistics pages?: These pages should be built by using functions defined by the individual question types.&lt;br /&gt;
* Manual grade override: Teachers should be able to override the automatically calculated grades and should be able to make comments.&lt;br /&gt;
* Off-line questions: The answers to these are handed in off-line in the conventional way (e.g., on paper) and teachers enter marks on Moodle.&lt;br /&gt;
* Batch printing of quiz sheets: We want to be able to hand out question sheets to students so they can start working on the questions before going to the computer.&lt;br /&gt;
* Question preview from question edit page: so the teacher can try the question already before saving the changes.&lt;br /&gt;
* Show table of questions on view.php: gives teachers and students a bit of an overview of the quiz.&lt;br /&gt;
* Extending deadlines for individual students: for example when a student misses a deadline for good reasons.&lt;br /&gt;
* Filtering questions by quiz and by search: More ways to restrict which questions are shown on the quiz editing page.&lt;br /&gt;
* Re-open quizzes for revision: After the due date has passed the quiz could allow practice attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4985</id>
		<title>Development:Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4985"/>
		<updated>2006-02-08T00:32:18Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Reverted edit of Gbrackett, changed back to last version by Gustav&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module with its own modular structure to allow question type plug-ins. The module has grown organically and in spite of a lot of rewriting for Moodle 1.5 the code is not very simple to understand. This page aims to collect useful documentation on how the module works. &lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the quiz module there are certain terms that can cause confusion because they can be used with different meanings. In Moodle we have adopted a certain terminology that will be explained below.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;question&#039;&#039;&#039; in the context of the quiz module is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it is much more than what one would in everyday language understand under a question and which in Moodle is just on field (the questiontext field) of the question object.&lt;br /&gt;
&lt;br /&gt;
What in Moodle we refer to as a &#039;question&#039; is what in the terminology of the QTI specification ismore appropriately called an &#039;&#039;&#039;assessment item&#039;&#039;&#039; or just &#039;item&#039; for short. &lt;br /&gt;
&lt;br /&gt;
There are different types of questions, like for example multiple-choice questions or numerical questions. These are referred to as &#039;&#039;&#039;[[Quiz developer docs#Question types|question types]]&#039;&#039;&#039; in Moodle.&lt;br /&gt;
&lt;br /&gt;
Since version 1.5 Moodle is able to handle so-called &#039;&#039;&#039;[[Adaptive questions]]&#039;&#039;&#039;, also known as &#039;adaptive items&#039; in QTI speak. These are qustions that walk the user through a directed graph of question states depending on the user&#039;s responses. For example a complicated mathematical question that is answered incorrectly, but is likely to be incorrect because of a common mistake, could provide the user with a hint towards this mistake, apply a penalty and allow a second attempt at this question. Quizzes can be run in &#039;adaptive mode&#039;, which provides buttons to mark each question individually.&lt;br /&gt;
&lt;br /&gt;
===Answers===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;answer&#039;&#039;&#039;&#039; is used exclusively for the &#039;&#039;&#039;teacher-defined answers&#039;&#039;&#039; of a question. When talking about the quiz module it is easy to get confused between these teacher-defined answers and the answers that the students actually give. We have therefore adopted the convention to refer to the student-supplied answers as &#039;responses&#039; and to reserve the term &#039;answers&#039; to apply to teacher-defined answers. In question types that rely on teacher-supplied answers these are used in the grading process by comparing them with the student responses. Of course not all question types use teacher-defined answers but use some more intelligent way to process the student responses. &lt;br /&gt;
&lt;br /&gt;
Perhaps one should also stress that &#039;answer&#039; is not always used in the sense of &#039;correct answer&#039;. For example every choice in a multiple-choice question is referred to as an answer. Other systems use the term &#039;distractor&#039; for wrong answers. &lt;br /&gt;
&lt;br /&gt;
In Moodle we always use the term &#039;&#039;&#039;&#039;responses&#039;&#039;&#039;&#039; to refer to the students&#039; responses to a question because term &#039;answers&#039; that one might also be tempted to use for this is already used to refer to the teacher-defined answers, see above. This term is always used in plural, although for some questiontypes there is only one possible response.&lt;br /&gt;
&lt;br /&gt;
There is unfortunately, for historical reasons, one exception to the above rule: The [[Quiz database structure#quiz_states|quiz_states table]] has a field &#039;answer&#039; whose purpose it actually is to hold the student&#039;s responses.&lt;br /&gt;
&lt;br /&gt;
===Attempts===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;attempt&#039;&#039;&#039;&#039; is used in the sense of &amp;quot;Attempt at the quiz&amp;quot;. Depending on the quiz settings, a student may be allowed several attempts at a quiz. An attempt is finished when the student clicks on the corresponding button on the attempt page. Students do not have to complete an attempt in one visit. They can navigate away from the quiz page and return later to continue the same attempt.&lt;br /&gt;
&lt;br /&gt;
Within one and the same quiz attempt a student may make several attempts at answering a particular question, at least if the questiontype allows it and the quiz is set up in adaptive mode. These will always be referred to as &#039;&#039;&#039;&#039;attempts at a question&#039;&#039;&#039;&#039;, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
Because a student can have several attempts at a question within the same attempt at the quiz, there is a lot of data that needs to be stored as the student takes the question through several &#039;&#039;&#039;&#039;states&#039;&#039;&#039;&#039; by repeated interactions with the question. A state object holds the most recent state of the question and whenever a student submits a response or a similar &#039;&#039;&#039;&#039;event&#039;&#039;&#039;&#039; occurs, the question goes to a new state. The complete history of question states that the question is taken through is saved and this is referred to as the question &#039;&#039;&#039;&#039;session&#039;&#039;&#039;&#039;. Usually only the most recent state and the last graded state are of interest though.&lt;br /&gt;
&lt;br /&gt;
==Code documentation==&lt;br /&gt;
&lt;br /&gt;
The code is documented according to phpdoc conventions. The explanations here in the wiki are meant to complement this.&lt;br /&gt;
&lt;br /&gt;
Inline comments should be used liberally in the code. The following conventions make it easier to search for comments with special meaning:&lt;br /&gt;
* use TODO in comments about things that need to be done&lt;br /&gt;
* use ??? in comments that are questions about the code&lt;br /&gt;
&lt;br /&gt;
There are three function libraries:&lt;br /&gt;
&lt;br /&gt;
;questionlib.php&lt;br /&gt;
:All functions that need to be available to any module wanting to use questions. This is New in Moodle 1.6, in Moodle 1.5 this was part of locallib.php. This instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core. This loads constants from &#039;&#039;&#039;constants.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;locallib.php&lt;br /&gt;
:All functions that are used only by the quiz module. This loads lib.php and questionlib.php&lt;br /&gt;
&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;questiontypes/questiontype.php&#039;&#039;&#039;. The individual questiontypes extend this class in their own questiontype.php file. For documentation of the questiontype classes one should often look at the documentation of the default question type because much of the documentation that is in the default class is not repeated in the other questiontype classes&lt;br /&gt;
&lt;br /&gt;
Constants are defined in .&lt;br /&gt;
&lt;br /&gt;
While questiontypes are realized as classes, the quiz module is not written in a truly object-oriented way. Instead it follows the Moodle model of using objects mostly only as alternatives to arrays to hold database records. So none of the quiz, question, attempt, and state objects that play a central role in the module have any methods. Only the questiontype objects have methods. Strangely enough the quiz module instantiates on object of each questiontype class at the start and then reuses their methods for the different questions. If one is used to the Moodle way of programming then this is easy enough to handle.&lt;br /&gt;
&lt;br /&gt;
==Objects and data structures==&lt;br /&gt;
&lt;br /&gt;
Key to understanding how the quiz module works is to understand the different kinds of object work together. The most important ones are:&lt;br /&gt;
&lt;br /&gt;
*Quizzes&lt;br /&gt;
*Questions&lt;br /&gt;
*Attempts&lt;br /&gt;
*States&lt;br /&gt;
&lt;br /&gt;
Quizzes and Questions are data created by the teacher when setting up and editing a quiz. Attempts and States are data created by the student when interacting with a quiz. &lt;br /&gt;
&lt;br /&gt;
Moodle allows students to make several attempts at a quiz. Data about such an attempt is stored in an attempt object. This holds for example how the quiz was randomized for this attempt and the ordering of the questions and answers. So attempts are indexed by user id and quiz id.&lt;br /&gt;
&lt;br /&gt;
Moodle allows students to interact repeatedly with a single question. So for example the student might initially just save an answer, later mark it, then correct it if it was marked incorrect. Each time the student interacts with a particular question inside a particular attempt at a quiz a new state is created. So states are indexed by user id, attempt id and question id.&lt;br /&gt;
&lt;br /&gt;
===Database structure===&lt;br /&gt;
All this data needs to be kept in Moodle&#039;s database. How this is achieved is explained on a separate page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;, which also contains a useful diagram.&lt;br /&gt;
&lt;br /&gt;
As is customary in Moodle, most runtime objects simply represent the data from a particular database record. So for example a $quiz object has fields corresponding to all the fields in the [[Quiz database structure#quiz|quiz table]]. In some cases the objects have some additional fields that are added at runtime. This is particularly the case for $question and $state objects. These additional fields are also described on the page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;. Many functions that are used to process these objects make use of the additional fields and it is therefore necessary to use the correct functions for creating these objects.&lt;br /&gt;
&lt;br /&gt;
===Runtime objects===&lt;br /&gt;
Some objects used by the quiz module are purely runtime object and do not correspond to a database table. The structure of these objects is explained in detail on a separate page about the &#039;&#039;&#039;[[Quiz runtime objects]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The main script of the quiz module is attempt.php which will have to deal with all these objects. Studying the &#039;&#039;&#039;[[Quiz attempt|explanation of attempt.php]]&#039;&#039;&#039; is therefore a good way to start to study the quiz module code.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The student&#039;s responses to a question are stored in &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt;. Questiontypes are completely free to implement the storage mechanism of their responses (and other state information) the way they want. Still, the standard questiontypes all follow a similar model. The default storage model and the questiontype specific variations are explained below.&lt;br /&gt;
&lt;br /&gt;
The flexibility for the questiontypes to choose their response storage mechanism freely and to convert from the storage model to the runtime model is provided by a set of three functions, which allow to initialise the runtime &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field, to convert from the runtime to the storage model and vice versa:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;create_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Initializes the $state object, in particular the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Loads the question type specific session data from the database into the &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; object, in particular it loads the responses that have been saved for the given &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; into the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Saves the question type specific session data from the $state object to the database. In particular, for most questiontypes, it saves the responses from the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; to the database.&lt;br /&gt;
&lt;br /&gt;
The generic quiz module code saves the contents form the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; field to the answer field in the [[Quiz database structure#quiz_states|quiz_states table]] and also automatically restores the contents of this field to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This means that any questiontype, which only expects a single value as its response can skip the implementation of the three methods described above. All questiontypes that have multiple value responses need to implement these methods. &lt;br /&gt;
&lt;br /&gt;
The default questiontypes handle this problem by serializing/de-serializing the responses to/from the answer field in the quiz_states table. However, it is also possible (and may be better practice) to extend the quiz_states table with a questiontype specific table, i.e. take the id of the quiz_states record as a foreign key in the questiontype specific table. Because the value of &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is set to the value of the answer field, questiontypes that serialize their response need to overwrite (in &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;) whatever value the generic code set this field to with their serialized value (usually achieved with a simple set_field). &lt;br /&gt;
&lt;br /&gt;
In the method &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; the serialized value can be read from &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; because this is where the value from answer field of the quiz_states table has been moved. Care needs to be taken that this array value is then unset or the whole array overwritten, so that the array does not accidentally contain a value with the empty string index.&lt;br /&gt;
&lt;br /&gt;
==Response processing==&lt;br /&gt;
&lt;br /&gt;
The runtime model for responses dictates the structure of the $state-&amp;gt;responses array. Starting with the names of the form elements this section goes through the relevant processing steps and thus attempts to clarify why the keys of the $state-&amp;gt;responses array can differ for different questiontypes; even more, it explains how the array keys are chosen and set.&lt;br /&gt;
&lt;br /&gt;
Although it may initially seem strange to start with the naming convention of the form fields, the reason for this will become clear later on. The controls (i.e. the form fields) of a question get printed by the method &amp;lt;code&amp;gt;print_question_formulation_and_controls()&amp;lt;/code&amp;gt;. The convention only dictates that the name of the control element(s) must begin with the value of &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt; is a string starting with &amp;quot;resp&amp;quot; followed by the question id and an underscore, e.g. &amp;lt;code&amp;gt;resp56_&amp;lt;/code&amp;gt;. In the default case, when there is only a single control element (this includes the case of a list of equally named radio buttons), no postfix is appended to the name prefix. For questiontypes that allow or require multiple form elements, an arbitrary string can be appended to the name prefix to form the name of these form elements. The postfix must not include any relational data (i.e. ids of records in the quiz_answers table), because this can lead to problems with regrading of versioned questions.&lt;br /&gt;
&lt;br /&gt;
After the printing of the question the server only sees it again when it is submitted. So the submitted data will contain several values indexed by strings starting with &amp;lt;code&amp;gt;respXX_&amp;lt;/code&amp;gt;. Upon submission, the function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; is called, which assigns the submitted responses to the state of the question with id XX, using the postfix (i.e. everything after the underscore) as array keys. In the default case with only one control element the name only consists of the name prefix. This explains why the default index of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array is the empty string. The value of each array element is obviously the value that was submitted by the form, basically a raw response.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; in turn calls the questiontype specific method &amp;lt;code&amp;gt;grade_responses()&amp;lt;/code&amp;gt; to assign a grade to the submitted responses and &amp;lt;code&amp;gt;compare_responses()&amp;lt;/code&amp;gt; to determine whether the response was identical to the previous submission and to avoid regrading the same responses repeatedly. These questiontype specific functions need to be aware of the expected keys of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
Finally, the methods &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt; also need to know the questiontype specific layout of the &amp;lt;code&amp;gt;$state-&amp;gt;responses array&amp;lt;/code&amp;gt; and restore or save the information, e.g. by converting from or to the data representation.&lt;br /&gt;
&lt;br /&gt;
==Question types==&lt;br /&gt;
{{Questiontype developer docs}}&lt;br /&gt;
The quiz module is itself modular and allows question type plug-ins. For each question type there should be a page, accessible via the menu at the right, which provides at least the dtails about&lt;br /&gt;
*Database tables&lt;br /&gt;
*Response storage&lt;br /&gt;
*Question options object&lt;br /&gt;
*State options object&lt;br /&gt;
&lt;br /&gt;
It is hoped that Moodlers will contribute a lot of non-core question types in the future. For this it would be good to start a [[Guide to question type plugins]].&lt;br /&gt;
&lt;br /&gt;
==Grades==&lt;br /&gt;
&lt;br /&gt;
The handling of grades is a bit complicated because there are so many different grades around that get rescaled and combined in various ways. This section should summarize how this is done and why.&lt;br /&gt;
&lt;br /&gt;
The following grade fields are being used:&lt;br /&gt;
*$question-&amp;gt;defaultgrade&lt;br /&gt;
::This is the default value for the maximum grade for this question. This is set up when the teacher creates the question and it is stored in an int(10) field in the [[Quiz database structure#quiz_questions|quiz_questions]] table. However when the question is actually used in a particular quiz the teacher can overrule this default and this is stored in:&lt;br /&gt;
*$question-&amp;gt;maxgrade&lt;br /&gt;
::This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in an int(10) field in the [[Quiz database structure#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
*$question-&amp;gt;penalty&lt;br /&gt;
&lt;br /&gt;
*$state-&amp;gt;raw_grade&lt;br /&gt;
*$state-&amp;gt;grade&lt;br /&gt;
*$state-&amp;gt;penalty&lt;br /&gt;
*$state-&amp;gt;sumpenalty&lt;br /&gt;
&lt;br /&gt;
*$attempt-&amp;gt;sumgrades&lt;br /&gt;
&lt;br /&gt;
The maximum grades set by the teacher, $question-&amp;gt;defaultgrade and $question-&amp;gt;maxgrade, are integers. All student-obtained grades are in principle floating point numbers. For historical reasons they are stored in the database as varchar(10) fields. Care has to be taken when writing to the database to make sure all grades are correctly rounded and squeezed into a string of no more than 10 characters, otherwise the writing to database will fail, see bug 4220.&lt;br /&gt;
&lt;br /&gt;
The final outcome of the calculation of the grade for a user at a particular quiz is stored in the &#039;grade&#039; field of the [[Quiz database structure#quiz_grades|quiz_grades table]]. This field has type double.&lt;br /&gt;
&lt;br /&gt;
==Penalty mechanism==&lt;br /&gt;
&lt;br /&gt;
===What it is for===&lt;br /&gt;
&lt;br /&gt;
When the quiz is run in adaptive mode the student can interact with a question repeatedly. So in particular the student can try again when he gets a wrong answer. Clearly the final mark for the question must reflect the fact that the student did not get it right originally. Therefore a penalty is subtracted from the final mark.&lt;br /&gt;
&lt;br /&gt;
===How the penalty is determined===&lt;br /&gt;
&lt;br /&gt;
First of all penalties are relevant only if a quiz is run in adaptive mode. Only in this case can a student have a second attempt and therefore only in this mode can there be any occasion to subtract a penalty.&lt;br /&gt;
&lt;br /&gt;
Even in adaptive mode the penalty mechanism is only used when it is selected in the quiz options. If &amp;quot;Apply penalties&amp;quot; is set to &amp;quot;No&amp;quot; then the final mark for the question is the mark for the last graded response.&lt;br /&gt;
&lt;br /&gt;
Each question has a &#039;penalty&#039; field (which should really be called &#039;penaltyfactor&#039;) which is a number between 0 and 1. The penalty for a wrong response is calculated as the product ($quiz-&amp;gt;penalty * $quiz-&amp;gt;grade), i.e., as the product of the penaltyfactor with the maximum achievable grade for the question. This product is stored in $state-&amp;gt;penalty. So $quiz-&amp;gt;penalty is the fraction of the maximum grade that is subtracted as a penalty for each wrong response.&lt;br /&gt;
&lt;br /&gt;
The $quiz-&amp;gt;penalty field has a default value of 0.1, both in the database and in mod/quiz/defaults.php. This default can of course be overwritten by the admin on the quiz configuration page. This admin-selected default is (as usual for admin defaults) stored in $CFG-&amp;gt;quiz_penalty. The teacher can choose a different penalty factor for each individual question when adding or editing a question.&lt;br /&gt;
&lt;br /&gt;
Now if a student makes repeated wrong attempts (or partially correct attempts) the penalties for all these attempts are added up in $state-&amp;gt;sumpenalties. The mark for the question is then calculated as the mark for the last graded response minus the sum of the penalties.&lt;br /&gt;
&lt;br /&gt;
One curious fact about $state-&amp;gt;sumpenalties is that, for efficiency reasons, it is not stored in the quiz_states table but instead in the &#039;sumpenalty&#039; field of the quiz_newest_states table. That way it only has to be stored once per attempt rather than once per response.&lt;br /&gt;
&lt;br /&gt;
===Where it is done in the code===&lt;br /&gt;
&lt;br /&gt;
The function quiz_apply_penalty_and_timelimit() subtracts the penalty in $state-&amp;gt;sumpenalty from the raw grade in $state-&amp;gt;raw_grade to obtain $state-&amp;gt;grade for the response. However it is ensured that the grade of a new attempt at the question never falls below the previously achieved grade. This function also increases $state-&amp;gt;sumpenalty by the amount in $state-&amp;gt;penalty. The assumption is that $state-&amp;gt;penalty has just been set appropriately by the code calling this function, e.g., quiz_process_responses.&lt;br /&gt;
&lt;br /&gt;
==Time limit==&lt;br /&gt;
&lt;br /&gt;
A quiz can have a time limit. This is stored in minutes in $quiz-&amp;gt;timelimit. So before using this in time calculations it always has to be multiplied by 60 to turn it into seconds like all other timestamps in moodle and php. If $quiz-&amp;gt;timelimit is zero it means there is no timelimit.&lt;br /&gt;
&lt;br /&gt;
If a student asks to start an attempt on view.php for a quiz with a timelimit then he is shown a javascript message alerting him to the timelimit and is asked to confirm.&lt;br /&gt;
&lt;br /&gt;
For quizzes with timelimit attempt.php shows a javascript timer that counts down and automatically submits and closes the attempt when the time is up.&lt;br /&gt;
&lt;br /&gt;
Confusingly there are two javascript timers in the quiz module. jsclock.php provides a countdown in the title bar that counts down to the quiz closing time if this is less than a day away. This has nothing to do with the timelimit. jstimer.php provides the countdown timer that implements the timelimit. It in turn uses timer.js.&lt;br /&gt;
&lt;br /&gt;
The time a response was submitted by the student is recorded by attempt.php right at the top of the page and is then passed on to quiz_process_responses in $action-&amp;gt;timestamp. This puts it into $state-&amp;gt;timestamp. Finally, after the responses have been graded, the function quiz_apply_penalty_and_timelimit() checks that the responses are within the timelimit to within 5% and if not it sets the grade to zero (or the previously obtained grade, if that is higher).&lt;br /&gt;
&lt;br /&gt;
==Pagination==&lt;br /&gt;
&lt;br /&gt;
Quiz attempts can be paginated, i.e., spread over several pages. The student can navigate between the pages using the standard Moodle paging bar. When the student navigates to a different quiz page the answers on the current page are automatically submitted for saving (but not grading).&lt;br /&gt;
&lt;br /&gt;
To do this automatic submission the paging bar needs some javascript. It is therefore not produced with Moodle&#039;s standard print_paging_bar() function from weblib.php but with quiz_print_navigation_panel() which is defined in mod/quiz/locallib.php and produces something that looks the same.&lt;br /&gt;
&lt;br /&gt;
The teacher has complete control via the edit interface on edit.php over where the page breaks should occur. He can repaginate the quiz with any chosen number of questions per page. He can also move the page-breaks up and down using the arrows.&lt;br /&gt;
&lt;br /&gt;
Internally page breaks are stored in the $quiz-&amp;gt;questions field (which now should really be called $quiz-&amp;gt;layout). This field contains a comma separated list of questionids and pagebreaks where the pagebreaks are represented by the id 0. For example 23,12,0,11, 0 means that the two questions with ids 23 and 12 are on the first page and the question with id 11 is on the second page. The last page break is invisible and Moodle sometimes puts it there itself for its own convenience.&lt;br /&gt;
&lt;br /&gt;
Because the quiz has an option $quiz-&amp;gt;shufflequestions to shuffle questions the layout that the student sees in a particular attempt does not necessarily have to be the same as that stored in $quiz-&amp;gt;questions. Therefore each attempt has its own $attemp-&amp;gt;layout field. If $quiz-&amp;gt;shufflequestions is false then this just contains a copy of $quiz-&amp;gt;questions but if it is true then during the creation of a new attempt by quiz_create_attempt() the function quiz_repaginate() is used to produce a layout with $quiz-&amp;gt;questionsperpage number of questions per page that are randomly ordered.&lt;br /&gt;
&lt;br /&gt;
Both attempt.php and review.php use the $attempt-&amp;gt;layout field to determine what questions to show on a particular page. That way we can guarantee that the student will, for a particular attempt, always see the questions in the same order and with the same pagination, both while attempting and during review. Also a teacher when reviewing a student&#039;s attempt sees the pages the same way they were shown to the student. However the teacher is also given the option to see all questions on one page.&lt;br /&gt;
&lt;br /&gt;
There are some functions in locallib.php dedicated to handling the layout fields: quiz_questions_on_page(), quiz_questions_in_quiz(), quiz_number_of_pages(), quiz_first_questionnumber(), quiz_repaginate(). They are very short functions. The function quiz_first_questionnumber() that determines the number of the first question on a particular page makes use of the $question-&amp;gt;length field. To allow this calculation to be fast is the main reason why that field is in the question table even though it could also be determined easily from the question type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Question versioning==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Question versioning is currently disabled until it is re-developed to fix all reported issues.&lt;br /&gt;
&lt;br /&gt;
When questions that were already attempted by a student are edited, it can be important to keep a copy of the question as it was before editing in order to reconstruct the quiz as it was seen by the student. To provide this functionality a question versioning mechanism was implemented.&lt;br /&gt;
&lt;br /&gt;
The first goal, namely keeping around old questions, is easily achieved. They are just not deleted any more. However, this is not enough; it is also necessary to store which questions are versions of others. To achieve this goal, there is an additional table, which stores the versioning information: quiz_question_versions.&lt;br /&gt;
&lt;br /&gt;
When a question is replaced for which there are already student attempts then all the attempt data gets associated to the new version of the question and is re-graded. This requires the question ids in the quiz_attempts, quiz_states and quiz_newest_states tables to be replaced by the new id. However we do also want to be able to reconstruct the quiz the way the student saw it when he gave his answers. For that purpose the id of the original question is always preserved in the &#039;originalquestion&#039; field of the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
If all old versions of questions are kept around this could horribly clutter the editing interface. Therefore a field called hidden was added to the quiz_questions table and all old versions of edited questions are automatically hidden. When this flag is set to 1 the question is not displayed in the list of available questions, unless the user chooses to show them.&lt;br /&gt;
&lt;br /&gt;
While the mechanism above should work as described, there is some additional complexity in order to minimise the number of versions created. If a question is created and has not been attempted by a student yet (this excludes teacher previews of the individual question and the quiz!), the database record will be reused (i.e. overwritten) and no new version will be created. This is especially important when the question is created and the first 2 or 3 mistakes are only noticed during preview.&lt;br /&gt;
&lt;br /&gt;
On the editing screen for questions an additional set of options was introduced (see image).&lt;br /&gt;
Replacement Options&lt;br /&gt;
It shows which quizzes use the edited question and how many students have attempted it in a particular quiz. Based on this information it is then possible to choose in which quizzes the new version of the question should be used and in which ones the old one should remain.&lt;br /&gt;
&lt;br /&gt;
By default the &#039;replace&#039; checkbox for all quizzes that don&#039;t have any students&#039; attempts are checked and in addition, if the question is edited out of a quiz context (i.e. not in the category question list), the &#039;replace&#039; option is checked for that quiz as well.&lt;br /&gt;
&lt;br /&gt;
===Database===&lt;br /&gt;
&lt;br /&gt;
The changes to the database structure are limited to an added field (hidden) in the quiz_questions table and an additional table called quiz_question_versions. However, dealing with the quiz_questions table has become slightly more complicated.&lt;br /&gt;
&lt;br /&gt;
The hidden field in the quiz_questions table has no implications for the core functionality. It is only used to determine, as the name implies, whether the question is shown in the category list or not.&lt;br /&gt;
&lt;br /&gt;
The table quiz_question_versions stores information about the actual change. This information includes the ids of the old question and the new question, the id of the user who did the change and a timestamp. Quite importantly, the id of the quiz, in which the question was replaced is also stored. This means that the versions table provides a history of the different states the quiz went through until it was edited to be at the current state. The information allows to recreate a quiz as it was at any point in time (from a data perspective - this possibility is not used extensively by the code).&lt;br /&gt;
&lt;br /&gt;
===Adjustments to the Data===&lt;br /&gt;
&lt;br /&gt;
When a question is replaced by a newer version, database records are updated in the order shown below (compare with question.php):&lt;br /&gt;
&lt;br /&gt;
* First a new record is inserted into the quiz_question_versions table for each affected quiz (i.e. each quiz in which the question was replaced).&lt;br /&gt;
* Then, for each affected quiz, the comma separated list of question ids in the question field is updated by replacing the old question id with the new one.&lt;br /&gt;
* In the quiz_question_instances table the record that links the old question to the quiz is also updated to point to the new question.&lt;br /&gt;
* In all attempts belonging to the old question the comma-separated list of question ids in the layout field are changed by replacing the old id by the new one.&lt;br /&gt;
* All states belonging to the old question are made to belong to the new version by changing the id in the &#039;question&#039; field. However if we are replacing the original question then the id of this original version is stored in the originalquestion field.&lt;br /&gt;
* We have to change the questionid field in quiz_newest_states.&lt;br /&gt;
* Finally we have to do any question-type specific changes. For example question types that store student responses by storing the id of the answer in the quiz_answers table will have to recode these ids in all the states to point to the corresponding answers in the new version. This is handled by the function replace_question_in_attempts() in the question type class.&lt;br /&gt;
&lt;br /&gt;
===Affected Code and Functionality===&lt;br /&gt;
&lt;br /&gt;
Note: This section should still be considered under construction until the question mark behind bug #3311 is taken off.&lt;br /&gt;
&lt;br /&gt;
In the file review.php and potentially also in the file attempt.php, if a question is edited during a student&#039;s attempt, the data from quiz_question_versions needs to be taken into account. If a student has attempted a quiz and a question was changed afterwards (i.e. a new version of that question was created), the question id of the old version remains in the comma separated list inside the attempt-&amp;gt;layout field. However, since the records in the quiz_question_instances table get updated, we need to go forward in the question history, by looping through entries from the quiz_question_versions table, to find out the id of the question version that is currently used in the quiz.&lt;br /&gt;
&lt;br /&gt;
Suggestion: With a fairly simple change to the convention of what is stored in the quiz_question_versions table we could get rid of the requirement of looping through all the versions. If in the newquestion field we store the id of the question that is currently used in the quiz, it would be possible to get the complete history for a question quite simply by selecting by quiz id and newquestion.&lt;br /&gt;
&lt;br /&gt;
It should be fairly simple to write an upgrade script for this change. Additionally, another set_field would need to be added to question.php to change the newquestion field to the new question id. The benefits would be a much simpler handling of the question history, resulting in more efficient code than the current fix for bug #3311 in review.php.&lt;br /&gt;
&lt;br /&gt;
The place where all the versioning actually takes place is question.php. Here the changes described in Adjustments to the Data are carried out.&lt;br /&gt;
&lt;br /&gt;
Obviously the backup and restore scripts also take quiz_question_versions into account, however, they don&#039;t need to be concerned with the ways the data is used.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.5: adaptive questions==&lt;br /&gt;
&lt;br /&gt;
During the first half of 2005 the quiz module code has undergone a considerable rewrite to allow for adaptive questions in which a question session can consist of several sequential student responses. The question can adapt itself to the student answers. For example in response to certain answers the question could provide feedback or hints and then ask the student to answer again or give the student a simpler or related question.&lt;br /&gt;
&lt;br /&gt;
Unfortunately many changes had to be made to the question type methods. This has however resulted in improved efficiency and has made the writing of question types easier. It also allows question types with more powerful features and has fixed some bugs / annoying behaviour. &lt;br /&gt;
&lt;br /&gt;
For details see:&lt;br /&gt;
*[[Quiz rewrite|Quiz module rewrite]]&lt;br /&gt;
*[[Quiz conversion|How to convert existing question types]]&lt;br /&gt;
&lt;br /&gt;
Of course there were countless other changes to the quiz module going from Moodle 1.4 to 1.5, especially to the teacher interface. However in spite of the fact that these changes are a lot more visible they were much less drastic from the point of view of the code. Here is a very incomplete list of changes:&lt;br /&gt;
&lt;br /&gt;
* New quiz results overview page&lt;br /&gt;
* Reform of the quiz edit page: Changes on the quiz edit page are saved straightaway, not only after Save button is pressed.&lt;br /&gt;
* Copying questions: The teacher can create a new question using a previous one as template.&lt;br /&gt;
* Moving questions: The teacher can now move selected questions to a different category.&lt;br /&gt;
* Re-marking after question editing: if a teacher corrects a question that students have already attempted the teacher can request a remark.&lt;br /&gt;
* Teacher preview tab.&lt;br /&gt;
* Detailed teacher control over what students can see during review.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.6: separating questions from quizzes==&lt;br /&gt;
&lt;br /&gt;
The quiz module is not the only activity module in Moodle that uses questions. The lesson does too and potentially questions could be useful in many modules. Therefore we have started to rewrite some  of the quiz module functions and move them from locallib.php to questionlib.php so that eventually they could be moved into a central library and be used by other modules. &lt;br /&gt;
&lt;br /&gt;
Module developers who want to use the &lt;br /&gt;
quiz module questions in their own module should take a look at the simple questiondemo module that you can find in CVS at [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/questiondemo contrib/questiondemo]. The idea is that it will be simpler&lt;br /&gt;
to understand this demonstration module than the code in the quiz module which&lt;br /&gt;
is very complicated due to the many options and features. The interesting code in the questiondemo module is in view.php. There you can see how to&lt;br /&gt;
both render and score questions. This module requires the version of the quiz module from Moodle 1.6dev or later.&lt;br /&gt;
&lt;br /&gt;
The details of the changes are explained on the page [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
==Future plans==&lt;br /&gt;
&lt;br /&gt;
The features below are in no particular order:&lt;br /&gt;
&lt;br /&gt;
* Editing questions: This is about editing questions after students have already attempted them. There needs to be a mechanism to keep the old versions of the question around for auditing purposes.&lt;br /&gt;
* New quiz statistics pages?: These pages should be built by using functions defined by the individual question types.&lt;br /&gt;
* Manual grade override: Teachers should be able to override the automatically calculated grades and should be able to make comments.&lt;br /&gt;
* Off-line questions: The answers to these are handed in off-line in the conventional way (e.g., on paper) and teachers enter marks on Moodle.&lt;br /&gt;
* Batch printing of quiz sheets: We want to be able to hand out question sheets to students so they can start working on the questions before going to the computer.&lt;br /&gt;
* Question preview from question edit page: so the teacher can try the question already before saving the changes.&lt;br /&gt;
* Show table of questions on view.php: gives teachers and students a bit of an overview of the quiz.&lt;br /&gt;
* Extending deadlines for individual students: for example when a student misses a deadline for good reasons.&lt;br /&gt;
* Filtering questions by quiz and by search: More ways to restrict which questions are shown on the quiz editing page.&lt;br /&gt;
* Re-open quizzes for revision: After the due date has passed the quiz could allow practice attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:RQP_question_type&amp;diff=4892</id>
		<title>Development:RQP question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:RQP_question_type&amp;diff=4892"/>
		<updated>2006-02-07T00:18:37Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Database tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_rqp===&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;type :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;source :longblob NOT NULL default &#039;&#039;,&lt;br /&gt;
;format :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
;flags :tinyint(3) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;maxscore :int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_rqp_servers===&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;typeid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;url :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
;can_render :tinyint(2) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;can_author :tinyint(2) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_rqp_states===&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;stateid :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;responses :text NOT NULL default &#039;&#039;,&lt;br /&gt;
;persistent_data :text NOT NULL default &#039;&#039;,&lt;br /&gt;
;template_vars :text NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_rqp_types===&lt;br /&gt;
&lt;br /&gt;
;id int(10) :unsigned NOT NULL auto_increment,&lt;br /&gt;
;name :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4891</id>
		<title>Development:Dataset dependent</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4891"/>
		<updated>2006-02-07T00:11:49Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_dataset_items */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_definitions=== &lt;br /&gt;
This table is an indirect extension to the quiz_questions table, because the quiz_question_datasets table can link a question to one or more datasets. Each dataset represents a variable, that is used either in the questiontext or in the answer to a dataset dependent question.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;category :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;name :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
;type :int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
;options :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
;itemcount :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_items===&lt;br /&gt;
&lt;br /&gt;
Dataset items can be created for each dataset. The quiz_dataset_items table stores these possible values for the variables defined in the quiz_dataset_definitions table.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;definition :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;number :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;value :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_datasets===&lt;br /&gt;
&lt;br /&gt;
The quiz_question_datasets table is used by dataset dependent questionypes (i.e. calculated) to link datasets to questions.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;datasetdefinition :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4890</id>
		<title>Development:Dataset dependent</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4890"/>
		<updated>2006-02-07T00:09:32Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_dataset_definitions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_definitions=== &lt;br /&gt;
This table is an indirect extension to the quiz_questions table, because the quiz_question_datasets table can link a question to one or more datasets. Each dataset represents a variable, that is used either in the questiontext or in the answer to a dataset dependent question.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;category :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;name :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
;type :int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
;options :varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
;itemcount :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_items===&lt;br /&gt;
&lt;br /&gt;
Dataset items can be created for each dataset. The quiz_dataset_items table stores these possible values for the variables defined in the quiz_dataset_definitions table. &lt;br /&gt;
&lt;br /&gt;
===quiz_question_datasets===&lt;br /&gt;
&lt;br /&gt;
The quiz_question_datasets table is used by dataset dependent questionypes (i.e. calculated) to link datasets to questions.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;datasetdefinition :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4889</id>
		<title>Development:Dataset dependent</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4889"/>
		<updated>2006-02-07T00:07:03Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* quiz_question_datasets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_definitions=== &lt;br /&gt;
This table is an indirect extension to the quiz_questions table, because the quiz_question_datasets table can link a question to one or more datasets. Each dataset represents a variable, that is used either in the questiontext or in the answer to a dataset dependent question.&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_items===&lt;br /&gt;
&lt;br /&gt;
Dataset items can be created for each dataset. The quiz_dataset_items table stores these possible values for the variables defined in the quiz_dataset_definitions table. &lt;br /&gt;
&lt;br /&gt;
===quiz_question_datasets===&lt;br /&gt;
&lt;br /&gt;
The quiz_question_datasets table is used by dataset dependent questionypes (i.e. calculated) to link datasets to questions.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;datasetdefinition :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Numerical_question_type&amp;diff=4887</id>
		<title>Development:Numerical question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Numerical_question_type&amp;diff=4887"/>
		<updated>2006-02-06T23:59:07Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Database tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical table is an extension of the quiz_answers table, defining a tolerance value for each answer.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;answer :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;tolerance :varchar(255) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical_units===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical_units table is used by the numerical questiontype and the calculated questionype. It extends the quiz_questions table, defining an arbitrary number of units that can be used in the responses.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;multiplier :decimal(40,20) NOT NULL default &#039;1.00000000000000000000&#039;,&lt;br /&gt;
;unit :varchar(50) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The numerical questiontype, which inherits the function print_question_formulation_and_controls() from the shortanswer questiontype, has only one response field, so its responses are handled by the default questiontype. The response is stored without any modifications in the answer field of the table quiz_states.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=4886</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=4886"/>
		<updated>2006-02-06T23:58:13Z</updated>

		<summary type="html">&lt;p&gt;Gustav: moved numerical tables to the numerical questiontype&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module runtime code. This $state runtime object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A timestamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previouse state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at runtime. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the runtime state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true amd must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indicies are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_attempts|quiz_attempts]] table&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4884</id>
		<title>Development:Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4884"/>
		<updated>2006-02-06T23:00:03Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Answers */  commented on misnamed answer field in states table&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module with its own modular structure to allow question type plug-ins. The module has grown organically and in spite of a lot of rewriting for Moodle 1.5 the code is not very simple to understand. This page aims to collect useful documentation on how the module works. &lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the quiz module there are certain terms that can cause confusion because they can be used with different meanings. In Moodle we have adopted a certain terminology that will be explained below.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;question&#039;&#039;&#039; in the context of the quiz module is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it is much more than what one would in everyday language understand under a question and which in Moodle is just on field (the questiontext field) of the question object.&lt;br /&gt;
&lt;br /&gt;
What in Moodle we refer to as a &#039;question&#039; is what in the terminology of the QTI specification ismore appropriately called an &#039;&#039;&#039;assessment item&#039;&#039;&#039; or just &#039;item&#039; for short. &lt;br /&gt;
&lt;br /&gt;
There are different types of questions, like for example multiple-choice questions or numerical questions. These are referred to as &#039;&#039;&#039;[[Quiz developer docs#Question types|question types]]&#039;&#039;&#039; in Moodle.&lt;br /&gt;
&lt;br /&gt;
Since version 1.5 Moodle is able to handle so-called &#039;&#039;&#039;[[Adaptive questions]]&#039;&#039;&#039;, also known as &#039;adaptive items&#039; in QTI speak. These are qustions that walk the user through a directed graph of question states depending on the user&#039;s responses. For example a complicated mathematical question that is answered incorrectly, but is likely to be incorrect because of a common mistake, could provide the user with a hint towards this mistake, apply a penalty and allow a second attempt at this question. Quizzes can be run in &#039;adaptive mode&#039;, which provides buttons to mark each question individually.&lt;br /&gt;
&lt;br /&gt;
===Answers===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;answer&#039;&#039;&#039;&#039; is used exclusively for the &#039;&#039;&#039;teacher-defined answers&#039;&#039;&#039; of a question. When talking about the quiz module it is easy to get confused between these teacher-defined answers and the answers that the students actually give. We have therefore adopted the convention to refer to the student-supplied answers as &#039;responses&#039; and to reserve the term &#039;answers&#039; to apply to teacher-defined answers. In question types that rely on teacher-supplied answers these are used in the grading process by comparing them with the student responses. Of course not all question types use teacher-defined answers but use some more intelligent way to process the student responses. &lt;br /&gt;
&lt;br /&gt;
Perhaps one should also stress that &#039;answer&#039; is not always used in the sense of &#039;correct answer&#039;. For example every choice in a multiple-choice question is referred to as an answer. Other systems use the term &#039;distractor&#039; for wrong answers. &lt;br /&gt;
&lt;br /&gt;
In Moodle we always use the term &#039;&#039;&#039;&#039;responses&#039;&#039;&#039;&#039; to refer to the students&#039; responses to a question because term &#039;answers&#039; that one might also be tempted to use for this is already used to refer to the teacher-defined answers, see above. This term is always used in plural, although for some questiontypes there is only one possible response.&lt;br /&gt;
&lt;br /&gt;
There is unfortunately, for historical reasons, one exception to the above rule: The [[Quiz database structure#quiz_states|quiz_states table]] has a field &#039;answer&#039; whose purpose it actually is to hold the student&#039;s responses.&lt;br /&gt;
&lt;br /&gt;
===Attempts===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;attempt&#039;&#039;&#039;&#039; is used in the sense of &amp;quot;Attempt at the quiz&amp;quot;. Depending on the quiz settings, a student may be allowed several attempts at a quiz. An attempt is finished when the student clicks on the corresponding button on the attempt page. Students do not have to complete an attempt in one visit. They can navigate away from the quiz page and return later to continue the same attempt.&lt;br /&gt;
&lt;br /&gt;
Within one and the same quiz attempt a student may make several attempts at answering a particular question, at least if the questiontype allows it and the quiz is set up in adaptive mode. These will always be referred to as &#039;&#039;&#039;&#039;attempts at a question&#039;&#039;&#039;&#039;, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
Because a student can have several attempts at a question within the same attempt at the quiz, there is a lot of data that needs to be stored as the student takes the question through several &#039;&#039;&#039;&#039;states&#039;&#039;&#039;&#039; by repeated interactions with the question. A state object holds the most recent state of the question and whenever a student submits a response or a similar &#039;&#039;&#039;&#039;event&#039;&#039;&#039;&#039; occurs, the question goes to a new state. The complete history of question states that the question is taken through is saved and this is referred to as the question &#039;&#039;&#039;&#039;session&#039;&#039;&#039;&#039;. Usually only the most recent state and the last graded state are of interest though.&lt;br /&gt;
&lt;br /&gt;
==Code documentation==&lt;br /&gt;
&lt;br /&gt;
The code is documented according to phpdoc conventions. The explanations here in the wiki are meant to complement this.&lt;br /&gt;
&lt;br /&gt;
Inline comments should be used liberally in the code. The following conventions make it easier to search for comments with special meaning:&lt;br /&gt;
* use TODO in comments about things that need to be done&lt;br /&gt;
* use ??? in comments that are questions about the code&lt;br /&gt;
&lt;br /&gt;
There are three function libraries:&lt;br /&gt;
&lt;br /&gt;
;questionlib.php&lt;br /&gt;
:All functions that need to be available to any module wanting to use questions. This is New in Moodle 1.6, in Moodle 1.5 this was part of locallib.php. This instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core. This loads constants from &#039;&#039;&#039;constants.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;locallib.php&lt;br /&gt;
:All functions that are used only by the quiz module. This loads lib.php and questionlib.php&lt;br /&gt;
&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;questiontypes/questiontype.php&#039;&#039;&#039;. The individual questiontypes extend this class in their own questiontype.php file. For documentation of the questiontype classes one should often look at the documentation of the default question type because much of the documentation that is in the default class is not repeated in the other questiontype classes&lt;br /&gt;
&lt;br /&gt;
Constants are defined in .&lt;br /&gt;
&lt;br /&gt;
While questiontypes are realized as classes, the quiz module is not written in a truly object-oriented way. Instead it follows the Moodle model of using objects mostly only as alternatives to arrays to hold database records. So none of the quiz, question, attempt, and state objects that play a central role in the module have any methods. Only the questiontype objects have methods. Strangely enough the quiz module instantiates on object of each questiontype class at the start and then reuses their methods for the different questions. If one is used to the Moodle way of programming then this is easy enough to handle.&lt;br /&gt;
&lt;br /&gt;
==Objects and data structures==&lt;br /&gt;
&lt;br /&gt;
Key to understanding how the quiz module works is to understand the different kinds of object work together. The most important ones are:&lt;br /&gt;
&lt;br /&gt;
*Quizzes&lt;br /&gt;
*Questions&lt;br /&gt;
*Attempts&lt;br /&gt;
*States&lt;br /&gt;
&lt;br /&gt;
Quizzes and Questions are data created by the teacher when setting up and editing a quiz. Attempts and States are data created by the student when interacting with a quiz. &lt;br /&gt;
&lt;br /&gt;
Moodle allows students to make several attempts at a quiz. Data about such an attempt is stored in an attempt object. This holds for example how the quiz was randomized for this attempt and the ordering of the questions and answers. So attempts are indexed by user id and quiz id.&lt;br /&gt;
&lt;br /&gt;
Moodle allows students to interact repeatedly with a single question. So for example the student might initially just save an answer, later mark it, then correct it if it was marked incorrect. Each time the student interacts with a particular question inside a particular attempt at a quiz a new state is created. So states are indexed by user id, attempt id and question id.&lt;br /&gt;
&lt;br /&gt;
===Database structure===&lt;br /&gt;
All this data needs to be kept in Moodle&#039;s database. How this is achieved is explained on a separate page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;, which also contains a useful diagram.&lt;br /&gt;
&lt;br /&gt;
As is customary in Moodle, most runtime objects simply represent the data from a particular database record. So for example a $quiz object has fields corresponding to all the fields in the [[Quiz database structure#quiz|quiz table]]. In some cases the objects have some additional fields that are added at runtime. This is particularly the case for $question and $state objects. These additional fields are also described on the page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;. Many functions that are used to process these objects make use of the additional fields and it is therefore necessary to use the correct functions for creating these objects.&lt;br /&gt;
&lt;br /&gt;
===Runtime objects===&lt;br /&gt;
Some objects used by the quiz module are purely runtime object and do not correspond to a database table. The structure of these objects is explained in detail on a separate page about the &#039;&#039;&#039;[[Quiz runtime objects]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The main script of the quiz module is attempt.php which will have to deal with all these objects. Studying the &#039;&#039;&#039;[[Quiz attempt|explanation of attempt.php]]&#039;&#039;&#039; is therefore a good way to start to study the quiz module code.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The student&#039;s responses to a question are stored in &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt;. Questiontypes are completely free to implement the storage mechanism of their responses (and other state information) the way they want. Still, the standard questiontypes all follow a similar model. The default storage model and the questiontype specific variations are explained below.&lt;br /&gt;
&lt;br /&gt;
The flexibility for the questiontypes to choose their response storage mechanism freely and to convert from the storage model to the runtime model is provided by a set of three functions, which allow to initialise the runtime &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field, to convert from the runtime to the storage model and vice versa:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;create_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Initializes the $state object, in particular the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Loads the question type specific session data from the database into the &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; object, in particular it loads the responses that have been saved for the given &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; into the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Saves the question type specific session data from the $state object to the database. In particular, for most questiontypes, it saves the responses from the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; to the database.&lt;br /&gt;
&lt;br /&gt;
The generic quiz module code saves the contents form the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; field to the answer field in the [[Quiz database structure#quiz_states|quiz_states table]] and also automatically restores the contents of this field to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This means that any questiontype, which only expects a single value as its response can skip the implementation of the three methods described above. All questiontypes that have multiple value responses need to implement these methods. &lt;br /&gt;
&lt;br /&gt;
The default questiontypes handle this problem by serializing/de-serializing the responses to/from the answer field in the quiz_states table. However, it is also possible (and may be better practice) to extend the quiz_states table with a questiontype specific table, i.e. take the id of the quiz_states record as a foreign key in the questiontype specific table. Because the value of &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is set to the value of the answer field, questiontypes that serialize their response need to overwrite (in &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;) whatever value the generic code set this field to with their serialized value (usually achieved with a simple set_field). &lt;br /&gt;
&lt;br /&gt;
In the method &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; the serialized value can be read from &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; because this is where the value from answer field of the quiz_states table has been moved. Care needs to be taken that this array value is then unset or the whole array overwritten, so that the array does not accidentally contain a value with the empty string index.&lt;br /&gt;
&lt;br /&gt;
==Response processing==&lt;br /&gt;
&lt;br /&gt;
The runtime model for responses dictates the structure of the $state-&amp;gt;responses array. Starting with the names of the form elements this section goes through the relevant processing steps and thus attempts to clarify why the keys of the $state-&amp;gt;responses array can differ for different questiontypes; even more, it explains how the array keys are chosen and set.&lt;br /&gt;
&lt;br /&gt;
Although it may initially seem strange to start with the naming convention of the form fields, the reason for this will become clear later on. The controls (i.e. the form fields) of a question get printed by the method &amp;lt;code&amp;gt;print_question_formulation_and_controls()&amp;lt;/code&amp;gt;. The convention only dictates that the name of the control element(s) must begin with the value of &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt; is a string starting with &amp;quot;resp&amp;quot; followed by the question id and an underscore, e.g. &amp;lt;code&amp;gt;resp56_&amp;lt;/code&amp;gt;. In the default case, when there is only a single control element (this includes the case of a list of equally named radio buttons), no postfix is appended to the name prefix. For questiontypes that allow or require multiple form elements, an arbitrary string can be appended to the name prefix to form the name of these form elements. The postfix must not include any relational data (i.e. ids of records in the quiz_answers table), because this can lead to problems with regrading of versioned questions.&lt;br /&gt;
&lt;br /&gt;
After the printing of the question the server only sees it again when it is submitted. So the submitted data will contain several values indexed by strings starting with &amp;lt;code&amp;gt;respXX_&amp;lt;/code&amp;gt;. Upon submission, the function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; is called, which assigns the submitted responses to the state of the question with id XX, using the postfix (i.e. everything after the underscore) as array keys. In the default case with only one control element the name only consists of the name prefix. This explains why the default index of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array is the empty string. The value of each array element is obviously the value that was submitted by the form, basically a raw response.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; in turn calls the questiontype specific method &amp;lt;code&amp;gt;grade_responses()&amp;lt;/code&amp;gt; to assign a grade to the submitted responses and &amp;lt;code&amp;gt;compare_responses()&amp;lt;/code&amp;gt; to determine whether the response was identical to the previous submission and to avoid regrading the same responses repeatedly. These questiontype specific functions need to be aware of the expected keys of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
Finally, the methods &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt; also need to know the questiontype specific layout of the &amp;lt;code&amp;gt;$state-&amp;gt;responses array&amp;lt;/code&amp;gt; and restore or save the information, e.g. by converting from or to the data representation.&lt;br /&gt;
&lt;br /&gt;
==Question types==&lt;br /&gt;
{{Questiontype developer docs}}&lt;br /&gt;
The quiz module is itself modular and allows question type plug-ins. For each question type there should be a page, accessible via the menu at the right, which provides at least the dtails about&lt;br /&gt;
*Database tables&lt;br /&gt;
*Response storage&lt;br /&gt;
*Question options object&lt;br /&gt;
*State options object&lt;br /&gt;
&lt;br /&gt;
It is hoped that Moodlers will contribute a lot of non-core question types in the future. For this it would be good to start a [[Guide to question type plugins]].&lt;br /&gt;
&lt;br /&gt;
==Grades==&lt;br /&gt;
&lt;br /&gt;
The handling of grades is a bit complicated because there are so many different grades around that get rescaled and combined in various ways. This section should summarize how this is done and why.&lt;br /&gt;
&lt;br /&gt;
The following grade fields are being used:&lt;br /&gt;
*$question-&amp;gt;defaultgrade&lt;br /&gt;
::This is the default value for the maximum grade for this question. This is set up when the teacher creates the question and it is stored in an int(10) field in the [[Quiz database structure#quiz_questions|quiz_questions]] table. However when the question is actually used in a particular quiz the teacher can overrule this default and this is stored in:&lt;br /&gt;
*$question-&amp;gt;maxgrade&lt;br /&gt;
::This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in an int(10) field in the [[Quiz database structure#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
*$question-&amp;gt;penalty&lt;br /&gt;
&lt;br /&gt;
*$state-&amp;gt;raw_grade&lt;br /&gt;
*$state-&amp;gt;grade&lt;br /&gt;
*$state-&amp;gt;penalty&lt;br /&gt;
*$state-&amp;gt;sumpenalty&lt;br /&gt;
&lt;br /&gt;
*$attempt-&amp;gt;sumgrades&lt;br /&gt;
&lt;br /&gt;
The maximum grades set by the teacher, $question-&amp;gt;defaultgrade and $question-&amp;gt;maxgrade, are integers. All student-obtained grades are in principle floating point numbers. For historical reasons they are stored in the database as varchar(10) fields. Care has to be taken when writing to the database to make sure all grades are correctly rounded and squeezed into a string of no more than 10 characters, otherwise the writing to database will fail, see bug 4220.&lt;br /&gt;
&lt;br /&gt;
The final outcome of the calculation of the grade for a user at a particular quiz is stored in the &#039;grade&#039; field of the [[Quiz database structure#quiz_grades|quiz_grades table]]. This field has type double.&lt;br /&gt;
&lt;br /&gt;
==Penalty mechanism==&lt;br /&gt;
&lt;br /&gt;
===What it is for===&lt;br /&gt;
&lt;br /&gt;
When the quiz is run in adaptive mode the student can interact with a question repeatedly. So in particular the student can try again when he gets a wrong answer. Clearly the final mark for the question must reflect the fact that the student did not get it right originally. Therefore a penalty is subtracted from the final mark.&lt;br /&gt;
&lt;br /&gt;
===How the penalty is determined===&lt;br /&gt;
&lt;br /&gt;
First of all penalties are relevant only if a quiz is run in adaptive mode. Only in this case can a student have a second attempt and therefore only in this mode can there be any occasion to subtract a penalty.&lt;br /&gt;
&lt;br /&gt;
Even in adaptive mode the penalty mechanism is only used when it is selected in the quiz options. If &amp;quot;Apply penalties&amp;quot; is set to &amp;quot;No&amp;quot; then the final mark for the question is the mark for the last graded response.&lt;br /&gt;
&lt;br /&gt;
Each question has a &#039;penalty&#039; field (which should really be called &#039;penaltyfactor&#039;) which is a number between 0 and 1. The penalty for a wrong response is calculated as the product ($quiz-&amp;gt;penalty * $quiz-&amp;gt;grade), i.e., as the product of the penaltyfactor with the maximum achievable grade for the question. This product is stored in $state-&amp;gt;penalty. So $quiz-&amp;gt;penalty is the fraction of the maximum grade that is subtracted as a penalty for each wrong response.&lt;br /&gt;
&lt;br /&gt;
The $quiz-&amp;gt;penalty field has a default value of 0.1, both in the database and in mod/quiz/defaults.php. This default can of course be overwritten by the admin on the quiz configuration page. This admin-selected default is (as usual for admin defaults) stored in $CFG-&amp;gt;quiz_penalty. The teacher can choose a different penalty factor for each individual question when adding or editing a question.&lt;br /&gt;
&lt;br /&gt;
Now if a student makes repeated wrong attempts (or partially correct attempts) the penalties for all these attempts are added up in $state-&amp;gt;sumpenalties. The mark for the question is then calculated as the mark for the last graded response minus the sum of the penalties.&lt;br /&gt;
&lt;br /&gt;
One curious fact about $state-&amp;gt;sumpenalties is that, for efficiency reasons, it is not stored in the quiz_states table but instead in the &#039;sumpenalty&#039; field of the quiz_newest_states table. That way it only has to be stored once per attempt rather than once per response.&lt;br /&gt;
&lt;br /&gt;
===Where it is done in the code===&lt;br /&gt;
&lt;br /&gt;
The function quiz_apply_penalty_and_timelimit() subtracts the penalty in $state-&amp;gt;sumpenalty from the raw grade in $state-&amp;gt;raw_grade to obtain $state-&amp;gt;grade for the response. However it is ensured that the grade of a new attempt at the question never falls below the previously achieved grade. This function also increases $state-&amp;gt;sumpenalty by the amount in $state-&amp;gt;penalty. The assumption is that $state-&amp;gt;penalty has just been set appropriately by the code calling this function, e.g., quiz_process_responses.&lt;br /&gt;
&lt;br /&gt;
==Time limit==&lt;br /&gt;
&lt;br /&gt;
A quiz can have a time limit. This is stored in minutes in $quiz-&amp;gt;timelimit. So before using this in time calculations it always has to be multiplied by 60 to turn it into seconds like all other timestamps in moodle and php. If $quiz-&amp;gt;timelimit is zero it means there is no timelimit.&lt;br /&gt;
&lt;br /&gt;
If a student asks to start an attempt on view.php for a quiz with a timelimit then he is shown a javascript message alerting him to the timelimit and is asked to confirm.&lt;br /&gt;
&lt;br /&gt;
For quizzes with timelimit attempt.php shows a javascript timer that counts down and automatically submits and closes the attempt when the time is up.&lt;br /&gt;
&lt;br /&gt;
Confusingly there are two javascript timers in the quiz module. jsclock.php provides a countdown in the title bar that counts down to the quiz closing time if this is less than a day away. This has nothing to do with the timelimit. jstimer.php provides the countdown timer that implements the timelimit. It in turn uses timer.js.&lt;br /&gt;
&lt;br /&gt;
The time a response was submitted by the student is recorded by attempt.php right at the top of the page and is then passed on to quiz_process_responses in $action-&amp;gt;timestamp. This puts it into $state-&amp;gt;timestamp. Finally, after the responses have been graded, the function quiz_apply_penalty_and_timelimit() checks that the responses are within the timelimit to within 5% and if not it sets the grade to zero (or the previously obtained grade, if that is higher).&lt;br /&gt;
&lt;br /&gt;
==Pagination==&lt;br /&gt;
&lt;br /&gt;
Quiz attempts can be paginated, i.e., spread over several pages. The student can navigate between the pages using the standard Moodle paging bar. When the student navigates to a different quiz page the answers on the current page are automatically submitted for saving (but not grading).&lt;br /&gt;
&lt;br /&gt;
To do this automatic submission the paging bar needs some javascript. It is therefore not produced with Moodle&#039;s standard print_paging_bar() function from weblib.php but with quiz_print_navigation_panel() which is defined in mod/quiz/locallib.php and produces something that looks the same.&lt;br /&gt;
&lt;br /&gt;
The teacher has complete control via the edit interface on edit.php over where the page breaks should occur. He can repaginate the quiz with any chosen number of questions per page. He can also move the page-breaks up and down using the arrows.&lt;br /&gt;
&lt;br /&gt;
Internally page breaks are stored in the $quiz-&amp;gt;questions field (which now should really be called $quiz-&amp;gt;layout). This field contains a comma separated list of questionids and pagebreaks where the pagebreaks are represented by the id 0. For example 23,12,0,11, 0 means that the two questions with ids 23 and 12 are on the first page and the question with id 11 is on the second page. The last page break is invisible and Moodle sometimes puts it there itself for its own convenience.&lt;br /&gt;
&lt;br /&gt;
Because the quiz has an option $quiz-&amp;gt;shufflequestions to shuffle questions the layout that the student sees in a particular attempt does not necessarily have to be the same as that stored in $quiz-&amp;gt;questions. Therefore each attempt has its own $attemp-&amp;gt;layout field. If $quiz-&amp;gt;shufflequestions is false then this just contains a copy of $quiz-&amp;gt;questions but if it is true then during the creation of a new attempt by quiz_create_attempt() the function quiz_repaginate() is used to produce a layout with $quiz-&amp;gt;questionsperpage number of questions per page that are randomly ordered.&lt;br /&gt;
&lt;br /&gt;
Both attempt.php and review.php use the $attempt-&amp;gt;layout field to determine what questions to show on a particular page. That way we can guarantee that the student will, for a particular attempt, always see the questions in the same order and with the same pagination, both while attempting and during review. Also a teacher when reviewing a student&#039;s attempt sees the pages the same way they were shown to the student. However the teacher is also given the option to see all questions on one page.&lt;br /&gt;
&lt;br /&gt;
There are some functions in locallib.php dedicated to handling the layout fields: quiz_questions_on_page(), quiz_questions_in_quiz(), quiz_number_of_pages(), quiz_first_questionnumber(), quiz_repaginate(). They are very short functions. The function quiz_first_questionnumber() that determines the number of the first question on a particular page makes use of the $question-&amp;gt;length field. To allow this calculation to be fast is the main reason why that field is in the question table even though it could also be determined easily from the question type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Question versioning==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Question versioning is currently disabled until it is re-developed to fix all reported issues.&lt;br /&gt;
&lt;br /&gt;
When questions that were already attempted by a student are edited, it can be important to keep a copy of the question as it was before editing in order to reconstruct the quiz as it was seen by the student. To provide this functionality a question versioning mechanism was implemented.&lt;br /&gt;
&lt;br /&gt;
The first goal, namely keeping around old questions, is easily achieved. They are just not deleted any more. However, this is not enough; it is also necessary to store which questions are versions of others. To achieve this goal, there is an additional table, which stores the versioning information: quiz_question_versions.&lt;br /&gt;
&lt;br /&gt;
When a question is replaced for which there are already student attempts then all the attempt data gets associated to the new version of the question and is re-graded. This requires the question ids in the quiz_attempts, quiz_states and quiz_newest_states tables to be replaced by the new id. However we do also want to be able to reconstruct the quiz the way the student saw it when he gave his answers. For that purpose the id of the original question is always preserved in the &#039;originalquestion&#039; field of the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
If all old versions of questions are kept around this could horribly clutter the editing interface. Therefore a field called hidden was added to the quiz_questions table and all old versions of edited questions are automatically hidden. When this flag is set to 1 the question is not displayed in the list of available questions, unless the user chooses to show them.&lt;br /&gt;
&lt;br /&gt;
While the mechanism above should work as described, there is some additional complexity in order to minimise the number of versions created. If a question is created and has not been attempted by a student yet (this excludes teacher previews of the individual question and the quiz!), the database record will be reused (i.e. overwritten) and no new version will be created. This is especially important when the question is created and the first 2 or 3 mistakes are only noticed during preview.&lt;br /&gt;
&lt;br /&gt;
On the editing screen for questions an additional set of options was introduced (see image).&lt;br /&gt;
Replacement Options&lt;br /&gt;
It shows which quizzes use the edited question and how many students have attempted it in a particular quiz. Based on this information it is then possible to choose in which quizzes the new version of the question should be used and in which ones the old one should remain.&lt;br /&gt;
&lt;br /&gt;
By default the &#039;replace&#039; checkbox for all quizzes that don&#039;t have any students&#039; attempts are checked and in addition, if the question is edited out of a quiz context (i.e. not in the category question list), the &#039;replace&#039; option is checked for that quiz as well.&lt;br /&gt;
&lt;br /&gt;
===Database===&lt;br /&gt;
&lt;br /&gt;
The changes to the database structure are limited to an added field (hidden) in the quiz_questions table and an additional table called quiz_question_versions. However, dealing with the quiz_questions table has become slightly more complicated.&lt;br /&gt;
&lt;br /&gt;
The hidden field in the quiz_questions table has no implications for the core functionality. It is only used to determine, as the name implies, whether the question is shown in the category list or not.&lt;br /&gt;
&lt;br /&gt;
The table quiz_question_versions stores information about the actual change. This information includes the ids of the old question and the new question, the id of the user who did the change and a timestamp. Quite importantly, the id of the quiz, in which the question was replaced is also stored. This means that the versions table provides a history of the different states the quiz went through until it was edited to be at the current state. The information allows to recreate a quiz as it was at any point in time (from a data perspective - this possibility is not used extensively by the code).&lt;br /&gt;
&lt;br /&gt;
===Adjustments to the Data===&lt;br /&gt;
&lt;br /&gt;
When a question is replaced by a newer version, database records are updated in the order shown below (compare with question.php):&lt;br /&gt;
&lt;br /&gt;
* First a new record is inserted into the quiz_question_versions table for each affected quiz (i.e. each quiz in which the question was replaced).&lt;br /&gt;
* Then, for each affected quiz, the comma separated list of question ids in the question field is updated by replacing the old question id with the new one.&lt;br /&gt;
* In the quiz_question_instances table the record that links the old question to the quiz is also updated to point to the new question.&lt;br /&gt;
* In all attempts belonging to the old question the comma-separated list of question ids in the layout field are changed by replacing the old id by the new one.&lt;br /&gt;
* All states belonging to the old question are made to belong to the new version by changing the id in the &#039;question&#039; field. However if we are replacing the original question then the id of this original version is stored in the originalquestion field.&lt;br /&gt;
* We have to change the questionid field in quiz_newest_states.&lt;br /&gt;
* Finally we have to do any question-type specific changes. For example question types that store student responses by storing the id of the answer in the quiz_answers table will have to recode these ids in all the states to point to the corresponding answers in the new version. This is handled by the function replace_question_in_attempts() in the question type class.&lt;br /&gt;
&lt;br /&gt;
===Affected Code and Functionality===&lt;br /&gt;
&lt;br /&gt;
Note: This section should still be considered under construction until the question mark behind bug #3311 is taken off.&lt;br /&gt;
&lt;br /&gt;
In the file review.php and potentially also in the file attempt.php, if a question is edited during a student&#039;s attempt, the data from quiz_question_versions needs to be taken into account. If a student has attempted a quiz and a question was changed afterwards (i.e. a new version of that question was created), the question id of the old version remains in the comma separated list inside the attempt-&amp;gt;layout field. However, since the records in the quiz_question_instances table get updated, we need to go forward in the question history, by looping through entries from the quiz_question_versions table, to find out the id of the question version that is currently used in the quiz.&lt;br /&gt;
&lt;br /&gt;
Suggestion: With a fairly simple change to the convention of what is stored in the quiz_question_versions table we could get rid of the requirement of looping through all the versions. If in the newquestion field we store the id of the question that is currently used in the quiz, it would be possible to get the complete history for a question quite simply by selecting by quiz id and newquestion.&lt;br /&gt;
&lt;br /&gt;
It should be fairly simple to write an upgrade script for this change. Additionally, another set_field would need to be added to question.php to change the newquestion field to the new question id. The benefits would be a much simpler handling of the question history, resulting in more efficient code than the current fix for bug #3311 in review.php.&lt;br /&gt;
&lt;br /&gt;
The place where all the versioning actually takes place is question.php. Here the changes described in Adjustments to the Data are carried out.&lt;br /&gt;
&lt;br /&gt;
Obviously the backup and restore scripts also take quiz_question_versions into account, however, they don&#039;t need to be concerned with the ways the data is used.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.5: adaptive questions==&lt;br /&gt;
&lt;br /&gt;
During the first half of 2005 the quiz module code has undergone a considerable rewrite to allow for adaptive questions in which a question session can consist of several sequential student responses. The question can adapt itself to the student answers. For example in response to certain answers the question could provide feedback or hints and then ask the student to answer again or give the student a simpler or related question.&lt;br /&gt;
&lt;br /&gt;
Unfortunately many changes had to be made to the question type methods. This has however resulted in improved efficiency and has made the writing of question types easier. It also allows question types with more powerful features and has fixed some bugs / annoying behaviour. &lt;br /&gt;
&lt;br /&gt;
For details see:&lt;br /&gt;
*[[Quiz rewrite|Quiz module rewrite]]&lt;br /&gt;
*[[Quiz conversion|How to convert existing question types]]&lt;br /&gt;
&lt;br /&gt;
Of course there were countless other changes to the quiz module going from Moodle 1.4 to 1.5, especially to the teacher interface. However in spite of the fact that these changes are a lot more visible they were much less drastic from the point of view of the code. Here is a very incomplete list of changes:&lt;br /&gt;
&lt;br /&gt;
* New quiz results overview page&lt;br /&gt;
* Reform of the quiz edit page: Changes on the quiz edit page are saved straightaway, not only after Save button is pressed.&lt;br /&gt;
* Copying questions: The teacher can create a new question using a previous one as template.&lt;br /&gt;
* Moving questions: The teacher can now move selected questions to a different category.&lt;br /&gt;
* Re-marking after question editing: if a teacher corrects a question that students have already attempted the teacher can request a remark.&lt;br /&gt;
* Teacher preview tab.&lt;br /&gt;
* Detailed teacher control over what students can see during review.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.6: separating questions from quizzes==&lt;br /&gt;
&lt;br /&gt;
The quiz module is not the only activity module in Moodle that uses questions. The lesson does too and potentially questions could be useful in many modules. Therefore we have started to rewrite some  of the quiz module functions and move them from locallib.php to questionlib.php so that eventually they could be moved into a central library and be used by other modules. &lt;br /&gt;
&lt;br /&gt;
Module developers who want to use the &lt;br /&gt;
quiz module questions in their own module should take a look at the simple questiondemo module that you can find in CVS at [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/questiondemo contrib/questiondemo]. The idea is that it will be simpler&lt;br /&gt;
to understand this demonstration module than the code in the quiz module which&lt;br /&gt;
is very complicated due to the many options and features. The interesting code in the questiondemo module is in view.php. There you can see how to&lt;br /&gt;
both render and score questions. This module requires the version of the quiz module from Moodle 1.6dev or later.&lt;br /&gt;
&lt;br /&gt;
The details of the changes are explained on the page [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
==Future plans==&lt;br /&gt;
&lt;br /&gt;
The features below are in no particular order:&lt;br /&gt;
&lt;br /&gt;
* Editing questions: This is about editing questions after students have already attempted them. There needs to be a mechanism to keep the old versions of the question around for auditing purposes.&lt;br /&gt;
* New quiz statistics pages?: These pages should be built by using functions defined by the individual question types.&lt;br /&gt;
* Manual grade override: Teachers should be able to override the automatically calculated grades and should be able to make comments.&lt;br /&gt;
* Off-line questions: The answers to these are handed in off-line in the conventional way (e.g., on paper) and teachers enter marks on Moodle.&lt;br /&gt;
* Batch printing of quiz sheets: We want to be able to hand out question sheets to students so they can start working on the questions before going to the computer.&lt;br /&gt;
* Question preview from question edit page: so the teacher can try the question already before saving the changes.&lt;br /&gt;
* Show table of questions on view.php: gives teachers and students a bit of an overview of the quiz.&lt;br /&gt;
* Extending deadlines for individual students: for example when a student misses a deadline for good reasons.&lt;br /&gt;
* Filtering questions by quiz and by search: More ways to restrict which questions are shown on the quiz editing page.&lt;br /&gt;
* Re-open quizzes for revision: After the due date has passed the quiz could allow practice attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4837</id>
		<title>Development:Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz&amp;diff=4837"/>
		<updated>2006-02-06T15:51:29Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Answers */  comment about wrong/correct answers&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module with its own modular structure to allow question type plug-ins. The module has grown organically and in spite of a lot of rewriting for Moodle 1.5 the code is not very simple to understand. This page aims to collect useful documentation on how the module works. &lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the quiz module there are certain terms that can cause confusion because they can be used with different meanings. In Moodle we have adopted a certain terminology that will be explained below.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;question&#039;&#039;&#039; in the context of the quiz module is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it is much more than what one would in everyday language understand under a question and which in Moodle is just on field (the questiontext field) of the question object.&lt;br /&gt;
&lt;br /&gt;
What in Moodle we refer to as a &#039;question&#039; is what in the terminology of the QTI specification ismore appropriately called an &#039;&#039;&#039;assessment item&#039;&#039;&#039; or just &#039;item&#039; for short. &lt;br /&gt;
&lt;br /&gt;
There are different types of questions, like for example multiple-choice questions or numerical questions. These are referred to as &#039;&#039;&#039;[[Quiz developer docs#Question types|question types]]&#039;&#039;&#039; in Moodle.&lt;br /&gt;
&lt;br /&gt;
Since version 1.5 Moodle is able to handle so-called &#039;&#039;&#039;[[Adaptive questions]]&#039;&#039;&#039;, also known as &#039;adaptive items&#039; in QTI speak. These are qustions that walk the user through a directed graph of question states depending on the user&#039;s responses. For example a complicated mathematical question that is answered incorrectly, but is likely to be incorrect because of a common mistake, could provide the user with a hint towards this mistake, apply a penalty and allow a second attempt at this question. Quizzes can be run in &#039;adaptive mode&#039;, which provides buttons to mark each question individually.&lt;br /&gt;
&lt;br /&gt;
===Answers===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;answer&#039;&#039;&#039;&#039; is used exclusively for the &#039;&#039;&#039;teacher-defined answers&#039;&#039;&#039; of a question. When talking about the quiz module it is easy to get confused between these teacher-defined answers and the answers that the students actually give. We have therefore adopted the convention to refer to the student-supplied answers as &#039;responses&#039; and to reserve the term &#039;answers&#039; to apply to teacher-defined answers. In question types that rely on teacher-supplied answers these are used in the grading process by comparing them with the student responses. Of course not all question types use teacher-defined answers but use some more intelligent way to process the student responses. &lt;br /&gt;
&lt;br /&gt;
Perhaps one should also stress that &#039;answer&#039; is not always used in the sense of &#039;correct answer&#039;. For example every choice in a multiple-choice question is referred to as an answer. Other systems use the term &#039;distractor&#039; for wrong answers. &lt;br /&gt;
&lt;br /&gt;
In Moodle we always use the term &#039;&#039;&#039;&#039;responses&#039;&#039;&#039;&#039; to refer to the students&#039; responses to a question because term &#039;answers&#039; that one might also be tempted to use for this is already used to refer to the teacher-defined answers, see above. This term is always used in plural, although for some questiontypes there is only one possible response.&lt;br /&gt;
&lt;br /&gt;
===Attempts===&lt;br /&gt;
&lt;br /&gt;
In Moodle the term &#039;&#039;&#039;&#039;attempt&#039;&#039;&#039;&#039; is used in the sense of &amp;quot;Attempt at the quiz&amp;quot;. Depending on the quiz settings, a student may be allowed several attempts at a quiz. An attempt is finished when the student clicks on the corresponding button on the attempt page. Students do not have to complete an attempt in one visit. They can navigate away from the quiz page and return later to continue the same attempt.&lt;br /&gt;
&lt;br /&gt;
Within one and the same quiz attempt a student may make several attempts at answering a particular question, at least if the questiontype allows it and the quiz is set up in adaptive mode. These will always be referred to as &#039;&#039;&#039;&#039;attempts at a question&#039;&#039;&#039;&#039;, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
Because a student can have several attempts at a question within the same attempt at the quiz, there is a lot of data that needs to be stored as the student takes the question through several &#039;&#039;&#039;&#039;states&#039;&#039;&#039;&#039; by repeated interactions with the question. A state object holds the most recent state of the question and whenever a student submits a response or a similar &#039;&#039;&#039;&#039;event&#039;&#039;&#039;&#039; occurs, the question goes to a new state. The complete history of question states that the question is taken through is saved and this is referred to as the question &#039;&#039;&#039;&#039;session&#039;&#039;&#039;&#039;. Usually only the most recent state and the last graded state are of interest though.&lt;br /&gt;
&lt;br /&gt;
==Code documentation==&lt;br /&gt;
&lt;br /&gt;
The code is documented according to phpdoc conventions. The explanations here in the wiki are meant to complement this.&lt;br /&gt;
&lt;br /&gt;
Inline comments should be used liberally in the code. The following conventions make it easier to search for comments with special meaning:&lt;br /&gt;
* use TODO in comments about things that need to be done&lt;br /&gt;
* use ??? in comments that are questions about the code&lt;br /&gt;
&lt;br /&gt;
There are three function libraries:&lt;br /&gt;
&lt;br /&gt;
;questionlib.php&lt;br /&gt;
:All functions that need to be available to any module wanting to use questions. This is New in Moodle 1.6, in Moodle 1.5 this was part of locallib.php. This instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core. This loads constants from &#039;&#039;&#039;constants.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
;locallib.php&lt;br /&gt;
:All functions that are used only by the quiz module. This loads lib.php and questionlib.php&lt;br /&gt;
&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;questiontypes/questiontype.php&#039;&#039;&#039;. The individual questiontypes extend this class in their own questiontype.php file. For documentation of the questiontype classes one should often look at the documentation of the default question type because much of the documentation that is in the default class is not repeated in the other questiontype classes&lt;br /&gt;
&lt;br /&gt;
Constants are defined in .&lt;br /&gt;
&lt;br /&gt;
While questiontypes are realized as classes, the quiz module is not written in a truly object-oriented way. Instead it follows the Moodle model of using objects mostly only as alternatives to arrays to hold database records. So none of the quiz, question, attempt, and state objects that play a central role in the module have any methods. Only the questiontype objects have methods. Strangely enough the quiz module instantiates on object of each questiontype class at the start and then reuses their methods for the different questions. If one is used to the Moodle way of programming then this is easy enough to handle.&lt;br /&gt;
&lt;br /&gt;
==Objects and data structures==&lt;br /&gt;
&lt;br /&gt;
Key to understanding how the quiz module works is to understand the different kinds of object work together. The most important ones are:&lt;br /&gt;
&lt;br /&gt;
*Quizzes&lt;br /&gt;
*Questions&lt;br /&gt;
*Attempts&lt;br /&gt;
*States&lt;br /&gt;
&lt;br /&gt;
Quizzes and Questions are data created by the teacher when setting up and editing a quiz. Attempts and States are data created by the student when interacting with a quiz. &lt;br /&gt;
&lt;br /&gt;
Moodle allows students to make several attempts at a quiz. Data about such an attempt is stored in an attempt object. This holds for example how the quiz was randomized for this attempt and the ordering of the questions and answers. So attempts are indexed by user id and quiz id.&lt;br /&gt;
&lt;br /&gt;
Moodle allows students to interact repeatedly with a single question. So for example the student might initially just save an answer, later mark it, then correct it if it was marked incorrect. Each time the student interacts with a particular question inside a particular attempt at a quiz a new state is created. So states are indexed by user id, attempt id and question id.&lt;br /&gt;
&lt;br /&gt;
===Database structure===&lt;br /&gt;
All this data needs to be kept in Moodle&#039;s database. How this is achieved is explained on a separate page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;, which also contains a useful diagram.&lt;br /&gt;
&lt;br /&gt;
As is customary in Moodle, most runtime objects simply represent the data from a particular database record. So for example a $quiz object has fields corresponding to all the fields in the [[Quiz database structure#quiz|quiz table]]. In some cases the objects have some additional fields that are added at runtime. This is particularly the case for $question and $state objects. These additional fields are also described on the page about the &#039;&#039;&#039;[[Quiz database structure]]&#039;&#039;&#039;. Many functions that are used to process these objects make use of the additional fields and it is therefore necessary to use the correct functions for creating these objects.&lt;br /&gt;
&lt;br /&gt;
===Runtime objects===&lt;br /&gt;
Some objects used by the quiz module are purely runtime object and do not correspond to a database table. The structure of these objects is explained in detail on a separate page about the &#039;&#039;&#039;[[Quiz runtime objects]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The main script of the quiz module is attempt.php which will have to deal with all these objects. Studying the &#039;&#039;&#039;[[Quiz attempt|explanation of attempt.php]]&#039;&#039;&#039; is therefore a good way to start to study the quiz module code.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The student&#039;s responses to a question are stored in &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt;. Questiontypes are completely free to implement the storage mechanism of their responses (and other state information) the way they want. Still, the standard questiontypes all follow a similar model. The default storage model and the questiontype specific variations are explained below.&lt;br /&gt;
&lt;br /&gt;
The flexibility for the questiontypes to choose their response storage mechanism freely and to convert from the storage model to the runtime model is provided by a set of three functions, which allow to initialise the runtime &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field, to convert from the runtime to the storage model and vice versa:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;create_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Initializes the $state object, in particular the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Loads the question type specific session data from the database into the &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; object, in particular it loads the responses that have been saved for the given &amp;lt;code&amp;gt;$state&amp;lt;/code&amp;gt; into the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; field.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;&lt;br /&gt;
:Saves the question type specific session data from the $state object to the database. In particular, for most questiontypes, it saves the responses from the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; to the database.&lt;br /&gt;
&lt;br /&gt;
The generic quiz module code saves the contents form the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; field to the answer field in the [[Quiz database structure#quiz_states|quiz_states table]] and also automatically restores the contents of this field to &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This means that any questiontype, which only expects a single value as its response can skip the implementation of the three methods described above. All questiontypes that have multiple value responses need to implement these methods. &lt;br /&gt;
&lt;br /&gt;
The default questiontypes handle this problem by serializing/de-serializing the responses to/from the answer field in the quiz_states table. However, it is also possible (and may be better practice) to extend the quiz_states table with a questiontype specific table, i.e. take the id of the quiz_states record as a foreign key in the questiontype specific table. Because the value of &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is set to the value of the answer field, questiontypes that serialize their response need to overwrite (in &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt;) whatever value the generic code set this field to with their serialized value (usually achieved with a simple set_field). &lt;br /&gt;
&lt;br /&gt;
In the method &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; the serialized value can be read from &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; because this is where the value from answer field of the quiz_states table has been moved. Care needs to be taken that this array value is then unset or the whole array overwritten, so that the array does not accidentally contain a value with the empty string index.&lt;br /&gt;
&lt;br /&gt;
==Response processing==&lt;br /&gt;
&lt;br /&gt;
The runtime model for responses dictates the structure of the $state-&amp;gt;responses array. Starting with the names of the form elements this section goes through the relevant processing steps and thus attempts to clarify why the keys of the $state-&amp;gt;responses array can differ for different questiontypes; even more, it explains how the array keys are chosen and set.&lt;br /&gt;
&lt;br /&gt;
Although it may initially seem strange to start with the naming convention of the form fields, the reason for this will become clear later on. The controls (i.e. the form fields) of a question get printed by the method &amp;lt;code&amp;gt;print_question_formulation_and_controls()&amp;lt;/code&amp;gt;. The convention only dictates that the name of the control element(s) must begin with the value of &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;$question-&amp;gt;name_prefix&amp;lt;/code&amp;gt; is a string starting with &amp;quot;resp&amp;quot; followed by the question id and an underscore, e.g. &amp;lt;code&amp;gt;resp56_&amp;lt;/code&amp;gt;. In the default case, when there is only a single control element (this includes the case of a list of equally named radio buttons), no postfix is appended to the name prefix. For questiontypes that allow or require multiple form elements, an arbitrary string can be appended to the name prefix to form the name of these form elements. The postfix must not include any relational data (i.e. ids of records in the quiz_answers table), because this can lead to problems with regrading of versioned questions.&lt;br /&gt;
&lt;br /&gt;
After the printing of the question the server only sees it again when it is submitted. So the submitted data will contain several values indexed by strings starting with &amp;lt;code&amp;gt;respXX_&amp;lt;/code&amp;gt;. Upon submission, the function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; is called, which assigns the submitted responses to the state of the question with id XX, using the postfix (i.e. everything after the underscore) as array keys. In the default case with only one control element the name only consists of the name prefix. This explains why the default index of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array is the empty string. The value of each array element is obviously the value that was submitted by the form, basically a raw response.&lt;br /&gt;
&lt;br /&gt;
The function &amp;lt;code&amp;gt;quiz_process_responses()&amp;lt;/code&amp;gt; in turn calls the questiontype specific method &amp;lt;code&amp;gt;grade_responses()&amp;lt;/code&amp;gt; to assign a grade to the submitted responses and &amp;lt;code&amp;gt;compare_responses()&amp;lt;/code&amp;gt; to determine whether the response was identical to the previous submission and to avoid regrading the same responses repeatedly. These questiontype specific functions need to be aware of the expected keys of the &amp;lt;code&amp;gt;$state-&amp;gt;responses&amp;lt;/code&amp;gt; array.&lt;br /&gt;
&lt;br /&gt;
Finally, the methods &amp;lt;code&amp;gt;restore_session_and_responses()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses()&amp;lt;/code&amp;gt; also need to know the questiontype specific layout of the &amp;lt;code&amp;gt;$state-&amp;gt;responses array&amp;lt;/code&amp;gt; and restore or save the information, e.g. by converting from or to the data representation.&lt;br /&gt;
&lt;br /&gt;
==Question types==&lt;br /&gt;
{{Questiontype developer docs}}&lt;br /&gt;
The quiz module is itself modular and allows question type plug-ins. For each question type there should be a page, accessible via the menu at the right, which provides at least the dtails about&lt;br /&gt;
*Database tables&lt;br /&gt;
*Response storage&lt;br /&gt;
*Question options object&lt;br /&gt;
*State options object&lt;br /&gt;
&lt;br /&gt;
It is hoped that Moodlers will contribute a lot of non-core question types in the future. For this it would be good to start a [[Guide to question type plugins]].&lt;br /&gt;
&lt;br /&gt;
==Grades==&lt;br /&gt;
&lt;br /&gt;
The handling of grades is a bit complicated because there are so many different grades around that get rescaled and combined in various ways. This section should summarize how this is done and why.&lt;br /&gt;
&lt;br /&gt;
The following grade fields are being used:&lt;br /&gt;
*$question-&amp;gt;defaultgrade&lt;br /&gt;
::This is the default value for the maximum grade for this question. This is set up when the teacher creates the question and it is stored in an int(10) field in the [[Quiz database structure#quiz_questions|quiz_questions]] table. However when the question is actually used in a particular quiz the teacher can overrule this default and this is stored in:&lt;br /&gt;
*$question-&amp;gt;maxgrade&lt;br /&gt;
::This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in an int(10) field in the [[Quiz database structure#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
*$question-&amp;gt;penalty&lt;br /&gt;
&lt;br /&gt;
*$state-&amp;gt;raw_grade&lt;br /&gt;
*$state-&amp;gt;grade&lt;br /&gt;
*$state-&amp;gt;penalty&lt;br /&gt;
*$state-&amp;gt;sumpenalty&lt;br /&gt;
&lt;br /&gt;
*$attempt-&amp;gt;sumgrades&lt;br /&gt;
&lt;br /&gt;
The maximum grades set by the teacher, $question-&amp;gt;defaultgrade and $question-&amp;gt;maxgrade, are integers. All student-obtained grades are in principle floating point numbers. For historical reasons they are stored in the database as varchar(10) fields. Care has to be taken when writing to the database to make sure all grades are correctly rounded and squeezed into a string of no more than 10 characters, otherwise the writing to database will fail, see bug 4220.&lt;br /&gt;
&lt;br /&gt;
The final outcome of the calculation of the grade for a user at a particular quiz is stored in the &#039;grade&#039; field of the [[Quiz database structure#quiz_grades|quiz_grades table]]. This field has type double.&lt;br /&gt;
&lt;br /&gt;
==Penalty mechanism==&lt;br /&gt;
&lt;br /&gt;
===What it is for===&lt;br /&gt;
&lt;br /&gt;
When the quiz is run in adaptive mode the student can interact with a question repeatedly. So in particular the student can try again when he gets a wrong answer. Clearly the final mark for the question must reflect the fact that the student did not get it right originally. Therefore a penalty is subtracted from the final mark.&lt;br /&gt;
&lt;br /&gt;
===How the penalty is determined===&lt;br /&gt;
&lt;br /&gt;
First of all penalties are relevant only if a quiz is run in adaptive mode. Only in this case can a student have a second attempt and therefore only in this mode can there be any occasion to subtract a penalty.&lt;br /&gt;
&lt;br /&gt;
Even in adaptive mode the penalty mechanism is only used when it is selected in the quiz options. If &amp;quot;Apply penalties&amp;quot; is set to &amp;quot;No&amp;quot; then the final mark for the question is the mark for the last graded response.&lt;br /&gt;
&lt;br /&gt;
Each question has a &#039;penalty&#039; field (which should really be called &#039;penaltyfactor&#039;) which is a number between 0 and 1. The penalty for a wrong response is calculated as the product ($quiz-&amp;gt;penalty * $quiz-&amp;gt;grade), i.e., as the product of the penaltyfactor with the maximum achievable grade for the question. This product is stored in $state-&amp;gt;penalty. So $quiz-&amp;gt;penalty is the fraction of the maximum grade that is subtracted as a penalty for each wrong response.&lt;br /&gt;
&lt;br /&gt;
The $quiz-&amp;gt;penalty field has a default value of 0.1, both in the database and in mod/quiz/defaults.php. This default can of course be overwritten by the admin on the quiz configuration page. This admin-selected default is (as usual for admin defaults) stored in $CFG-&amp;gt;quiz_penalty. The teacher can choose a different penalty factor for each individual question when adding or editing a question.&lt;br /&gt;
&lt;br /&gt;
Now if a student makes repeated wrong attempts (or partially correct attempts) the penalties for all these attempts are added up in $state-&amp;gt;sumpenalties. The mark for the question is then calculated as the mark for the last graded response minus the sum of the penalties.&lt;br /&gt;
&lt;br /&gt;
One curious fact about $state-&amp;gt;sumpenalties is that, for efficiency reasons, it is not stored in the quiz_states table but instead in the &#039;sumpenalty&#039; field of the quiz_newest_states table. That way it only has to be stored once per attempt rather than once per response.&lt;br /&gt;
&lt;br /&gt;
===Where it is done in the code===&lt;br /&gt;
&lt;br /&gt;
The function quiz_apply_penalty_and_timelimit() subtracts the penalty in $state-&amp;gt;sumpenalty from the raw grade in $state-&amp;gt;raw_grade to obtain $state-&amp;gt;grade for the response. However it is ensured that the grade of a new attempt at the question never falls below the previously achieved grade. This function also increases $state-&amp;gt;sumpenalty by the amount in $state-&amp;gt;penalty. The assumption is that $state-&amp;gt;penalty has just been set appropriately by the code calling this function, e.g., quiz_process_responses.&lt;br /&gt;
&lt;br /&gt;
==Time limit==&lt;br /&gt;
&lt;br /&gt;
A quiz can have a time limit. This is stored in minutes in $quiz-&amp;gt;timelimit. So before using this in time calculations it always has to be multiplied by 60 to turn it into seconds like all other timestamps in moodle and php. If $quiz-&amp;gt;timelimit is zero it means there is no timelimit.&lt;br /&gt;
&lt;br /&gt;
If a student asks to start an attempt on view.php for a quiz with a timelimit then he is shown a javascript message alerting him to the timelimit and is asked to confirm.&lt;br /&gt;
&lt;br /&gt;
For quizzes with timelimit attempt.php shows a javascript timer that counts down and automatically submits and closes the attempt when the time is up.&lt;br /&gt;
&lt;br /&gt;
Confusingly there are two javascript timers in the quiz module. jsclock.php provides a countdown in the title bar that counts down to the quiz closing time if this is less than a day away. This has nothing to do with the timelimit. jstimer.php provides the countdown timer that implements the timelimit. It in turn uses timer.js.&lt;br /&gt;
&lt;br /&gt;
The time a response was submitted by the student is recorded by attempt.php right at the top of the page and is then passed on to quiz_process_responses in $action-&amp;gt;timestamp. This puts it into $state-&amp;gt;timestamp. Finally, after the responses have been graded, the function quiz_apply_penalty_and_timelimit() checks that the responses are within the timelimit to within 5% and if not it sets the grade to zero (or the previously obtained grade, if that is higher).&lt;br /&gt;
&lt;br /&gt;
==Pagination==&lt;br /&gt;
&lt;br /&gt;
Quiz attempts can be paginated, i.e., spread over several pages. The student can navigate between the pages using the standard Moodle paging bar. When the student navigates to a different quiz page the answers on the current page are automatically submitted for saving (but not grading).&lt;br /&gt;
&lt;br /&gt;
To do this automatic submission the paging bar needs some javascript. It is therefore not produced with Moodle&#039;s standard print_paging_bar() function from weblib.php but with quiz_print_navigation_panel() which is defined in mod/quiz/locallib.php and produces something that looks the same.&lt;br /&gt;
&lt;br /&gt;
The teacher has complete control via the edit interface on edit.php over where the page breaks should occur. He can repaginate the quiz with any chosen number of questions per page. He can also move the page-breaks up and down using the arrows.&lt;br /&gt;
&lt;br /&gt;
Internally page breaks are stored in the $quiz-&amp;gt;questions field (which now should really be called $quiz-&amp;gt;layout). This field contains a comma separated list of questionids and pagebreaks where the pagebreaks are represented by the id 0. For example 23,12,0,11, 0 means that the two questions with ids 23 and 12 are on the first page and the question with id 11 is on the second page. The last page break is invisible and Moodle sometimes puts it there itself for its own convenience.&lt;br /&gt;
&lt;br /&gt;
Because the quiz has an option $quiz-&amp;gt;shufflequestions to shuffle questions the layout that the student sees in a particular attempt does not necessarily have to be the same as that stored in $quiz-&amp;gt;questions. Therefore each attempt has its own $attemp-&amp;gt;layout field. If $quiz-&amp;gt;shufflequestions is false then this just contains a copy of $quiz-&amp;gt;questions but if it is true then during the creation of a new attempt by quiz_create_attempt() the function quiz_repaginate() is used to produce a layout with $quiz-&amp;gt;questionsperpage number of questions per page that are randomly ordered.&lt;br /&gt;
&lt;br /&gt;
Both attempt.php and review.php use the $attempt-&amp;gt;layout field to determine what questions to show on a particular page. That way we can guarantee that the student will, for a particular attempt, always see the questions in the same order and with the same pagination, both while attempting and during review. Also a teacher when reviewing a student&#039;s attempt sees the pages the same way they were shown to the student. However the teacher is also given the option to see all questions on one page.&lt;br /&gt;
&lt;br /&gt;
There are some functions in locallib.php dedicated to handling the layout fields: quiz_questions_on_page(), quiz_questions_in_quiz(), quiz_number_of_pages(), quiz_first_questionnumber(), quiz_repaginate(). They are very short functions. The function quiz_first_questionnumber() that determines the number of the first question on a particular page makes use of the $question-&amp;gt;length field. To allow this calculation to be fast is the main reason why that field is in the question table even though it could also be determined easily from the question type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Question versioning==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Question versioning is currently disabled until it is re-developed to fix all reported issues.&lt;br /&gt;
&lt;br /&gt;
When questions that were already attempted by a student are edited, it can be important to keep a copy of the question as it was before editing in order to reconstruct the quiz as it was seen by the student. To provide this functionality a question versioning mechanism was implemented.&lt;br /&gt;
&lt;br /&gt;
The first goal, namely keeping around old questions, is easily achieved. They are just not deleted any more. However, this is not enough; it is also necessary to store which questions are versions of others. To achieve this goal, there is an additional table, which stores the versioning information: quiz_question_versions.&lt;br /&gt;
&lt;br /&gt;
When a question is replaced for which there are already student attempts then all the attempt data gets associated to the new version of the question and is re-graded. This requires the question ids in the quiz_attempts, quiz_states and quiz_newest_states tables to be replaced by the new id. However we do also want to be able to reconstruct the quiz the way the student saw it when he gave his answers. For that purpose the id of the original question is always preserved in the &#039;originalquestion&#039; field of the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
If all old versions of questions are kept around this could horribly clutter the editing interface. Therefore a field called hidden was added to the quiz_questions table and all old versions of edited questions are automatically hidden. When this flag is set to 1 the question is not displayed in the list of available questions, unless the user chooses to show them.&lt;br /&gt;
&lt;br /&gt;
While the mechanism above should work as described, there is some additional complexity in order to minimise the number of versions created. If a question is created and has not been attempted by a student yet (this excludes teacher previews of the individual question and the quiz!), the database record will be reused (i.e. overwritten) and no new version will be created. This is especially important when the question is created and the first 2 or 3 mistakes are only noticed during preview.&lt;br /&gt;
&lt;br /&gt;
On the editing screen for questions an additional set of options was introduced (see image).&lt;br /&gt;
Replacement Options&lt;br /&gt;
It shows which quizzes use the edited question and how many students have attempted it in a particular quiz. Based on this information it is then possible to choose in which quizzes the new version of the question should be used and in which ones the old one should remain.&lt;br /&gt;
&lt;br /&gt;
By default the &#039;replace&#039; checkbox for all quizzes that don&#039;t have any students&#039; attempts are checked and in addition, if the question is edited out of a quiz context (i.e. not in the category question list), the &#039;replace&#039; option is checked for that quiz as well.&lt;br /&gt;
&lt;br /&gt;
===Database===&lt;br /&gt;
&lt;br /&gt;
The changes to the database structure are limited to an added field (hidden) in the quiz_questions table and an additional table called quiz_question_versions. However, dealing with the quiz_questions table has become slightly more complicated.&lt;br /&gt;
&lt;br /&gt;
The hidden field in the quiz_questions table has no implications for the core functionality. It is only used to determine, as the name implies, whether the question is shown in the category list or not.&lt;br /&gt;
&lt;br /&gt;
The table quiz_question_versions stores information about the actual change. This information includes the ids of the old question and the new question, the id of the user who did the change and a timestamp. Quite importantly, the id of the quiz, in which the question was replaced is also stored. This means that the versions table provides a history of the different states the quiz went through until it was edited to be at the current state. The information allows to recreate a quiz as it was at any point in time (from a data perspective - this possibility is not used extensively by the code).&lt;br /&gt;
&lt;br /&gt;
===Adjustments to the Data===&lt;br /&gt;
&lt;br /&gt;
When a question is replaced by a newer version, database records are updated in the order shown below (compare with question.php):&lt;br /&gt;
&lt;br /&gt;
* First a new record is inserted into the quiz_question_versions table for each affected quiz (i.e. each quiz in which the question was replaced).&lt;br /&gt;
* Then, for each affected quiz, the comma separated list of question ids in the question field is updated by replacing the old question id with the new one.&lt;br /&gt;
* In the quiz_question_instances table the record that links the old question to the quiz is also updated to point to the new question.&lt;br /&gt;
* In all attempts belonging to the old question the comma-separated list of question ids in the layout field are changed by replacing the old id by the new one.&lt;br /&gt;
* All states belonging to the old question are made to belong to the new version by changing the id in the &#039;question&#039; field. However if we are replacing the original question then the id of this original version is stored in the originalquestion field.&lt;br /&gt;
* We have to change the questionid field in quiz_newest_states.&lt;br /&gt;
* Finally we have to do any question-type specific changes. For example question types that store student responses by storing the id of the answer in the quiz_answers table will have to recode these ids in all the states to point to the corresponding answers in the new version. This is handled by the function replace_question_in_attempts() in the question type class.&lt;br /&gt;
&lt;br /&gt;
===Affected Code and Functionality===&lt;br /&gt;
&lt;br /&gt;
Note: This section should still be considered under construction until the question mark behind bug #3311 is taken off.&lt;br /&gt;
&lt;br /&gt;
In the file review.php and potentially also in the file attempt.php, if a question is edited during a student&#039;s attempt, the data from quiz_question_versions needs to be taken into account. If a student has attempted a quiz and a question was changed afterwards (i.e. a new version of that question was created), the question id of the old version remains in the comma separated list inside the attempt-&amp;gt;layout field. However, since the records in the quiz_question_instances table get updated, we need to go forward in the question history, by looping through entries from the quiz_question_versions table, to find out the id of the question version that is currently used in the quiz.&lt;br /&gt;
&lt;br /&gt;
Suggestion: With a fairly simple change to the convention of what is stored in the quiz_question_versions table we could get rid of the requirement of looping through all the versions. If in the newquestion field we store the id of the question that is currently used in the quiz, it would be possible to get the complete history for a question quite simply by selecting by quiz id and newquestion.&lt;br /&gt;
&lt;br /&gt;
It should be fairly simple to write an upgrade script for this change. Additionally, another set_field would need to be added to question.php to change the newquestion field to the new question id. The benefits would be a much simpler handling of the question history, resulting in more efficient code than the current fix for bug #3311 in review.php.&lt;br /&gt;
&lt;br /&gt;
The place where all the versioning actually takes place is question.php. Here the changes described in Adjustments to the Data are carried out.&lt;br /&gt;
&lt;br /&gt;
Obviously the backup and restore scripts also take quiz_question_versions into account, however, they don&#039;t need to be concerned with the ways the data is used.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.5: adaptive questions==&lt;br /&gt;
&lt;br /&gt;
During the first half of 2005 the quiz module code has undergone a considerable rewrite to allow for adaptive questions in which a question session can consist of several sequential student responses. The question can adapt itself to the student answers. For example in response to certain answers the question could provide feedback or hints and then ask the student to answer again or give the student a simpler or related question.&lt;br /&gt;
&lt;br /&gt;
Unfortunately many changes had to be made to the question type methods. This has however resulted in improved efficiency and has made the writing of question types easier. It also allows question types with more powerful features and has fixed some bugs / annoying behaviour. &lt;br /&gt;
&lt;br /&gt;
For details see:&lt;br /&gt;
*[[Quiz rewrite|Quiz module rewrite]]&lt;br /&gt;
*[[Quiz conversion|How to convert existing question types]]&lt;br /&gt;
&lt;br /&gt;
Of course there were countless other changes to the quiz module going from Moodle 1.4 to 1.5, especially to the teacher interface. However in spite of the fact that these changes are a lot more visible they were much less drastic from the point of view of the code. Here is a very incomplete list of changes:&lt;br /&gt;
&lt;br /&gt;
* New quiz results overview page&lt;br /&gt;
* Reform of the quiz edit page: Changes on the quiz edit page are saved straightaway, not only after Save button is pressed.&lt;br /&gt;
* Copying questions: The teacher can create a new question using a previous one as template.&lt;br /&gt;
* Moving questions: The teacher can now move selected questions to a different category.&lt;br /&gt;
* Re-marking after question editing: if a teacher corrects a question that students have already attempted the teacher can request a remark.&lt;br /&gt;
* Teacher preview tab.&lt;br /&gt;
* Detailed teacher control over what students can see during review.&lt;br /&gt;
&lt;br /&gt;
==Changes for Moodle 1.6: separating questions from quizzes==&lt;br /&gt;
&lt;br /&gt;
The quiz module is not the only activity module in Moodle that uses questions. The lesson does too and potentially questions could be useful in many modules. Therefore we have started to rewrite some  of the quiz module functions and move them from locallib.php to questionlib.php so that eventually they could be moved into a central library and be used by other modules. &lt;br /&gt;
&lt;br /&gt;
Module developers who want to use the &lt;br /&gt;
quiz module questions in their own module should take a look at the simple questiondemo module that you can find in CVS at [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/questiondemo contrib/questiondemo]. The idea is that it will be simpler&lt;br /&gt;
to understand this demonstration module than the code in the quiz module which&lt;br /&gt;
is very complicated due to the many options and features. The interesting code in the questiondemo module is in view.php. There you can see how to&lt;br /&gt;
both render and score questions. This module requires the version of the quiz module from Moodle 1.6dev or later.&lt;br /&gt;
&lt;br /&gt;
The details of the changes are explained on the page [[Separating questions from quizzes]].&lt;br /&gt;
&lt;br /&gt;
==Future plans==&lt;br /&gt;
&lt;br /&gt;
The features below are in no particular order:&lt;br /&gt;
&lt;br /&gt;
* Editing questions: This is about editing questions after students have already attempted them. There needs to be a mechanism to keep the old versions of the question around for auditing purposes.&lt;br /&gt;
* New quiz statistics pages?: These pages should be built by using functions defined by the individual question types.&lt;br /&gt;
* Manual grade override: Teachers should be able to override the automatically calculated grades and should be able to make comments.&lt;br /&gt;
* Off-line questions: The answers to these are handed in off-line in the conventional way (e.g., on paper) and teachers enter marks on Moodle.&lt;br /&gt;
* Batch printing of quiz sheets: We want to be able to hand out question sheets to students so they can start working on the questions before going to the computer.&lt;br /&gt;
* Question preview from question edit page: so the teacher can try the question already before saving the changes.&lt;br /&gt;
* Show table of questions on view.php: gives teachers and students a bit of an overview of the quiz.&lt;br /&gt;
* Extending deadlines for individual students: for example when a student misses a deadline for good reasons.&lt;br /&gt;
* Filtering questions by quiz and by search: More ways to restrict which questions are shown on the quiz editing page.&lt;br /&gt;
* Re-open quizzes for revision: After the due date has passed the quiz could allow practice attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Quiz_preview&amp;diff=4808</id>
		<title>Quiz preview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Quiz_preview&amp;diff=4808"/>
		<updated>2006-02-06T09:52:48Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Asking for volunteers&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quizzes}}&lt;br /&gt;
&lt;br /&gt;
=Quiz attempt=&lt;br /&gt;
&lt;br /&gt;
==For Students==&lt;br /&gt;
&lt;br /&gt;
Any volunteers for writing a help text here that could later become part of the standard Moodle documentation and be made accessible to students via a question mark icon on their attempt page?&lt;br /&gt;
&lt;br /&gt;
==For Teachers==&lt;br /&gt;
This section needs serious editing.&lt;br /&gt;
&lt;br /&gt;
=== Quiz preview ===&lt;br /&gt;
This will show you the quiz the way the student will see it. The only difference is that you will see a little link below each question number that you can click to be taken directly to the question editing page for that question. This makes it convenient for you to correct mistakes in questions straight from the preview page.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;quiz preview&#039;&#039;&#039; enables you to try the quiz. In a preview it will say &#039;Preview check&#039;. Attempting a quiz, it will say which attempt at the test it is. Also, all the questions will have a mark index, i.e. the number of points gained per the number of points that could be gained for doing a given question. You will find it under the question number. Also, each question is given a Submit button. &lt;br /&gt;
&lt;br /&gt;
The quiz questions being answered, you will find three options to go for: &lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Save without submitting&#039;&#039;&#039; - which, as its name says, saves the answers without submitting them &lt;br /&gt;
# &#039;&#039;&#039;Submit page&#039;&#039;&#039; (optional) - which submits only a given quiz page &lt;br /&gt;
# &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; - which saves the whole quiz&lt;br /&gt;
&lt;br /&gt;
[[Category:Teacher]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:True/False_question_type&amp;diff=4805</id>
		<title>Development:True/False question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:True/False_question_type&amp;diff=4805"/>
		<updated>2006-02-06T08:32:36Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Response storage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
An extension of the quiz_questions table the quiz_truefalse table stores the answer ids for the true and for the false answers.&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;trueanswer &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;falseanswer &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
==Response storage==&lt;br /&gt;
The true/false questiontype stores a single answer id (from the table quiz_answers) in the answer field. Each true/false question defines two answer records, one for the &#039;true&#039; option, one for the &#039;false&#039; option, so either of these two ids gets stored as response.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Short_Answer_question_type&amp;diff=4804</id>
		<title>Development:Short Answer question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Short_Answer_question_type&amp;diff=4804"/>
		<updated>2006-02-06T08:32:08Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Response storage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The quiz_shortanswer table is an extension of the quiz_questions table. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field of the quiz_questions table&lt;br /&gt;
;answers &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:A comma separated list of answer ids. This is redundant&lt;br /&gt;
;usecase &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:used to decide whether to do a case sensitive or case insensitive comparison for grading.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
The shortanswer questiontype is the ideal example of the default case. It does not overwrite any of the default implementations of the three methods mentioned above, because it uses the default $state-&amp;gt;responses array indexed with the empty string. The value entered into the shortanswer input field is entered directly into the answer field.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Random_Short-Answer_Matching_question_type&amp;diff=4803</id>
		<title>Development:Random Short-Answer Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Random_Short-Answer_Matching_question_type&amp;diff=4803"/>
		<updated>2006-02-06T08:31:32Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Response storage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The &#039;&#039;&#039;quiz_randomsamatch&#039;&#039;&#039; table is an extension of the quiz_questions table&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id field of the quiz_questions table&lt;br /&gt;
;choose &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;4&#039;,&lt;br /&gt;
:The number of shortanswer questions should be randomly chosen to build this randomsamatch question.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
The random shortanswer matching questiontype reuses the save_session_and_responses method of the matching questiontype and therefore stores its responses in the same format. The difference is that the first id in the pair is the question id (quiz_questions) of the selected shortanswer and the second id is the id of the first correct answer that is found ofr that shortanswer question in the quiz_answers table.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Numerical_question_type&amp;diff=4802</id>
		<title>Development:Numerical question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Numerical_question_type&amp;diff=4802"/>
		<updated>2006-02-06T08:31:04Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Response storage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The numerical questiontype, which inherits the function print_question_formulation_and_controls() from the shortanswer questiontype, has only one response field, so its responses are handled by the default questiontype. The response is stored without any modifications in the answer field of the table quiz_states.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Roadmap&amp;diff=4787</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Roadmap&amp;diff=4787"/>
		<updated>2006-02-05T23:58:20Z</updated>

		<summary type="html">&lt;p&gt;Gustav: link to UTF-8_migration&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This roadmap collects the best information about upcoming features in Moodle.   It is not 100% certain - features may change according to available funding and developers.&lt;br /&gt;
&lt;br /&gt;
== Version 1.6 - Beta expected late February 2006 ==&lt;br /&gt;
&lt;br /&gt;
* [[UTF-8_migration|Unicode]] - Moodle.com, Eloy Lafuente and Koen Roggemans&lt;br /&gt;
::Moodle is now 100% Unicode, which means any language can be mixed together and an end to a number of problems that different character sets caused us.&lt;br /&gt;
* [[MoodleDocs development|Documentation]] - Moodle.com and Helen Foster&lt;br /&gt;
::A new one-stop wiki site for ALL Moodle documentation, including links from Moodle itself&lt;br /&gt;
* [[Database]] - Moodle.com &lt;br /&gt;
::A new activity module that allows collaborative collection of structured data, useful for many things!&lt;br /&gt;
* [[LAMS]] - LAMS Foundation&lt;br /&gt;
::Integrated via a course format and an activity module&lt;br /&gt;
* [[Blogs]] - Daryl Hawes and Moodle.com&lt;br /&gt;
::Allows reflection on an ongoing basis.  Entries are marked and can be viewed by user, course, group, site etc.  Contains new keyword support.  &lt;br /&gt;
* [[Site stats]] - Catalyst&lt;br /&gt;
::Provides statistics at a higher level than before (by course etc.)&lt;br /&gt;
* [[My Moodle]] - Catalyst&lt;br /&gt;
::A dashboard interface that allows an overview for each user of all their courses etc.&lt;br /&gt;
* [[Hive integration]] - Moodle.com and Harvest Road&lt;br /&gt;
::This initial integration with Hive allows teachers to upload, browse, search and select [[mod/resource/index|Resources]] within the external repository.&lt;br /&gt;
* [[Multiple groups]] - Moodle.com and Arab Open University&lt;br /&gt;
::Users can be part of multiple groups within a course&lt;br /&gt;
* [[IMS resource]] - Eloy Lafuente and Alton College&lt;br /&gt;
::Supports the loading of any content package as a resource, plus special support for a repository of NLN materials&lt;br /&gt;
* [[Learning Design export]] - Moodle.com and Open University of The Netherlands&lt;br /&gt;
::We plan to have a very simple export for any Moodle course into IMS LD format, as a proof of concept and to help the community start learning about IMS LD.&lt;br /&gt;
* [[Granularised backup]] - Catalyst and Eloy Lafuente&lt;br /&gt;
* [[Chameleon|Chameleon theme]] - Andy Walker and Urs Hunkler &lt;br /&gt;
:: An interactive Moodle theme&lt;br /&gt;
* [[Multi Authentication]] - Iñaki Arenaza?&lt;br /&gt;
* [[Multi Enrolment]] - Catalyst&lt;br /&gt;
&lt;br /&gt;
== Version 2.0 - Expected end of 2006 ==&lt;br /&gt;
&lt;br /&gt;
* [[IMS Learning Design]] - Moodle.com&lt;br /&gt;
::Support for importing/exporting LD, converting Moodle activities and sequences of activities into a standard format for sharing, and importing standard sequences into Moodle courses&lt;br /&gt;
* [[Conditional activities]] - Moodle.com&lt;br /&gt;
::Allowing dependencies and forced paths through the content&lt;br /&gt;
* [[Roles]] - Moodle.com&lt;br /&gt;
::This new system will allow the creation of custom roles at site, course and activity level&lt;br /&gt;
* [[Metadata]] - Moodle.com&lt;br /&gt;
::Build on the keywords in 1.6 to provide metadata for all activities and courses, linkable to standard lists of metadata such as State-based learning outomes and curricula&lt;br /&gt;
* [[Accessibility]] - Moodle.com &lt;br /&gt;
::Full compliance with all major accessibility standards&lt;br /&gt;
* [[Web Services API]]&lt;br /&gt;
::Providing remote control and access of Moodle services by other systems, as well as sharing of information between Moodle sites with trust relationships.&lt;br /&gt;
* [[Repository API]] - Moodle.com&lt;br /&gt;
::Abstract all file operations to an API that allows plugins for different external repositories&lt;br /&gt;
* [[Student Information API]]&lt;br /&gt;
::API for integrating external systems for managing student information&lt;br /&gt;
* [[Community hub]] - Moodle.com &lt;br /&gt;
::Leverage above improvements into a system to network Moodles together&lt;br /&gt;
&lt;br /&gt;
== Version 2.1 ==&lt;br /&gt;
&lt;br /&gt;
* [[Groups]] &lt;br /&gt;
::Groups can also be defined at the site level, and activities can be assigned to course groups&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
::Interface Moodle activities and repositories to help produce portfolios for internal assessment AND external publication&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=4785</id>
		<title>Development:Quiz database structure</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Quiz_database_structure&amp;diff=4785"/>
		<updated>2006-02-05T23:52:57Z</updated>

		<summary type="html">&lt;p&gt;Gustav: Question type specific tables have been move to questiontype pages&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz data model has a fairly large pool of database tables, so the first step in explaining them is to provide some order. Conceptually it is possible to distinguish between the tables holding the teacher-supplied data, defining quizzes and questions, and the tables storing all the data that is generated when students interact with the quizzes and questions. &lt;br /&gt;
&lt;br /&gt;
A further simplification is possible by separating out the questiontype specific tables. They are logical extensions to other tables and therefore are not necessary for understanding the general basic model. They are therefore explained on the developer documentation page for the individual [[Quiz developer docs#Question types|question types]].&lt;br /&gt;
&lt;br /&gt;
The diagram below shows how the most important tables are linked to one another.&lt;br /&gt;
&lt;br /&gt;
[[image:Quiz_database_tables.gif]]&lt;br /&gt;
&lt;br /&gt;
==Teacher-supplied data==&lt;br /&gt;
&lt;br /&gt;
===quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz table contains the definition for all the quizzes. Each quiz belongs to a course, reflected by the course id, has a name and a short descriptive text (intro), an opening and a closing time and several fields that store the settings of various quiz options, each of which is explained in the quiz help that is linked to from the quiz settings page. &lt;br /&gt;
&lt;br /&gt;
The only field that requires additional information is the optionsflag, which... I will put an explanation here eventually --[[User:Gustav|Gustav]] 06:02, 5 February 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
For quizzes that contain random questions the $quiz object may acquire an additional property&lt;br /&gt;
;questionsinuse&lt;br /&gt;
:A comma separated list of questions that are being used in the quiz. This is used by the random questiontype to avoid choosing a question that is already being used.&lt;br /&gt;
&lt;br /&gt;
===quiz_questions===&lt;br /&gt;
&lt;br /&gt;
This table constitutes the item or question bank, i.e. the repository of defined questions. The quiz_questions table defines the data that is common to questions of all types. &lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) NOT NULL auto_increment,&lt;br /&gt;
:Primary key. This is used as a foreign key in many other tables. for example the quiz_answers table allows to define an arbitrary number of answers that are part of the question. And many questiontypes have their own tables that hold more information about the question.&lt;br /&gt;
&lt;br /&gt;
;category &lt;br /&gt;
:int(10) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_categories|quiz_categories]]&lt;br /&gt;
&lt;br /&gt;
;parent &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. This field is set to zero except in the case of wrapped questions as they are used for example in the multianswer questiontype. When a question wraps around any number of subquestions the subquestions will have their parent id field set to the id of the main question, thus allowing the question to find all its sub-questions (or wrapped questions). If parent is not &#039;0&#039; the question is never shown in a list of questions, because it is not a valid question by itself. This is also used for hiding random questions from the question list. Their parent field is simply set to their own id. &lt;br /&gt;
&lt;br /&gt;
;name&lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Question name that is used in question lists on the quiz editing pages&lt;br /&gt;
&lt;br /&gt;
;questiontext &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Main text of the question&lt;br /&gt;
&lt;br /&gt;
;questiontextformat &lt;br /&gt;
:tinyint(2) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;image &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;defaultgrade &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:Default grade for a question, usually &#039;1&#039;. In the wrapped parts of cloze questions defaultgrade represents the weight of the part.&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:float NOT NULL default &#039;0.1&#039;,&lt;br /&gt;
:The penalty that is applied (if the respective quiz option is set) for an incorrect attempt at the question.&lt;br /&gt;
&lt;br /&gt;
;qtype &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The questiontype of the question. (Constants are defined in locallib.php)&lt;br /&gt;
&lt;br /&gt;
;length &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;1&#039;,&lt;br /&gt;
:This defines how many question numbers are required for this question. It is generally set to &amp;quot;1&amp;quot;, but the description questiontype, for example, sets it to &amp;quot;0&amp;quot;, reflecting the fact that it doesn&#039;t have a question number.&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
:Unique identifier&lt;br /&gt;
&lt;br /&gt;
;version &lt;br /&gt;
:int(10) NOT NULL default &#039;1&#039;,&lt;br /&gt;
:A number representing how often the question was edited.&lt;br /&gt;
&lt;br /&gt;
;hidden &lt;br /&gt;
:int(1) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Controls whether to display a question in the question bank list in edit.php. Hiding questions is  a mechanism to &amp;quot;delete&amp;quot; questions without removing them from the database and thus to allow them to be restored or &amp;quot;unhidden&amp;quot; at a later stage. Also the (unfinished and disabled) [[Quiz_developer_docs#Question_versioning|versioning feature]] uses the hidden field to prevent older versions of a question from cluttering the user interface.&lt;br /&gt;
&lt;br /&gt;
In addition to these static fields, which are part of the generic question definitions, there are some additional fields that are only added to the object at runtime. There are two different kinds of fields: On the one hand there are questiontype specific fields, which are also part of the static question definition, but only apply to some questions. On the other hand there are fields that refer to the question instance, i.e. the question in the context of a particular quiz. The values for these later fields can differ when a question is used in different quizzes.&lt;br /&gt;
&lt;br /&gt;
The runtime fields are added to question objects with the function &amp;lt;code&amp;gt;quiz_get_questions_options()&amp;lt;/code&amp;gt; is called. This in turn calls the questiontype specific &amp;lt;code&amp;gt;get_question_options()&amp;lt;/code&amp;gt; method for to add the options field.&lt;br /&gt;
&lt;br /&gt;
;maxgrade&lt;br /&gt;
:This is the maximum grade that the teacher has assigned to this question in the context of the current quiz. This is by default equal to $questions-&amp;gt;defaultgrade but the teacher can change this when editing the quiz. In the database it is stored in the [[#quiz_question_instances|quiz_question_instances table]].&lt;br /&gt;
&lt;br /&gt;
;instance&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_question_instances|quiz_question_instances]]&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. It provides a namespace for any questiontype specific information that may be stored in this field. It is generally set by the &amp;lt;code&amp;gt;get_question_options&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
;name_prefix&lt;br /&gt;
:The prefix to be used on all interactions printed as part of the question.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables for the teacher-provided data.&lt;br /&gt;
&lt;br /&gt;
===quiz_answers===&lt;br /&gt;
&lt;br /&gt;
This table allows a common way to store one or more teacher-defined answers for each question. It is not mandatory for a questiontype to make use of this table however. A questiontype may choose to store it&#039;s teacher-defined answers in an entirely different way, or even to do away with teacher-defined answers and use some other method to mark the student-supplied answer. For example it could calculate the correct answer on the fly.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:The string that represents the teacher-defined answer that will be compared to the student responses for grading and feedback purposes. The format of this field is entirely up to the question type.&lt;br /&gt;
&lt;br /&gt;
;fraction &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The fraction of the total mark that the student should earn for giving this particular answer. This could be a negative number for wrong answers. Note that it is stored in a varchar(10) field.&lt;br /&gt;
&lt;br /&gt;
;feedback &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:Text that can be displayed to student as feedback when the student&#039;s responses match this particular answer.&lt;br /&gt;
&lt;br /&gt;
In the past there was also a sequence number field was sometimes used to store the order of the different answers and was set to &#039;0&#039; if the order was of no importance.&lt;br /&gt;
&lt;br /&gt;
===quiz_categories===&lt;br /&gt;
&lt;br /&gt;
Categories are provided as a way to organize questions. Each category has a name and a descriptive text (info) and the sortorder as metadata. Categories allow hierarchical nesting via the parent id and can be private or published, i.e. they can be made available to teachers in other courses.&lt;br /&gt;
&lt;br /&gt;
Since categories are simply a means for organising questions they are not vital for understanding how the quiz module works.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;course &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the course table&lt;br /&gt;
&lt;br /&gt;
;name &lt;br /&gt;
varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;info &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
&lt;br /&gt;
;publish &lt;br /&gt;
:tinyint(4) NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;stamp &lt;br /&gt;
:varchar(255) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
;parent int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;sortorder int(10) &lt;br /&gt;
:unsigned NOT NULL default &#039;999&#039;,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical table belongs to the numerical questiontype and is an extension of the quiz_answers table, defining a tolerance value for each answer.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;answer :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;tolerance :varchar(255) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical_units===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical_units table is used by the numerical questiontype and the calculated questionype. It extends the quiz_questions table, defining an arbitrary number of units that can be used in the responses.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;multiplier :decimal(40,20) NOT NULL default &#039;1.00000000000000000000&#039;,&lt;br /&gt;
;unit :varchar(50) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_question_instances===&lt;br /&gt;
&lt;br /&gt;
Questions can be assigned different grades in different quizzes. These are stored in this table. &lt;br /&gt;
&lt;br /&gt;
While, after a small extension, this table could also fulfill the purpose of storing the order of the questions in a quiz, this is currently still done in the questions field in the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz|quiz]] table.&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key to the id of the [[#quiz_questions|quiz_questions]] table.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The maximum grade assigned to this question in this quiz. This grade was set by the teacher on the [[mod/quiz/edit|quiz editing page]]. At runtime this information is stored in the $question-&amp;gt;maxgrade field.&lt;br /&gt;
&lt;br /&gt;
===quiz_question_versions===&lt;br /&gt;
&lt;br /&gt;
This feature is not finished and disabled. The table structure may still change. See [[Quiz developer docs#Question versioning]] for a discussion.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;oldquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;newquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
&lt;br /&gt;
==Student-created data==&lt;br /&gt;
&lt;br /&gt;
===quiz_attempts===&lt;br /&gt;
&lt;br /&gt;
In the quiz_attempts table a record is created each time a user starts an attempt at a quiz. This is one of the important tables and the corresponding $attempt object is passed between many of the quiz module functions and methods.&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the quiz that is attempted&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br /&amp;gt;The id of the user who is attempting the quiz&lt;br /&gt;
;attempt &lt;br /&gt;
:smallint(6) NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;It is possible for a user to attempt a quiz several times, therefore the number of the attempt is stored in this field.&lt;br /&gt;
;sumgrades &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&amp;lt;br&amp;gt;The (unscaled) grade for the attempt, i.e. if the grades assigned to the questions add up to 8, but the maximum grade for the quiz is set to 10, then the sumgrades field can contain 8 at maximum.&lt;br /&gt;
;timestart &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timestart field is set to the current time when an attempt is started and is never changed afterwards.&lt;br /&gt;
;timefinish &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;The timefinish field is set to &amp;quot;0&amp;quot; initially and to the current time when the attempt is closed. This is exploited at several places in the code to determine whether an attempt has been closed or not (i.e. closed = timefinish &amp;gt; 0). For all other modifications of an attempt record the timemodified field should be changed as well.&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;This should be changed each time data in the record is modified.&lt;br /&gt;
;layout &lt;br /&gt;
:text NOT NULL,&amp;lt;br&amp;gt;a comma separated list of question ids, with a &amp;quot;0&amp;quot; denoting a page break. Usually the comma separated list ends with &amp;quot;,0&amp;quot;.&lt;br /&gt;
;preview &lt;br /&gt;
:tinyint(3) unsigned NOT NULL default &#039;0&#039;,&amp;lt;br&amp;gt;A flag that marks a teacher preview (i.e. an attempt by a user with teacher privileges) that may be automatically deleted when the quiz is previewed again, and which is not taken into account when viewing statistics.&lt;br /&gt;
&lt;br /&gt;
===quiz_states===&lt;br /&gt;
&lt;br /&gt;
States are saved for each interaction with a question. This allows a review of the complete history of a user&#039;s interactions with individual questions. The current state is the most important object used by the quiz module runtime code. This $state runtime object has a few additional fields not in the database that will be explained further down. The database fields are:&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;attempt &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_attempts|quiz_attempts]]&lt;br /&gt;
&lt;br /&gt;
;question &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table [[#quiz_questions|quiz_questions]]. The attempt id and the question id together sufficiently identify a question instance that a state belongs to.&lt;br /&gt;
&lt;br /&gt;
;originalquestion &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key: refers to an id in the table quiz_questions. It identifies which question was in use when the student attempted the question. This is part of the [[Quiz_developer_docs#Question_versioning|question versioning]] code.&lt;br /&gt;
&lt;br /&gt;
;seq_number &lt;br /&gt;
:int(6) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A counter that provides information about the sequence in which the states were created.&lt;br /&gt;
&lt;br /&gt;
;answer &lt;br /&gt;
:text NOT NULL,&lt;br /&gt;
:This field is deleted during runtime and replaced with the responses field. For legacy reasons it is still called answer in the database. Questiontypes can store students&#039; responses (usually in a serialized format) in this field using the method save_session_and_responses. Questiontypes are allowed to deviate from this and handle their response storage in any desired way. Some questiontypes do not use this field but instead store the student response in their own table extending this table.&lt;br /&gt;
&lt;br /&gt;
;timestamp &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:A timestamp to record when the state was created. This could mainly be useful for audit purposes.&lt;br /&gt;
&lt;br /&gt;
;event &lt;br /&gt;
:int(4) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Records the event or interaction type that lead from the previouse state to the current one. The field can take the value of any of the following constants (defined in locallib.php):&lt;br /&gt;
:*EVENTOPEN: The attempt has just been opened and this is the initial state of a question, i.e. the user has seen the question did not interact with it yet.&lt;br /&gt;
:*EVENTSAVE: The responses are just being saved, either because the student requested this explicitly or because the student navigated to another quiz page.&lt;br /&gt;
:*EVENTVALIDATE: The student requested a validation of the responses. (This is not supported by all questiontypes.)&lt;br /&gt;
:*EVENTGRADE: The responses are being graded but the question session is not closed. This is generally the case for adaptive questions.&lt;br /&gt;
:*EVENTCLOSE: The responses are being graded and the question session is closed. Usually this happens because the whole attempt closes, either because the student requests it or because the time is up or because we are beyond the due date.&lt;br /&gt;
:*EVENTDUPLICATEGRADE: This is a strange one. It indicates that the responses would have been graded had they not been found to be identical to previous responses.&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:Calculated from the raw grade by deducting the penalty and rescaling to the defaultgrade value of the question. Note that this is a varchar(10) field like most grade-related fields in the quiz module.&lt;br /&gt;
&lt;br /&gt;
;raw_grade &lt;br /&gt;
:varchar(10) NOT NULL default &#039;&#039;,&lt;br /&gt;
:The grade that was achieved for the question scaled to the question&#039;s weight or grade as assigned in the quiz_question_instances table&lt;br /&gt;
&lt;br /&gt;
;penalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
:The penalty incurred during the transition from the previous state to this one. This is different to the cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. &lt;br /&gt;
&lt;br /&gt;
In addition to the database fields a few fields are added to the states at runtime. They are dealt with by the questiontypes with the methods &amp;lt;code&amp;gt;create_session_and_responses&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;restore_session_and_responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;save_session_and_responses&amp;lt;/code&amp;gt; and are defined as follows.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty&lt;br /&gt;
:The cumulative penalty, which can be calculated by adding up all the penalties from previous marking events. For efficiency these cumulative penalties are stored in the table [[#quiz_newest_states|quiz_newest_states]] so that they do not need to be re-calculated each time.&lt;br /&gt;
&lt;br /&gt;
;changed&lt;br /&gt;
:This records whether a change has taken place to the runtime state. This is set to false when the state is restored from the database. Any code which changes the question state must set this field to true amd must increment seq_number. The &amp;lt;code&amp;gt;quiz_save_question_session()&amp;lt;/code&amp;gt; function will save the new state object to the database if the field is set to true.&lt;br /&gt;
&lt;br /&gt;
;responses 	&lt;br /&gt;
:This is automatically set to the value of the database field &amp;lt;code&amp;gt;answer&amp;lt;/code&amp;gt; before that one is removed. The responses field contains an array of responses. In the default case of a single response the value can be found in -&amp;gt;responses[&#039;&#039;]. For questiontypes using several HTML form elements for their responses the array contains a value for each of the interaction elements. The indicies are determined by the name of the elements after the name_prefix is stripped.&lt;br /&gt;
&lt;br /&gt;
;last_graded&lt;br /&gt;
:This field contains another state object representing the most recent graded state in the history of this question attempt. This is necessary, because if a state merely represents a save interaction, it should not affect the session in any way. Therefore another grade interaction has to proceed from the last graded state.&lt;br /&gt;
&lt;br /&gt;
;options&lt;br /&gt;
:Optional field. Similarly to the options field in the question object, this field provides a namespace for any questiontype specific information. The difference is that the information in the state-&amp;gt;options field should be state specific, whereas the question-&amp;gt;options field should be static.&lt;br /&gt;
&lt;br /&gt;
We now deal in alphabetical order with the remaining tables holding the student-created data.&lt;br /&gt;
&lt;br /&gt;
===quiz_grades===&lt;br /&gt;
&lt;br /&gt;
The quiz_grades table merely stores a student&#039;s awarded grade for a quiz. Since it is possible to allow several attempts on a quiz, the grade stored is calculated depending on the quiz setting grademethod. This table exists mainly for convenience, because the values of its fields can be recalculated.&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
:Primary key&lt;br /&gt;
&lt;br /&gt;
;quiz &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the [[#quiz|quiz]] table&lt;br /&gt;
&lt;br /&gt;
;userid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Foreign key refering to the id of the user table&lt;br /&gt;
&lt;br /&gt;
;grade &lt;br /&gt;
:double NOT NULL default &#039;0&#039;,&lt;br /&gt;
:The grade awarded for this quiz to this user&lt;br /&gt;
&lt;br /&gt;
;timemodified &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:Unix timestamp to be updated each time the grade is changed&lt;br /&gt;
&lt;br /&gt;
===quiz_newest_states===&lt;br /&gt;
&lt;br /&gt;
This table exists only for efficiency reasons:&lt;br /&gt;
#Via its &#039;newest&#039; and &#039;newgraded&#039; fields it gives attempt.php a way to quickly find the newest state and the newest graded state for an attempt. It allows the construction of SQL to select all the states that need to be loaded on attempt.php or review.php.&lt;br /&gt;
#Via its &#039;sumpenalty&#039; field it gives quiz_apply_penalty() a quick way for getting at the accumulated penalty that needs to be applied. Without this field the penalties from all previous graded states would have to be added up each time. Not a big deal actually because this could be achieved with a single SQL query (using SUM) but this field was introduced when we still had the multiplicative penalty scheme around which would have been more difficult to recompute.&lt;br /&gt;
&lt;br /&gt;
This table was introduced in Moodle 1.5 and is not populated for all states during the upgrade because on sites with a lot of existing states that could take too long. Rather it is done whenever needed by quiz_upgrade_states().&lt;br /&gt;
&lt;br /&gt;
;id &lt;br /&gt;
:int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
Primary key&lt;br /&gt;
&lt;br /&gt;
;attemptid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_attempts|quiz_attempts]] table&lt;br /&gt;
&lt;br /&gt;
;questionid &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_questions|quiz_questions]] table&lt;br /&gt;
&lt;br /&gt;
;newest &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state for this attempt and this question.&lt;br /&gt;
&lt;br /&gt;
;newgraded &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
Foreign key refering to the id in the [[#quiz_states|quiz_states]] table. This points to the newest state created by a grading event.&lt;br /&gt;
&lt;br /&gt;
;sumpenalty &lt;br /&gt;
:varchar(10) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
This stores the total penalty that this user has accumulated over previous graded responses to this question in this attempt.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4784</id>
		<title>Development:Dataset dependent</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4784"/>
		<updated>2006-02-05T23:41:00Z</updated>

		<summary type="html">&lt;p&gt;Gustav: /* Database tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_definitions=== &lt;br /&gt;
This table is an indirect extension to the quiz_questions table, because the quiz_question_datasets table can link a question to one or more datasets. Each dataset represents a variable, that is used either in the questiontext or in the answer to a dataset dependent question.&lt;br /&gt;
&lt;br /&gt;
===quiz_dataset_items===&lt;br /&gt;
&lt;br /&gt;
Dataset items can be created for each dataset. The quiz_dataset_items table stores these possible values for the variables defined in the quiz_dataset_definitions table. &lt;br /&gt;
&lt;br /&gt;
===quiz_question_datasets===&lt;br /&gt;
&lt;br /&gt;
The quiz_question_datasets table is used by dataset dependent questionypes (i.e. calculated) to link datasets to questions.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4783</id>
		<title>Development:Dataset dependent</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/401/en/index.php?title=Development:Dataset_dependent&amp;diff=4783"/>
		<updated>2006-02-05T23:38:13Z</updated>

		<summary type="html">&lt;p&gt;Gustav: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
This is an abstract questiontype that is currently only used by the calculated questiontype.&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Gustav</name></author>
	</entry>
</feed>