<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Delius</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Delius"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Delius"/>
	<updated>2026-04-17T16:09:04Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Roles&amp;diff=3170</id>
		<title>Roles</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Roles&amp;diff=3170"/>
		<updated>2008-10-26T10:00:15Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* The existing system */  Changed title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 1.7}}&lt;br /&gt;
&#039;&#039;&#039;Roles and permissions&#039;&#039;&#039; is in Moodle 1.7 onwards.&lt;br /&gt;
&lt;br /&gt;
==Definitions==&lt;br /&gt;
&lt;br /&gt;
A role is an identifier of the user&#039;s status in some context. For example: Teacher, Student and Forum moderator are examples of roles.&lt;br /&gt;
&lt;br /&gt;
A capability is a description of some particular Moodle feature. Capabilities are associated with roles. For example, &#039;&#039;mod/forum:replypost&#039;&#039; is a capability.&lt;br /&gt;
&lt;br /&gt;
A permission is some value that is assigned for a capability for a particular role.  For example, allow or prevent.&lt;br /&gt;
&lt;br /&gt;
A context is a &amp;quot;space&amp;quot; in the Moodle, such as courses, activity modules, blocks etc.&lt;br /&gt;
&lt;br /&gt;
==The system prior to v1.7==&lt;br /&gt;
&lt;br /&gt;
In versions prior to v1.7, Moodle uses a fixed set of roles i.e. primary admin, admins, course creators, editing teachers, non-editing teachers, students, and guests. For each role, the capability or actions that they can perform are fixed. For example, the role student allows the user to submit an assignment, but doesn&#039;t allow the user to browse/edit other users&#039; work. By using this setup we limit ourselves to a rather rigid set of capabilities for each role. If we want, say a particular student or group to be able to mark assignments in a particular course, we can&#039;t do that without giving these users teacher privileges.&lt;br /&gt;
&lt;br /&gt;
==The new roles and capability system==&lt;br /&gt;
&lt;br /&gt;
With v1.7 and greater, Moodle introduces a roles and capabilities system.&lt;br /&gt;
&lt;br /&gt;
Role has two primary functions:&lt;br /&gt;
# define list of permissions - role definition is global for all contexts, but can be changed by local context overrides&lt;br /&gt;
# replace old course enrolments - role assignment in course context is similar to the old enrolment process&lt;br /&gt;
&lt;br /&gt;
The new system will allow authorized users to define an arbitrary number of roles (eg a teacher) &lt;br /&gt;
&lt;br /&gt;
A role consists of a list of permissions for different possible actions within Moodle (eg delete discussions, add activities etc)&lt;br /&gt;
&lt;br /&gt;
Roles can be applied to users in a context (eg assign Fred as a teacher in a particular course)&lt;br /&gt;
&lt;br /&gt;
Here are the possible contexts, listed from the most general to the most specific. &lt;br /&gt;
&lt;br /&gt;
[[Image:Moodle-contexts-1.8.png|right|thumbnail|200px|A diagram of the contexts in Moodle. Click on the diagram to see a more detailed view of it.]]&lt;br /&gt;
&lt;br /&gt;
#CONTEXT_SYSTEM       -- the whole site&lt;br /&gt;
#CONTEXT_USER         -- another user&lt;br /&gt;
#CONTEXT_COURSECAT    -- a course category&lt;br /&gt;
#CONTEXT_COURSE       -- a course&lt;br /&gt;
#CONTEXT_MODULE       -- an activity module&lt;br /&gt;
#CONTEXT_BLOCK        -- a block&lt;br /&gt;
&lt;br /&gt;
Please note that CONTEXT_PERSONAL (present in 1.7-1.8) was never implemented and was removed in 1.9. CONTEXT_GROUP is also not implemented and can not be used.&lt;br /&gt;
&lt;br /&gt;
An authorized user will be able to assign an arbitrary number of roles to each user in any context.&lt;br /&gt;
&lt;br /&gt;
Capabilities can have the following permissions:&lt;br /&gt;
&lt;br /&gt;
#CAP_INHERIT&lt;br /&gt;
#CAP_ALLOW&lt;br /&gt;
#CAP_PREVENT&lt;br /&gt;
#CAP_PROHIBIT&lt;br /&gt;
&lt;br /&gt;
If no permission is defined, then the capability permission is inherited from a context that is more general than the current context. If we define different permission values for the same capability in different contexts, we say that we are overriding the capability in the more specific context.&lt;br /&gt;
&lt;br /&gt;
Since the capabilities in each role could be different, there could be conflict in capabilities. This is resolved by enforcing the rule that the capability defined for a more specific context will win, unless a prohibit is encountered in a less specific context.&lt;br /&gt;
&lt;br /&gt;
For example, Mark has a student role at course level, which allows him to write into a wiki. But Mark also got assigned a Visitor role at a module context level (for a particular wiki) which prevents him from writing to the wiki (read only). Therefore, for this particular wiki, Mark will not be able to write to the wiki since the more specific context wins.&lt;br /&gt;
&lt;br /&gt;
If we set a PROHIBIT on a capability, it means that the capability cannot be overridden and will ALWAYS  have a permission of prevent (deny). Prohibit always wins.   For example, Jeff has a naughty student role that prohibits him from postings in any forums (for the whole site), but he&#039;s also assigned a facilitator role in &amp;quot;Science forum&amp;quot; in the course Science and Math 101. Since prohibit always wins, Jeff is unable to post in &amp;quot;Science forum&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Allow and prevent will cancel each other out if set for the same capability at the same context level. If this happens, we refer to the previous context level to determine the permission for the capability.&lt;br /&gt;
&lt;br /&gt;
This may sound more complex than it really is in practice.  The upshot is that the system can be flexible enough to allow pretty much any combination of permissions.&lt;br /&gt;
&lt;br /&gt;
===Capability-locality changes in v1.9===&lt;br /&gt;
&lt;br /&gt;
When resolving conflicts between &amp;quot;allow&amp;quot; and &amp;quot;prevent&amp;quot; in v1.7 and v1.8 the locality of the capability is taken into account, although with less weight than the locality of the role assignment. In v1.9 the process has been simplified, we consider locality of the role assignment when dealing with allow/prevent conflicts, but ignore where the capability has been defined (as long as it applies to the context).&lt;br /&gt;
&lt;br /&gt;
For example - for the situation where there is&lt;br /&gt;
&lt;br /&gt;
* two roles assigned to one user in a context (eg student role and teacher role)&lt;br /&gt;
* one override on one of those roles ( eg student role), at the same context&lt;br /&gt;
 &lt;br /&gt;
then&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;1.7/1.8&#039;&#039;&#039; The override used to &#039;&#039;always&#039;&#039; win over the settings from the combined roles.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;1.9&#039;&#039;&#039; The override is combined with the student role first. and then the roles are combined. This is more logical, as the override is acting like a modification to the student role.&lt;br /&gt;
&lt;br /&gt;
For more details, see [http://tracker.moodle.org/browse/MDL-11218 MDL-11218]&lt;br /&gt;
&lt;br /&gt;
==Upgrading from 1.6==&lt;br /&gt;
&lt;br /&gt;
A smooth upgrade will be provided with 1.7. The existing roles (admin, teacher, student, etc), and the existing capabilities will be automatically retained.  This is done by creating default roles at site/course levels, and assigning the current users to these roles accordingly. The default roles will have default capabilities associated with them, mirroring what we have  in 1.6.   With no modifications, Moodle will operate exactly the same before and after the upgrade.&lt;br /&gt;
&lt;br /&gt;
===Admins===&lt;br /&gt;
&lt;br /&gt;
Admin users will be assigned the default legacy admin role in the system (site) context&lt;br /&gt;
&lt;br /&gt;
===Course Creators===&lt;br /&gt;
&lt;br /&gt;
Course Creators will be assigned the default legacy course creator role in the system (site) context&lt;br /&gt;
&lt;br /&gt;
===Teachers===&lt;br /&gt;
&lt;br /&gt;
Users who were teachers will be assigned the default legacy teacher role (or non-editing teacher role) in all courses they were teacher.&lt;br /&gt;
&lt;br /&gt;
===Students===&lt;br /&gt;
&lt;br /&gt;
Users who were students will be assigned the default student role in all courses they were student.&lt;br /&gt;
&lt;br /&gt;
===Guests===&lt;br /&gt;
&lt;br /&gt;
There will still be a single guest user with no default role at site level.   For each course that allows guest access, the guest role will be assigned to the guest user for that course context.   The guest control for the course will be modified from three to two options (guests always need to enter enrolment key - on/off).  This setting is checked as now to force guests to enter key.&lt;br /&gt;
&lt;br /&gt;
==Capabilities==&lt;br /&gt;
&lt;br /&gt;
This will be a comprehensive list of capabilities (it&#039;s not complete yet). It is important that capability names are unique.&lt;br /&gt;
&lt;br /&gt;
===Core-level Capabilities===&lt;br /&gt;
&lt;br /&gt;
Moodle core capability names start with &#039;moodle/&#039;.  The next word indicates what type of core capability it is, and the last word is the actual capability itself.  The capabilities for the Moodle core are defined in lib/db/access.php&lt;br /&gt;
&lt;br /&gt;
#moodle/legacy:guest - legacy capabilities are used to transition existing users to the new roles system during the upgrade to Moodle 1.7&lt;br /&gt;
#moodle/legacy:student&lt;br /&gt;
#moodle/legacy:teacher&lt;br /&gt;
#moodle/legacy:editingteacher&lt;br /&gt;
#moodle/legacy:coursecreator&lt;br /&gt;
#moodle/legacy:admin&lt;br /&gt;
#moodle/site:doanything - special capability, meant for admins, if is set, overrides all other capability settings&lt;br /&gt;
#moodle/site:config - applicable in admin/index.php and config.php (might break down later) : 1)admin/config.php 2)admin/configure.php 3)blocks/admin/block_admin.php load_content_for_site()&lt;br /&gt;
#moodle/site:readallmessages - reads all messages and history&lt;br /&gt;
#moodle/site:approvecourse - approves a pending course&lt;br /&gt;
#moodle/site:manageblocks - adding/removing/editing blocks (site, course contexts only for now) : 1)_add_edit_controls moodleblock.class.php &lt;br /&gt;
#moodle/site:backup - can create a course backup : 1)course/category.php 2)block_admin.php&lt;br /&gt;
#moodle/site:restore - can restore into this context : 1)course/category.php 2)block_admin.php&lt;br /&gt;
#moodle/site:import - can import other courses into this context : 1)block_admin.php&lt;br /&gt;
#moodle/site:accessallgroups - able to access all groups irrespective of what group the user is in&lt;br /&gt;
#moodle/site:accessdb - directly accessing db (phpmyadmin)&lt;br /&gt;
#moodle/site:viewfullnames - able to see fullnames of other users&lt;br /&gt;
#moodle/site:viewparticipants - able to view participants&lt;br /&gt;
#moodle/site:viewreports - able to view site/course reports&lt;br /&gt;
#moodle/site:trustcontent - ability to use trusttext feature and bypass cleaning in specific areas&lt;br /&gt;
#moodle/site:uploadusers - ability to upload/update users from text file; moodle/role:assign capability is needed for course enrolling&lt;br /&gt;
#moodle/blog:view - read blogs (usable in system or course context)&lt;br /&gt;
#moodle/blog:create - write new blog posts (usable in system context only)&lt;br /&gt;
#moodle/blog:manageofficialtags - create/delete official blog tags that others can use (usable in system context only)&lt;br /&gt;
#moodle/blog:managepersonaltags - delete personal blog tags that others can use (usable in system context only) Note: users can always add own personal tags. This setting should be off for students by default.&lt;br /&gt;
#moodle/blog:manageentries - edit/delete all blog entries (usable in system context only)&lt;br /&gt;
#moodle/course:setcurrentsection - mark course section&lt;br /&gt;
#moodle/course:create - create courses : 1)course/edit.php 2)course/category.php 3)course/index.php&lt;br /&gt;
#moodle/course:delete - create courses : 1)course/category.php&lt;br /&gt;
#moodle/course:update - update course settings&lt;br /&gt;
#moodle/course:view - can use this to find participants&lt;br /&gt;
#moodle/course:viewparticipants - allows a user to view participant list&lt;br /&gt;
#moodle/course:viewscales - view scales (i.e. in a help window?) : 1)course/scales.php&lt;br /&gt;
#moodle/course:manageactivities - adding/removing/editing activities and resources (don&#039;t think it makes any sense to split these)&lt;br /&gt;
#moodle/course:managescales - add, delete, edit scales, move scales up and down : 1)blocks/block_admin.php 2)course/scales.php&lt;br /&gt;
#moodle/course:managegroups - managing groups, add, edit, delete : 1)course/groups.php 2)course/group.php&lt;br /&gt;
#moodle/course:managefiles - manage course files and folders&lt;br /&gt;
#moodle/course:managequestions - manage course questions&lt;br /&gt;
#moodle/course:managemetacourse - manage child courses in metacourse&lt;br /&gt;
#moodle/course:reset - able to reset the course&lt;br /&gt;
#moodle/course:useremail - Can use the enable/disable email stuff&lt;br /&gt;
#moodle/course:visibility - hide/show courses : 1)course/category.php&lt;br /&gt;
#moodle/course:viewhiddencourses - see hidden courses&lt;br /&gt;
#moodle/course:activityvisibility - hide/show activities within a course&lt;br /&gt;
#moodle/course:viewhiddenactivities - able to see activities that have been hidden&lt;br /&gt;
#moodle/course:sectionvisibility - hide/show sections&lt;br /&gt;
#moodle/course:viewhiddensections - view hidden sections&lt;br /&gt;
#moodle/course:viewcoursegrades - views all grades in course&lt;br /&gt;
#moodle/course:viewhiddenuserfields - view all hidden user fields&lt;br /&gt;
#moodle/course:managegrades - manages grades settings in course&lt;br /&gt;
#moodle/category:create - create category : 1)course/index.php&lt;br /&gt;
#moodle/category:delete - delete category : 1)course/index.php&lt;br /&gt;
#moodle/category:update - update category settings (sort and rename) this is currently an admin capability : 1)course/category.php&lt;br /&gt;
#moodle/category:visibility - hide/show categories : 1)course/index.php&lt;br /&gt;
#moodle/user:viewusergrades - view your own, or other user&#039;s grades (with specified context)&lt;br /&gt;
#moodle/user:create - create user : 1) user/edit.php&lt;br /&gt;
#moodle/user:delete - delete user : 1) admin/user.php&lt;br /&gt;
#moodle/user:readuserblogs - read blog entries&lt;br /&gt;
#moodle/user:update - update user settings : 1) user/edit.php&lt;br /&gt;
#moodle/user:viewdetails - view personally-identifying user details (e.g. name, photo).&lt;br /&gt;
#moodle/user:viewhiddendetails - view user details marked as &amp;quot;hidden&amp;quot;&lt;br /&gt;
#moodle/calendar:manageownentries - create/edit/delete &lt;br /&gt;
#moodle/calendar:manageentries - create/edit/delete&lt;br /&gt;
#moodle/role:assign - assign roles to users&lt;br /&gt;
#moodle/role:override - can override role capabilities (depending on context)&lt;br /&gt;
#moodle/role:manage - create/edit/delete roles, set capability permissions for each role&lt;br /&gt;
#moodle/role:unassignself - unassign yourself from your own roles&lt;br /&gt;
#moodle/role:viewhiddenassigns - view role assignments that have been marked as hidden&lt;br /&gt;
#moodle/question:import - imports questions (course level?) - Yes, question permissions currently need to be course-level.--[[User:Tim Hunt|Tim Hunt]]&lt;br /&gt;
#moodle/question:export - exports questions (course level?)&lt;br /&gt;
#moodle/question:managecategory - add/delete/edit question categories (course level?)&lt;br /&gt;
#moodle/question:manage - add/edit/delete a question (course level)&lt;br /&gt;
&lt;br /&gt;
===User-level Capabilities===&lt;br /&gt;
# moodle/user:readuserposts -read individual user posts on profile page (parent?)&lt;br /&gt;
# moodle/user:readuserblogs -read individual user blogs on profile page (parent?)&lt;br /&gt;
# moodle/user:viewuseractivitiesreport-read individual activity report on profile page (parent?)&lt;br /&gt;
# moodle/user:editprofile - edit profile (normally used in CONTEXT_USERID and CONTEXT_SYSTEM)&lt;br /&gt;
&lt;br /&gt;
===Module-level Capabilities===&lt;br /&gt;
The capabilities are cached into a database table when a module is installed or updated. Whenever the capability definitions are updated, the module version number should be bumped up so that the database table can be updated.&lt;br /&gt;
&lt;br /&gt;
The naming convention for capabilities that are specific to modules and blocks is &#039;mod/mod_name:capability&#039;.  The part before the colon is the full path to the module in the Moodle code.  The module capabilities are defined in mod/mod_name/db/access.php.&lt;br /&gt;
&lt;br /&gt;
#Assignment&lt;br /&gt;
##mod/assignment:view- reading the assignment description&lt;br /&gt;
##mod/assignment:submit - turn assignment in&lt;br /&gt;
##mod/assignment:grade - grading, viewing of list of submitted assignments&lt;br /&gt;
#Chat&lt;br /&gt;
##mod/chat:chat - allows a user to participate in this chat&lt;br /&gt;
##mod/chat:readlog - allows a user to read past chat session logs&lt;br /&gt;
##mod/chat:deletelog - allows a user to delete past chat logs&lt;br /&gt;
#Choice&lt;br /&gt;
##mod/choice:choose - make a choice&lt;br /&gt;
##mod/choice:readresponses - read all responses&lt;br /&gt;
##mod/choice:deleteresponses - deletes all responses&lt;br /&gt;
##mod/choice:downloadresponses - download responses&lt;br /&gt;
#Database&lt;br /&gt;
##mod/data:viewentry - reads other people&#039;s entry&lt;br /&gt;
##mod/data:writeentry - add / edit and delete (own) entries&lt;br /&gt;
##mod/data:managetemplates - add, delete, edit fields and templates&lt;br /&gt;
##mod/data:manageentries - edit/delete all entries&lt;br /&gt;
##mod/data:comment - comment&lt;br /&gt;
##mod/data:managecomments - edit/delete all comments&lt;br /&gt;
##mod/data:rate - rate an entry&lt;br /&gt;
##mod/data:viewrating&lt;br /&gt;
##mod/data:approve - approves an entry&lt;br /&gt;
##mod/data:uploadentries - batch upload of entries&lt;br /&gt;
#Exercise&lt;br /&gt;
##mod/exercise:assess&lt;br /&gt;
#Forum&lt;br /&gt;
##mod/forum:viewdiscussion&lt;br /&gt;
##mod/forum:viewdiscussionsfromallgroups&lt;br /&gt;
##mod/forum:viewhiddentimedposts&lt;br /&gt;
##mod/forum:startdiscussion&lt;br /&gt;
##mod/forum:replypost&lt;br /&gt;
##mod/forum:viewrating&lt;br /&gt;
##mod/forum:viewanyrating&lt;br /&gt;
##mod/forum:rate&lt;br /&gt;
##mod/forum:createattachment&lt;br /&gt;
##mod/forum:deleteownpost&lt;br /&gt;
##mod/forum:deleteanypost&lt;br /&gt;
##mod/forum:splitdiscussions&lt;br /&gt;
##mod/forum:movediscussions&lt;br /&gt;
##mod/forum:editanypost&lt;br /&gt;
##mod/forum:viewqandawithoutposting&lt;br /&gt;
##mod/forum:viewsubscribers&lt;br /&gt;
##mod/forum:managesubscriptions&lt;br /&gt;
##mod/forum:throttlingapplies&lt;br /&gt;
#Glossary&lt;br /&gt;
##mod/glossary:write - add entries&lt;br /&gt;
##mod/glossary:manageentries - add, edit, delete entries&lt;br /&gt;
##mod/glossary:managecategories - create, delete, edit categories&lt;br /&gt;
##mod/glossary:comment - comment on an entry&lt;br /&gt;
##mod/glossary:managecomments - edit, delete comments&lt;br /&gt;
##mod/glossary:import - import glossaries&lt;br /&gt;
##mod/glossary:export - export glossaries&lt;br /&gt;
##mod/glossary:approve - approve glossaries&lt;br /&gt;
##mod/glossary:rate - rates glossary&lt;br /&gt;
##mod/glossary:viewrating - view ratings&lt;br /&gt;
#Hotpot&lt;br /&gt;
##mod/hotpot:attempt - attempt a hotpot&lt;br /&gt;
##mod/hotpot:viewreport - review and view reports&lt;br /&gt;
##mod/hotpot:grade - (grade? and) regrade&lt;br /&gt;
##mod/hotpot:deleteattempt - deletes attempts&lt;br /&gt;
#Label&lt;br /&gt;
##none&lt;br /&gt;
#Lams&lt;br /&gt;
##mod/lams:participate - original student&lt;br /&gt;
##mod/lams:manage - original teacher&lt;br /&gt;
#Lesson&lt;br /&gt;
##mod/lesson:edit - add and edit pages&lt;br /&gt;
##mod/lesson:manage - view student attempts&lt;br /&gt;
#Quiz&lt;br /&gt;
##mod/quiz:grade - comment, override grade, manual grade&lt;br /&gt;
##mod/quiz:preview - previews the quiz&lt;br /&gt;
##mod/quiz:viewreports - view quiz result reports&lt;br /&gt;
##mod/quiz:manage - add/delete/move (up or down) questions for a quiz&lt;br /&gt;
##mod/quiz:attempt - attempt the quiz--[[User:Tim Hunt|Tim Hunt]]&lt;br /&gt;
#Resource&lt;br /&gt;
#Scorm&lt;br /&gt;
##mod/scorm:viewgrades&lt;br /&gt;
#Survey&lt;br /&gt;
##mod/survey:download - downloads survery result&lt;br /&gt;
##mod/survey:participate - participate/ do survey&lt;br /&gt;
##mod/survey:readresponses - read all user&#039;s responese&lt;br /&gt;
#Wiki&lt;br /&gt;
##mod/wiki:participate - original student, meaning depends of type and course setting&lt;br /&gt;
##mod/wiki:manage - original teacher, manages assigned group; moodle/site:accessallgroups is needed to manage all groups &lt;br /&gt;
##(Waiting on new wiki)&lt;br /&gt;
#Workshop&lt;br /&gt;
##mod/workshop:participate - original student, allows user to submit and assess&lt;br /&gt;
##mod/workshop:manage - original teacher, user can manage others&lt;br /&gt;
##(Waiting on new Workshop)&lt;br /&gt;
&lt;br /&gt;
===Enrolment-level Capabilities===&lt;br /&gt;
&lt;br /&gt;
The naming convention for capabilities that are specific to enrolment is &#039;enrol/enrol_name:capability&#039;. The enrolment capabilities are defined in enrol/enrol_name/db/access.php.&lt;br /&gt;
&lt;br /&gt;
#Authorize.net Payment Gateway &lt;br /&gt;
##enrol/authorize:managepayments - manage user payments, capture, void, refund, delete etc.&lt;br /&gt;
&lt;br /&gt;
===Blocks===&lt;br /&gt;
#activity_modules&lt;br /&gt;
##None&lt;br /&gt;
#admin&lt;br /&gt;
#admin_2&lt;br /&gt;
#admin_bookmarks&lt;br /&gt;
#blog_menu&lt;br /&gt;
#blog_tags&lt;br /&gt;
#calendar_month&lt;br /&gt;
#calendar_upcoming&lt;br /&gt;
#course_list&lt;br /&gt;
#course_summary&lt;br /&gt;
#glossary_random&lt;br /&gt;
#html&lt;br /&gt;
#loancalc&lt;br /&gt;
#login&lt;br /&gt;
#messages&lt;br /&gt;
#news_items&lt;br /&gt;
#online_users&lt;br /&gt;
#participants&lt;br /&gt;
#quiz_results&lt;br /&gt;
#recent_activity&lt;br /&gt;
#rss_client&lt;br /&gt;
##block/rss_client:createprivatefeeds&lt;br /&gt;
##block/rss_client:createsharedfeeds&lt;br /&gt;
##block/rss_client:manageownfeeds&lt;br /&gt;
##block/rss_client:manageanyfeeds&lt;br /&gt;
#search&lt;br /&gt;
#search_forums&lt;br /&gt;
#section_links&lt;br /&gt;
#site_main_menu&lt;br /&gt;
#social_activities&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
I am adding question categories here because they seem to have been forgotten in the whole scheme of things since having been removed from the quiz module itself. I&#039;ve made a suggestion on how these could be handled in [http://www.moodle.org/bugs/bug.php?op=show&amp;amp;bugid=6118&amp;amp;pos= bug 6118].&lt;br /&gt;
&lt;br /&gt;
See [http://moodle.org/mod/forum/discuss.php?d=51143 this forum thread] for a discussion about the current problems wth publishing question categories.[[User:Tim Hunt|Tim Hunt]] 18:50, 8 August 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
==Programming Interface==&lt;br /&gt;
&lt;br /&gt;
Although the Roles system may look complicated at first glance, implementing it in Moodle code is fairly simple.&lt;br /&gt;
&lt;br /&gt;
* You need to define each capability once, so that Moodle can upgrade existing roles to take advantage of it.  You do this in an access.php inside the db folder of any module (eg see mod/forum/db/access.php).  The array contains entries like this (note the descriptions for the legacy roles which provides forward compatibility):&lt;br /&gt;
    &#039;mod/forum:viewforum&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;legacy&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;guest&#039; =&amp;gt; CAP_PREVENT,&lt;br /&gt;
            &#039;student&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;teacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;coursecreator&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;admin&#039; =&amp;gt; CAP_ALLOW&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
* To load/change these capabilities you need to bump the module version.   There&#039;s no need to provide changes or differences as Moodle will scan the whole array and sort it out.&lt;br /&gt;
* On each page you need to find the context the user is working in, using the get_context_instance() function.  For example, in the forum module:&lt;br /&gt;
&lt;br /&gt;
  $context = get_context_instance(CONTEXT_MODULE, $cm-&amp;gt;id);&lt;br /&gt;
* or to at the course level:&lt;br /&gt;
  $context = get_context_instance(CONTEXT_COURSE, $id);&lt;br /&gt;
* Then, whenever you want to check that the current user has rights to do something, call has_capability() like this:&lt;br /&gt;
    if (!has_capability(&#039;mod/forum:viewforum&#039;, $context)) {&lt;br /&gt;
        print_error(&#039;nopermissiontoviewforum&#039;);&lt;br /&gt;
    }&lt;br /&gt;
* If you just want to assert a capability and then finish with an error message if it&#039;s not met (as we did above), then a shorter way it to use require_capability() like this:&lt;br /&gt;
&lt;br /&gt;
    require_capability(&#039;mod/forum:viewforum&#039;, $context);&lt;br /&gt;
&lt;br /&gt;
* Note that there are extra parameters you can specify to get a custom error message, otherwise users get an automated &amp;quot;No permissions&amp;quot; message that lists the permission they were missing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As a result of the new Roles System, all calls to isadmin(), iscoursecreator, isteacheredit(), isteacher(), isstudent(), and isguest() will have to be replaced with calls to has_capability() or require_capability().   However, these functions will be retained for some backward compatibility with old code, using the legacy capabilities to try and work out what to do.&lt;br /&gt;
&lt;br /&gt;
==Metacourses==&lt;br /&gt;
&lt;br /&gt;
The behaviour of metacourses in Moodle 1.7 changed slightly, in that where it used to just synch students from child courses to the parent course, it will now synch ALL roles. Teachers etc of the child courses will have the same role in the meta course. Technically metacourse synchronises all role assignments in CONTEXT_COURSE with its child courses; the only exception are users with moodle/course:managemetacourse capability, these users are synchronized only upwards, they are not unenrolled from metacourse when unenroling from child course or when removing the child from metacourse.&lt;br /&gt;
&lt;br /&gt;
In order to import/enrol other courses into metacourse you need to have moodle/course:managemetacourse capability. You can add manually only participants with moodle/course:managemetacourse, all other participants are automatically synced with child courses - if you try to manually enrol user without this capability error is displayed. Similar error is shown also when you try to manually unenrol participant from meta course while still being enrolled in child course.&lt;br /&gt;
&lt;br /&gt;
Sample setup:&lt;br /&gt;
* metacourse manager has been assigned role with moodle/course:managemetacourse capability in system or course category context&lt;br /&gt;
* students are enrolled in several child courses&lt;br /&gt;
* teachers are enrolled in separate child course(s)&lt;br /&gt;
&lt;br /&gt;
==Problem areas we are working on ==&lt;br /&gt;
&lt;br /&gt;
===Student view===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Student view&amp;quot; button has been removed completely.&lt;br /&gt;
&lt;br /&gt;
If there is time and a secure way can be found, it will be replaced by a menu to let the user assume a temporary role in the context of that course.&lt;br /&gt;
&lt;br /&gt;
===Teacher forum===&lt;br /&gt;
&lt;br /&gt;
Teacher forums were always a curious exception to normal forums, as they were not part of a course as such, and were not backed up.&lt;br /&gt;
&lt;br /&gt;
We&#039;re taking the opportunity to rectify this.   The upgrade converts teacher forums with content to normal forums in section 0 of the course, and ensures that only teachers can access them.  If the teacher forum had not been used in the course then it&#039;s not converted and will just dissappear.&lt;br /&gt;
&lt;br /&gt;
===Enrolment plugins===&lt;br /&gt;
&lt;br /&gt;
====Process of logging in====&lt;br /&gt;
&lt;br /&gt;
# load_user_capability() is called to load all the capabilities&lt;br /&gt;
# check_enrolment_plugins() is called at the top of load_user_capability() to check all the enrolment plugins.&lt;br /&gt;
# For each active plugin:&lt;br /&gt;
##Check for setup_enrolments($user) and run it.  This function will do all the processing needed to assign or unassign roles from the current user.&lt;br /&gt;
# load_user_capability() continues and loads up all the roles&lt;br /&gt;
# load_defaultuser_role() is called to add default site permissions (all users)&lt;br /&gt;
&lt;br /&gt;
====Process of checking access to a course====&lt;br /&gt;
&lt;br /&gt;
require_login($course-&amp;gt;id) is called by the script and has logic like this:&lt;br /&gt;
&lt;br /&gt;
# Is the user a guest at site level?&lt;br /&gt;
## Yes: Does the course allow guests?&lt;br /&gt;
### Yes: return true (and further capabilities are checked by the script)&lt;br /&gt;
### No:  send the user to course/enrol.php for enrolment&lt;br /&gt;
## No: continue below&lt;br /&gt;
&lt;br /&gt;
# Does the user have moodle/course:view in that (course) context?&lt;br /&gt;
## Yes: then they can enter (and further capabilities are checked by the script)&lt;br /&gt;
##  No: is guest access allowed on the course?&lt;br /&gt;
### Yes: assign temporary guest role to that user for that context (in session cache).&lt;br /&gt;
### No: send the user to course/enrol.php for enrolment.&lt;br /&gt;
&lt;br /&gt;
====Process of enrolling====&lt;br /&gt;
&lt;br /&gt;
(more soon)&lt;br /&gt;
&lt;br /&gt;
==Scenario brainstorming==&lt;br /&gt;
&lt;br /&gt;
This section is for brainstorming some example roles that we would like to support.  Note some of these *may* not be possible in 1.7.&lt;br /&gt;
&lt;br /&gt;
===Student===&lt;br /&gt;
Obviously.&lt;br /&gt;
&lt;br /&gt;
===Site Designers===&lt;br /&gt;
Is there a role for people involved in how the site looks but not full administrators? Thinking here of online control of themes rather than FTP theme uploading. But in either case they caneditlogos, caneditcss, candeditlevelatwhichthemeapplies.&lt;br /&gt;
&lt;br /&gt;
===Educational Authority Adviser===&lt;br /&gt;
Someone who would want to browse the site and may be asked to comment or contribute to particular discussions or developments in school. Access for this role would be controlled by the school in the case of school level moodles but may be different if there were to be a Local Authority wide Moodle.&lt;br /&gt;
&lt;br /&gt;
===Educational Inspector===&lt;br /&gt;
Someone who will visit the site to verify the school&#039;s self review that comments on home school relationships, extending the classroom etc. They may want to see summaries of usage and reports from surveys garnering parent and pupil views.&lt;br /&gt;
&lt;br /&gt;
===Second Marker / Moderator===&lt;br /&gt;
A teacher within ths site that has access to assignments and quizzes from another teacher&#039;s course for second marking purposes. This may need additional functionality adding to the assignment module so that two sets of grades/feedback can be given to one set of assignments.&lt;br /&gt;
&lt;br /&gt;
===Peer observer of teaching===&lt;br /&gt;
Many institutions encourage peer observation of teaching, to encourage reflection on practice. In online environments this will be similar to moderation or inspection. The peer observer would need to be able to experience the course &amp;quot;as a student&amp;quot;, but also to be able to view summaries of usage, transcripts of interactions (forums/surveys/polls etc), grades assigned (e.g. in assignments).&lt;br /&gt;
&lt;br /&gt;
===External Examiner===&lt;br /&gt;
Has all the rights of inspectors, but would also need to be able to review assignments and feedback, view forums, glossaries etc. However, would not want to post, feedback onto the site at all.&lt;br /&gt;
&lt;br /&gt;
===Parent===&lt;br /&gt;
A parent will have one or more children in one or more institutions which could be using one or more moodle instances or a mixture of Learning Platforms. A parent&#039;s role will vary depending on the age of their children and whether they are contributing as a parent or a school supporter.&lt;br /&gt;
&lt;br /&gt;
In Early Years (EY=3+4 yr olds) and Key Stage 1 (KS1=5+6 yr olds) they may play/learn on an activity or write for the child. Parents often interpret homework tasks and read to their children perhaps filling in a joint reading diary. In Key Stage 2 (KS2=7-11 yr olds) parents would be more monitoring but may join in as well.&lt;br /&gt;
&lt;br /&gt;
In Key stages 3 (KS3=12-14 yr olds) and 4 (KS4=15+16 yr olds) this changes to more of a monitoring/awareness role where a parent would expect to have a summary report of attendance, attainment and general achievement on a weekly/monthly/termly or annual basis. Parents will often be asked to sign and write back comments about this review report.&lt;br /&gt;
&lt;br /&gt;
In all Key Stages there is a great need for parents to receive communication from the school which they can confirm they have received by signing a form. In some cases this may also involve making choices from a list. It may also involve payment for a trip or disco being returned so there could be the possibility of electronic payments. Also in all Key Satges there may be a home-school agreement which may be signed up to. Could this form part of a site policy system that incorporates a tickable list of activities the parent agrees to the child using (blogs/wikis/forums etc.)?&lt;br /&gt;
&lt;br /&gt;
Parent&#039;s evenings often involve complex booking systems that attempt to get parent&#039;s and teachers together. Easy for EY/KS1/KS2 very difficult for KS3/KS4. Wow would this help if it was built into the Learning Platform.&lt;br /&gt;
&lt;br /&gt;
In some cases there needs to be confidential communication between the parent and the teacher without the child being party to this. It may involve teaching and learning but could also involve a behaviour or medical issue. Often this may be done via a sealed letter or face to face. &lt;br /&gt;
&lt;br /&gt;
The latest incarnation of OfSTED with the Self Review Framework (SEF) there is a greater emphasis on schools gathering parent voice via surveys and discussion. There is a clear match here with parents have access to parental votes, questionnaires and discussions and for schools to be able to publish news, results and reports back to parents.&lt;br /&gt;
&lt;br /&gt;
In the UK the LP framework and agenda as being pushed by the DfES via Becta emphasises that within the mandatory groups and roles functionality the parent role is likely to be required to meet the LP Framework procurement standard.&lt;br /&gt;
&lt;br /&gt;
Again in the UK, parents have their own independent right of access to a child&#039;s educational records. Obviously, children&#039;s records must not be made available to other parties, including the parents of other children in the same class. Thus it would be necessary to associate parent accounts with their own child&#039;s accounts in such a way that they could, if so desired, have read access to their child&#039;s grades, answers and contributions, but generally not those of other children - this may be problematic in the case of wiki activities or forum posts.&lt;br /&gt;
&lt;br /&gt;
There is some concern that children&#039;s forum contributions etc may be constrained if their parents are able to read all that they write; this may be particularly problematic in areas such as Personal, Social and Health Education (PSHE), where some schools may choose to use obfuscated usernames.&lt;br /&gt;
&lt;br /&gt;
===Manager===&lt;br /&gt;
&#039;&#039;Please add text here...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Weekly Seminar Leader===&lt;br /&gt;
&#039;&#039;In a university seminar, typically 8-15 students in their 3rd/4th year, each student is responsible for leading one topic in a study series.  I ask each student to research 5-10 resources, then give a powerpoint presentation to the other students.  This is followed by an in-class discussion and then online homework.  The homework involves some fun quiz questions and then some reflective journal questions.  I ask each seminar leader to prepare the quiz questions and journal questions as well as their presentation.  To do that, I would like to assign activity-making/authoring roles to the student--either for a short period, or for duration of the whole course.  Thus &amp;quot;Allow Quiz Authoring Role&amp;quot; or &amp;quot;Allow Assignment Authoring Role&amp;quot; at the course level or, if possible, even the Topic level (in a topic or week format course) would be important.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Mentor/Mentee===&lt;br /&gt;
&#039;&#039;Please add text here...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Community-Designed Rating Criteria===&lt;br /&gt;
&#039;&#039;The gradebook tends to be the domain of the teacher.  What if community/peer ratings/marks could also be entered there? What if peer assessment criteria could be designed by the students, not just the teacher?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Visitor===&lt;br /&gt;
&lt;br /&gt;
This would be a role whereby one could allow a visitor to visit one&#039;s classroom. This might be a colleague interested in seeing your course, or a journalist who might be writing an article about one&#039;s site. They should not be able to see the names of any students anywhere (eg recent activity, forum posts) for privacy reasons. They should be able to try out things like quizzes, and lessons but no grades would be recorded (like in teacher preview mode). They would not be able to participate in choices and forums but could view them. It would be read only in a way like former-student role below but without access to a particular student&#039;s records that former student role would grant.&lt;br /&gt;
&lt;br /&gt;
===Guest Speaker===&lt;br /&gt;
&lt;br /&gt;
This role would be similar to the Visitor role above, but would allow seeing student names, and also allow both reading and posting to a specific forum or forums. We often have &amp;quot;guest speakers&amp;quot; who read and respond to student forum posts. Right now we have to add them as students, which isn&#039;t ideal.&lt;br /&gt;
&lt;br /&gt;
===Former Student===&lt;br /&gt;
This role would be of particular use for courses with rolling enrollments. This role would be one where a student had completed all of the requirements of a course (ie. assignments, quizzes etc.) but wished to have continued access to the course material for review or consultation. The key factor is that one would give access to the completed student to the notes he read, his work and the teacher&#039;s comments on it, but he would not be allowed to do anything that would take up the teacher&#039;s time. In other words, a sort-of read-only access to the course. How forums, which might contain pertinent information and would continue to grow, would be handled is a question. Perhaps the student would be shown only what was in the forums at the time he completed the course. He would not be allowed to see any new posts or add any himself. Same thing for database and glossary entries. In other words, a snapshot of the course at the time his regular enrollment ended. He shouldn&#039;t be able to see the names or profiles of any newly enrolled students for privacy reasons-hence the restrictions on forum access. One issue that would have to be dealt with would be changes to existing modules-such as resources. Does the student get access to the module as it was or as it is? We have no versioning of resources in Moodle so this would be a problem. What about a teacher changing a quiz question so that the answer is different? What would a former student see?&lt;br /&gt;
&lt;br /&gt;
===Alumnus=== &lt;br /&gt;
An ALUMNUS should be able to search for all other ALUMNI of the school, interact with them and be enrolled in a separate course - which is like a META course with all the content of his learning and interaction - as well as capabilities to be a part of this ALUMNI only course.  All the teachers of courses during school years should automatically be a part of the ALUMNI course .. which means when an ALUMNUS is enrolled in a course, the original teachers of all his courses get enrolled ?  --[[User:Anil Sharma|Anil Sharma]] 20:54, 15 July 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
===Librarian===&lt;br /&gt;
&lt;br /&gt;
Reference Librarians have an active role in most of the courses taught at some schools such as Earlham College (with Bibliographic Instruction). The Librarian role within Moodle could encompass default read access to all courses (unless prohibited by course teacher) and read access to all components of the course unless access is barred (again by teacher). The Librarians would also perhaps have a block called perhaps Reference Services or Reference Desk with write access where they could deposit resources. Also this block might have a chat applet whereby enrolled students could chat to the Reference Librarian on duty about their bibliographic research needs.&lt;br /&gt;
&lt;br /&gt;
In schools there is often a book review system. This may be covered by the lending system database but may not in which case a librarian may neeed to have a course area they can create a database template to handle the reviews in which case they may have a normal teacher style role? Off topic but course an integration with common schools database systems would be great.&lt;br /&gt;
&lt;br /&gt;
===Teacher===&lt;br /&gt;
&lt;br /&gt;
Teachers should have read access to other Teacher&#039;s courses unless explictly prohibited. They should be able to set parts of their own course to be totally private (perhaps even to admin?). Just as each activity can currently be set to have group access, each activity could have a permissions field. Teachers could set default permissions for all activities on their course (eg they might disallow Librarian access for example) and then change the access permission for an individual activity. &lt;br /&gt;
&lt;br /&gt;
I think that what is needed is a simple heirarchy of permissions and levels of granularity.&lt;br /&gt;
&lt;br /&gt;
I would take issue with &amp;quot;teachers should have read access to other teacher&#039;s courses unless explicitly prohibited.&amp;quot; This is a violation of the students&#039; privacy as how they perform and what they do in one class isn&#039;t the business of another teacher. Moreover, in the real world a teacher wouldn&#039;t suddenly go sit in on a colleague&#039;s class without asking permission first. I would not have appreciated such an invasion of privacy as either a teacher or a student. It could be an option, but shouldn&#039;t be default.--[[User:N Hansen|N Hansen]] 19:54, 12 June 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
===Community Education Tutors/Trainers===&lt;br /&gt;
Teachers may be community adult education trainers making use of a school moodle so must only have access to their courses unless given access elsewhere. They would not necessarily get the default teacher privileges.&lt;br /&gt;
&lt;br /&gt;
===Secretary/Student Worker===&lt;br /&gt;
&lt;br /&gt;
We often have faculty who want their departmental secretary or student worker to scan and upload files and perhaps create resources. Currently they have to be given teacher access to the course. This is dangerous from a FERPA standpoint since they could easily get access to grades.&lt;br /&gt;
&lt;br /&gt;
===Teaching Assistant===&lt;br /&gt;
&lt;br /&gt;
Our Faculty frequently have undergraduate students acting as Teaching Assistants. These students need to be able to add resources, create assignments, and possibly grade assignments. However, due to FERPA they cannot have access to other students&#039; overall grade information. I think the requirements here are slightly different than those of Secretary/Student Worker&lt;br /&gt;
&lt;br /&gt;
===Student - FERPA rights===&lt;br /&gt;
&lt;br /&gt;
A student that has asserted their FERPA rights to non-disclosure.  Typically includes not publishing their name&lt;br /&gt;
in any public place.  Could include this student only being seen with an &amp;quot;alias&amp;quot; within course spaces.  Is this an attribute rather&lt;br /&gt;
than a role?&lt;br /&gt;
&lt;br /&gt;
===Help Desk===&lt;br /&gt;
&lt;br /&gt;
Help desk agents that have read access for the purposes of trouble shooting.  Some care in placing this role within a hierarchy&lt;br /&gt;
of inheritance is needed, full access will be problematic with FERPA.&lt;br /&gt;
&lt;br /&gt;
===Admin - Catgory based===&lt;br /&gt;
&lt;br /&gt;
Basically a person in between full Admin and Creator that has the permissions of an Admin but only with respect to courses and students. Currently a Creator has permissions site-wide which does not always meet the requirements of a given organisation (e.g. Department A may not be happy that a person from Department B can create/modify courses within Department A&#039;s area). The ability to designate a Creator within a specific category would allow areas to be set up for a faculty/department/organisation and allow the Admin for that area to create/delete courses, upload users, add site-wide entries to the calendar etc.&lt;br /&gt;
&lt;br /&gt;
===Process Roles===&lt;br /&gt;
&lt;br /&gt;
organising the learning process for a group you wish to have the choice to place students in differnt roles: examples of this are:&lt;br /&gt;
* Give a student the role of forum-moderator with edit and chunk-rights&lt;br /&gt;
* Give students different roles &amp;amp; rights in a Webquest design (and change these roles next week&lt;br /&gt;
* Give students different resources, depending of their roles in a rolegame/simulation&lt;br /&gt;
* Give a student the rights to create the section content of next week (and only that week..)&lt;br /&gt;
&lt;br /&gt;
==Things to finish for 1.7 Beta==&lt;br /&gt;
&#039;&#039;&#039;18 Sept 2006&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
#Remove core references to user_student, user_teacher, user_admin, user_coursecreator tables.  [Yu]&lt;br /&gt;
#Address function: isteacher, isadmin, isstudent [Yu]&lt;br /&gt;
#Remove &amp;quot;view&amp;quot; capabilities from all modules unless required [Vy]&lt;br /&gt;
#Remove all old references from remaining Blocks [Vy]&lt;br /&gt;
#Metacourses [Skodak]&lt;br /&gt;
#Add risks to GUI[Skodak]&lt;br /&gt;
#Enrolment plugins  [Martin and Alastair]&lt;br /&gt;
#[[Stats_roles_1.7|Statistics]] [Penny]&lt;br /&gt;
#Fix Loginas&lt;br /&gt;
#Add category-level assigns [Yu]&lt;br /&gt;
#[[Backup_roles_1.7|Backups]] [Eloy?]&lt;br /&gt;
&lt;br /&gt;
===Proposal for interface enhancement===&lt;br /&gt;
Martin asked some questions, here are my answers. The sketches below are not worked out proposals. Their task is to visualize the idea. The exact colours and functionality may be defined after possible agreement about the proposals. The Green, orange and red columns support the meaning of the options from &amp;quot;allow&amp;quot; to &amp;quot;prohibit&amp;quot; (If you may want to see larger images please click onto the image or the &amp;quot;Enlarge&amp;quot; icon below the image.)&lt;br /&gt;
&lt;br /&gt;
The list of possible settings is very long and &#039;&#039; &amp;quot;... the problem is not to overwhelm people with information&amp;quot; &#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
[[Image:01_moodle_define_roles_structured.png|thumb=01_moodle_define_roles_structured_pre.png]]&lt;br /&gt;
&lt;br /&gt;
1) One proposal is to use colour to structure the sections and the columns. Picture 1 shows that the user can keep a much better overview when the list is divided into meaningful different coloured columns and clear sections.&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:02_moodle_define_roles_collapsed.png|thumb=02_moodle_define_roles_collapsed_pre.png]]&lt;br /&gt;
&lt;br /&gt;
2) A second proposal is to reduce the amount of information the user is shown at the same time. The YUI interface library offers great support to show/hide sections of the page by clicking on specific elements. &lt;br /&gt;
&lt;br /&gt;
For example click on an icon beside the sub heading &amp;quot;Course categories&amp;quot; and show/hide all table rows with the CLASS &amp;quot;course-category&amp;quot;.&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:03_moodle_define_roles_tooltip.png|thumb=03_moodle_define_roles_tooltip_pre.png]]&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039; &amp;quot;The main problem is the last column for risk ... we were thinking of putting little icons in there ...&amp;quot; &#039;&#039;&lt;br /&gt;
Icons are good when they tell the user more about possible actions/meanings then the letters. I am not sure if this is the case here. For both - icons or letters - the YUI tool-tip function would be able to give the user valuable information about the meaning.&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Hardening new Roles system]]&lt;br /&gt;
*[[Roles and modules]]&lt;br /&gt;
*Using Moodle course:&lt;br /&gt;
**[http://moodle.org/mod/forum/view.php?f=941 Roles and Capabilities forum]&lt;br /&gt;
**Key discussions at Using Moodle forums:&lt;br /&gt;
***[http://moodle.org/mod/forum/discuss.php?d=38788 Roles and Permissions architecture]&lt;br /&gt;
***[http://moodle.org/mod/forum/discuss.php?d=56302#256313 An example of admin roles as set in the database]&lt;br /&gt;
&lt;br /&gt;
[[Category:Roles]]&lt;br /&gt;
[[Category:Roles]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Developpement:Roles]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=510</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=510"/>
		<updated>2007-01-07T11:25:30Z</updated>

		<summary type="html">&lt;p&gt;Delius: Undoing last edits which changed text to Russian&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;Note:&#039;&#039;&#039; New developer documentation pages should be added to the &#039;&#039;Development namespace&#039;&#039; by typing &amp;lt;code&amp;gt;Development:&amp;lt;/code&amp;gt; before the new page name i.e. &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[New page name]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If you are a developer, you probably want to change your [[Special:Preferences|preferences]] to include the Development namespace in searches.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
*[[Unit tests]] explains how to run the unit tests, and how to write new test cases.&lt;br /&gt;
*[[Tracker]] explains the Moodle Tracker for keeping track of bugs, issues, feature requests etc&lt;br /&gt;
*[[Working with the Community|Working with the Community]] explains how to engage with the dev community and discuss changes&lt;br /&gt;
&lt;br /&gt;
== Resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[[Developer FAQ]] - frequently asked questions, especially useful for newcomers to Moodle&lt;br /&gt;
*[http://tracker.moodle.org/ Moodle tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://moodle.cvs.sourceforge.net/moodle/moodle/ CVS code] - browse the Moodle code via the web&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://phpdocs.moodle.org/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[[Database Schema|Database Schema]] - for recent releases&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[http://developer.yahoo.com/yui YUI documentation] - YUI is the official AJAX library in moodle.&lt;br /&gt;
*[[Setting up Eclipse for Moodle development]] - Eclipse is a great editor to use for php development, if you can work out how to set it up.&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&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 functionality. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. The following types of plugins currently exist (in alphabetical order):&lt;br /&gt;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Admin reports|Admin reports]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Authentication|Authentication methods]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Database fields (developer)|Database fields]]&lt;br /&gt;
*[[Database presets]]&lt;br /&gt;
*[[Enrolment plugins (developer)|Enrolment plugins]]&lt;br /&gt;
*[[Filters|Filters]]&lt;br /&gt;
*[[Question_engine]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Question bank|Question bank teacher docs]]&lt;br /&gt;
*[[Question_engine#Question_types|Question types developper docs]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[SSO plugins]]&lt;br /&gt;
&lt;br /&gt;
There are also ways you can contribute that don&#039;t involve PHP programming:&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Tracker|Participating in the bug tracker]]&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;
*[[Student projects]]&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;
*[[Migration to Role-driven model|Migration to Role-driven model]] @ v[[1.7]]&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]] @ v[[:Category:Moodle 1.6|1.6]]&lt;br /&gt;
*[[Question engine]]&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;
*[[lib/formslib.php|Formslib]] for quickly writing code to display and process more accessible and secure forms.&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 area] of the Moodle [[CVS]] repository. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;br /&gt;
[[fr:Documentation développeur]]&lt;br /&gt;
[[zh:开发者文档]]&lt;br /&gt;
[[ja:開発者ドキュメント]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Open_protocol_for_accessing_question_engines&amp;diff=27115</id>
		<title>Talk:Open protocol for accessing question engines</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Open_protocol_for_accessing_question_engines&amp;diff=27115"/>
		<updated>2006-11-29T15:17:50Z</updated>

		<summary type="html">&lt;p&gt;Delius: My support&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I very much support Tim&#039;s work on this. I will be watching this page and whenever our experience from designing and then simplifying RQP might be helpful I will mention it. --[[User:Gustav Delius|Gustav Delius]] 09:17, 29 November 2006 (CST)&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5424</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5424"/>
		<updated>2006-10-12T15:31:07Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stripslashes.jpg|none]]&lt;br /&gt;
&lt;br /&gt;
Neither &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when going from User Input to the Database or from the Database to Screen Output (black arrows) but &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; should be used when displaying user input on the screen (red arrow) and &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when reinserting data in to the database that came from the database (blue arrow). These last two are rare, so the use of addslashes and stripslashes should be rare.&lt;br /&gt;
&lt;br /&gt;
Please note that when outputting strings from the database, you should never simply use echo or something similar but should use Moodle&#039;s [[Output functions|output functions]].&lt;br /&gt;
&lt;br /&gt;
Sometimes you may want to add slashes or remove slashes from all proprties of an object at once. Moodle provides the very convenient functions &amp;lt;code&amp;gt;addslashes_object()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes_recursive()&amp;lt;/code&amp;gt;. The latter also works on arrays.&lt;br /&gt;
&lt;br /&gt;
One thing to watch out for is that the parameter type PARAM_CLEANHTML strips slashes, so you have to add slashes before putting data cleaned this way into the database or user PARAM_CLEAN instead.&lt;br /&gt;
&lt;br /&gt;
Moodle provides a function called &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt; which only strips slashes in front of single and double quotes and in front of a backslash, so \&#039; becomes &#039;, \&amp;quot; becomes &amp;quot;, and \\ becomes \. Any other slashes, as in C:\Moodle for example, are preserved. It was introduced because in some circumstances it may not matter if this function is applied too often. However I find this function dangerous, because it may make you think that everything is fine until one of your users wants to include a bit of code in their input for example. I would not have been able to write this paragraph (with the \&#039; in it) if it had been passed through &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some core Moodle functions use &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;:&lt;br /&gt;
 print_heading()&lt;br /&gt;
 print_heading_with_help()&lt;br /&gt;
 print_heading_block()&lt;br /&gt;
 print_simple_box()&lt;br /&gt;
It usually doesn&#039;t matter too much for headings, because including \\, \&#039;, or \&amp;quot; in headings is unusual, but it does matter in print_simple_box() and therefore the advice would be to avoid using this function and to use the &amp;lt;code&amp;gt;print_simple_box_start()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;print_simple_box_end()&amp;lt;/code&amp;gt; pair.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5423</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5423"/>
		<updated>2006-10-12T15:28:20Z</updated>

		<summary type="html">&lt;p&gt;Delius: Added comment about strange behaviour of PARAM_CLEANHTML&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stripslashes.jpg|none]]&lt;br /&gt;
&lt;br /&gt;
Neither &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when going from User Input to the Database or from the Database to Screen Output (black arrows) but &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; should be used when displaying user input on the screen (red arrow) and &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when reinserting data in to the database that came from the database (blue arrow). These last two are rare, so the use of addslashes and stripslashes should be rare.&lt;br /&gt;
&lt;br /&gt;
Please note that when outputting strings from the database, you should never simply use echo or something similar but should use Moodle&#039;s [[Output functions|output functions]].&lt;br /&gt;
&lt;br /&gt;
Sometimes you may want to add slashes or remove slashes from all proprties of an object at once. Moodle provides the very convenient functions &amp;lt;code&amp;gt;addslashes_object()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes_recursive()&amp;lt;/code&amp;gt;. The latter also works on arrays.&lt;br /&gt;
&lt;br /&gt;
One thing to watch out for is that the parameter type PARAM_CLEANHTML strips slashes, so you have to add slashes before putting data cleaned this way into the database.&lt;br /&gt;
&lt;br /&gt;
Moodle provides a function called &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt; which only strips slashes in front of single and double quotes and in front of a backslash, so \&#039; becomes &#039;, \&amp;quot; becomes &amp;quot;, and \\ becomes \. Any other slashes, as in C:\Moodle for example, are preserved. It was introduced because in some circumstances it may not matter if this function is applied too often. However I find this function dangerous, because it may make you think that everything is fine until one of your users wants to include a bit of code in their input for example. I would not have been able to write this paragraph (with the \&#039; in it) if it had been passed through &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some core Moodle functions use &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;:&lt;br /&gt;
 print_heading()&lt;br /&gt;
 print_heading_with_help()&lt;br /&gt;
 print_heading_block()&lt;br /&gt;
 print_simple_box()&lt;br /&gt;
It usually doesn&#039;t matter too much for headings, because including \\, \&#039;, or \&amp;quot; in headings is unusual, but it does matter in print_simple_box() and therefore the advice would be to avoid using this function and to use the &amp;lt;code&amp;gt;print_simple_box_start()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;print_simple_box_end()&amp;lt;/code&amp;gt; pair.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5422</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5422"/>
		<updated>2006-10-08T18:47:52Z</updated>

		<summary type="html">&lt;p&gt;Delius: Added link to Output functions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stripslashes.jpg|none]]&lt;br /&gt;
&lt;br /&gt;
Neither &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when going from User Input to the Database or from the Database to Screen Output (black arrows) but &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; should be used when displaying user input on the screen (red arrow) and &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when reinserting data in to the database that came from the database (blue arrow). These last two are rare, so the use of addslashes and stripslashes should be rare.&lt;br /&gt;
&lt;br /&gt;
Please note that when outputting strings from the database, you should never simply use echo or something similar but should use Moodle&#039;s [[Output functions|output functions]].&lt;br /&gt;
&lt;br /&gt;
Sometimes you may want to add slashes or remove slashes from all proprties of an object at once. Moodle provides the very convenient functions &amp;lt;code&amp;gt;addslashes_object()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes_recursive()&amp;lt;/code&amp;gt;. The latter also works on arrays.&lt;br /&gt;
&lt;br /&gt;
Moodle provides a function called &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt; which only strips slashes in front of single and double quotes and in front of a backslash, so \&#039; becomes &#039;, \&amp;quot; becomes &amp;quot;, and \\ becomes \. Any other slashes, as in C:\Moodle for example, are preserved. It was introduced because in some circumstances it may not matter if this function is applied too often. However I find this function dangerous, because it may make you think that everything is fine until one of your users wants to include a bit of code in their input for example. I would not have been able to write this paragraph (with the \&#039; in it) if it had been passed through &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some core Moodle functions use &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;:&lt;br /&gt;
 print_heading()&lt;br /&gt;
 print_heading_with_help()&lt;br /&gt;
 print_heading_block()&lt;br /&gt;
 print_simple_box()&lt;br /&gt;
It usually doesn&#039;t matter too much for headings, because including \\, \&#039;, or \&amp;quot; in headings is unusual, but it does matter in print_simple_box() and therefore the advice would be to avoid using this function and to use the &amp;lt;code&amp;gt;print_simple_box_start()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;print_simple_box_end()&amp;lt;/code&amp;gt; pair.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=927</id>
		<title>Coding</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=927"/>
		<updated>2006-10-07T12:46:30Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Security issues (and handling form and URL data) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any collaborative project needs consistency and stability to stay strong.&lt;br /&gt;
&lt;br /&gt;
These &#039;&#039;&#039;coding guidelines&#039;&#039;&#039; are to provide a goal for all Moodle code to strive to. It&#039;s true that some of the older existing code falls short in a few areas, but it will all be fixed eventually. All new code definitely must adhere to these standards as closely as possible.&lt;br /&gt;
&lt;br /&gt;
==General rules==&lt;br /&gt;
&lt;br /&gt;
# All code files should use the .php extension.&lt;br /&gt;
# All template files should use the .html extension.&lt;br /&gt;
# All text files should use Unix-style text format (most text editors have this as an option).&lt;br /&gt;
# All php tags must be &#039;full&#039; tags like &amp;lt;?php ?&amp;gt; ... not &#039;short&#039; tags like &amp;lt;? ?&amp;gt;.&lt;br /&gt;
# All existing copyright notices must be retained. You can add your own if necessary.&lt;br /&gt;
# Each file should include the main config.php file.&lt;br /&gt;
# Each file should check that the user is authenticated correctly, using require_login() and isadmin(), isteacher(), iscreator() or isstudent().&lt;br /&gt;
# All access to databases should use the functions in &#039;&#039;lib/dmllib.php&#039;&#039; whenever possible - this allows compatibility across a wide range of databases. You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions within your code (usually a lib.php file); and clearly marked.&lt;br /&gt;
# Don&#039;t create or use global variables except for the standard $CFG, $SESSION, $THEME, $SITE, $COURSE and $USER.&lt;br /&gt;
# All variables should be initialised or at least tested for existence using isset() or empty() before they are used.&lt;br /&gt;
# All strings should be translatable - create new texts in the &amp;quot;lang/en_utf8&amp;quot; files with concise English lowercase names and retrieve them from your code using get_string() or print_string().&lt;br /&gt;
# All help files should be translatable - create new texts in the &amp;quot;lang/en_utf8/help&amp;quot; directory and call them using helpbutton(). If you need to update a help file:&lt;br /&gt;
#* with a minor change, where an old translation of the file would still make sense, then it&#039;s OK to make the change but you should notify translation AT moodle DOT org.&lt;br /&gt;
#* for a major change you should create a new file by adding an incrementing number (eg filename2.html) so that translators can easily see it&#039;s a new version of the file. Obviously the new code and the help index files should also be modified to point to the newest versions.&lt;br /&gt;
# Incoming data from the browser (sent via GET or POST) automatically has magic_quotes applied (regardless of the PHP settings) so that you can safely insert it straight into the database. All other raw data (from files, or from databases) must be escaped with addslashes() before inserting it into the database. Because this is so often done incorrectly, there is more explanation on this issue of adding and stripping slashes on a [[Developer:Slashes|separate page]].&lt;br /&gt;
# VERY IMPORTANT: All texts within Moodle, especially those that have come from users, should be printed using the format_text() function. This ensures that text is filtered and cleaned correctly. More information can be found on the page about [[Developer:Output_functions|output functions]].&lt;br /&gt;
# User actions should be logged using the [[Logs|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].&lt;br /&gt;
&lt;br /&gt;
==Coding style==&lt;br /&gt;
&lt;br /&gt;
I know it can be a little annoying to change your style if you&#039;re used to something else, but balance that annoyance against the annoyance of all the people trying later on to make sense of Moodle code with mixed styles. There are obviously many good points for and against any style that people use, but the current style just is, so please stick to it.&lt;br /&gt;
&lt;br /&gt;
1. Indenting should be consistently 4 spaces. Don&#039;t use tabs AT ALL.&lt;br /&gt;
&lt;br /&gt;
2. Variable names should always be easy-to-read, meaningful lowercase English words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.&lt;br /&gt;
&lt;br /&gt;
      GOOD: $quiz&lt;br /&gt;
      GOOD: $errorstring&lt;br /&gt;
      GOOD: $assignments (for an array of objects)&lt;br /&gt;
      GOOD: $i (but only in little loops)&lt;br /&gt;
&lt;br /&gt;
      BAD: $Quiz&lt;br /&gt;
      BAD: $aReallyLongVariableNameWithoutAGoodReason&lt;br /&gt;
      BAD: $error_string&lt;br /&gt;
&lt;br /&gt;
3. Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.&lt;br /&gt;
&lt;br /&gt;
      define(&amp;quot;FORUM_MODE_FLATOLDEST&amp;quot;, 1);&lt;br /&gt;
4. Function names should be simple English lowercase words, and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores. Parameters should always have sensible defaults if possible. Note there is no space between the function name and the following (brackets).&lt;br /&gt;
&lt;br /&gt;
      function forum_set_display_mode($mode=0) {&lt;br /&gt;
          global $USER, $CFG;&lt;br /&gt;
          &lt;br /&gt;
          if ($mode) {&lt;br /&gt;
              $USER-&amp;gt;mode = $mode;&lt;br /&gt;
          } else if (empty($USER-&amp;gt;mode)) {&lt;br /&gt;
              $USER-&amp;gt;mode = $CFG-&amp;gt;forum_displaymode;&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
5. Blocks must always be enclosed in curly braces (even if there is only one line). Moodle uses this style:&lt;br /&gt;
&lt;br /&gt;
      if ($quiz-&amp;gt;attempts) {&lt;br /&gt;
          if ($numattempts &amp;gt; $quiz-&amp;gt;attempts) {&lt;br /&gt;
              error($strtoomanyattempts, &amp;quot;view.php?id=$cm-&amp;gt;id&amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
6. Strings should be defined using single quotes where possible, for increased speed.&lt;br /&gt;
&lt;br /&gt;
      $var = &#039;some text without any variables&#039;;&lt;br /&gt;
      $var = &amp;quot;with special characters like a new line \n&amp;quot;;&lt;br /&gt;
      $var = &#039;a very, very long string with a &#039;.$single.&#039; variable in it&#039;;&lt;br /&gt;
      $var = &amp;quot;some $text with $many variables $within it&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
7. Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.&lt;br /&gt;
&lt;br /&gt;
* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.&lt;br /&gt;
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
      * The description should be first, with asterisks laid out exactly&lt;br /&gt;
      * like this example. If you want to refer to a another function,&lt;br /&gt;
      * do it like this: {@link clean_param()}. Then, add descriptions&lt;br /&gt;
      * for each parameter as follows.&lt;br /&gt;
      *&lt;br /&gt;
      * @param int $postid The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $scale The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $ratings The PHP type is followed by the variable name&lt;br /&gt;
      * @return mixed&lt;br /&gt;
      */&lt;br /&gt;
      function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {&lt;br /&gt;
          if (!$ratings) {&lt;br /&gt;
              $ratings = array();     // Initialize the empty array&lt;br /&gt;
              if ($rates = get_records(&amp;quot;forum_ratings&amp;quot;, &amp;quot;post&amp;quot;, $postid)) {&lt;br /&gt;
                  // Process each rating in turn&lt;br /&gt;
                  foreach ($rates as $rate) {&lt;br /&gt;
      ....etc&lt;br /&gt;
&lt;br /&gt;
8. Space should be used liberally - don&#039;t be afraid to spread things out a little to gain some clarity. Generally, there should be one space between brackets and normal statements, but no space between brackets and variables or functions:&lt;br /&gt;
&lt;br /&gt;
      foreach ($objects as $key =&amp;gt; $thing) {&lt;br /&gt;
          process($thing);&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      if ($x == $y) {&lt;br /&gt;
          $a = $b;&lt;br /&gt;
      } else if ($x == $z) {&lt;br /&gt;
          $a = $c;&lt;br /&gt;
      } else {&lt;br /&gt;
          $a = $d;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
9. When making a COPY of an object, always use the php5 clone() function (otherwise you may end up with just a reference to the first object).  Moodle will make sure this works consistently on php4 too.&lt;br /&gt;
&lt;br /&gt;
      BAD:   $b = $a;&lt;br /&gt;
      GOOD:  $b = clone($a);&lt;br /&gt;
&lt;br /&gt;
If the thing you want to copy is not an object, but may contain objects (eg an array of objects) then use fullclone() instead.&lt;br /&gt;
&lt;br /&gt;
==Database structures==&lt;br /&gt;
&lt;br /&gt;
# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])&lt;br /&gt;
# The main table containing instances of each module must have the same name as the module (eg widget) and contain the following minimum fields:&lt;br /&gt;
#* id - as described above&lt;br /&gt;
#* course - the id of the course that each instance belongs to&lt;br /&gt;
#* name - the full name of each instance of the module&lt;br /&gt;
# Other tables associated with a module that contain information about &#039;things&#039; should be named widget_things (note the plural).&lt;br /&gt;
# Table and column names should avoid using [[Database reserved words|reserved words in any database]]. Please check them before creation.&lt;br /&gt;
# Column names should be always lowercase, simple and short, following the same rules as for variable names.&lt;br /&gt;
# Where possible, columns that contain a reference to the id field of another table (eg widget) should be called widgetid. (Note that this convention is newish and not followed in some older tables)&lt;br /&gt;
# Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.&lt;br /&gt;
# Most tables should have a timemodified field (INT10) which is updated with a current timestamp obtained with the PHP time() function.&lt;br /&gt;
# Always define a default value for each field (and make it sensible)&lt;br /&gt;
# Each table name should start with the database prefix ($CFG-&amp;gt;prefix). In a lot of cases, this is taken care of for you automatically. Also, under Postgres, the name of every index must start with the prefix too.&lt;br /&gt;
# In order to guarantee [[XMLDB problems#Table and column aliases - the AS keyword|cross-db compatibility]] follow these simple rules about the use of the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword (only if you need table/colum aliases, of course):&lt;br /&gt;
#* &#039;&#039;&#039;Don&#039;t use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;table aliases&#039;&#039;&#039;.&lt;br /&gt;
#* &#039;&#039;&#039;Do use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;column aliases&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Never&#039;&#039;&#039; create UNIQUE KEYs (constraints) at all. Instead use UNIQUE INDEXes. In the future, if we decide to add referential integrity to Moodle and we need UNIQUE KEYs they will be used, but not now. Please note that the XMLDB editor allows you to specify both XMLDB-only UNIQUE and FOREIGN constraints (and that&#039;s good, in order to have the XML well defined) but only underlying INDEXes will be generated. &lt;br /&gt;
# Those XMLDB-only UNIQUE KEYs (read previous point) only must be defined if such field/fields &#039;&#039;&#039;are going to be the target&#039;&#039;&#039; for some (XMLDB-only too) FOREIGN KEY. Else, create them as simple UNIQUE INDEXes.&lt;br /&gt;
# Tables associated &#039;&#039;&#039;with one block&#039;&#039;&#039; must follow this convention with their names: &#039;&#039;&#039;$CFG-&amp;gt;prefix + &amp;quot;block_&amp;quot; + name_of_the_block + anything_else&#039;&#039;&#039;. For example, assuming that $CFG-&amp;gt;prefix is &#039;mdl_&#039;, all the tables for the block &amp;quot;rss_client&amp;quot; must start by &#039;mdl_block_rss_client&#039; (being possible to add more words at the end, i.e. &#039;mdl_block_rss_client_anothertable&#039;...). This rule will be 100% enforced with Moodle 2.0, giving time to developers until then. See [http://tracker.moodle.org/browse/MDL-6786 Task 6786] for more info about this.&lt;br /&gt;
&lt;br /&gt;
==Security issues (and handling form and URL data)==&lt;br /&gt;
&lt;br /&gt;
# Do not rely on &#039;register_globals&#039;. Every variable must be properly initialised in every code file. It must be obvious where the variable came from&lt;br /&gt;
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.&lt;br /&gt;
# Do not use the optional_variable() function (this function is now deprecated). Use the optional_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Do not use the require_variable() function (this function is now deprecated). Use the required_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Use data_submitted(), with care. Data must still be cleaned before use.&lt;br /&gt;
# Do not use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.&lt;br /&gt;
# Do not check for an action using something like if (isset($_GET[&#039;something&#039;])). Use, e.g., $something = optional_param( &#039;something&#039;,-1,PARAM_INT ) and then perform proper test for it being in its expected range of values e.g., if ($something&amp;gt;=0) {....&lt;br /&gt;
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.&lt;br /&gt;
# Use &#039;sesskey&#039; mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;sesskey&amp;quot; value=&amp;quot;&amp;lt;?php echo sesskey(); ?&amp;gt;&amp;quot; /&amp;gt;. When you process the form check with if (!confirm_sesskey()) {error(&#039;Bad Session Key&#039;);}.&lt;br /&gt;
# All filenames must be &#039;cleaned&#039; using the clean_filename() function, if this has not been done already by appropriate use of required_param() or optional_param()&lt;br /&gt;
# Any data read from the database must have [[Developer:Slashes|addslashes()]] applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object().&lt;br /&gt;
# Wherever possible, data to be stored in the database must come from POST data (from a form with method=&amp;quot;POST&amp;quot;) as opposed to GET data (ie, data from the URL line).&lt;br /&gt;
# Do not use data from $_SERVER if you can avoid it. This has portability issues.&lt;br /&gt;
# If it hasn&#039;t been done somewhere else, make sure all data written to the database has been through the clean_param() function using the appropriate PARAM_XXXX for the datatype.&lt;br /&gt;
# If you write custom SQL code, make very sure it is correct. In particular watch out for missing quotes around values. Possible SQL &#039;injection&#039; exploit.&lt;br /&gt;
# Check all data (particularly that written to the database) in every file it is used. Do not expect or rely on it being done somewhere else.&lt;br /&gt;
# Blocks of code to be included should contain a definite PHP structure (e.g, a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised variable usage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Manual de Estilo de Código]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5420</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5420"/>
		<updated>2006-10-07T12:08:44Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stripslashes.jpg|none]]&lt;br /&gt;
&lt;br /&gt;
Neither &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when going from User Input to the Database or from the Database to Screen Output (black arrows) but &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; should be used when displaying user input on the screen (red arrow) and &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when reinserting data in to the database that came from the database (blue arrow). These last two are rare, so the use of addslashes and stripslashes should be rare.&lt;br /&gt;
&lt;br /&gt;
Sometimes you may want to add slashes or remove slashes from all proprties of an object at once. Moodle provides the very convenient functions &amp;lt;code&amp;gt;addslashes_object()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes_recursive()&amp;lt;/code&amp;gt;. The latter also works on arrays.&lt;br /&gt;
&lt;br /&gt;
Moodle provides a function called &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt; which only strips slashes in front of single and double quotes and in front of a backslash, so \&#039; becomes &#039;, \&amp;quot; becomes &amp;quot;, and \\ becomes \. Any other slashes, as in C:\Moodle for example, are preserved. It was introduced because in some circumstances it may not matter if this function is applied too often. However I find this function dangerous, because it may make you think that everything is fine until one of your users wants to include a bit of code in their input for example. I would not have been able to write this paragraph (with the \&#039; in it) if it had been passed through &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some core Moodle functions use &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;:&lt;br /&gt;
 print_heading()&lt;br /&gt;
 print_heading_with_help()&lt;br /&gt;
 print_heading_block()&lt;br /&gt;
 print_simple_box()&lt;br /&gt;
It usually doesn&#039;t matter too much for headings, because including \\, \&#039;, or \&amp;quot; in headings is unusual, but it does matter in print_simple_box() and therefore the advice would be to avoid using this function and to use the &amp;lt;code&amp;gt;print_simple_box_start()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;print_simple_box_end()&amp;lt;/code&amp;gt; pair.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5419</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5419"/>
		<updated>2006-10-07T12:07:27Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
&lt;br /&gt;
[[Image:stripslashes.jpg|none]]&lt;br /&gt;
&lt;br /&gt;
Neither &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when going from User Input to the Database or from the Database to Screen Output (black arrows) but &amp;lt;code&amp;gt;stripslashes()&amp;lt;/code&amp;gt; should be used when displaying user input on the screen (red arrow) and &amp;lt;code&amp;gt;addslashes()&amp;lt;/code&amp;gt; should be used when reinserting data in to the database that came from the database (blue arrow). These last two are rare, so the use of addslashes and stripslashes should be rare.&lt;br /&gt;
&lt;br /&gt;
Sometimes you may want to add slashes or remove slashes from all proprties of an object at once. Moodle provides the very convenient functions &amp;lt;code&amp;gt;addslashes_object()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes_recursive()&amp;lt;/code&amp;gt;. The latter also works on arrays.&lt;br /&gt;
&lt;br /&gt;
Moodle provides a function called &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt; which only strips slashes in front of single and double quotes and in front of a backslash, so \&#039; becomes &#039;, \&amp;quot; becomes &amp;quot;, and \\ becomes \. Any other slashes, as in C:\Moodle for example, are preserved. It was introduced because in some circumstances it may not matter if this function is applied too often. However I find this function dangerous, because it may make you think that everything is fine until one of your users wants to include a bit of code in their input for example. I would not have been able to write this paragraph (with the \&#039; in it) if it had been passed through &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some core Moodle functions use &amp;lt;code&amp;gt;stripslashes_safe()&amp;lt;/code&amp;gt;:&lt;br /&gt;
 print_heading()&lt;br /&gt;
 print_heading_with_help()&lt;br /&gt;
 print_heading_block()&lt;br /&gt;
 print_simple_box()&lt;br /&gt;
It usually doesn&#039;t matter too much for headings, because including \\, \&#039;, or \&amp;quot; in headings is unusual, but it does matter in print_simple_box() and therefore the advice would be to avoid using this function and to use the &amp;lt;code&amp;gt;print_simple_box_start()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;print_simple_box_end()&amp;lt;/code&amp;gt; pair.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5418</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5418"/>
		<updated>2006-10-07T11:59:35Z</updated>

		<summary type="html">&lt;p&gt;Delius: Added diagram and explanations&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions addslashes() and stripslashes() are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the addslashes() function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the stripslashes() function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
[[Image:stripslashes.jpg]]&lt;br /&gt;
&lt;br /&gt;
Neither stripslashes() nor addslashes() should be used when going from User Input to the Database or from the Database to Screen Output (black arrows) but stripslashes() should be used when displaying user input on the screen (red arrow) or when reinserting data in to the database that came from the database (blue arrow). These last two are rare, so the use of addslashes and stripslashes should be rare.&lt;br /&gt;
&lt;br /&gt;
Sometimes you may want to add slashes or remove slashes from all proprties of an object at once. Moodle provides the very convenient functions &amp;lt;code&amp;gt;addslashes_object()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;stripslashes_recursive()&amp;lt;/code&amp;gt;. The latter also works on arrays.&lt;br /&gt;
&lt;br /&gt;
Moodle provides a function called stripslashes_safe() which only strips slashes in front of single and double quotes and in front of a backslash, so \&#039; becomes &#039;, \&amp;quot; becomes &amp;quot;, and \\ becomes \. Any other slashes, as in C:\Moodle for example, are preserved. It was introduced because in some circumstances it may not matter if this function is applied too often. However I find this function dangerous, because it may make you think that everything is fine until one of your users wants to include a bit of code in their input for example. I would not have been able to write this paragraph (with the \&#039; in it) if it had been passed through stripslashes_safe().&lt;br /&gt;
&lt;br /&gt;
Some core Moodle functions use stripslashes_safe():&lt;br /&gt;
 print_heading()&lt;br /&gt;
 print_heading_with_help()&lt;br /&gt;
 print_heading_block()&lt;br /&gt;
 print_simple_box()&lt;br /&gt;
It usually doesn&#039;t matter too much for headings, because including \\, \&#039;, or \&amp;quot; in headings is unusual, but it does matter in print_simple_box() and therefore the advice would be to avoid using this function and to use the print_simple_box_start() and print_simple_box_end() pair.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3405</id>
		<title>Output functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3405"/>
		<updated>2006-10-07T11:01:37Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page tries to explain a bit how dynamic data should be sent from Moodle to the browser in an organised and standard way. Obviously it&#039;s possible to have your own output methods but, thinking that you are going to share your code (yep, this is an OpenSource project!) and in the collaborative way we try to build and maintain the system every day, it would be really better to follow the basic guidelines explained below.&lt;br /&gt;
&lt;br /&gt;
By using them you will be helping to have better, more secure and readable code. Spend some minutes trying to understand them, please!&lt;br /&gt;
&lt;br /&gt;
Of course, thess functions can be discussed, modified and new functions can arrive if there are some good reasons for it. Just discuss it in the [http://moodle.org/mod/forum/view.php?id=55 General developer forum] at [http://moodle.org moodle.org].&lt;br /&gt;
&lt;br /&gt;
For each of the functions below we&#039;ll try to explain when they should be used, explaining the most important parameters supported and their meaning. Let&#039;s review them!&lt;br /&gt;
&lt;br /&gt;
=== p() and s() ===&lt;br /&gt;
&lt;br /&gt;
 function s($var, $strip=false) and function p($var, $strip=false)&lt;br /&gt;
&lt;br /&gt;
These functions share the same code so they will be explained together. The only difference is that s() returns the string while p() prints it directly.&lt;br /&gt;
&lt;br /&gt;
These functions should be used to:&lt;br /&gt;
&lt;br /&gt;
* print all the &#039;&#039;&#039;values of form fields&#039;&#039;&#039; like &amp;lt;nowiki&amp;gt;&amp;lt;input&amp;gt;&amp;lt;/nowiki&amp;gt; or &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; tags.&lt;br /&gt;
* to &#039;&#039;&#039;show plain (non html) text&#039;&#039;&#039; that has been introduced by the user (search string, quiz responses...).&lt;br /&gt;
* in general, all the &#039;&#039;&#039;dynamic data, not being html&#039;&#039;&#039;, that doesn&#039;t need to be cleaned nor processed by filters&lt;br /&gt;
&lt;br /&gt;
It is important not to use these functions for strings that contain html markup.&lt;br /&gt;
&lt;br /&gt;
The functions replace certain characters that would have special meaning in html ( &amp;lt;, &amp;gt;, &amp;quot;, &#039;, and &amp;amp;) by html entities so that they are displayed as intended. Note that even though the value of form fields printed with p() will have these characters converted to html entities, the submitted values will contain the original characters again.&lt;br /&gt;
&lt;br /&gt;
The key parameter for this function is:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;strip&#039;&#039;&#039;: it decides if we want to strip slashes from the string or no. By default it&#039;s &#039;false&#039; so no strip will be performed. We should set such parameter to &#039;true&#039; only when data to be processed isn&#039;t coming from database but from http requests (forms, links...).&lt;br /&gt;
&lt;br /&gt;
=== format_text() ===&lt;br /&gt;
&lt;br /&gt;
 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) &lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;any html/plain/markdown/moodle text&#039;&#039;&#039;, needing any of the features below. Mainly used for long strings like posts, answers, glossary items...&lt;br /&gt;
&lt;br /&gt;
Note that this function is really &#039;&#039;&#039;heavy&#039;&#039;&#039; because it supports &#039;&#039;&#039;cleaning&#039;&#039;&#039; of dangerous contents, delegates processing to enabled &#039;&#039;&#039;filter&#039;&#039;&#039;s, supports different &#039;&#039;&#039;formats&#039;&#039;&#039; of text (HTML, PLAIN, MARKDOWN, MOODLE) and performs a lot of &#039;&#039;&#039;automatic conversions&#039;&#039;&#039; like adding smilies, build links. Also, it includes a strong &#039;&#039;&#039;cache mechanism&#039;&#039;&#039; (DB based) that will alleviate the server from a lot of work processing the same texts time and again.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039;: To tell the function about how the data has been entered. It defaults to FORMAT_MOODLE that is a cool format to process plain text because it features automatic link conversion, smilies and good conversion to html output. Other formats are FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOW.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039;: Here we can specify how we want the process to be performed. You only need to define them if they are different from the default value assumed. Main options are:&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;noclean&#039;&#039;&#039;: To decide if we want to skip the clean of text, &#039;&#039;&#039;un-protecting us&#039;&#039;&#039; from attacks and other security flaws (defaults to false, so protection is enabled. You &#039;&#039;&#039;shouldn&#039;t set it to true never&#039;&#039;&#039; unless you are 200% sure that only controlled users can edit it (mainly admins). &#039;&#039;&#039;Never use it for general text places&#039;&#039;&#039; (posts...) or you will be, sooner or later, attacked! Note that this option is ignored for FORMAT_PLAIN, the text is never cleaned.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;filter&#039;&#039;&#039;: To decide if you want to allow filters to process the text (defaults to true). This is ignored by FORMAT_PLAIN for which filters are never applied.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;smiley&#039;&#039;&#039;: To decide if we want automatic conversion of smilies to images (defaults to true). This is ignored by FORMAT_PLAIN for which smileys are never converted.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;para&#039;&#039;&#039;: To decide if you want every paragraph automatically enclosed between html paragraph tags (&amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;...&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true). This option only applies to FORMAT_MOODLE.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;newlines&#039;&#039;&#039;: To decide if linefeeds in text should be converted to html newlines (&amp;lt;nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true). This option only applies to FORMAT_MOODLE.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== format_string() ===&lt;br /&gt;
&lt;br /&gt;
 function format_string ($string, $striplinks = false, $courseid=NULL )&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;short strings (non html) that need filter processing&#039;&#039;&#039; (activity titles, post subjects, glossary concepts...).&lt;br /&gt;
&lt;br /&gt;
Please note that this function is basically one stripped version of the full format_text() function detailed above and &#039;&#039;&#039;it doesn&#039;t offer any of it options nor protections&#039;&#039;&#039;. It simply filters the strings and return the result, so we must ensure that text being processed has been properly cleaned at input time, using the proper xxx_param() functions.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;striplinks&#039;&#039;&#039;: To decide if, after the text has been processed by filters, we must delete any link from the result test. Used when we want to show the text inside menus, page titles... (defaults to false).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== print_textarea() ===&lt;br /&gt;
&lt;br /&gt;
 function print_textarea($usehtmleditor, $rows, $cols, $width, &lt;br /&gt;
                        $height, $name, $value=&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;, $courseid=0, $return=false)&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* display &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; fields when we want to allow users (based in their preferences and browser capabilities) &#039;&#039;&#039;to use the visual HTML editor&#039;&#039;&#039; instead of one standard &#039;plain&#039; area.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;usehtmleditor&#039;&#039;&#039;: to decide if the HTML editor must be showed. The value of this parameter must be calculated by the can_use_html_editor() function.&lt;br /&gt;
* &#039;&#039;&#039;rows, cols&#039;&#039;&#039;: to be applied it the standard textarea is showed.&lt;br /&gt;
* &#039;&#039;&#039;width, height&#039;&#039;&#039;: to be applied if the HTML editor is used.&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039;: the name of the field that will contain the text once the form was submitted.&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039;: the initial value of the textarea.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help the editor to know where it is work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
* &#039;&#039;&#039;return&#039;&#039;&#039;: to decide if the generated html code must be returned to the caller (true) or printed directly (false). Defaults to false.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5417</id>
		<title>Slashes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Slashes&amp;diff=5417"/>
		<updated>2006-10-07T10:46:53Z</updated>

		<summary type="html">&lt;p&gt;Delius: I still have to draw the diagram for this page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The functions addslashes() and stripslashes() are misused often, so here is a short explanation of what they are for and when they should be used.&lt;br /&gt;
&lt;br /&gt;
Before entering data into a database, special symbols like single or double quotes need to be escaped by a backslash. So for example every &#039; needs to be converted to \&#039; in any string that is to be stored in the database. When the string is fetched back from the database it comes back without those slashes. So if data that comes directly from the database is to be written back to the database it needs to have the slashes added to it again. This is an example where the addslashes() function should be used. &lt;br /&gt;
&lt;br /&gt;
Because data submitted by the user will often need to be written to the database, Moodle ensures that it automatically gets slashes added to it. So you never have to use addslashes() on data that comes from the user. If however you want to display data that was submitted by the user then you have to strip the slashes that have been added. This is an example where the stripslashes() function should be used.&lt;br /&gt;
&lt;br /&gt;
The whole situation can be summarized in the following diagram:&lt;br /&gt;
&lt;br /&gt;
(Diagram in preparation)&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=926</id>
		<title>Coding</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=926"/>
		<updated>2006-10-07T10:35:26Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* General rules */  Added link to Developer:Output_functions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any collaborative project needs consistency and stability to stay strong.&lt;br /&gt;
&lt;br /&gt;
These &#039;&#039;&#039;coding guidelines&#039;&#039;&#039; are to provide a goal for all Moodle code to strive to. It&#039;s true that some of the older existing code falls short in a few areas, but it will all be fixed eventually. All new code definitely must adhere to these standards as closely as possible.&lt;br /&gt;
&lt;br /&gt;
==General rules==&lt;br /&gt;
&lt;br /&gt;
# All code files should use the .php extension.&lt;br /&gt;
# All template files should use the .html extension.&lt;br /&gt;
# All text files should use Unix-style text format (most text editors have this as an option).&lt;br /&gt;
# All php tags must be &#039;full&#039; tags like &amp;lt;?php ?&amp;gt; ... not &#039;short&#039; tags like &amp;lt;? ?&amp;gt;.&lt;br /&gt;
# All existing copyright notices must be retained. You can add your own if necessary.&lt;br /&gt;
# Each file should include the main config.php file.&lt;br /&gt;
# Each file should check that the user is authenticated correctly, using require_login() and isadmin(), isteacher(), iscreator() or isstudent().&lt;br /&gt;
# All access to databases should use the functions in &#039;&#039;lib/dmllib.php&#039;&#039; whenever possible - this allows compatibility across a wide range of databases. You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions within your code (usually a lib.php file); and clearly marked.&lt;br /&gt;
# Don&#039;t create or use global variables except for the standard $CFG, $SESSION, $THEME, $SITE, $COURSE and $USER.&lt;br /&gt;
# All variables should be initialised or at least tested for existence using isset() or empty() before they are used.&lt;br /&gt;
# All strings should be translatable - create new texts in the &amp;quot;lang/en_utf8&amp;quot; files with concise English lowercase names and retrieve them from your code using get_string() or print_string().&lt;br /&gt;
# All help files should be translatable - create new texts in the &amp;quot;lang/en_utf8/help&amp;quot; directory and call them using helpbutton(). If you need to update a help file:&lt;br /&gt;
#* with a minor change, where an old translation of the file would still make sense, then it&#039;s OK to make the change but you should notify translation AT moodle DOT org.&lt;br /&gt;
#* for a major change you should create a new file by adding an incrementing number (eg filename2.html) so that translators can easily see it&#039;s a new version of the file. Obviously the new code and the help index files should also be modified to point to the newest versions.&lt;br /&gt;
# Incoming data from the browser (sent via GET or POST) automatically has magic_quotes applied (regardless of the PHP settings) so that you can safely insert it straight into the database. All other raw data (from files, or from databases) must be escaped with addslashes() before inserting it into the database. Because this is so often done incorrectly, there is more explanation on this issue of adding and stripping slashes on a [[Developer:Slashes|separate page]].&lt;br /&gt;
# VERY IMPORTANT: All texts within Moodle, especially those that have come from users, should be printed using the format_text() function. This ensures that text is filtered and cleaned correctly. More information can be found on the page about [[Developer:Output_functions|output functions]].&lt;br /&gt;
# User actions should be logged using the [[Logs|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].&lt;br /&gt;
&lt;br /&gt;
==Coding style==&lt;br /&gt;
&lt;br /&gt;
I know it can be a little annoying to change your style if you&#039;re used to something else, but balance that annoyance against the annoyance of all the people trying later on to make sense of Moodle code with mixed styles. There are obviously many good points for and against any style that people use, but the current style just is, so please stick to it.&lt;br /&gt;
&lt;br /&gt;
1. Indenting should be consistently 4 spaces. Don&#039;t use tabs AT ALL.&lt;br /&gt;
&lt;br /&gt;
2. Variable names should always be easy-to-read, meaningful lowercase English words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.&lt;br /&gt;
&lt;br /&gt;
      GOOD: $quiz&lt;br /&gt;
      GOOD: $errorstring&lt;br /&gt;
      GOOD: $assignments (for an array of objects)&lt;br /&gt;
      GOOD: $i (but only in little loops)&lt;br /&gt;
&lt;br /&gt;
      BAD: $Quiz&lt;br /&gt;
      BAD: $aReallyLongVariableNameWithoutAGoodReason&lt;br /&gt;
      BAD: $error_string&lt;br /&gt;
&lt;br /&gt;
3. Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.&lt;br /&gt;
&lt;br /&gt;
      define(&amp;quot;FORUM_MODE_FLATOLDEST&amp;quot;, 1);&lt;br /&gt;
4. Function names should be simple English lowercase words, and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores. Parameters should always have sensible defaults if possible. Note there is no space between the function name and the following (brackets).&lt;br /&gt;
&lt;br /&gt;
      function forum_set_display_mode($mode=0) {&lt;br /&gt;
          global $USER, $CFG;&lt;br /&gt;
          &lt;br /&gt;
          if ($mode) {&lt;br /&gt;
              $USER-&amp;gt;mode = $mode;&lt;br /&gt;
          } else if (empty($USER-&amp;gt;mode)) {&lt;br /&gt;
              $USER-&amp;gt;mode = $CFG-&amp;gt;forum_displaymode;&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
5. Blocks must always be enclosed in curly braces (even if there is only one line). Moodle uses this style:&lt;br /&gt;
&lt;br /&gt;
      if ($quiz-&amp;gt;attempts) {&lt;br /&gt;
          if ($numattempts &amp;gt; $quiz-&amp;gt;attempts) {&lt;br /&gt;
              error($strtoomanyattempts, &amp;quot;view.php?id=$cm-&amp;gt;id&amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
6. Strings should be defined using single quotes where possible, for increased speed.&lt;br /&gt;
&lt;br /&gt;
      $var = &#039;some text without any variables&#039;;&lt;br /&gt;
      $var = &amp;quot;with special characters like a new line \n&amp;quot;;&lt;br /&gt;
      $var = &#039;a very, very long string with a &#039;.$single.&#039; variable in it&#039;;&lt;br /&gt;
      $var = &amp;quot;some $text with $many variables $within it&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
7. Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.&lt;br /&gt;
&lt;br /&gt;
* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.&lt;br /&gt;
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
      * The description should be first, with asterisks laid out exactly&lt;br /&gt;
      * like this example. If you want to refer to a another function,&lt;br /&gt;
      * do it like this: {@link clean_param()}. Then, add descriptions&lt;br /&gt;
      * for each parameter as follows.&lt;br /&gt;
      *&lt;br /&gt;
      * @param int $postid The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $scale The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $ratings The PHP type is followed by the variable name&lt;br /&gt;
      * @return mixed&lt;br /&gt;
      */&lt;br /&gt;
      function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {&lt;br /&gt;
          if (!$ratings) {&lt;br /&gt;
              $ratings = array();     // Initialize the empty array&lt;br /&gt;
              if ($rates = get_records(&amp;quot;forum_ratings&amp;quot;, &amp;quot;post&amp;quot;, $postid)) {&lt;br /&gt;
                  // Process each rating in turn&lt;br /&gt;
                  foreach ($rates as $rate) {&lt;br /&gt;
      ....etc&lt;br /&gt;
&lt;br /&gt;
8. Space should be used liberally - don&#039;t be afraid to spread things out a little to gain some clarity. Generally, there should be one space between brackets and normal statements, but no space between brackets and variables or functions:&lt;br /&gt;
&lt;br /&gt;
      foreach ($objects as $key =&amp;gt; $thing) {&lt;br /&gt;
          process($thing);&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      if ($x == $y) {&lt;br /&gt;
          $a = $b;&lt;br /&gt;
      } else if ($x == $z) {&lt;br /&gt;
          $a = $c;&lt;br /&gt;
      } else {&lt;br /&gt;
          $a = $d;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
9. When making a COPY of an object, always use the php5 clone() function (otherwise you may end up with just a reference to the first object).  Moodle will make sure this works consistently on php4 too.&lt;br /&gt;
&lt;br /&gt;
      BAD:   $b = $a;&lt;br /&gt;
      GOOD:  $b = clone($a);&lt;br /&gt;
&lt;br /&gt;
If the thing you want to copy is not an object, but may contain objects (eg an array of objects) then use fullclone() instead.&lt;br /&gt;
&lt;br /&gt;
==Database structures==&lt;br /&gt;
&lt;br /&gt;
# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])&lt;br /&gt;
# The main table containing instances of each module must have the same name as the module (eg widget) and contain the following minimum fields:&lt;br /&gt;
#* id - as described above&lt;br /&gt;
#* course - the id of the course that each instance belongs to&lt;br /&gt;
#* name - the full name of each instance of the module&lt;br /&gt;
# Other tables associated with a module that contain information about &#039;things&#039; should be named widget_things (note the plural).&lt;br /&gt;
# Table and column names should avoid using [[Database reserved words|reserved words in any database]]. Please check them before creation.&lt;br /&gt;
# Column names should be always lowercase, simple and short, following the same rules as for variable names.&lt;br /&gt;
# Where possible, columns that contain a reference to the id field of another table (eg widget) should be called widgetid. (Note that this convention is newish and not followed in some older tables)&lt;br /&gt;
# Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.&lt;br /&gt;
# Most tables should have a timemodified field (INT10) which is updated with a current timestamp obtained with the PHP time() function.&lt;br /&gt;
# Always define a default value for each field (and make it sensible)&lt;br /&gt;
# Each table name should start with the database prefix ($CFG-&amp;gt;prefix). In a lot of cases, this is taken care of for you automatically. Also, under Postgres, the name of every index must start with the prefix too.&lt;br /&gt;
# In order to guarantee [[XMLDB problems#Table and column aliases - the AS keyword|cross-db compatibility]] follow these simple rules about the use of the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword (only if you need table/colum aliases, of course):&lt;br /&gt;
#* &#039;&#039;&#039;Don&#039;t use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;table aliases&#039;&#039;&#039;.&lt;br /&gt;
#* &#039;&#039;&#039;Do use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;column aliases&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Never&#039;&#039;&#039; create UNIQUE KEYs (constraints) at all. Instead use UNIQUE INDEXes. In the future, if we decide to add referential integrity to Moodle and we need UNIQUE KEYs they will be used, but not now. Please note that the XMLDB editor allows you to specify both XMLDB-only UNIQUE and FOREIGN constraints (and that&#039;s good, in order to have the XML well defined) but only underlying INDEXes will be generated. &lt;br /&gt;
# Those XMLDB-only UNIQUE KEYs (read previous point) only must be defined if such field/fields &#039;&#039;&#039;are going to be the target&#039;&#039;&#039; for some (XMLDB-only too) FOREIGN KEY. Else, create them as simple UNIQUE INDEXes.&lt;br /&gt;
# Tables associated &#039;&#039;&#039;with one block&#039;&#039;&#039; must follow this convention with their names: &#039;&#039;&#039;$CFG-&amp;gt;prefix + &amp;quot;block_&amp;quot; + name_of_the_block + anything_else&#039;&#039;&#039;. For example, assuming that $CFG-&amp;gt;prefix is &#039;mdl_&#039;, all the tables for the block &amp;quot;rss_client&amp;quot; must start by &#039;mdl_block_rss_client&#039; (being possible to add more words at the end, i.e. &#039;mdl_block_rss_client_anothertable&#039;...). This rule will be 100% enforced with Moodle 2.0, giving time to developers until then. See [http://tracker.moodle.org/browse/MDL-6786 Task 6786] for more info about this.&lt;br /&gt;
&lt;br /&gt;
==Security issues (and handling form and URL data)==&lt;br /&gt;
&lt;br /&gt;
# Do not rely on &#039;register_globals&#039;. Every variable must be properly initialised in every code file. It must be obvious where the variable came from&lt;br /&gt;
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.&lt;br /&gt;
# Do not use the optional_variable() function (this function is now deprecated). Use the optional_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Do not use the require_variable() function (this function is now deprecated). Use the required_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Use data_submitted(), with care. Data must still be cleaned before use.&lt;br /&gt;
# Do not use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.&lt;br /&gt;
# Do not check for an action using something like if (isset($_GET[&#039;something&#039;])). Use, e.g., $something = optional_param( &#039;something&#039;,-1,PARAM_INT ) and then perform proper test for it being in its expected range of values e.g., if ($something&amp;gt;=0) {....&lt;br /&gt;
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.&lt;br /&gt;
# Use &#039;sesskey&#039; mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;sesskey&amp;quot; value=&amp;quot;&amp;lt;?php echo sesskey(); ?&amp;gt;&amp;quot; /&amp;gt;. When you process the form check with if (!confirm_sesskey()) {error(&#039;Bad Session Key&#039;);}.&lt;br /&gt;
# All filenames must be &#039;cleaned&#039; using the clean_filename() function, if this has not been done already by appropriate use of required_param() or optional_param()&lt;br /&gt;
# Any data read from the database must have addslashes() applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object().&lt;br /&gt;
# Wherever possible, data to be stored in the database must come from POST data (from a form with method=&amp;quot;POST&amp;quot;) as opposed to GET data (ie, data from the URL line).&lt;br /&gt;
# Do not use data from $_SERVER if you can avoid it. This has portability issues.&lt;br /&gt;
# If it hasn&#039;t been done somewhere else, make sure all data written to the database has been through the clean_param() function using the appropriate PARAM_XXXX for the datatype.&lt;br /&gt;
# If you write custom SQL code, make very sure it is correct. In particular watch out for missing quotes around values. Possible SQL &#039;injection&#039; exploit.&lt;br /&gt;
# Check all data (particularly that written to the database) in every file it is used. Do not expect or rely on it being done somewhere else.&lt;br /&gt;
# Blocks of code to be included should contain a definite PHP structure (e.g, a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised variable usage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Manual de Estilo de Código]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3291</id>
		<title>Filters 1.9 and before</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3291"/>
		<updated>2006-10-07T10:33:54Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* To create a filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Please note:&#039;&#039;&#039; This page contains information for developers. You may prefer to read the [[Filters (administrator)| information about filters for teachers and administrators]].&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Filters&#039;&#039;&#039; allow for the for the automatic transformation of entered text into different, often more complex forms. For example the titles of [[Resources]] can automatically become hyperlinks that take you to the relevant resource, URLs pointing to [[mp3]] files can become [[Flash]] controls embedded in the webpage that let you pause and rewind the audio. The possibilities are endless and there are a number of standard filters included with Moodle and many more specialized filters contributed by the community.&lt;br /&gt;
&lt;br /&gt;
==To create a filter==&lt;br /&gt;
&lt;br /&gt;
To create a filter that removes all occurrences of the letter &amp;quot;x&amp;quot; - we&#039;ll call it &amp;quot;removex&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Create a new folder inside Moodle&#039;s /filter/ folder, called &amp;quot;removex&amp;quot;&lt;br /&gt;
# Create a new PHP script file inside the folder you&#039;ve just created - name it &amp;quot;filter.php&amp;quot;&lt;br /&gt;
# Write a new PHP function in this file, called &amp;quot;removex_filter()&amp;quot; which takes two parameters - a course ID and a piece of text to be filtered - and returns the processed text.&lt;br /&gt;
&lt;br /&gt;
For our example the filter.php file would look like:&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 function filter_removex($courseid, $text) {&lt;br /&gt;
     return str_replace(&amp;quot;x&amp;quot;, &amp;quot;&amp;quot;, $text);&lt;br /&gt;
 }&lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When trying this out, remember to make sure that you activate the filter in the [[Filters (administrator)|filters administration screen]].&lt;br /&gt;
&lt;br /&gt;
Also remember that text filtering functions, when activated, will be used intensively by the server, so you should optimise the filters as far as possible (cut down on database calls etc). Moodle caches the results of filtering to help with processing speed, but it&#039;s still worth being careful about your filter design.&lt;br /&gt;
&lt;br /&gt;
Filters are applied to all text that is printed with the [[Developer:Output functions|output functions]] format_text() or format_string(). One thing to keep in mind when designing the filter is that the function format_text() first applies other transformations (for example text_to_html() or replace_smilies()) before the strings are passed to your filter. The function format_string() on the other hand passes the string as it is.&lt;br /&gt;
&lt;br /&gt;
==Adding a settings screen==&lt;br /&gt;
&lt;br /&gt;
Moodle 1.6 added the options for filters to have their own settings screen. To do this perform the following steps:&lt;br /&gt;
* In the same folder as the filter create a file called &#039;&#039;&#039;filterconfig.html&#039;&#039;&#039;.&lt;br /&gt;
* For the parameters you want to be edited provide appropriate form fields (note you should not provide the actual form tag itself)&lt;br /&gt;
* The format of the field names should be &#039;&#039;&#039;filter_filtername_fieldname&#039;&#039;&#039;; where &#039;&#039;&#039;filtername&#039;&#039;&#039; is the name of the filter (ie, the name of the folder) and &#039;&#039;&#039;fieldname&#039;&#039;&#039; the name of the field (&#039;&#039;&#039;filter&#039;&#039;&#039; is the actual word &#039;&#039;filter&#039;&#039;). The field will be created as a config variable, so you can display the current value with &#039;&#039;&#039;$CFG-&amp;gt;filter_filtername_fieldname. Example:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;textarea type=&amp;quot;text&amp;quot; name=&amp;quot;filter_censor_badwords&amp;quot; cols=&amp;quot;60&amp;quot; rows=&amp;quot;10&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;?php echo &amp;quot;$CFG-&amp;gt;filter_censor_badwords&amp;quot;; ?&amp;gt;&lt;br /&gt;
    &amp;lt;/textarea&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* you will need to pay attention to setting the default value for these parameters. As filters are pluggable it is best to do it in the filter, but bear in mind that you must check the default both in the settings screen and in the filter itself as you cannot know which will be called first. Some filters with extensive lists of parameters call an external script for this purpose (see, for example, the multimedia filter)&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Filters schema]] - a page containing some ideas and thoughts about modifications to the filters system&lt;br /&gt;
* [[Filters (administrator)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Filter]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3404</id>
		<title>Output functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3404"/>
		<updated>2006-10-07T10:32:41Z</updated>

		<summary type="html">&lt;p&gt;Delius: Output functions moved to Developer:Output functions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page tries to explain a bit how dynamic data should be sent from Moodle to the browser in a organised and standard way. Obviously it&#039;s possible to have your own output methods but, thinking that you are going to share your code (yep, this is an OpenSource project!) and in the collaborative way we try to build and maintain the system every day, it would be really better to follow the basic guidelines explained below.&lt;br /&gt;
&lt;br /&gt;
By using them you will be helping to have better, more secure and readable code. Spend some minutes trying to understand them, please!&lt;br /&gt;
&lt;br /&gt;
Of course, this functions can be discused, modified and new functions can arrive if there are some good reasons for it. Just discuss it in the [http://moodle.org/mod/forum/view.php?id=55 General developer forum] at [http://moodle.org moodle.org].&lt;br /&gt;
&lt;br /&gt;
For each of the functions below we&#039;ll try to explain when they should be used, commenting the most important parameters supported and their meaning. Let&#039;s review them!&lt;br /&gt;
&lt;br /&gt;
=== p() and s() ===&lt;br /&gt;
&lt;br /&gt;
 function s($var, $strip=false) and function p($var, $strip=false)&lt;br /&gt;
&lt;br /&gt;
This functions share the same code so they will be explained together. The only difference is that s() returns the string while p() prints it directly.&lt;br /&gt;
&lt;br /&gt;
This functions should be used to:&lt;br /&gt;
&lt;br /&gt;
* print all the &#039;&#039;&#039;values of form fields&#039;&#039;&#039; like &amp;lt;nowiki&amp;gt;&amp;lt;input&amp;gt;&amp;lt;/nowiki&amp;gt; or &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; tags.&lt;br /&gt;
* to &#039;&#039;&#039;show plain (non html) text&#039;&#039;&#039; that have been introduced by the user (search string, quiz responses...).&lt;br /&gt;
* in general, all the &#039;&#039;&#039;dynamic data, not being html&#039;&#039;&#039;, that doesn&#039;t need to be cleaned nor processed by filters&lt;br /&gt;
&lt;br /&gt;
It is important not to use these functions for strings that contain html markup.&lt;br /&gt;
&lt;br /&gt;
The functions replace certain characters that would have special meaning in html ( &amp;lt;, &amp;gt;, &amp;quot;, &#039;, and &amp;amp;) by html entities so that they are displayed as intended. Note that even though the value of form fields printed with p() will have these characters converted to html entities, the submitted values will contain the original characters again.&lt;br /&gt;
&lt;br /&gt;
The key parameter for this function is:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;strip&#039;&#039;&#039;: it decides if we want to strip slashes from the string or no. By default it&#039;s &#039;false&#039; so no strip will be performed. We should set such parameter to &#039;true&#039; only when data to be processed isn&#039;t coming from database but from http requests (forms, links...).&lt;br /&gt;
&lt;br /&gt;
=== format_text() ===&lt;br /&gt;
&lt;br /&gt;
 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) &lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;any html/plain/markdown/moodle text&#039;&#039;&#039;, needing any of the features below. Mainly used for long strings like posts, answers, glossary items...&lt;br /&gt;
&lt;br /&gt;
Note that this function is really &#039;&#039;&#039;heavy&#039;&#039;&#039; because it supports &#039;&#039;&#039;cleaning&#039;&#039;&#039; of dangerous contents, delegates process to enabled &#039;&#039;&#039;filter&#039;&#039;&#039;s, supports different &#039;&#039;&#039;formats&#039;&#039;&#039; of text (HTML, PLAIN, MARKDOWN, MOODLE) and performs a lot of &#039;&#039;&#039;automatic conversions&#039;&#039;&#039; like adding smilies, build links, so it&#039;s a really heavy function. Also, it includes one strong &#039;&#039;&#039;cache mechanism&#039;&#039;&#039; (DB based) that will alleviate the server from a lot of work processing the same texts time and again.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039;: To tell the function about how the data has been entered. It defaults to FORMAT_MOODLE that is a cool format to process plain text because it features automatic link conversion, smilies and good conversion to html output. Other formats are FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOW.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039;: Here we can specify how we want the process to be performed. You only need to define them if they are different from the default value assumed. Main options are:&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;noclean&#039;&#039;&#039;: To decide if we want to skip the clean of text, &#039;&#039;&#039;un-protecting us&#039;&#039;&#039; from attacks and other security flaws (defaults to false, so protection is enabled. You &#039;&#039;&#039;shouldn&#039;t set it to true never&#039;&#039;&#039; unless you are 200% sure that only controlled users can edit it (mainly admins). &#039;&#039;&#039;Never use it for general text places&#039;&#039;&#039; (posts...) or you will be, sooner or later, attacked! Note that this option is ignored for FORMAT_PLAIN, the text is never cleaned.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;filter&#039;&#039;&#039;: To decide if you want to allow filters to process the text (defaults to true). This is ignored by FORMAT_PLAIN for which filters are never applied.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;smiley&#039;&#039;&#039;: To decide if we want automatic conversion of smilies to images (defaults to true). This is ignored by FORMAT_PLAIN for which smileys are never converted.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;para&#039;&#039;&#039;: To decide if you want every paragraph automatically enclosed between html paragraph tags (&amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;...&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true). This option only applies to FORMAT_MOODLE.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;newlines&#039;&#039;&#039;: To decide if linefeeds in text should be converted to html newlines (&amp;lt;nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true). This option only applies to FORMAT_MOODLE.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== format_string() ===&lt;br /&gt;
&lt;br /&gt;
 function format_string ($string, $striplinks = false, $courseid=NULL )&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;short strings (non html) that need filter processing&#039;&#039;&#039; (activity titles, post subjects, glossary concepts...).&lt;br /&gt;
&lt;br /&gt;
Please note that this function is basically one stripped version of the full format_text() function detailed above and &#039;&#039;&#039;it doesn&#039;t offer any of it options nor protections&#039;&#039;&#039;. It simply filters the strings and return the result, so we must ensure that text being processed has been properly cleaned at input time, using the proper xxx_param() functions.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;striplinks&#039;&#039;&#039;: To decide if, after the text has been processed by filters, we must delete any link from the result test. Used when we want to show the text inside menus, page titles... (defaults to false).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== print_textarea() ===&lt;br /&gt;
&lt;br /&gt;
 function print_textarea($usehtmleditor, $rows, $cols, $width, &lt;br /&gt;
                        $height, $name, $value=&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;, $courseid=0, $return=false)&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* display &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; fields when we want to allow users (based in their preferences and browser capabilities) &#039;&#039;&#039;to use the visual HTML editor&#039;&#039;&#039; instead of one standard &#039;plain&#039; area.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;usehtmleditor&#039;&#039;&#039;: to decide if the HTML editor must be showed. The value of this parameter must be calculated by the can_use_html_editor() function.&lt;br /&gt;
* &#039;&#039;&#039;rows, cols&#039;&#039;&#039;: to be applied it the standard textarea is showed.&lt;br /&gt;
* &#039;&#039;&#039;width, height&#039;&#039;&#039;: to be applied if the HTML editor is used.&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039;: the name of the field that will contain the text once the form was submitted.&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039;: the initial value of the textarea.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help the editor to know where it is work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
* &#039;&#039;&#039;return&#039;&#039;&#039;: to decide if the generated html code must be returned to the caller (true) or printed directly (false). Defaults to false.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=925</id>
		<title>Coding</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=925"/>
		<updated>2006-10-07T10:29:11Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* General rules */  Added link to pages about slashes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any collaborative project needs consistency and stability to stay strong.&lt;br /&gt;
&lt;br /&gt;
These &#039;&#039;&#039;coding guidelines&#039;&#039;&#039; are to provide a goal for all Moodle code to strive to. It&#039;s true that some of the older existing code falls short in a few areas, but it will all be fixed eventually. All new code definitely must adhere to these standards as closely as possible.&lt;br /&gt;
&lt;br /&gt;
==General rules==&lt;br /&gt;
&lt;br /&gt;
# All code files should use the .php extension.&lt;br /&gt;
# All template files should use the .html extension.&lt;br /&gt;
# All text files should use Unix-style text format (most text editors have this as an option).&lt;br /&gt;
# All php tags must be &#039;full&#039; tags like &amp;lt;?php ?&amp;gt; ... not &#039;short&#039; tags like &amp;lt;? ?&amp;gt;.&lt;br /&gt;
# All existing copyright notices must be retained. You can add your own if necessary.&lt;br /&gt;
# Each file should include the main config.php file.&lt;br /&gt;
# Each file should check that the user is authenticated correctly, using require_login() and isadmin(), isteacher(), iscreator() or isstudent().&lt;br /&gt;
# All access to databases should use the functions in &#039;&#039;lib/dmllib.php&#039;&#039; whenever possible - this allows compatibility across a wide range of databases. You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions within your code (usually a lib.php file); and clearly marked.&lt;br /&gt;
# Don&#039;t create or use global variables except for the standard $CFG, $SESSION, $THEME, $SITE, $COURSE and $USER.&lt;br /&gt;
# All variables should be initialised or at least tested for existence using isset() or empty() before they are used.&lt;br /&gt;
# All strings should be translatable - create new texts in the &amp;quot;lang/en_utf8&amp;quot; files with concise English lowercase names and retrieve them from your code using get_string() or print_string().&lt;br /&gt;
# All help files should be translatable - create new texts in the &amp;quot;lang/en_utf8/help&amp;quot; directory and call them using helpbutton(). If you need to update a help file:&lt;br /&gt;
#* with a minor change, where an old translation of the file would still make sense, then it&#039;s OK to make the change but you should notify translation AT moodle DOT org.&lt;br /&gt;
#* for a major change you should create a new file by adding an incrementing number (eg filename2.html) so that translators can easily see it&#039;s a new version of the file. Obviously the new code and the help index files should also be modified to point to the newest versions.&lt;br /&gt;
# Incoming data from the browser (sent via GET or POST) automatically has magic_quotes applied (regardless of the PHP settings) so that you can safely insert it straight into the database. All other raw data (from files, or from databases) must be escaped with addslashes() before inserting it into the database. Because this is so often done incorrectly, there is more explanation on this issue of adding and stripping slashes on a [[Developer:Slashes|separate page]].&lt;br /&gt;
# VERY IMPORTANT: All texts within Moodle, especially those that have come from users, should be printed using the format_text() function. This ensures that text is filtered and cleaned correctly.&lt;br /&gt;
# User actions should be logged using the [[Logs|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].&lt;br /&gt;
&lt;br /&gt;
==Coding style==&lt;br /&gt;
&lt;br /&gt;
I know it can be a little annoying to change your style if you&#039;re used to something else, but balance that annoyance against the annoyance of all the people trying later on to make sense of Moodle code with mixed styles. There are obviously many good points for and against any style that people use, but the current style just is, so please stick to it.&lt;br /&gt;
&lt;br /&gt;
1. Indenting should be consistently 4 spaces. Don&#039;t use tabs AT ALL.&lt;br /&gt;
&lt;br /&gt;
2. Variable names should always be easy-to-read, meaningful lowercase English words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.&lt;br /&gt;
&lt;br /&gt;
      GOOD: $quiz&lt;br /&gt;
      GOOD: $errorstring&lt;br /&gt;
      GOOD: $assignments (for an array of objects)&lt;br /&gt;
      GOOD: $i (but only in little loops)&lt;br /&gt;
&lt;br /&gt;
      BAD: $Quiz&lt;br /&gt;
      BAD: $aReallyLongVariableNameWithoutAGoodReason&lt;br /&gt;
      BAD: $error_string&lt;br /&gt;
&lt;br /&gt;
3. Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.&lt;br /&gt;
&lt;br /&gt;
      define(&amp;quot;FORUM_MODE_FLATOLDEST&amp;quot;, 1);&lt;br /&gt;
4. Function names should be simple English lowercase words, and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores. Parameters should always have sensible defaults if possible. Note there is no space between the function name and the following (brackets).&lt;br /&gt;
&lt;br /&gt;
      function forum_set_display_mode($mode=0) {&lt;br /&gt;
          global $USER, $CFG;&lt;br /&gt;
          &lt;br /&gt;
          if ($mode) {&lt;br /&gt;
              $USER-&amp;gt;mode = $mode;&lt;br /&gt;
          } else if (empty($USER-&amp;gt;mode)) {&lt;br /&gt;
              $USER-&amp;gt;mode = $CFG-&amp;gt;forum_displaymode;&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
5. Blocks must always be enclosed in curly braces (even if there is only one line). Moodle uses this style:&lt;br /&gt;
&lt;br /&gt;
      if ($quiz-&amp;gt;attempts) {&lt;br /&gt;
          if ($numattempts &amp;gt; $quiz-&amp;gt;attempts) {&lt;br /&gt;
              error($strtoomanyattempts, &amp;quot;view.php?id=$cm-&amp;gt;id&amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
6. Strings should be defined using single quotes where possible, for increased speed.&lt;br /&gt;
&lt;br /&gt;
      $var = &#039;some text without any variables&#039;;&lt;br /&gt;
      $var = &amp;quot;with special characters like a new line \n&amp;quot;;&lt;br /&gt;
      $var = &#039;a very, very long string with a &#039;.$single.&#039; variable in it&#039;;&lt;br /&gt;
      $var = &amp;quot;some $text with $many variables $within it&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
7. Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.&lt;br /&gt;
&lt;br /&gt;
* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.&lt;br /&gt;
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
      * The description should be first, with asterisks laid out exactly&lt;br /&gt;
      * like this example. If you want to refer to a another function,&lt;br /&gt;
      * do it like this: {@link clean_param()}. Then, add descriptions&lt;br /&gt;
      * for each parameter as follows.&lt;br /&gt;
      *&lt;br /&gt;
      * @param int $postid The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $scale The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $ratings The PHP type is followed by the variable name&lt;br /&gt;
      * @return mixed&lt;br /&gt;
      */&lt;br /&gt;
      function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {&lt;br /&gt;
          if (!$ratings) {&lt;br /&gt;
              $ratings = array();     // Initialize the empty array&lt;br /&gt;
              if ($rates = get_records(&amp;quot;forum_ratings&amp;quot;, &amp;quot;post&amp;quot;, $postid)) {&lt;br /&gt;
                  // Process each rating in turn&lt;br /&gt;
                  foreach ($rates as $rate) {&lt;br /&gt;
      ....etc&lt;br /&gt;
&lt;br /&gt;
8. Space should be used liberally - don&#039;t be afraid to spread things out a little to gain some clarity. Generally, there should be one space between brackets and normal statements, but no space between brackets and variables or functions:&lt;br /&gt;
&lt;br /&gt;
      foreach ($objects as $key =&amp;gt; $thing) {&lt;br /&gt;
          process($thing);&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      if ($x == $y) {&lt;br /&gt;
          $a = $b;&lt;br /&gt;
      } else if ($x == $z) {&lt;br /&gt;
          $a = $c;&lt;br /&gt;
      } else {&lt;br /&gt;
          $a = $d;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
9. When making a COPY of an object, always use the php5 clone() function (otherwise you may end up with just a reference to the first object).  Moodle will make sure this works consistently on php4 too.&lt;br /&gt;
&lt;br /&gt;
      BAD:   $b = $a;&lt;br /&gt;
      GOOD:  $b = clone($a);&lt;br /&gt;
&lt;br /&gt;
If the thing you want to copy is not an object, but may contain objects (eg an array of objects) then use fullclone() instead.&lt;br /&gt;
&lt;br /&gt;
==Database structures==&lt;br /&gt;
&lt;br /&gt;
# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])&lt;br /&gt;
# The main table containing instances of each module must have the same name as the module (eg widget) and contain the following minimum fields:&lt;br /&gt;
#* id - as described above&lt;br /&gt;
#* course - the id of the course that each instance belongs to&lt;br /&gt;
#* name - the full name of each instance of the module&lt;br /&gt;
# Other tables associated with a module that contain information about &#039;things&#039; should be named widget_things (note the plural).&lt;br /&gt;
# Table and column names should avoid using [[Database reserved words|reserved words in any database]]. Please check them before creation.&lt;br /&gt;
# Column names should be always lowercase, simple and short, following the same rules as for variable names.&lt;br /&gt;
# Where possible, columns that contain a reference to the id field of another table (eg widget) should be called widgetid. (Note that this convention is newish and not followed in some older tables)&lt;br /&gt;
# Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.&lt;br /&gt;
# Most tables should have a timemodified field (INT10) which is updated with a current timestamp obtained with the PHP time() function.&lt;br /&gt;
# Always define a default value for each field (and make it sensible)&lt;br /&gt;
# Each table name should start with the database prefix ($CFG-&amp;gt;prefix). In a lot of cases, this is taken care of for you automatically. Also, under Postgres, the name of every index must start with the prefix too.&lt;br /&gt;
# In order to guarantee [[XMLDB problems#Table and column aliases - the AS keyword|cross-db compatibility]] follow these simple rules about the use of the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword (only if you need table/colum aliases, of course):&lt;br /&gt;
#* &#039;&#039;&#039;Don&#039;t use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;table aliases&#039;&#039;&#039;.&lt;br /&gt;
#* &#039;&#039;&#039;Do use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;column aliases&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Never&#039;&#039;&#039; create UNIQUE KEYs (constraints) at all. Instead use UNIQUE INDEXes. In the future, if we decide to add referential integrity to Moodle and we need UNIQUE KEYs they will be used, but not now. Please note that the XMLDB editor allows you to specify both XMLDB-only UNIQUE and FOREIGN constraints (and that&#039;s good, in order to have the XML well defined) but only underlying INDEXes will be generated. &lt;br /&gt;
# Those XMLDB-only UNIQUE KEYs (read previous point) only must be defined if such field/fields &#039;&#039;&#039;are going to be the target&#039;&#039;&#039; for some (XMLDB-only too) FOREIGN KEY. Else, create them as simple UNIQUE INDEXes.&lt;br /&gt;
# Tables associated &#039;&#039;&#039;with one block&#039;&#039;&#039; must follow this convention with their names: &#039;&#039;&#039;$CFG-&amp;gt;prefix + &amp;quot;block_&amp;quot; + name_of_the_block + anything_else&#039;&#039;&#039;. For example, assuming that $CFG-&amp;gt;prefix is &#039;mdl_&#039;, all the tables for the block &amp;quot;rss_client&amp;quot; must start by &#039;mdl_block_rss_client&#039; (being possible to add more words at the end, i.e. &#039;mdl_block_rss_client_anothertable&#039;...). This rule will be 100% enforced with Moodle 2.0, giving time to developers until then. See [http://tracker.moodle.org/browse/MDL-6786 Task 6786] for more info about this.&lt;br /&gt;
&lt;br /&gt;
==Security issues (and handling form and URL data)==&lt;br /&gt;
&lt;br /&gt;
# Do not rely on &#039;register_globals&#039;. Every variable must be properly initialised in every code file. It must be obvious where the variable came from&lt;br /&gt;
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.&lt;br /&gt;
# Do not use the optional_variable() function (this function is now deprecated). Use the optional_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Do not use the require_variable() function (this function is now deprecated). Use the required_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Use data_submitted(), with care. Data must still be cleaned before use.&lt;br /&gt;
# Do not use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.&lt;br /&gt;
# Do not check for an action using something like if (isset($_GET[&#039;something&#039;])). Use, e.g., $something = optional_param( &#039;something&#039;,-1,PARAM_INT ) and then perform proper test for it being in its expected range of values e.g., if ($something&amp;gt;=0) {....&lt;br /&gt;
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.&lt;br /&gt;
# Use &#039;sesskey&#039; mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;sesskey&amp;quot; value=&amp;quot;&amp;lt;?php echo sesskey(); ?&amp;gt;&amp;quot; /&amp;gt;. When you process the form check with if (!confirm_sesskey()) {error(&#039;Bad Session Key&#039;);}.&lt;br /&gt;
# All filenames must be &#039;cleaned&#039; using the clean_filename() function, if this has not been done already by appropriate use of required_param() or optional_param()&lt;br /&gt;
# Any data read from the database must have addslashes() applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object().&lt;br /&gt;
# Wherever possible, data to be stored in the database must come from POST data (from a form with method=&amp;quot;POST&amp;quot;) as opposed to GET data (ie, data from the URL line).&lt;br /&gt;
# Do not use data from $_SERVER if you can avoid it. This has portability issues.&lt;br /&gt;
# If it hasn&#039;t been done somewhere else, make sure all data written to the database has been through the clean_param() function using the appropriate PARAM_XXXX for the datatype.&lt;br /&gt;
# If you write custom SQL code, make very sure it is correct. In particular watch out for missing quotes around values. Possible SQL &#039;injection&#039; exploit.&lt;br /&gt;
# Check all data (particularly that written to the database) in every file it is used. Do not expect or rely on it being done somewhere else.&lt;br /&gt;
# Blocks of code to be included should contain a definite PHP structure (e.g, a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised variable usage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Manual de Estilo de Código]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=491</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=491"/>
		<updated>2006-09-29T20:38:57Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Resources and tools */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;Note:&#039;&#039;&#039; New developer documentation pages should be added to the &#039;&#039;Development namespace&#039;&#039; by typing &amp;lt;code&amp;gt;Development:&amp;lt;/code&amp;gt; before the new page name i.e. &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[New page name]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
*[[Unit tests]] explains how to run the unit tests, and how to write new test cases.&lt;br /&gt;
*[[Tracker]] explains the Moodle Tracker for keeping track of bugs, issues, feature requests etc &lt;br /&gt;
&lt;br /&gt;
== Resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[[Developer FAQ]] - frequently asked questions, especially useful for newcomers to Moodle&lt;br /&gt;
*[http://tracker.moodle.org/ Moodle tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://moodle.cvs.sourceforge.net/moodle/moodle/ CVS code] - browse the Moodle code via the web&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://phpdocs.moodle.org/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[http://developer.yahoo.com/yui YUI documentation] - YUI is the official AJAX library in moodle.&lt;br /&gt;
*[[Setting up Eclipse for Moodle development]] - Eclipse is a great editor to use for php development, if you can work out how to set it up.&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&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 functionality. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. The following types of plugins currently exist (in alphabetical order):&lt;br /&gt;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Authentication|Authentication methods]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Database fields (developer)|Database fields]]&lt;br /&gt;
*[[Database presets]]&lt;br /&gt;
*[[Enrolment plugins (developer)|Enrolment plugins]]&lt;br /&gt;
*[[Filters (developer)|Filters]]&lt;br /&gt;
*[[Question_engine]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Question bank|Question bank teacher docs]]&lt;br /&gt;
*[[Question_engine#Question_types|Question types developper docs]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[SSO plugins]]&lt;br /&gt;
&lt;br /&gt;
There are also ways you can contribute that don&#039;t involve PHP programming:&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Tracker|Participating in the bug tracker]]&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;
*[[Student projects]]&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;
*[[Migration to Role-driven model|Migration to Role-driven model]] @ v[[1.7]]&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]] @ v[[:Category:Moodle 1.6|1.6]]&lt;br /&gt;
*[[Question engine]]&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 area] of the Moodle [[CVS]] repository. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;br /&gt;
[[fr:Documentation développeur]]&lt;br /&gt;
[[zh:开发者文档]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Development:Developer_FAQ&amp;diff=29758</id>
		<title>Development:Developer FAQ</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Development:Developer_FAQ&amp;diff=29758"/>
		<updated>2006-09-29T20:38:09Z</updated>

		<summary type="html">&lt;p&gt;Delius: Mention that datalib.php has moved to dmllib.php&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FAQ}}&lt;br /&gt;
&lt;br /&gt;
==Help for new coders==&lt;br /&gt;
&lt;br /&gt;
===Where can &amp;quot;newbies&amp;quot; to Moodle get help?===&lt;br /&gt;
&lt;br /&gt;
The [http://moodle.org/mod/forum/view.php?f=33 General developer forum]! Feel free to ask any question, no matter how basic or advanced. Many people ask different levels of question every day, and the community is generally welcoming and quick to respond.&lt;br /&gt;
&lt;br /&gt;
==Moodle&#039;s database==&lt;br /&gt;
&lt;br /&gt;
===Where can I see a schema for the structure of the Moodle database?===&lt;br /&gt;
&lt;br /&gt;
When installing Moodle, the database tables are generated and updated by various db-handling scripts located in various places. There is no canonical schema representation, although the [[Coding#Database_structures | coding guidelines for database structure]] give an outline of the general approach.&lt;br /&gt;
&lt;br /&gt;
The reason that the database information isn&#039;t stored in one place is because of Moodle&#039;s &#039;&#039;&#039;modular structure&#039;&#039;&#039;. Each activity module, for example, comes as a folder with script files inside. If the module needs to store information in the database, it must include scripts in a &amp;quot;db&amp;quot; subfolder which define and update the database structure.&lt;br /&gt;
&lt;br /&gt;
==How to get/set information when writing new Moodle code==&lt;br /&gt;
&lt;br /&gt;
===How do I find out the currently-logged-on user?===&lt;br /&gt;
&lt;br /&gt;
The global object $USER, which contains the numeric $USER-&amp;gt;id among other things.&lt;br /&gt;
&lt;br /&gt;
===How do I find out the current course?===&lt;br /&gt;
The global object $COURSE, which contains the numeric $COURSE-&amp;gt;id&lt;br /&gt;
&lt;br /&gt;
===How do I insert/retrieve records in the database, without creating my own database connections?===&lt;br /&gt;
&lt;br /&gt;
Always use the &amp;quot;datalib&amp;quot; functions, such as insert_record() or get_record(). Since Moodle 1.7 these are found in lib/dmllib.php. Using these functions helps with database abstraction (e.g. running on either MySQL or Postgres) as well as maintaining a single database connection. Moodle uses ADODB for database abstraction.&lt;br /&gt;
&lt;br /&gt;
Look at [http://moodle.sourceforge.net/dhawes-phpdoc/moodlecore/_lib_datalib_php.html the documentation for datalib.php] for the list of functions and details of use.&lt;br /&gt;
&lt;br /&gt;
===How do I get/set configuration settings?===&lt;br /&gt;
&lt;br /&gt;
To get config values you would typically access the global $CFG object directly, which is automatically created by the core Moodle scripts. To set these &amp;quot;main&amp;quot; config values use set_config($name, $value). The values are stored in the Moodle &amp;quot;config&amp;quot; database table, but these functions take care of cacheing on your behalf, so you should always use these rather than fetching the records directly.&lt;br /&gt;
&lt;br /&gt;
There is also a second table of config settings specifically for plugins (&amp;quot;config_plugin&amp;quot;). These are not automatically loaded into the $CFG object, so to fetch these you would use get_config($plugin, $name). To set them use set_config($name, $value, $plugin).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Developer]]&lt;br /&gt;
[[Category: FAQ]]&lt;br /&gt;
&lt;br /&gt;
[[es:FAQ Desarrollador]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_FAQ&amp;diff=3345</id>
		<title>Developer FAQ</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_FAQ&amp;diff=3345"/>
		<updated>2006-09-29T20:38:09Z</updated>

		<summary type="html">&lt;p&gt;Delius: Mention that datalib.php has moved to dmllib.php&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FAQ}}&lt;br /&gt;
&lt;br /&gt;
==Help for new coders==&lt;br /&gt;
&lt;br /&gt;
===Where can &amp;quot;newbies&amp;quot; to Moodle get help?===&lt;br /&gt;
&lt;br /&gt;
The [http://moodle.org/mod/forum/view.php?f=33 General developer forum]! Feel free to ask any question, no matter how basic or advanced. Many people ask different levels of question every day, and the community is generally welcoming and quick to respond.&lt;br /&gt;
&lt;br /&gt;
==Moodle&#039;s database==&lt;br /&gt;
&lt;br /&gt;
===Where can I see a schema for the structure of the Moodle database?===&lt;br /&gt;
&lt;br /&gt;
When installing Moodle, the database tables are generated and updated by various db-handling scripts located in various places. There is no canonical schema representation, although the [[Coding#Database_structures | coding guidelines for database structure]] give an outline of the general approach.&lt;br /&gt;
&lt;br /&gt;
The reason that the database information isn&#039;t stored in one place is because of Moodle&#039;s &#039;&#039;&#039;modular structure&#039;&#039;&#039;. Each activity module, for example, comes as a folder with script files inside. If the module needs to store information in the database, it must include scripts in a &amp;quot;db&amp;quot; subfolder which define and update the database structure.&lt;br /&gt;
&lt;br /&gt;
==How to get/set information when writing new Moodle code==&lt;br /&gt;
&lt;br /&gt;
===How do I find out the currently-logged-on user?===&lt;br /&gt;
&lt;br /&gt;
The global object $USER, which contains the numeric $USER-&amp;gt;id among other things.&lt;br /&gt;
&lt;br /&gt;
===How do I find out the current course?===&lt;br /&gt;
The global object $COURSE, which contains the numeric $COURSE-&amp;gt;id&lt;br /&gt;
&lt;br /&gt;
===How do I insert/retrieve records in the database, without creating my own database connections?===&lt;br /&gt;
&lt;br /&gt;
Always use the &amp;quot;datalib&amp;quot; functions, such as insert_record() or get_record(). Since Moodle 1.7 these are found in lib/dmllib.php. Using these functions helps with database abstraction (e.g. running on either MySQL or Postgres) as well as maintaining a single database connection. Moodle uses ADODB for database abstraction.&lt;br /&gt;
&lt;br /&gt;
Look at [http://moodle.sourceforge.net/dhawes-phpdoc/moodlecore/_lib_datalib_php.html the documentation for datalib.php] for the list of functions and details of use.&lt;br /&gt;
&lt;br /&gt;
===How do I get/set configuration settings?===&lt;br /&gt;
&lt;br /&gt;
To get config values you would typically access the global $CFG object directly, which is automatically created by the core Moodle scripts. To set these &amp;quot;main&amp;quot; config values use set_config($name, $value). The values are stored in the Moodle &amp;quot;config&amp;quot; database table, but these functions take care of cacheing on your behalf, so you should always use these rather than fetching the records directly.&lt;br /&gt;
&lt;br /&gt;
There is also a second table of config settings specifically for plugins (&amp;quot;config_plugin&amp;quot;). These are not automatically loaded into the $CFG object, so to fetch these you would use get_config($plugin, $name). To set them use set_config($name, $value, $plugin).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Developer]]&lt;br /&gt;
[[Category: FAQ]]&lt;br /&gt;
&lt;br /&gt;
[[es:FAQ Desarrollador]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=920</id>
		<title>Coding</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=920"/>
		<updated>2006-09-29T20:00:57Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* General rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any collaborative project needs consistency and stability to stay strong.&lt;br /&gt;
&lt;br /&gt;
These &#039;&#039;&#039;coding guidelines&#039;&#039;&#039; are to provide a goal for all Moodle code to strive to. It&#039;s true that some of the older existing code falls short in a few areas, but it will all be fixed eventually. All new code definitely must adhere to these standards as closely as possible.&lt;br /&gt;
&lt;br /&gt;
==General rules==&lt;br /&gt;
&lt;br /&gt;
# All code files should use the .php extension.&lt;br /&gt;
# All template files should use the .html extension.&lt;br /&gt;
# All text files should use Unix-style text format (most text editors have this as an option).&lt;br /&gt;
# All php tags must be &#039;full&#039; tags like &amp;lt;?php ?&amp;gt; ... not &#039;short&#039; tags like &amp;lt;? ?&amp;gt;.&lt;br /&gt;
# All existing copyright notices must be retained. You can add your own if necessary.&lt;br /&gt;
# Each file should include the main config.php file.&lt;br /&gt;
# Each file should check that the user is authenticated correctly, using require_login() and isadmin(), isteacher(), iscreator() or isstudent().&lt;br /&gt;
# All access to databases should use the functions in &#039;&#039;lib/dmllib.php&#039;&#039; whenever possible - this allows compatibility across a wide range of databases. You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions within your code (usually a lib.php file); and clearly marked.&lt;br /&gt;
# Don&#039;t create or use global variables except for the standard $CFG, $SESSION, $THEME, $SITE, $COURSE and $USER.&lt;br /&gt;
# All variables should be initialised or at least tested for existence using isset() or empty() before they are used.&lt;br /&gt;
# All strings should be translatable - create new texts in the &amp;quot;lang/en_utf8&amp;quot; files with concise English lowercase names and retrieve them from your code using get_string() or print_string().&lt;br /&gt;
# All help files should be translatable - create new texts in the &amp;quot;lang/en_utf8/help&amp;quot; directory and call them using helpbutton(). If you need to update a help file:&lt;br /&gt;
#* with a minor change, where an old translation of the file would still make sense, then it&#039;s OK to make the change but you should notify translation AT moodle DOT org.&lt;br /&gt;
#* for a major change you should create a new file by adding an incrementing number (eg filename2.html) so that translators can easily see it&#039;s a new version of the file. Obviously the new code and the help index files should also be modified to point to the newest versions.&lt;br /&gt;
# Incoming data from the browser (sent via GET or POST) automatically has magic_quotes applied (regardless of the PHP settings) so that you can safely insert it straight into the database. All other raw data (from files, or from databases) must be escaped with addslashes() before inserting it into the database.&lt;br /&gt;
# VERY IMPORTANT: All texts within Moodle, especially those that have come from users, should be printed using the format_text() function. This ensures that text is filtered and cleaned correctly.&lt;br /&gt;
# User actions should be logged using the [[Logs|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].&lt;br /&gt;
&lt;br /&gt;
==Coding style==&lt;br /&gt;
&lt;br /&gt;
I know it can be a little annoying to change your style if you&#039;re used to something else, but balance that annoyance against the annoyance of all the people trying later on to make sense of Moodle code with mixed styles. There are obviously many good points for and against any style that people use, but the current style just is, so please stick to it.&lt;br /&gt;
&lt;br /&gt;
1. Indenting should be consistently 4 spaces. Don&#039;t use tabs AT ALL.&lt;br /&gt;
&lt;br /&gt;
2. Variable names should always be easy-to-read, meaningful lowercase English words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.&lt;br /&gt;
&lt;br /&gt;
      GOOD: $quiz&lt;br /&gt;
      GOOD: $errorstring&lt;br /&gt;
      GOOD: $assignments (for an array of objects)&lt;br /&gt;
      GOOD: $i (but only in little loops)&lt;br /&gt;
&lt;br /&gt;
      BAD: $Quiz&lt;br /&gt;
      BAD: $aReallyLongVariableNameWithoutAGoodReason&lt;br /&gt;
      BAD: $error_string&lt;br /&gt;
&lt;br /&gt;
3. Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.&lt;br /&gt;
&lt;br /&gt;
      define(&amp;quot;FORUM_MODE_FLATOLDEST&amp;quot;, 1);&lt;br /&gt;
4. Function names should be simple English lowercase words, and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores. Parameters should always have sensible defaults if possible. Note there is no space between the function name and the following (brackets).&lt;br /&gt;
&lt;br /&gt;
      function forum_set_display_mode($mode=0) {&lt;br /&gt;
          global $USER, $CFG;&lt;br /&gt;
          &lt;br /&gt;
          if ($mode) {&lt;br /&gt;
              $USER-&amp;gt;mode = $mode;&lt;br /&gt;
          } else if (empty($USER-&amp;gt;mode)) {&lt;br /&gt;
              $USER-&amp;gt;mode = $CFG-&amp;gt;forum_displaymode;&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
5. Blocks must always be enclosed in curly braces (even if there is only one line). Moodle uses this style:&lt;br /&gt;
&lt;br /&gt;
      if ($quiz-&amp;gt;attempts) {&lt;br /&gt;
          if ($numattempts &amp;gt; $quiz-&amp;gt;attempts) {&lt;br /&gt;
              error($strtoomanyattempts, &amp;quot;view.php?id=$cm-&amp;gt;id&amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
6. Strings should be defined using single quotes where possible, for increased speed.&lt;br /&gt;
&lt;br /&gt;
      $var = &#039;some text without any variables&#039;;&lt;br /&gt;
      $var = &amp;quot;with special characters like a new line \n&amp;quot;;&lt;br /&gt;
      $var = &#039;a very, very long string with a &#039;.$single.&#039; variable in it&#039;;&lt;br /&gt;
      $var = &amp;quot;some $text with $many variables $within it&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
7. Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.&lt;br /&gt;
&lt;br /&gt;
* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.&lt;br /&gt;
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
      * The description should be first, with asterisks laid out exactly&lt;br /&gt;
      * like this example. If you want to refer to a another function,&lt;br /&gt;
      * do it like this: {@link clean_param()}. Then, add descriptions&lt;br /&gt;
      * for each parameter as follows.&lt;br /&gt;
      *&lt;br /&gt;
      * @param int $postid The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $scale The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $ratings The PHP type is followed by the variable name&lt;br /&gt;
      * @return mixed&lt;br /&gt;
      */&lt;br /&gt;
      function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {&lt;br /&gt;
          if (!$ratings) {&lt;br /&gt;
              $ratings = array();     // Initialize the empty array&lt;br /&gt;
              if ($rates = get_records(&amp;quot;forum_ratings&amp;quot;, &amp;quot;post&amp;quot;, $postid)) {&lt;br /&gt;
                  // Process each rating in turn&lt;br /&gt;
                  foreach ($rates as $rate) {&lt;br /&gt;
      ....etc&lt;br /&gt;
&lt;br /&gt;
8. Space should be used liberally - don&#039;t be afraid to spread things out a little to gain some clarity. Generally, there should be one space between brackets and normal statements, but no space between brackets and variables or functions:&lt;br /&gt;
&lt;br /&gt;
      foreach ($objects as $key =&amp;gt; $thing) {&lt;br /&gt;
          process($thing);&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      if ($x == $y) {&lt;br /&gt;
          $a = $b;&lt;br /&gt;
      } else if ($x == $z) {&lt;br /&gt;
          $a = $c;&lt;br /&gt;
      } else {&lt;br /&gt;
          $a = $d;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
9. When making a COPY of an object, always use the php5 clone() function (otherwise you may end up with just a reference to the first object).  Moodle will make sure this works consistently on php4 too.&lt;br /&gt;
&lt;br /&gt;
      BAD:   $b = $a;&lt;br /&gt;
      GOOD:  $b = clone($a);&lt;br /&gt;
&lt;br /&gt;
If the thing you want to copy is not an object, but may contain objects (eg an array of objects) then use fullclone() instead.&lt;br /&gt;
&lt;br /&gt;
==Database structures==&lt;br /&gt;
&lt;br /&gt;
# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])&lt;br /&gt;
# The main table containing instances of each module must have the same name as the module (eg widget) and contain the following minimum fields:&lt;br /&gt;
#* id - as described above&lt;br /&gt;
#* course - the id of the course that each instance belongs to&lt;br /&gt;
#* name - the full name of each instance of the module&lt;br /&gt;
# Other tables associated with a module that contain information about &#039;things&#039; should be named widget_things (note the plural).&lt;br /&gt;
# Table and column names should avoid using [[Database reserved words|reserved words in any database]]. Please check them before creation.&lt;br /&gt;
# Column names should be always lowercase, simple and short, following the same rules as for variable names.&lt;br /&gt;
# Where possible, columns that contain a reference to the id field of another table (eg widget) should be called widgetid. (Note that this convention is newish and not followed in some older tables)&lt;br /&gt;
# Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.&lt;br /&gt;
# Most tables should have a timemodified field (INT10) which is updated with a current timestamp obtained with the PHP time() function.&lt;br /&gt;
# Always define a default value for each field (and make it sensible)&lt;br /&gt;
# Each table name should start with the database prefix ($CFG-&amp;gt;prefix). In a lot of cases, this is taken care of for you automatically. Also, under Postgres, the name of every index must start with the prefix too.&lt;br /&gt;
# In order to guarantee [[XMLDB problems#Table and column aliases - the AS keyword|cross-db compatibility]] follow these simple rules about the use of the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword (only if you need table/colum aliases, of course):&lt;br /&gt;
#* &#039;&#039;&#039;Don&#039;t use&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;table aliases&#039;&#039;&#039;.&lt;br /&gt;
#* &#039;&#039;&#039;Use&#039;&#039;&#039;&#039; the &#039;&#039;&#039;AS&#039;&#039;&#039; keyword for &#039;&#039;&#039;column aliases&#039;&#039;&#039;.&lt;br /&gt;
# &#039;&#039;&#039;Never&#039;&#039;&#039; create UNIQUE KEYs (constraints) at all. Instead use UNIQUE INDEXes. In the future, if we decide to add referential integrity to Moodle and we need UNIQUE KEYs they will be used, but not now. Please note that the XMLDB editor allows you to specify both XMLDB-only UNIQUE and FOREIGN constraints (and that&#039;s good, in order to have the XML well defined) but only underlying INDEXes will be generated. &lt;br /&gt;
# Those XMLDB-only UNIQUE KEYs (read previous point) only must be defined if such field/fields &#039;&#039;&#039;are going to be the target&#039;&#039;&#039; for some (XMLDB-only too) FOREIGN KEY. Else, create them as simple UNIQUE INDEXes.&lt;br /&gt;
&lt;br /&gt;
==Security issues (and handling form and URL data)==&lt;br /&gt;
&lt;br /&gt;
# Do not rely on &#039;register_globals&#039;. Every variable must be properly initialised in every code file. It must be obvious where the variable came from&lt;br /&gt;
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.&lt;br /&gt;
# Do not use the optional_variable() function (this function is now deprecated). Use the optional_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Do not use the require_variable() function (this function is now deprecated). Use the required_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Use data_submitted(), with care. Data must still be cleaned before use.&lt;br /&gt;
# Do not use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.&lt;br /&gt;
# Do not check for an action using something like if (isset($_GET[&#039;something&#039;])). Use, e.g., $something = optional_param( &#039;something&#039;,-1,PARAM_INT ) and then perform proper test for it being in its expected range of values e.g., if ($something&amp;gt;=0) {....&lt;br /&gt;
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.&lt;br /&gt;
# Use &#039;sesskey&#039; mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;sesskey&amp;quot; value=&amp;quot;&amp;lt;?php echo sesskey(); ?&amp;gt;&amp;quot; /&amp;gt;. When you process the form check with if (!confirm_sesskey()) {error(&#039;Bad Session Key&#039;);}.&lt;br /&gt;
# All filenames must be &#039;cleaned&#039; using the clean_filename() function, if this has not been done already by appropriate use of required_param() or optional_param()&lt;br /&gt;
# Any data read from the database must have addslashes() applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object().&lt;br /&gt;
# Wherever possible, data to be stored in the database must come from POST data (from a form with method=&amp;quot;POST&amp;quot;) as opposed to GET data (ie, data from the URL line).&lt;br /&gt;
# Do not use data from $_SERVER if you can avoid it. This has portability issues.&lt;br /&gt;
# If it hasn&#039;t been done somewhere else, make sure all data written to the database has been through the clean_param() function using the appropriate PARAM_XXXX for the datatype.&lt;br /&gt;
# If you write custom SQL code, make very sure it is correct. In particular watch out for missing quotes around values. Possible SQL &#039;injection&#039; exploit.&lt;br /&gt;
# Check all data (particularly that written to the database) in every file it is used. Do not expect or rely on it being done somewhere else.&lt;br /&gt;
# Blocks of code to be included should contain a definite PHP structure (e.g, a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised variable usage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Manual de Estilo de Código]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3315</id>
		<title>Question engine</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3315"/>
		<updated>2006-04-24T11:35:50Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Objects and data structures */  This section still needs more work to update it to Moodle 1.6&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle has a powerful question engine with a modular structure to allow question type plug-ins. The question engine is responsible for rendering the questions and for processing student responses. It is used by the [[Quiz developer docs|quiz module]] and it is planned that in future it will be used by the Lesson and other modules.&lt;br /&gt;
&lt;br /&gt;
Historically the question engine started as a part of the quiz module. Only since Moodle 1.6 is it a separate core component of Moodle that can be used by any other Moodle component or module. During this restructuring the code was moved from mod/quiz/ to question/ and the tables and functions were renamed. Wherever the old table or function name contained &#039;quiz_&#039; the new one will contain &#039;question_&#039;&lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the question engine 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; is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it includes much more than what one would in everyday language call a question.&lt;br /&gt;
In the terminology of the QTI specification a &#039;question&#039; is more 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;[[Question engine#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 questions that interact with the student by going through several states depending on the student 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;, in which case Moodle 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. 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. 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 question_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 a quiz&amp;quot; (or another activity involving questions). 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;
Each module that uses the question engine should hold its own data for the attempts in its own tables. When the module calls the question engine functions it is often expected to pass an attempt object.&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;question sessions&#039;&#039;&#039;&#039; or sometimes &#039;attempts at a question, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
===Sessions, States, Events===&lt;br /&gt;
&lt;br /&gt;
When a new attempt is started, a new &#039;&#039;&#039;session&#039;&#039;&#039; is started for each question. So in a sense a session is for a question what an attempt is for a whole quiz. A question session lasts no longer than an attempt and for each question there can only by one session within one attempt.&lt;br /&gt;
&lt;br /&gt;
Moodle allows the student to interact with a question repeatedly within one session and each such interaction leads to a new &#039;&#039;&#039;state&#039;&#039;&#039;. The first state is created when the session is created. A new state is then created when a student saves and answer or validates an answer or submits an answer or .... The student&#039;s responses and, if appropriate, the results of response processing (grading) are stored in the new state that gets created.&lt;br /&gt;
&lt;br /&gt;
The type of &#039;&#039;&#039;event&#039;&#039;&#039; that led to the creation of a particular state is saved along with the state. The types of events currently used are:&lt;br /&gt;
;open :A new session has just been created and this is the opening state. Usually it doesn&#039;t hold student responses yet (except where a quiz attempt is based on a previous attempt because the &#039;attemptonlast&#039; option is set).&lt;br /&gt;
;save:The student has clicked the save button.&lt;br /&gt;
;validate:The student has asked for his responses to be validated. This means it is checked that they are valid responses. In the case of mathematical questions which requires the input of a mathematical expression in some linear format the question type may want to display the validated result back to the student in typeset form. Similar things may apply to other subject-specific question types. If a student response is found to be invalid the student is told so but no penalty is applied. The invalid response is stored with the state.&lt;br /&gt;
;grade:The student has pressed the submit button. The grade is calculated and stored with the attempt.&lt;br /&gt;
;duplicategrade:The student has pressed the submit button but the response to this question has not actually changed. This happens a lot in quizzes with several questions on on page where the student may have changed the responses for one question only. I believe that states created by this type of event are not stored in the database.&lt;br /&gt;
;close:The last state in a session which is now closed. Currently a session closes only when the attempt closes, either because the student requests it or because the timelimit elapses.&lt;br /&gt;
&lt;br /&gt;
There are now plans to introduce another event type&lt;br /&gt;
;submit:The student has submitted his responses for grading but grading has not yet taken place. This will be used by teacher-marked question types like the essay questions for example.&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;
==API==&lt;br /&gt;
&lt;br /&gt;
The library lib/questionlib.php contains 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 mod/quiz/locallib.php). Loading this library instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
A description of the API still needs to be written. Also lib/questionlib.php should be cleaned up a bit to distinguish between the API functions and the helper functions.&lt;br /&gt;
&lt;br /&gt;
==Organisation==&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;question/type/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in mod/quiz/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;
While questiontypes are realized as classes, the question engine 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 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 one 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 question engine works is to understand how the different kinds of object work together. The most important ones are:&lt;br /&gt;
&lt;br /&gt;
*Questions&lt;br /&gt;
*Attempts&lt;br /&gt;
*States&lt;br /&gt;
&lt;br /&gt;
Questions are data created by the teacher. Attempts and States are data created by the student when interacting with a quiz. &lt;br /&gt;
&lt;br /&gt;
The Moodle quiz module allows students to make several attempts at a quiz. Data about such an &#039;&#039;&#039;attempt&#039;&#039;&#039; is stored in an attempt object. The Moodle question engine was optimized to deal with such attempts and therefore every module wanting to use the question engine also has to implement the attempt object and pass it to many of the question engine functions. The attempt object holds for example information about how the quiz was randomized for this attempt and the ordering of the questions and answers.&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. When the student first views a question within a particular attempt a &#039;&#039;&#039;question session&#039;&#039;&#039; and the first question state is created. Each time the student interacts with the question a new &#039;&#039;&#039;question state&#039;&#039;&#039; 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;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3314</id>
		<title>Question engine</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3314"/>
		<updated>2006-04-24T11:08:53Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Attempts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle has a powerful question engine with a modular structure to allow question type plug-ins. The question engine is responsible for rendering the questions and for processing student responses. It is used by the [[Quiz developer docs|quiz module]] and it is planned that in future it will be used by the Lesson and other modules.&lt;br /&gt;
&lt;br /&gt;
Historically the question engine started as a part of the quiz module. Only since Moodle 1.6 is it a separate core component of Moodle that can be used by any other Moodle component or module. During this restructuring the code was moved from mod/quiz/ to question/ and the tables and functions were renamed. Wherever the old table or function name contained &#039;quiz_&#039; the new one will contain &#039;question_&#039;&lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the question engine 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; is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it includes much more than what one would in everyday language call a question.&lt;br /&gt;
In the terminology of the QTI specification a &#039;question&#039; is more 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;[[Question engine#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 questions that interact with the student by going through several states depending on the student 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;, in which case Moodle 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. 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. 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 question_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 a quiz&amp;quot; (or another activity involving questions). 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;
Each module that uses the question engine should hold its own data for the attempts in its own tables. When the module calls the question engine functions it is often expected to pass an attempt object.&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;question sessions&#039;&#039;&#039;&#039; or sometimes &#039;attempts at a question, never just as &#039;attempts&#039;.&lt;br /&gt;
&lt;br /&gt;
===Sessions, States, Events===&lt;br /&gt;
&lt;br /&gt;
When a new attempt is started, a new &#039;&#039;&#039;session&#039;&#039;&#039; is started for each question. So in a sense a session is for a question what an attempt is for a whole quiz. A question session lasts no longer than an attempt and for each question there can only by one session within one attempt.&lt;br /&gt;
&lt;br /&gt;
Moodle allows the student to interact with a question repeatedly within one session and each such interaction leads to a new &#039;&#039;&#039;state&#039;&#039;&#039;. The first state is created when the session is created. A new state is then created when a student saves and answer or validates an answer or submits an answer or .... The student&#039;s responses and, if appropriate, the results of response processing (grading) are stored in the new state that gets created.&lt;br /&gt;
&lt;br /&gt;
The type of &#039;&#039;&#039;event&#039;&#039;&#039; that led to the creation of a particular state is saved along with the state. The types of events currently used are:&lt;br /&gt;
;open :A new session has just been created and this is the opening state. Usually it doesn&#039;t hold student responses yet (except where a quiz attempt is based on a previous attempt because the &#039;attemptonlast&#039; option is set).&lt;br /&gt;
;save:The student has clicked the save button.&lt;br /&gt;
;validate:The student has asked for his responses to be validated. This means it is checked that they are valid responses. In the case of mathematical questions which requires the input of a mathematical expression in some linear format the question type may want to display the validated result back to the student in typeset form. Similar things may apply to other subject-specific question types. If a student response is found to be invalid the student is told so but no penalty is applied. The invalid response is stored with the state.&lt;br /&gt;
;grade:The student has pressed the submit button. The grade is calculated and stored with the attempt.&lt;br /&gt;
;duplicategrade:The student has pressed the submit button but the response to this question has not actually changed. This happens a lot in quizzes with several questions on on page where the student may have changed the responses for one question only. I believe that states created by this type of event are not stored in the database.&lt;br /&gt;
;close:The last state in a session which is now closed. Currently a session closes only when the attempt closes, either because the student requests it or because the timelimit elapses.&lt;br /&gt;
&lt;br /&gt;
There are now plans to introduce another event type&lt;br /&gt;
;submit:The student has submitted his responses for grading but grading has not yet taken place. This will be used by teacher-marked question types like the essay questions for example.&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;
==API==&lt;br /&gt;
&lt;br /&gt;
The library lib/questionlib.php contains 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 mod/quiz/locallib.php). Loading this library instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
A description of the API still needs to be written. Also lib/questionlib.php should be cleaned up a bit to distinguish between the API functions and the helper functions.&lt;br /&gt;
&lt;br /&gt;
==Organisation==&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;question/type/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in mod/quiz/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;
While questiontypes are realized as classes, the question engine 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 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 one 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;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3313</id>
		<title>Question engine</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3313"/>
		<updated>2006-04-24T11:04:37Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Answers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle has a powerful question engine with a modular structure to allow question type plug-ins. The question engine is responsible for rendering the questions and for processing student responses. It is used by the [[Quiz developer docs|quiz module]] and it is planned that in future it will be used by the Lesson and other modules.&lt;br /&gt;
&lt;br /&gt;
Historically the question engine started as a part of the quiz module. Only since Moodle 1.6 is it a separate core component of Moodle that can be used by any other Moodle component or module. During this restructuring the code was moved from mod/quiz/ to question/ and the tables and functions were renamed. Wherever the old table or function name contained &#039;quiz_&#039; the new one will contain &#039;question_&#039;&lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the question engine 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; is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it includes much more than what one would in everyday language call a question.&lt;br /&gt;
In the terminology of the QTI specification a &#039;question&#039; is more 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;[[Question engine#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 questions that interact with the student by going through several states depending on the student 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;, in which case Moodle 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. 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. 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 question_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 a quiz&amp;quot; (or another activity involving questions). 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;
===Sessions, States, Events===&lt;br /&gt;
&lt;br /&gt;
When a new attempt is started, a new &#039;&#039;&#039;session&#039;&#039;&#039; is started for each question. So in a sense a session is for a question what an attempt is for a whole quiz. A question session lasts no longer than an attempt and for each question there can only by one session within one attempt.&lt;br /&gt;
&lt;br /&gt;
Moodle allows the student to interact with a question repeatedly within one session and each such interaction leads to a new &#039;&#039;&#039;state&#039;&#039;&#039;. The first state is created when the session is created. A new state is then created when a student saves and answer or validates an answer or submits an answer or .... The student&#039;s responses and, if appropriate, the results of response processing (grading) are stored in the new state that gets created.&lt;br /&gt;
&lt;br /&gt;
The type of &#039;&#039;&#039;event&#039;&#039;&#039; that led to the creation of a particular state is saved along with the state. The types of events currently used are:&lt;br /&gt;
;open :A new session has just been created and this is the opening state. Usually it doesn&#039;t hold student responses yet (except where a quiz attempt is based on a previous attempt because the &#039;attemptonlast&#039; option is set).&lt;br /&gt;
;save:The student has clicked the save button.&lt;br /&gt;
;validate:The student has asked for his responses to be validated. This means it is checked that they are valid responses. In the case of mathematical questions which requires the input of a mathematical expression in some linear format the question type may want to display the validated result back to the student in typeset form. Similar things may apply to other subject-specific question types. If a student response is found to be invalid the student is told so but no penalty is applied. The invalid response is stored with the state.&lt;br /&gt;
;grade:The student has pressed the submit button. The grade is calculated and stored with the attempt.&lt;br /&gt;
;duplicategrade:The student has pressed the submit button but the response to this question has not actually changed. This happens a lot in quizzes with several questions on on page where the student may have changed the responses for one question only. I believe that states created by this type of event are not stored in the database.&lt;br /&gt;
;close:The last state in a session which is now closed. Currently a session closes only when the attempt closes, either because the student requests it or because the timelimit elapses.&lt;br /&gt;
&lt;br /&gt;
There are now plans to introduce another event type&lt;br /&gt;
;submit:The student has submitted his responses for grading but grading has not yet taken place. This will be used by teacher-marked question types like the essay questions for example.&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;
==API==&lt;br /&gt;
&lt;br /&gt;
The library lib/questionlib.php contains 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 mod/quiz/locallib.php). Loading this library instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
A description of the API still needs to be written. Also lib/questionlib.php should be cleaned up a bit to distinguish between the API functions and the helper functions.&lt;br /&gt;
&lt;br /&gt;
==Organisation==&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;question/type/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in mod/quiz/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;
While questiontypes are realized as classes, the question engine 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 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 one 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;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3312</id>
		<title>Question engine</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3312"/>
		<updated>2006-04-24T11:01:45Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle has a powerful question engine with a modular structure to allow question type plug-ins. The question engine is responsible for rendering the questions and for processing student responses. It is used by the [[Quiz developer docs|quiz module]] and it is planned that in future it will be used by the Lesson and other modules.&lt;br /&gt;
&lt;br /&gt;
Historically the question engine started as a part of the quiz module. Only since Moodle 1.6 is it a separate core component of Moodle that can be used by any other Moodle component or module. During this restructuring the code was moved from mod/quiz/ to question/ and the tables and functions were renamed. Wherever the old table or function name contained &#039;quiz_&#039; the new one will contain &#039;question_&#039;&lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the question engine 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; is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it includes much more than what one would in everyday language call a question.&lt;br /&gt;
In the terminology of the QTI specification a &#039;question&#039; is more 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;[[Question engine#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 questions that interact with the student by going through several states depending on the student 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;, in which case Moodle 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 the 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 [[Question 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 a quiz&amp;quot; (or another activity involving questions). 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;
===Sessions, States, Events===&lt;br /&gt;
&lt;br /&gt;
When a new attempt is started, a new &#039;&#039;&#039;session&#039;&#039;&#039; is started for each question. So in a sense a session is for a question what an attempt is for a whole quiz. A question session lasts no longer than an attempt and for each question there can only by one session within one attempt.&lt;br /&gt;
&lt;br /&gt;
Moodle allows the student to interact with a question repeatedly within one session and each such interaction leads to a new &#039;&#039;&#039;state&#039;&#039;&#039;. The first state is created when the session is created. A new state is then created when a student saves and answer or validates an answer or submits an answer or .... The student&#039;s responses and, if appropriate, the results of response processing (grading) are stored in the new state that gets created.&lt;br /&gt;
&lt;br /&gt;
The type of &#039;&#039;&#039;event&#039;&#039;&#039; that led to the creation of a particular state is saved along with the state. The types of events currently used are:&lt;br /&gt;
;open :A new session has just been created and this is the opening state. Usually it doesn&#039;t hold student responses yet (except where a quiz attempt is based on a previous attempt because the &#039;attemptonlast&#039; option is set).&lt;br /&gt;
;save:The student has clicked the save button.&lt;br /&gt;
;validate:The student has asked for his responses to be validated. This means it is checked that they are valid responses. In the case of mathematical questions which requires the input of a mathematical expression in some linear format the question type may want to display the validated result back to the student in typeset form. Similar things may apply to other subject-specific question types. If a student response is found to be invalid the student is told so but no penalty is applied. The invalid response is stored with the state.&lt;br /&gt;
;grade:The student has pressed the submit button. The grade is calculated and stored with the attempt.&lt;br /&gt;
;duplicategrade:The student has pressed the submit button but the response to this question has not actually changed. This happens a lot in quizzes with several questions on on page where the student may have changed the responses for one question only. I believe that states created by this type of event are not stored in the database.&lt;br /&gt;
;close:The last state in a session which is now closed. Currently a session closes only when the attempt closes, either because the student requests it or because the timelimit elapses.&lt;br /&gt;
&lt;br /&gt;
There are now plans to introduce another event type&lt;br /&gt;
;submit:The student has submitted his responses for grading but grading has not yet taken place. This will be used by teacher-marked question types like the essay questions for example.&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;
==API==&lt;br /&gt;
&lt;br /&gt;
The library lib/questionlib.php contains 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 mod/quiz/locallib.php). Loading this library instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
A description of the API still needs to be written. Also lib/questionlib.php should be cleaned up a bit to distinguish between the API functions and the helper functions.&lt;br /&gt;
&lt;br /&gt;
==Organisation==&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;question/type/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in mod/quiz/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;
While questiontypes are realized as classes, the question engine 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 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 one 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;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3403</id>
		<title>Output functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3403"/>
		<updated>2006-04-12T21:06:33Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* format_text() */  explained scope of options&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page tries to explain a bit how dynamic data should be sent from Moodle to the browser in a organised and standard way. Obviously it&#039;s possible to have your own output methods but, thinking that you are going to share your code (yep, this is an OpenSource project!) and in the collaborative way we try to build and maintain the system every day, it would be really better to follow the basic guidelines explained below.&lt;br /&gt;
&lt;br /&gt;
By using them you will be helping to have better, more secure and readable code. Spend some minutes trying to understand them, please!&lt;br /&gt;
&lt;br /&gt;
Of course, this functions can be discused, modified and new functions can arrive if there are some good reasons for it. Just discuss it in the [http://moodle.org/mod/forum/view.php?id=55 General developer forum] at [http://moodle.org moodle.org].&lt;br /&gt;
&lt;br /&gt;
For each of the functions below we&#039;ll try to explain when they should be used, commenting the most important parameters supported and their meaning. Let&#039;s review them!&lt;br /&gt;
&lt;br /&gt;
=== p() and s() ===&lt;br /&gt;
&lt;br /&gt;
 function s($var, $strip=false) and function p($var, $strip=false)&lt;br /&gt;
&lt;br /&gt;
This functions share the same code so they will be explained together. The only difference is that s() returns the string while p() prints it directly.&lt;br /&gt;
&lt;br /&gt;
This functions should be used to:&lt;br /&gt;
&lt;br /&gt;
* print all the &#039;&#039;&#039;values of form fields&#039;&#039;&#039; like &amp;lt;nowiki&amp;gt;&amp;lt;input&amp;gt;&amp;lt;/nowiki&amp;gt; or &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; tags.&lt;br /&gt;
* to &#039;&#039;&#039;show plain (non html) text&#039;&#039;&#039; that have been introduced by the user (search string, quiz responses...).&lt;br /&gt;
* in general, all the &#039;&#039;&#039;dynamic data, not being html&#039;&#039;&#039;, that doesn&#039;t need to be cleaned nor processed by filters&lt;br /&gt;
&lt;br /&gt;
It is important not to use these functions for strings that contain html markup.&lt;br /&gt;
&lt;br /&gt;
The functions replace certain characters that would have special meaning in html ( &amp;lt;, &amp;gt;, &amp;quot;, &#039;, and &amp;amp;) by html entities so that they are displayed as intended. Note that even though the value of form fields printed with p() will have these characters converted to html entities, the submitted values will contain the original characters again.&lt;br /&gt;
&lt;br /&gt;
The key parameter for this function is:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;strip&#039;&#039;&#039;: it decides if we want to strip slashes from the string or no. By default it&#039;s &#039;false&#039; so no strip will be performed. We should set such parameter to &#039;true&#039; only when data to be processed isn&#039;t coming from database but from http requests (forms, links...).&lt;br /&gt;
&lt;br /&gt;
=== format_text() ===&lt;br /&gt;
&lt;br /&gt;
 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) &lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;any html/plain/markdown/moodle text&#039;&#039;&#039;, needing any of the features below. Mainly used for long strings like posts, answers, glossary items...&lt;br /&gt;
&lt;br /&gt;
Note that this function is really &#039;&#039;&#039;heavy&#039;&#039;&#039; because it supports &#039;&#039;&#039;cleaning&#039;&#039;&#039; of dangerous contents, delegates process to enabled &#039;&#039;&#039;filter&#039;&#039;&#039;s, supports different &#039;&#039;&#039;formats&#039;&#039;&#039; of text (HTML, PLAIN, MARKDOWN, MOODLE) and performs a lot of &#039;&#039;&#039;automatic conversions&#039;&#039;&#039; like adding smilies, build links, so it&#039;s a really heavy function. Also, it includes one strong &#039;&#039;&#039;cache mechanism&#039;&#039;&#039; (DB based) that will alleviate the server from a lot of work processing the same texts time and again.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039;: To tell the function about how the data has been entered. It defaults to FORMAT_MOODLE that is a cool format to process plain text because it features automatic link conversion, smilies and good conversion to html output. Other formats are FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOW.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039;: Here we can specify how we want the process to be performed. You only need to define them if they are different from the default value assumed. Main options are:&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;noclean&#039;&#039;&#039;: To decide if we want to skip the clean of text, &#039;&#039;&#039;un-protecting us&#039;&#039;&#039; from attacks and other security flaws (defaults to false, so protection is enabled. You &#039;&#039;&#039;shouldn&#039;t set it to true never&#039;&#039;&#039; unless you are 200% sure that only controlled users can edit it (mainly admins). &#039;&#039;&#039;Never use it for general text places&#039;&#039;&#039; (posts...) or you will be, sooner or later, attacked! Note that this option is ignored for FORMAT_PLAIN, the text is never cleaned.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;filter&#039;&#039;&#039;: To decide if you want to allow filters to process the text (defaults to true). This is ignored by FORMAT_PLAIN for which filters are never applied.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;smiley&#039;&#039;&#039;: To decide if we want automatic conversion of smilies to images (defaults to true). This is ignored by FORMAT_PLAIN for which smileys are never converted.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;para&#039;&#039;&#039;: To decide if you want every paragraph automatically enclosed between html paragraph tags (&amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;...&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true). This option only applies to FORMAT_MOODLE.&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;newlines&#039;&#039;&#039;: To decide if linefeeds in text should be converted to html newlines (&amp;lt;nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true). This option only applies to FORMAT_MOODLE.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== format_string() ===&lt;br /&gt;
&lt;br /&gt;
 function format_string ($string, $striplinks = false, $courseid=NULL )&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;short strings (non html) that need filter processing&#039;&#039;&#039; (activity titles, post subjects, glossary concepts...).&lt;br /&gt;
&lt;br /&gt;
Please note that this function is basically one stripped version of the full format_text() function detailed above and &#039;&#039;&#039;it doesn&#039;t offer any of it options nor protections&#039;&#039;&#039;. It simply filters the strings and return the result, so we must ensure that text being processed has been properly cleaned at input time, using the proper xxx_param() functions.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;striplinks&#039;&#039;&#039;: To decide if, after the text has been processed by filters, we must delete any link from the result test. Used when we want to show the text inside menus, page titles... (defaults to false).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== print_textarea() ===&lt;br /&gt;
&lt;br /&gt;
 function print_textarea($usehtmleditor, $rows, $cols, $width, &lt;br /&gt;
                        $height, $name, $value=&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;, $courseid=0, $return=false)&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* display &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; fields when we want to allow users (based in their preferences and browser capabilities) &#039;&#039;&#039;to use the visual HTML editor&#039;&#039;&#039; instead of one standard &#039;plain&#039; area.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;usehtmleditor&#039;&#039;&#039;: to decide if the HTML editor must be showed. The value of this parameter must be calculated by the can_use_html_editor() function.&lt;br /&gt;
* &#039;&#039;&#039;rows, cols&#039;&#039;&#039;: to be applied it the standard textarea is showed.&lt;br /&gt;
* &#039;&#039;&#039;width, height&#039;&#039;&#039;: to be applied if the HTML editor is used.&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039;: the name of the field that will contain the text once the form was submitted.&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039;: the initial value of the textarea.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help the editor to know where it is work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
* &#039;&#039;&#039;return&#039;&#039;&#039;: to decide if the generated html code must be returned to the caller (true) or printed directly (false). Defaults to false.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3287</id>
		<title>Filters 1.9 and before</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3287"/>
		<updated>2006-04-12T21:02:35Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* To create a filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Please note:&#039;&#039;&#039; This page contains information for developers. You may prefer to read the [[Filters (administrator)| information about filters for teachers and administrators]].&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Filters&#039;&#039;&#039; allow for the for the automatic transformation of entered text into different, often more complex forms. For example the titles of [[Resources]] can automatically become hyperlinks that take you to the relevant resource, URLs pointing to [[mp3]] files can become [[Flash]] controls embedded in the webpage that let you pause and rewind the audio. The possibilities are endless and there are a number of standard filters included with Moodle and many more specialized filters contributed by the community.&lt;br /&gt;
&lt;br /&gt;
==To create a filter==&lt;br /&gt;
&lt;br /&gt;
To create a filter that removes all occurrences of the letter &amp;quot;x&amp;quot; - we&#039;ll call it &amp;quot;removex&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Create a new folder inside Moodle&#039;s /filter/ folder, called &amp;quot;removex&amp;quot;&lt;br /&gt;
# Create a new PHP script file inside the folder you&#039;ve just created - name it &amp;quot;filter_removex.php&amp;quot;&lt;br /&gt;
# Write a new PHP function in this file, called &amp;quot;filter_removex()&amp;quot; which takes two parameters - a piece of text to be filtered and a course ID - and returns the processed text.&lt;br /&gt;
&lt;br /&gt;
For our example the function would look like:&lt;br /&gt;
&lt;br /&gt;
 function filter_removex($text, $courseid) {&lt;br /&gt;
     return str_replace(&amp;quot;x&amp;quot;, &amp;quot;&amp;quot;, $text);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
When trying this out, remember to make sure that you activate the filter in the [[Filters (administrator)|filters administration screen]].&lt;br /&gt;
&lt;br /&gt;
Also remember that text filtering functions, when activated, will be used intensively by the server, so you should optimise the filters as far as possible (cut down on database calls etc). Moodle caches the results of filtering to help with processing speed, but it&#039;s still worth being careful about your filter design.&lt;br /&gt;
&lt;br /&gt;
Filters are applied to all text that is printed with the [[Output functions|output functions]] format_text() or format_string(). One thing to keep in mind when designing the filter is that the function format_text() first applies other transformations (for example text_to_html() or replace_smilies()) before the strings are passed to your filter. The function format_string() on the other hand passes the string as it is.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Filters schema]] - a page containing some ideas and thoughts about modifications to the filters system&lt;br /&gt;
* [[Filters (administrator)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Filter]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3286</id>
		<title>Filters 1.9 and before</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3286"/>
		<updated>2006-04-12T20:53:26Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* To create a filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Please note:&#039;&#039;&#039; This page contains information for developers. You may prefer to read the [[Filters (administrator)| information about filters for teachers and administrators]].&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Filters&#039;&#039;&#039; allow for the for the automatic transformation of entered text into different, often more complex forms. For example the titles of [[Resources]] can automatically become hyperlinks that take you to the relevant resource, URLs pointing to [[mp3]] files can become [[Flash]] controls embedded in the webpage that let you pause and rewind the audio. The possibilities are endless and there are a number of standard filters included with Moodle and many more specialized filters contributed by the community.&lt;br /&gt;
&lt;br /&gt;
==To create a filter==&lt;br /&gt;
&lt;br /&gt;
To create a filter that removes all occurrences of the letter &amp;quot;x&amp;quot; - we&#039;ll call it &amp;quot;removex&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Create a new folder inside Moodle&#039;s /filter/ folder, called &amp;quot;removex&amp;quot;&lt;br /&gt;
# Create a new PHP script file inside the folder you&#039;ve just created - name it &amp;quot;filter_removex.php&amp;quot;&lt;br /&gt;
# Write a new PHP function in this file, called &amp;quot;filter_removex()&amp;quot; which takes two parameters - a piece of text to be filtered and a course ID - and returns the processed text.&lt;br /&gt;
&lt;br /&gt;
For our example the function would look like:&lt;br /&gt;
&lt;br /&gt;
 function filter_removex($text, $courseid) {&lt;br /&gt;
     return str_replace(&amp;quot;x&amp;quot;, &amp;quot;&amp;quot;, $text);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
When trying this out, remember to make sure that you activate the filter in the [[Filters (administrator)|filters administration screen]].&lt;br /&gt;
&lt;br /&gt;
Also remember that text filtering functions, when activated, will be used intensively by the server, so you should optimise the filters as far as possible (cut down on database calls etc). Moodle caches the results of filtering to help with processing speed, but it&#039;s still worth being careful about your filter design.&lt;br /&gt;
&lt;br /&gt;
Filters are applied to all text that is printed with the [[Output functions|output functions]] format_text() or format_string(). One thing to keep in mind when designing the filter is that these output functions first apply other transformations (for example text_to_html() or replace_smilies()) before the strings are passed to your filter.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Filters schema]] - a page containing some ideas and thoughts about modifications to the filters system&lt;br /&gt;
* [[Filters (administrator)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Filter]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3402</id>
		<title>Output functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3402"/>
		<updated>2006-04-12T20:44:25Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* p() and s() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page tries to explain a bit how dynamic data should be sent from Moodle to the browser in a organised and standard way. Obviously it&#039;s possible to have your own output methods but, thinking that you are going to share your code (yep, this is an OpenSource project!) and in the collaborative way we try to build and maintain the system every day, it would be really better to follow the basic guidelines explained below.&lt;br /&gt;
&lt;br /&gt;
By using them you will be helping to have better, more secure and readable code. Spend some minutes trying to understand them, please!&lt;br /&gt;
&lt;br /&gt;
Of course, this functions can be discused, modified and new functions can arrive if there are some good reasons for it. Just discuss it in the [http://moodle.org/mod/forum/view.php?id=55 General developer forum] at [http://moodle.org moodle.org].&lt;br /&gt;
&lt;br /&gt;
For each of the functions below we&#039;ll try to explain when they should be used, commenting the most important parameters supported and their meaning. Let&#039;s review them!&lt;br /&gt;
&lt;br /&gt;
=== p() and s() ===&lt;br /&gt;
&lt;br /&gt;
 function s($var, $strip=false) and function p($var, $strip=false)&lt;br /&gt;
&lt;br /&gt;
This functions share the same code so they will be explained together. The only difference is that s() returns the string while p() prints it directly.&lt;br /&gt;
&lt;br /&gt;
This functions should be used to:&lt;br /&gt;
&lt;br /&gt;
* print all the &#039;&#039;&#039;values of form fields&#039;&#039;&#039; like &amp;lt;nowiki&amp;gt;&amp;lt;input&amp;gt;&amp;lt;/nowiki&amp;gt; or &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; tags.&lt;br /&gt;
* to &#039;&#039;&#039;show plain (non html) text&#039;&#039;&#039; that have been introduced by the user (search string, quiz responses...).&lt;br /&gt;
* in general, all the &#039;&#039;&#039;dynamic data, not being html&#039;&#039;&#039;, that doesn&#039;t need to be cleaned nor processed by filters&lt;br /&gt;
&lt;br /&gt;
It is important not to use these functions for strings that contain html markup.&lt;br /&gt;
&lt;br /&gt;
The functions replace certain characters that would have special meaning in html ( &amp;lt;, &amp;gt;, &amp;quot;, &#039;, and &amp;amp;) by html entities so that they are displayed as intended. Note that even though the value of form fields printed with p() will have these characters converted to html entities, the submitted values will contain the original characters again.&lt;br /&gt;
&lt;br /&gt;
The key parameter for this function is:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;strip&#039;&#039;&#039;: it decides if we want to strip slashes from the string or no. By default it&#039;s &#039;false&#039; so no strip will be performed. We should set such parameter to &#039;true&#039; only when data to be processed isn&#039;t coming from database but from http requests (forms, links...).&lt;br /&gt;
&lt;br /&gt;
=== format_text() ===&lt;br /&gt;
&lt;br /&gt;
 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) &lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;any html/plain/markdown/moodle text&#039;&#039;&#039;, needing any of the features below. Mainly used for long strings like posts, answers, glossary items...&lt;br /&gt;
&lt;br /&gt;
Note that this function is really &#039;&#039;&#039;heavy&#039;&#039;&#039; because it supports &#039;&#039;&#039;cleaning&#039;&#039;&#039; of dangerous contents, delegates process to enabled &#039;&#039;&#039;filter&#039;&#039;&#039;s, supports different &#039;&#039;&#039;formats&#039;&#039;&#039; of text (HTML, PLAIN, MARKDOWN, MOODLE) and performs a lot of &#039;&#039;&#039;automatic conversions&#039;&#039;&#039; like adding smilies, build links, so it&#039;s a really heavy function. Also, it includes one strong &#039;&#039;&#039;cache mechanism&#039;&#039;&#039; (DB based) that will alleviate the server from a lot of work processing the same texts time and again.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039;: To tell the function about how the data has been entered. It defaults to FORMAT_MOODLE that is a cool format to process plain text because it features automatic link conversion, smilies and good conversion to html output. Other formats are FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOW.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039;: Here we can specify how we want the process to be performed. You only need to define them if they are different from the default value assumed. Main options are:&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;noclean&#039;&#039;&#039;: To decide if we want to skip the clean of text, &#039;&#039;&#039;un-protecting us&#039;&#039;&#039; from attacks and other security flaws (defaults to false, so protection is enabled. You &#039;&#039;&#039;shouldn&#039;t set it to true never&#039;&#039;&#039; unless you are 200% sure that only controlled users can edit it (mainly admins). &#039;&#039;&#039;Never use it for general text places&#039;&#039;&#039; (posts...) or you will be, sooner or later, attacked! &lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;filter&#039;&#039;&#039;: To decide if you want to allow filters to process the text (defaults to true).&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;smiley&#039;&#039;&#039;: To decide if we want automatic conversion of smilies to images (defaults to true).&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;para&#039;&#039;&#039;: To decide if you want every paragraph automatically enclosed between html paragraph tags (&amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;...&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true).&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;newlines&#039;&#039;&#039;: To decide if linefeeds in text should be converted to html newlines (&amp;lt;nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== format_string() ===&lt;br /&gt;
&lt;br /&gt;
 function format_string ($string, $striplinks = false, $courseid=NULL )&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;short strings (non html) that need filter processing&#039;&#039;&#039; (activity titles, post subjects, glossary concepts...).&lt;br /&gt;
&lt;br /&gt;
Please note that this function is basically one stripped version of the full format_text() function detailed above and &#039;&#039;&#039;it doesn&#039;t offer any of it options nor protections&#039;&#039;&#039;. It simply filters the strings and return the result, so we must ensure that text being processed has been properly cleaned at input time, using the proper xxx_param() functions.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;striplinks&#039;&#039;&#039;: To decide if, after the text has been processed by filters, we must delete any link from the result test. Used when we want to show the text inside menus, page titles... (defaults to false).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== print_textarea() ===&lt;br /&gt;
&lt;br /&gt;
 function print_textarea($usehtmleditor, $rows, $cols, $width, &lt;br /&gt;
                        $height, $name, $value=&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;, $courseid=0, $return=false)&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* display &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; fields when we want to allow users (based in their preferences and browser capabilities) &#039;&#039;&#039;to use the visual HTML editor&#039;&#039;&#039; instead of one standard &#039;plain&#039; area.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;usehtmleditor&#039;&#039;&#039;: to decide if the HTML editor must be showed. The value of this parameter must be calculated by the can_use_html_editor() function.&lt;br /&gt;
* &#039;&#039;&#039;rows, cols&#039;&#039;&#039;: to be applied it the standard textarea is showed.&lt;br /&gt;
* &#039;&#039;&#039;width, height&#039;&#039;&#039;: to be applied if the HTML editor is used.&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039;: the name of the field that will contain the text once the form was submitted.&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039;: the initial value of the textarea.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help the editor to know where it is work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
* &#039;&#039;&#039;return&#039;&#039;&#039;: to decide if the generated html code must be returned to the caller (true) or printed directly (false). Defaults to false.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3401</id>
		<title>Output functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_functions&amp;diff=3401"/>
		<updated>2006-04-12T20:27:50Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* p() and s() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page tries to explain a bit how dynamic data should be sent from Moodle to the browser in a organised and standard way. Obviously it&#039;s possible to have your own output methods but, thinking that you are going to share your code (yep, this is an OpenSource project!) and in the collaborative way we try to build and maintain the system every day, it would be really better to follow the basic guidelines explained below.&lt;br /&gt;
&lt;br /&gt;
By using them you will be helping to have better, more secure and readable code. Spend some minutes trying to understand them, please!&lt;br /&gt;
&lt;br /&gt;
Of course, this functions can be discused, modified and new functions can arrive if there are some good reasons for it. Just discuss it in the [http://moodle.org/mod/forum/view.php?id=55 General developer forum] at [http://moodle.org moodle.org].&lt;br /&gt;
&lt;br /&gt;
For each of the functions below we&#039;ll try to explain when they should be used, commenting the most important parameters supported and their meaning. Let&#039;s review them!&lt;br /&gt;
&lt;br /&gt;
=== p() and s() ===&lt;br /&gt;
&lt;br /&gt;
 function s($var, $strip=false) and function p($var, $strip=false)&lt;br /&gt;
&lt;br /&gt;
This functions share the same code so they will be explained together. The only difference is that s() returns the string while p() prints it directly.&lt;br /&gt;
&lt;br /&gt;
This functions should be used to:&lt;br /&gt;
&lt;br /&gt;
* print all the &#039;&#039;&#039;values of form fields&#039;&#039;&#039; like &amp;lt;nowiki&amp;gt;&amp;lt;input&amp;gt;&amp;lt;/nowiki&amp;gt; or &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; tags.&lt;br /&gt;
* to &#039;&#039;&#039;show plain (non html) text&#039;&#039;&#039; that have been introduced by the user (search string, quiz responses...).&lt;br /&gt;
* in general, all the &#039;&#039;&#039;dynamic data, not being html&#039;&#039;&#039;, that doesn&#039;t need to be cleaned nor processed by filters&lt;br /&gt;
&lt;br /&gt;
It is important not to use these functions for strings that contain html markup.&lt;br /&gt;
&lt;br /&gt;
The functions replaces certain characters that would have special meaning in html ( &amp;lt;, &amp;gt;, &amp;quot;, &#039;, and &amp;amp;) by html entities so that they are displayed as intended.&lt;br /&gt;
&lt;br /&gt;
The key parameter for this function is:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;strip&#039;&#039;&#039;: it decides if we want to strip slashes from the string or no. By default it&#039;s &#039;false&#039; so no strip will be performed. We should set such parameter to &#039;true&#039; only when data to be processed isn&#039;t coming from database but from http requests (forms, links...).&lt;br /&gt;
&lt;br /&gt;
=== format_text() ===&lt;br /&gt;
&lt;br /&gt;
 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) &lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;any html/plain/markdown/moodle text&#039;&#039;&#039;, needing any of the features below. Mainly used for long strings like posts, answers, glossary items...&lt;br /&gt;
&lt;br /&gt;
Note that this function is really &#039;&#039;&#039;heavy&#039;&#039;&#039; because it supports &#039;&#039;&#039;cleaning&#039;&#039;&#039; of dangerous contents, delegates process to enabled &#039;&#039;&#039;filter&#039;&#039;&#039;s, supports different &#039;&#039;&#039;formats&#039;&#039;&#039; of text (HTML, PLAIN, MARKDOWN, MOODLE) and performs a lot of &#039;&#039;&#039;automatic conversions&#039;&#039;&#039; like adding smilies, build links, so it&#039;s a really heavy function. Also, it includes one strong &#039;&#039;&#039;cache mechanism&#039;&#039;&#039; (DB based) that will alleviate the server from a lot of work processing the same texts time and again.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039;: To tell the function about how the data has been entered. It defaults to FORMAT_MOODLE that is a cool format to process plain text because it features automatic link conversion, smilies and good conversion to html output. Other formats are FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOW.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039;: Here we can specify how we want the process to be performed. You only need to define them if they are different from the default value assumed. Main options are:&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;noclean&#039;&#039;&#039;: To decide if we want to skip the clean of text, &#039;&#039;&#039;un-protecting us&#039;&#039;&#039; from attacks and other security flaws (defaults to false, so protection is enabled. You &#039;&#039;&#039;shouldn&#039;t set it to true never&#039;&#039;&#039; unless you are 200% sure that only controlled users can edit it (mainly admins). &#039;&#039;&#039;Never use it for general text places&#039;&#039;&#039; (posts...) or you will be, sooner or later, attacked! &lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;filter&#039;&#039;&#039;: To decide if you want to allow filters to process the text (defaults to true).&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;smiley&#039;&#039;&#039;: To decide if we want automatic conversion of smilies to images (defaults to true).&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;para&#039;&#039;&#039;: To decide if you want every paragraph automatically enclosed between html paragraph tags (&amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;...&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true).&lt;br /&gt;
**&#039;&#039;&#039;options-&amp;gt;newlines&#039;&#039;&#039;: To decide if linefeeds in text should be converted to html newlines (&amp;lt;nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/nowiki&amp;gt;) (defaults to true).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== format_string() ===&lt;br /&gt;
&lt;br /&gt;
 function format_string ($string, $striplinks = false, $courseid=NULL )&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* print &#039;&#039;&#039;short strings (non html) that need filter processing&#039;&#039;&#039; (activity titles, post subjects, glossary concepts...).&lt;br /&gt;
&lt;br /&gt;
Please note that this function is basically one stripped version of the full format_text() function detailed above and &#039;&#039;&#039;it doesn&#039;t offer any of it options nor protections&#039;&#039;&#039;. It simply filters the strings and return the result, so we must ensure that text being processed has been properly cleaned at input time, using the proper xxx_param() functions.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;striplinks&#039;&#039;&#039;: To decide if, after the text has been processed by filters, we must delete any link from the result test. Used when we want to show the text inside menus, page titles... (defaults to false).&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help filters to know how they should work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
&lt;br /&gt;
=== print_textarea() ===&lt;br /&gt;
&lt;br /&gt;
 function print_textarea($usehtmleditor, $rows, $cols, $width, &lt;br /&gt;
                        $height, $name, $value=&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;, $courseid=0, $return=false)&lt;br /&gt;
&lt;br /&gt;
This function should be used to:&lt;br /&gt;
&lt;br /&gt;
* display &amp;lt;nowiki&amp;gt;&amp;lt;textarea&amp;gt;&amp;lt;/nowiki&amp;gt; fields when we want to allow users (based in their preferences and browser capabilities) &#039;&#039;&#039;to use the visual HTML editor&#039;&#039;&#039; instead of one standard &#039;plain&#039; area.&lt;br /&gt;
&lt;br /&gt;
Some interesting parameters for this function are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;usehtmleditor&#039;&#039;&#039;: to decide if the HTML editor must be showed. The value of this parameter must be calculated by the can_use_html_editor() function.&lt;br /&gt;
* &#039;&#039;&#039;rows, cols&#039;&#039;&#039;: to be applied it the standard textarea is showed.&lt;br /&gt;
* &#039;&#039;&#039;width, height&#039;&#039;&#039;: to be applied if the HTML editor is used.&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039;: the name of the field that will contain the text once the form was submitted.&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039;: the initial value of the textarea.&lt;br /&gt;
* &#039;&#039;&#039;courseid&#039;&#039;&#039;: This parameter should be passed always to help the editor to know where it is work. This parameter will become less and less important Moodle was 100% of the current course using some session or global variable (it&#039;s one work in progress just now) but, for now, it&#039;s recommended to set it always in the function call.&lt;br /&gt;
* &#039;&#039;&#039;return&#039;&#039;&#039;: to decide if the generated html code must be returned to the caller (true) or printed directly (false). Defaults to false.&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=901</id>
		<title>Coding</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=901"/>
		<updated>2006-04-10T16:02:19Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* General rules */  added rule about logging&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Any collaborative project needs consistency and stability to stay strong.&lt;br /&gt;
&lt;br /&gt;
These &#039;&#039;&#039;coding guidelines&#039;&#039;&#039; are to provide a goal for all Moodle code to strive to. It&#039;s true that some of the older existing code falls short in a few areas, but it will all be fixed eventually. All new code definitely must adhere to these standards as closely as possible.&lt;br /&gt;
&lt;br /&gt;
==General rules==&lt;br /&gt;
&lt;br /&gt;
# All code files should use the .php extension.&lt;br /&gt;
# All template files should use the .html extension.&lt;br /&gt;
# All text files should use Unix-style text format (most text editors have this as an option).&lt;br /&gt;
# All php tags must be &#039;full&#039; tags like &amp;lt;?php ?&amp;gt; ... not &#039;short&#039; tags like &amp;lt;? ?&amp;gt;.&lt;br /&gt;
# All existing copyright notices must be retained. You can add your own if necessary.&lt;br /&gt;
# Each file should include the main config.php file.&lt;br /&gt;
# Each file should check that the user is authenticated correctly, using require_login() and isadmin(), isteacher(), iscreator() or isstudent().&lt;br /&gt;
# All access to databases should use the functions in &#039;&#039;lib/datalib.php&#039;&#039; whenever possible - this allows compatibility across a wide range of databases. You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions within your code (usually a lib.php file); and clearly marked.&lt;br /&gt;
# Don&#039;t create or use global variables except for the standard $CFG, $SESSION, $THEME and $USER.&lt;br /&gt;
# All variables should be initialised or at least tested for existence using isset() or empty() before they are used.&lt;br /&gt;
# All strings should be translatable - create new texts in the &amp;quot;lang/en&amp;quot; files with concise English lowercase names and retrieve them from your code using get_string() or print_string().&lt;br /&gt;
# All help files should be translatable - create new texts in the &amp;quot;en/help&amp;quot; directory and call them using helpbutton(). If you need to update a help file:&lt;br /&gt;
#* with a minor change, where an old translation of the file would still make sense, then it&#039;s OK to make the change but you should notify translation AT moodle DOT org.&lt;br /&gt;
#* for a major change you should create a new file by adding an incrementing number (eg filename2.html) so that translators can easily see it&#039;s a new version of the file. Obviously the new code and the help index files should also be modified to point to the newest versions.&lt;br /&gt;
# Incoming data from the browser (sent via GET or POST) automatically has magic_quotes applied (regardless of the PHP settings) so that you can safely insert it straight into the database. All other raw data (from files, or from databases) must be escaped with addslashes() before inserting it into the database.&lt;br /&gt;
# IMPORTANT: All texts within Moodle, especially those that have come from users, should be printed using the format_text() function. This ensures that text is filtered and cleaned correctly.&lt;br /&gt;
# User actions should be logged using the [[add_to_log|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].&lt;br /&gt;
&lt;br /&gt;
==Coding style==&lt;br /&gt;
&lt;br /&gt;
I know it can be a little annoying to change your style if you&#039;re used to something else, but balance that annoyance against the annoyance of all the people trying later on to make sense of Moodle code with mixed styles. There are obviously many good points for and against any style that people use, but the current style just is, so please stick to it.&lt;br /&gt;
&lt;br /&gt;
1. Indenting should be consistently 4 spaces. Don&#039;t use tabs AT ALL.&lt;br /&gt;
&lt;br /&gt;
2. Variable names should always be easy-to-read, meaningful lowercase English words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.&lt;br /&gt;
&lt;br /&gt;
      GOOD: $quiz&lt;br /&gt;
      GOOD: $errorstring&lt;br /&gt;
      GOOD: $assignments (for an array of objects)&lt;br /&gt;
      GOOD: $i (but only in little loops)&lt;br /&gt;
&lt;br /&gt;
      BAD: $Quiz&lt;br /&gt;
      BAD: $aReallyLongVariableNameWithoutAGoodReason&lt;br /&gt;
      BAD: $error_string&lt;br /&gt;
&lt;br /&gt;
3. Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.&lt;br /&gt;
&lt;br /&gt;
      define(&amp;quot;FORUM_MODE_FLATOLDEST&amp;quot;, 1);&lt;br /&gt;
4. Function names should be simple English lowercase words, and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores. Parameters should always have sensible defaults if possible. Note there is no space between the function name and the following (brackets).&lt;br /&gt;
&lt;br /&gt;
      function forum_set_display_mode($mode=0) {&lt;br /&gt;
          global $USER, $CFG;&lt;br /&gt;
&lt;br /&gt;
          if ($mode) {&lt;br /&gt;
              $USER-&amp;gt;mode = $mode;&lt;br /&gt;
          } else if (empty($USER-&amp;gt;mode)) {&lt;br /&gt;
              $USER-&amp;gt;mode = $CFG-&amp;gt;forum_displaymode;&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
5. Blocks must always be enclosed in curly braces (even if there is only one line). Moodle uses this style:&lt;br /&gt;
&lt;br /&gt;
      if ($quiz-&amp;gt;attempts) {&lt;br /&gt;
          if ($numattempts &amp;gt; $quiz-&amp;gt;attempts) {&lt;br /&gt;
              error($strtoomanyattempts, &amp;quot;view.php?id=$cm-&amp;gt;id&amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
6. Strings should be defined using single quotes where possible, for increased speed.&lt;br /&gt;
&lt;br /&gt;
      $var = &#039;some text without any variables&#039;;&lt;br /&gt;
      $var = &amp;quot;with special characters like a new line \n&amp;quot;;&lt;br /&gt;
      $var = &#039;a very, very long string with a &#039;.$single.&#039; variable in it&#039;;&lt;br /&gt;
      $var = &amp;quot;some $text with $many variables $within it&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
7. Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.&lt;br /&gt;
&lt;br /&gt;
* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.&lt;br /&gt;
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
      * The description should be first, with asterisks laid out exactly&lt;br /&gt;
      * like this example. If you want to refer to a another function,&lt;br /&gt;
      * do it like this: {@link clean_param()}. Then, add descriptions&lt;br /&gt;
      * for each parameter as follows.&lt;br /&gt;
      *&lt;br /&gt;
      * @param int $postid The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $scale The PHP type is followed by the variable name&lt;br /&gt;
      * @param array $ratings The PHP type is followed by the variable name&lt;br /&gt;
      * @return mixed&lt;br /&gt;
      */&lt;br /&gt;
      function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {&lt;br /&gt;
          if (!$ratings) {&lt;br /&gt;
              $ratings = array();     // Initialize the empty array&lt;br /&gt;
              if ($rates = get_records(&amp;quot;forum_ratings&amp;quot;, &amp;quot;post&amp;quot;, $postid)) {&lt;br /&gt;
                  // Process each rating in turn&lt;br /&gt;
                  foreach ($rates as $rate) {&lt;br /&gt;
      ....etc&lt;br /&gt;
&lt;br /&gt;
8. Space should be used liberally - don&#039;t be afraid to spread things out a little to gain some clarity. Generally, there should be one space between brackets and normal statements, but no space between brackets and variables or functions:&lt;br /&gt;
&lt;br /&gt;
      foreach ($objects as $key =&amp;gt; $thing) {&lt;br /&gt;
          process($thing);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if ($x == $y) {&lt;br /&gt;
          $a = $b;&lt;br /&gt;
      } else if ($x == $z) {&lt;br /&gt;
          $a = $c;&lt;br /&gt;
      } else {&lt;br /&gt;
          $a = $d;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
==Database structures==&lt;br /&gt;
&lt;br /&gt;
# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])&lt;br /&gt;
# The main table containing instances of each module must have the same name as the module (eg widget) and contain the following minimum fields:&lt;br /&gt;
#* id - as described above&lt;br /&gt;
#* course - the id of the course that each instance belongs to&lt;br /&gt;
#* name - the full name of each instance of the module&lt;br /&gt;
# Other tables associated with a module that contain information about &#039;things&#039; should be named widget_things (note the plural).&lt;br /&gt;
# Column names should be simple and short, following the same rules as for variable names.&lt;br /&gt;
# Where possible, columns that contain a reference to the id field of another table (eg widget) should be called widgetid. (Note that this convention is newish and not followed in some older tables)&lt;br /&gt;
# Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.&lt;br /&gt;
# Most tables should have a timemodified field (INT10) which is updated with a current timestamp obtained with the PHP time() function.&lt;br /&gt;
&lt;br /&gt;
==Security issues (and handling form and URL data)==&lt;br /&gt;
&lt;br /&gt;
# Do not rely on &#039;register_globals&#039;. Every variable must be properly initialised in every code file. It must be obvious where the variable came from&lt;br /&gt;
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.&lt;br /&gt;
# Do not use the optional_variable() function (this function is now deprecated). Use the optional_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Do not use the require_variable() function (this function is now deprecated). Use the required_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.&lt;br /&gt;
# Use data_submitted(), with care. Data must still be cleaned before use.&lt;br /&gt;
# Do not use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.&lt;br /&gt;
# Do not check for an action using something like if (isset($_GET[&#039;something&#039;])). Use, e.g., $something = optional_param( &#039;something&#039;,-1,PARAM_INT ) and then perform proper test for it being in its expected range of values e.g., if ($something&amp;gt;=0) {....&lt;br /&gt;
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.&lt;br /&gt;
# Use &#039;sesskey&#039; mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;sesskey&amp;quot; value=&amp;quot;&amp;lt;?php echo sesskey(); ?&amp;gt;&amp;quot; /&amp;gt;. When you process the form check with if (!confirm_sesskey()) {error(&#039;Bad Session Key&#039;);}.&lt;br /&gt;
# All filenames must be &#039;cleaned&#039; using the clean_filename() function, if this has not been done already by appropriate use of required_param() or optional_param()&lt;br /&gt;
# Any data read from the database must have addslashes() applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object().&lt;br /&gt;
# Wherever possible, data to be stored in the database must come from POST data (from a form with method=&amp;quot;POST&amp;quot;) as opposed to GET data (ie, data from the URL line).&lt;br /&gt;
# Do not use data from $_SERVER if you can avoid it. This has portability issues.&lt;br /&gt;
# If it hasn&#039;t been done somewhere else, make sure all data written to the database has been through the clean_param() function using the appropriate PARAM_XXXX for the datatype.&lt;br /&gt;
# If you write custom SQL code, make very sure it is correct. In particular watch out for missing quotes around values. Possible SQL &#039;injection&#039; exploit.&lt;br /&gt;
# Check all data (particularly that written to the database) in every file it is used. Do not expect or rely on it being done somewhere else.&lt;br /&gt;
# Blocks of code to be included should contain a definite PHP structure (e.g, a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised variable usage.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Manual de Estilo de Código]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Gustav_Delius&amp;diff=23227</id>
		<title>User talk:Gustav Delius</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Gustav_Delius&amp;diff=23227"/>
		<updated>2006-04-04T07:46:21Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Developer wiki quiz pages==&lt;br /&gt;
&lt;br /&gt;
Hi Gustav, please let me know whether it would be helpful if the quiz pages from the Using Moodle developer wiki should be moved into [[Developer notes]]. --[[User:Helen|Helen]] 07:04, 28 January 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
:Hi Helen, I had indeed been looking for those pages. They are of course outdated but would be a good starting point for a more up-to-date version. If you let me know where I can find them then I can copy them over myself. --[[User:Gustav|Gustav]] 07:08, 28 January 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
Thanks very much for working on these, Gustav, it will help a lot of future quiz programmers.  --[[User:Martin|Martin]] 28 January 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
:Yes, I am very sorry that I neglected the quiz module the way I did in the past months. Ideally I would like to be able to hand over of the module to the OU team, perhaps when I see Jason Cole in Savannah. --[[User:Gustav|Gustav]] 17:02, 28 January 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
::Gustav, you have absolutely nothing to be sorry about. Your huge contribution to Moodle is greatly appreciated. --[[User:Helen|Helen]] 22:02, 28 January 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
Here I am testing the signature string which yesterday afternoon always gave midnight as the time. --[[User:Gustav Delius|Gustav Delius]] 15:46, 4 April 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
:Apparently it works in the morning. My suspicion is that as soon as WST goes beyond midnight it gets stuck at midnight, so I will test this again this afternoon GMT. Clearly Moodle is much more sophisticated with timezones than WikiMedia. --[[User:Gustav Delius|Gustav Delius]] 15:46, 4 April 2006 (WST)&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=455</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=455"/>
		<updated>2006-04-03T15:54:00Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Documentation for contributed code */  link to database of modules and plugins&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
&lt;br /&gt;
== 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://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code] - browse the Moodle code via the web&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.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&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. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. The following types of plugins currently exist (in alphabetical order):&lt;br /&gt;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Authentication|Authentication methods]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Database fields]]&lt;br /&gt;
*[[Database presets]]&lt;br /&gt;
*[[Enrolment plugins]]&lt;br /&gt;
*[[Filters (developer)|Filters]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Question types]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[SSO plugins]]&lt;br /&gt;
&lt;br /&gt;
There are also ways you can contribute that don&#039;t involve PHP programming:&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&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;
*[[Question engine]]&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 area] of the Moodle [[CVS]] repository. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3285</id>
		<title>Filters 1.9 and before</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Filters_1.9_and_before&amp;diff=3285"/>
		<updated>2006-04-01T13:28:59Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* To create a filter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Please note:&#039;&#039;&#039; This page contains information for developers. You may prefer to read the [[Filters (administrator)| information about filters for teachers and administrators]].&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Filters&#039;&#039;&#039; allow for the for the automatic transformation of entered text into different, often more complex forms. For example the titles of [[Resources]] can automatically become hyperlinks that take you to the relevant resource, URLs pointing to [[mp3]] files can become [[Flash]] controls embedded in the webpage that let you pause and rewind the audio. The possibilities are endless and there are a number of standard filters included with Moodle and many more specialized filters contributed by the community.&lt;br /&gt;
&lt;br /&gt;
==To create a filter==&lt;br /&gt;
&lt;br /&gt;
To create a filter that removes all occurrences of the letter &amp;quot;x&amp;quot; - we&#039;ll call it &amp;quot;removex&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Create a new folder inside Moodle&#039;s /filter/ folder, called &amp;quot;removex&amp;quot;&lt;br /&gt;
# Create a new PHP script file inside the folder you&#039;ve just created - name it &amp;quot;filter_removex.php&amp;quot;&lt;br /&gt;
# Write a new PHP function in this file, called &amp;quot;filter_removex()&amp;quot; which takes two parameters - a piece of text to be filtered and a course ID - and returns the processed text.&lt;br /&gt;
&lt;br /&gt;
For our example the function would look like:&lt;br /&gt;
&lt;br /&gt;
 function filter_removex($text, $courseid) {&lt;br /&gt;
     return str_replace(&amp;quot;x&amp;quot;, &amp;quot;&amp;quot;, $text);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
When trying this out, remember to make sure that you activate the filter in the [[Filters (administrator)|filters administration screen]].&lt;br /&gt;
&lt;br /&gt;
Also remember that text filtering functions, when activated, will be used intensively by the server, so you should optimise the filters as far as possible (cut down on database calls etc). Moodle caches the results of filtering to help with processing speed, but it&#039;s still worth being careful about your filter design.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Filters schema]] - a page containing some ideas and thoughts about modifications to the filters system&lt;br /&gt;
* [[Filters (administrator)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Filter]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Delius&amp;diff=19495</id>
		<title>User:Delius</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Delius&amp;diff=19495"/>
		<updated>2006-04-01T13:22:44Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[User:Gustav_Delius]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1997</id>
		<title>Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1997"/>
		<updated>2006-04-01T13:17:59Z</updated>

		<summary type="html">&lt;p&gt;Delius: Removed quiz developer docs template&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The quiz module is a complex module. 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;
The quiz module uses the Moodle [[Question engine]] which is responsible for the rendering of questions and for the processing of student responses. The quiz module itself is only responsible for assembling questions into quizzes and for presenting the results.&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;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core.&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 lib/questionlib.php&lt;br /&gt;
&lt;br /&gt;
The [[Quiz_attempt|attempt.php]] script is one of the most complicated scripts of the quiz module. It is responsible for displaying questions to a user and to evaluate and grade the users&#039; responses. The reason it is complicated is that it has to take a large array of quiz options into account. There is a [[Quiz_attempt|separate page with explanations]] of this script.&lt;br /&gt;
&lt;br /&gt;
==Objects==&lt;br /&gt;
&lt;br /&gt;
Most objects in Moodle are simply devices to hold records from the corresponding database table. However the question engine extends some objects with additional properties that do not correspond to database fields. Furthermore the quiz engine uses a few objects that do not correspond to database tables at all. I intend to give descriptions of these below.&lt;br /&gt;
&lt;br /&gt;
=== The options object ===&lt;br /&gt;
&lt;br /&gt;
The options object is used to carry information about which optional bits of a question should be printed. That can be feedback, correct responses or any other information that a teacher can choose to show or hide to the students during different phases of the quiz lifecycle.&lt;br /&gt;
&lt;br /&gt;
;feedback&lt;br /&gt;
:The feedback field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether or not to print feedback (if available) for the submitted responses.&lt;br /&gt;
&lt;br /&gt;
;correct_responses&lt;br /&gt;
:The correct_responses field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether or not to provide the correct responses (if available) inline with the question.&lt;br /&gt;
&lt;br /&gt;
;readonly&lt;br /&gt;
:The readonly field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether the interaction elements should be disabled or not.&lt;br /&gt;
&lt;br /&gt;
;validation&lt;br /&gt;
:The validation field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether or not to print question validation information. (This is currently only used by the RQP questiontype.)&lt;br /&gt;
&lt;br /&gt;
;responses&lt;br /&gt;
:The responses field holds a boolean value, indicating to the questiontypes&#039; print methods whether or not to print a student&#039;s responses. This only makes sense for reviewing.&lt;br /&gt;
&lt;br /&gt;
;scores&lt;br /&gt;
:The scores field holds a boolean value, indicating to the questiontypes&#039; print methods whether or not to print the grade awarded to student.&lt;br /&gt;
&lt;br /&gt;
;solutions&lt;br /&gt;
:The solutions field holds a boolean value, indicating to the questiontypes&#039; print methods whether or not to show the worked solution provided by the teacher (if any). This only makes sense for reviewing.&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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1996</id>
		<title>Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1996"/>
		<updated>2006-04-01T13:16:27Z</updated>

		<summary type="html">&lt;p&gt;Delius: Added section about objects&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module. 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;
The quiz module uses the Moodle [[Question engine]] which is responsible for the rendering of questions and for the processing of student responses. The quiz module itself is only responsible for assembling questions into quizzes and for presenting the results.&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;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core.&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 lib/questionlib.php&lt;br /&gt;
&lt;br /&gt;
The [[Quiz_attempt|attempt.php]] script is one of the most complicated scripts of the quiz module. It is responsible for displaying questions to a user and to evaluate and grade the users&#039; responses. The reason it is complicated is that it has to take a large array of quiz options into account. There is a [[Quiz_attempt|separate page with explanations]] of this script.&lt;br /&gt;
&lt;br /&gt;
==Objects==&lt;br /&gt;
&lt;br /&gt;
Most objects in Moodle are simply devices to hold records from the corresponding database table. However the question engine extends some objects with additional properties that do not correspond to database fields. Furthermore the quiz engine uses a few objects that do not correspond to database tables at all. I intend to give descriptions of these below.&lt;br /&gt;
&lt;br /&gt;
=== The options object ===&lt;br /&gt;
&lt;br /&gt;
The options object is used to carry information about which optional bits of a question should be printed. That can be feedback, correct responses or any other information that a teacher can choose to show or hide to the students during different phases of the quiz lifecycle.&lt;br /&gt;
&lt;br /&gt;
;feedback&lt;br /&gt;
:The feedback field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether or not to print feedback (if available) for the submitted responses.&lt;br /&gt;
&lt;br /&gt;
;correct_responses&lt;br /&gt;
:The correct_responses field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether or not to provide the correct responses (if available) inline with the question.&lt;br /&gt;
&lt;br /&gt;
;readonly&lt;br /&gt;
:The readonly field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether the interaction elements should be disabled or not.&lt;br /&gt;
&lt;br /&gt;
;validation&lt;br /&gt;
:The validation field holds a boolean value, indicating to the questiontypes&#039; &amp;lt;code&amp;gt;print_question_formulation_and_controls&amp;lt;/code&amp;gt; method whether or not to print question validation information. (This is currently only used by the RQP questiontype.)&lt;br /&gt;
&lt;br /&gt;
;responses&lt;br /&gt;
:The responses field holds a boolean value, indicating to the questiontypes&#039; print methods whether or not to print a student&#039;s responses. This only makes sense for reviewing.&lt;br /&gt;
&lt;br /&gt;
;scores&lt;br /&gt;
:The scores field holds a boolean value, indicating to the questiontypes&#039; print methods whether or not to print the grade awarded to student.&lt;br /&gt;
&lt;br /&gt;
;solutions&lt;br /&gt;
:The solutions field holds a boolean value, indicating to the questiontypes&#039; print methods whether or not to show the worked solution provided by the teacher (if any). This only makes sense for reviewing.&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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1995</id>
		<title>Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1995"/>
		<updated>2006-04-01T13:10:39Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Code documentation */  Added link to description of attempt.php&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module. 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;
The quiz module uses the Moodle [[Question engine]] which is responsible for the rendering of questions and for the processing of student responses. The quiz module itself is only responsible for assembling questions into quizzes and for presenting the results.&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;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core.&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 lib/questionlib.php&lt;br /&gt;
&lt;br /&gt;
The [[Quiz_attempt|attempt.php]] script is one of the most complicated scripts of the quiz module. It is responsible for displaying questions to a user and to evaluate and grade the users&#039; responses. The reason it is complicated is that it has to take a large array of quiz options into account. There is a [[Quiz_attempt|separate page with explanations]] of this script.&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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1994</id>
		<title>Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1994"/>
		<updated>2006-04-01T13:03:27Z</updated>

		<summary type="html">&lt;p&gt;Delius: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module. 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;
The quiz module uses the Moodle [[Question engine]] which is responsible for the rendering of questions and for the processing of student responses. The quiz module itself is only responsible for assembling questions into quizzes and for presenting the results.&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;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core.&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 lib/questionlib.php&lt;br /&gt;
&lt;br /&gt;
&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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1993</id>
		<title>Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1993"/>
		<updated>2006-04-01T12:45:45Z</updated>

		<summary type="html">&lt;p&gt;Delius: Moved some of the documentation to Question engine&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Quiz developer docs}}The quiz module is a complex module with its own  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;
The quiz module uses the Moodle [[Question engine]] which is responsible for the rendering of questions and for the processing of student responses. The quiz module itself is only responsible for assembling questions into quizzes and for presenting the results.&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;
;lib.php&lt;br /&gt;
:All the functions that are sometimes called by the Moodle core.&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 lib/questionlib.php&lt;br /&gt;
&lt;br /&gt;
&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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3310</id>
		<title>Question engine</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_engine&amp;diff=3310"/>
		<updated>2006-04-01T12:44:04Z</updated>

		<summary type="html">&lt;p&gt;Delius: Moved over some of the documentation from the quiz module&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle has a powerful question engine with a modular structure to allow question type plug-ins. The question engine is responsible for rendering the questions and for processing student responses. It is used by the [[Quiz developer docs|quiz module]] and it is planned that in future it will be used by the Lesson and other modules.&lt;br /&gt;
&lt;br /&gt;
Historically the question engine started as a part of the quiz module. Only since Moodle 1.6 is it a separate core component of Moodle that can be used by any other Moodle component or module. During this restructuring the code was moved from mod/quiz/ to question/ and the tables and functions were renamed. Wherever the old table or function name contained &#039;quiz_&#039; the new one will contain &#039;question_&#039;&lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
When talking about the question engine 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; is the set of definitions (question name, question text, possible answers, grading rules, feedback, etc.) that constitute a reusable assessment item. So it includes much more than what one would in everyday language understand under a question.&lt;br /&gt;
In the terminology of the QTI specification a &#039;question&#039; is more 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;[[Question engine#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 questions 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;, in which case Moodle 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 the 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 [[Question 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 a quiz&amp;quot; (or another activity involving questions). 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;
===Sessions, States, Events===&lt;br /&gt;
&lt;br /&gt;
When a new attempt is started, a new &#039;&#039;&#039;session&#039;&#039;&#039; is started for each question. So in a sense a session is for a question what an attempt is for a whole quiz. A question session lasts no longer than an attempt and for each question there can only by one session within one attempt.&lt;br /&gt;
&lt;br /&gt;
Moodle allows the student to interact with a question repeatedly within one session and each such interaction leads to a new &#039;&#039;&#039;state&#039;&#039;&#039;. The first state is created when the session is created. A new state is then created when a student saves and answer or validates an answer or submits an answer or .... The student&#039;s responses and, if appropriate, the results of response processing (grading) are stored in the new state that gets created.&lt;br /&gt;
&lt;br /&gt;
The type of &#039;&#039;&#039;event&#039;&#039;&#039; that led to the creation of a particular state is saved along with the state. The types of events currently used are:&lt;br /&gt;
;open :A new session has just been created and this is the opening state. Usually it doesn&#039;t hold student responses yet (except where a quiz attempt is based on a previous attempt because the &#039;attemptonlast&#039; option is set).&lt;br /&gt;
;save:The student has clicked the save button.&lt;br /&gt;
;validate:The student has asked for his responses to be validated. This means it is checked that they are valid responses. In the case of mathematical questions which requires the input of a mathematical expression in some linear format the question type may want to display the validated result back to the student in typeset form. Similar things may apply to other subject-specific question types. If a student response is found to be invalid the student is told so but no penalty is applied. The invalid response is stored with the state.&lt;br /&gt;
;grade:The student has pressed the submit button. The grade is calculated and stored with the attempt.&lt;br /&gt;
;duplicategrade:The student has pressed the submit button but the response to this question has not actually changed. This happens a lot in quizzes with several questions on on page where the student may have changed the responses for one question only. I believe that states created by this type of event are not stored in the database.&lt;br /&gt;
;close:The last state in a session which is now closed. Currently a session closes only when the attempt closes, either because the student requests it or because the timelimit elapses.&lt;br /&gt;
&lt;br /&gt;
There are now plans to introduce another event type&lt;br /&gt;
;submit:The student has submitted his responses for grading but grading has not yet taken place. This will be used by teacher-marked question types like the essay questions for example.&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;
==API==&lt;br /&gt;
&lt;br /&gt;
The library lib/questionlib.php contains 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 mod/quiz/locallib.php). Loading this library instantiates all questiontype classes by loading the questiontype.php files&lt;br /&gt;
&lt;br /&gt;
A description of the API still needs to be written. Also lib/questionlib.php should be cleaned up a bit to distinguish between the API functions and the helper functions.&lt;br /&gt;
&lt;br /&gt;
==Organisation==&lt;br /&gt;
The default questiontype class is defined in &#039;&#039;&#039;question/type/questiontype.php&#039;&#039;&#039; (in Moodle 1.5 this was still in mod/quiz/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;
While questiontypes are realized as classes, the question engine 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 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 one 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;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=453</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=453"/>
		<updated>2006-04-01T12:14:44Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Documentation for core components */  Added question engine&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
&lt;br /&gt;
== 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://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code] - browse the Moodle code via the web&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.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&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. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. The following types of plugins currently exist (in alphabetical order):&lt;br /&gt;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Authentication|Authentication methods]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Database fields]]&lt;br /&gt;
*[[Database presets]]&lt;br /&gt;
*[[Enrolment plugins|Enrollment methods]]&lt;br /&gt;
*[[Text filters|Filters]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Question types]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[SSO plugins]]&lt;br /&gt;
&lt;br /&gt;
There are also ways you can contribute that don&#039;t involve PHP programming:&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&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;
*[[Question engine]]&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 area] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=452</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=452"/>
		<updated>2006-04-01T08:30:51Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* How you can contribute */  related to new database of modules and plugins&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
&lt;br /&gt;
== 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://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code] - browse the Moodle code via the web&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.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&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. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. The following types of plugins currently exist (in alphabetical order):&lt;br /&gt;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Authentication|Authentication methods]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Database fields]]&lt;br /&gt;
*[[Database presets]]&lt;br /&gt;
*[[Enrolment plugins|Enrollment methods]]&lt;br /&gt;
*[[Text filters|Filters]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Question types]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[SSO plugins]]&lt;br /&gt;
&lt;br /&gt;
There are also ways you can contribute that don&#039;t involve PHP programming:&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&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 area] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=451</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=451"/>
		<updated>2006-04-01T08:15:03Z</updated>

		<summary type="html">&lt;p&gt;Delius: Moved guidelines and resources to the top and edited the sections a bit&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
&lt;br /&gt;
== 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://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://cvs.sourceforge.net/viewcvs.py/moodle/moodle/ CVS code] - browse the Moodle code via the web&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.sourceforge.net/dhawes-phpdoc/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&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;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Themes]]&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;
*[[Enrolment plugins]]&lt;br /&gt;
*[[Authentication]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Bug tracker|Participating in the bug tracker]]&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 area] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=450</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=450"/>
		<updated>2006-03-25T19:42:19Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* How you can contribute */  added enrolment and authentication&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;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Themes]]&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;
*[[Enrolment plugins]]&lt;br /&gt;
*[[Authentication]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Translation|Translations]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&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 (developer)|Moodle CVS for developers]]&lt;br /&gt;
*[[Tracking Moodle CVS with git]]&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 area] of the Moodle [[CVS]] repository. Developer documentation for these components should be listed here.&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;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Matching_question_type&amp;diff=2159</id>
		<title>Matching question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Matching_question_type&amp;diff=2159"/>
		<updated>2006-03-19T09:37:26Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Response storage */  correction&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 match_sub record that provided the subquestion and then the code of the match_sub record that provided the selected response. 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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1992</id>
		<title>Quiz</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Quiz&amp;diff=1992"/>
		<updated>2006-02-22T08:12:39Z</updated>

		<summary type="html">&lt;p&gt;Delius: New section about sessions, states and events&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 questions 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;
&lt;br /&gt;
===Sessions, States, Events===&lt;br /&gt;
&lt;br /&gt;
When a new attempt is started, a new &#039;&#039;&#039;session&#039;&#039;&#039; is started for each question. So in a sense a session is for a question what an attempt is for the whole quiz. A question session lasts no longer than an attempt and for each question there can only by one session within one attempt.&lt;br /&gt;
&lt;br /&gt;
Moodle allows the student to interact with a question repeatedly within one session and each such interaction leads to a new &#039;&#039;&#039;state&#039;&#039;&#039;. The first state is created when the session is created. A new state is then created when a student saves and answer or validates an answer or submits an answer or .... The student&#039;s responses and, if appropriate, the results of response processing (grading) are stored in the new state that gets created.&lt;br /&gt;
&lt;br /&gt;
The type of &#039;&#039;&#039;event&#039;&#039;&#039; that led to the creation of a particular state is saved along with the state. The types of events currently used are:&lt;br /&gt;
;open :A new session has just been created and this is the opening state. Usually it doesn&#039;t hold student responses yet, except where the quiz attempt is based on a previous attempt because the &#039;attemptonlast&#039; option is set.&lt;br /&gt;
;navigate:When a student navigates from one page of a quiz to another all the responses are saved. We thought it would be nice to distinguish these events from the ones where the student actually consciously saves the responses. I don&#039;t think this is actually used currently.&lt;br /&gt;
;save:The student has clicked the save button.&lt;br /&gt;
;validate:The student has asked for his responses to be validated. This means it is checked that they are valid responses. In the case of mathematical questions which requires the input of a mathematical expression in some linear format the question type may want to display the validated result back to the student in typeset form. Similar things may apply to other subject-specific question types. If a student response is found to be invalid the student is told so but no penalty is applied. The invalid response is stored with the state.&lt;br /&gt;
;grade:The student has pressed the submit button. The grade is calculated and stored with the attempt.&lt;br /&gt;
;duplicategrade:The student has pressed the submit button but the response to this question has not actually changed. This happens a lot in quizzes with several questions on on page where the student may have changed the responses for one question only. I believe that states created by this type of event are not stored in the database.&lt;br /&gt;
;close:The last state in a session which is now closed. Currently a session closes only when the attempt closes, either because the student requests it or because the timelimit elapses.&lt;br /&gt;
&lt;br /&gt;
There are now plans to introduce another event type&lt;br /&gt;
;submit:The student has submitted his responses for grading but grading has not yet taken place. This will be used by teacher-marked question types like the essay questions for example.&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;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2229</id>
		<title>True/False question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2229"/>
		<updated>2006-02-21T21:43:59Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* State-&amp;gt;options */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
Each true/false question creates two records in the quiz_answers table, one for the &#039;true&#039; option, one for the &#039;false&#039; option. The ids of these answers are stored in the &#039;trueanswer&#039; and &#039;falseanswer&#039; field of the quiz_truefalse table.&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;
:id of the answer &#039;True&#039; (not necessarily the correct answer).&lt;br /&gt;
;falseanswer &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:id of the answer &#039;False&#039; (not necessarily the wrong answer).&lt;br /&gt;
&lt;br /&gt;
It is important to distinguish between the answer &#039;True&#039; and the correct answer. When setting up a true/false question the teacher decides whether the answer &#039;True&#039; or the answer &#039;False&#039; is the correct answer. So &#039;true&#039; and &#039;false&#039; here refer to the statement in the question text, not to the correctness of the answer.&lt;br /&gt;
&lt;br /&gt;
The way Moodle stores which of the answers is the correct answer is via the &#039;fraction&#039; field in the quiz_answers table. The correct answer has &#039;fraction&#039; = 1, the wrong one has &#039;fraction&#039; = 0.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The response from the student in &amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt; is the id of the answer chosen by the student. This then also gets stored in the &#039;answer&#039; field in the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
$question-&amp;gt;options object holds the data from the quiz_truefalse table and the -&amp;gt;answers property is an array of answers, indexed by the answer id. In the case of the true/false question $question-&amp;gt;options-&amp;gt;answers should of course be an array of only two answers.&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
True/false questions do not use the $state-&amp;gt;options property.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2228</id>
		<title>True/False question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2228"/>
		<updated>2006-02-21T21:42:10Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* Question-&amp;gt;options */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
Each true/false question creates two records in the quiz_answers table, one for the &#039;true&#039; option, one for the &#039;false&#039; option. The ids of these answers are stored in the &#039;trueanswer&#039; and &#039;falseanswer&#039; field of the quiz_truefalse table.&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;
:id of the answer &#039;True&#039; (not necessarily the correct answer).&lt;br /&gt;
;falseanswer &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:id of the answer &#039;False&#039; (not necessarily the wrong answer).&lt;br /&gt;
&lt;br /&gt;
It is important to distinguish between the answer &#039;True&#039; and the correct answer. When setting up a true/false question the teacher decides whether the answer &#039;True&#039; or the answer &#039;False&#039; is the correct answer. So &#039;true&#039; and &#039;false&#039; here refer to the statement in the question text, not to the correctness of the answer.&lt;br /&gt;
&lt;br /&gt;
The way Moodle stores which of the answers is the correct answer is via the &#039;fraction&#039; field in the quiz_answers table. The correct answer has &#039;fraction&#039; = 1, the wrong one has &#039;fraction&#039; = 0.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The response from the student in &amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt; is the id of the answer chosen by the student. This then also gets stored in the &#039;answer&#039; field in the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
$question-&amp;gt;options object holds the data from the quiz_truefalse table and the -&amp;gt;answers property is an array of answers, indexed by the answer id. In the case of the true/false question $question-&amp;gt;options-&amp;gt;answers should of course be an array of only two answers.&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2227</id>
		<title>True/False question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2227"/>
		<updated>2006-02-21T21:39:52Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* 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;
Each true/false question creates two records in the quiz_answers table, one for the &#039;true&#039; option, one for the &#039;false&#039; option. The ids of these answers are stored in the &#039;trueanswer&#039; and &#039;falseanswer&#039; field of the quiz_truefalse table.&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;
:id of the answer &#039;True&#039; (not necessarily the correct answer).&lt;br /&gt;
;falseanswer &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:id of the answer &#039;False&#039; (not necessarily the wrong answer).&lt;br /&gt;
&lt;br /&gt;
It is important to distinguish between the answer &#039;True&#039; and the correct answer. When setting up a true/false question the teacher decides whether the answer &#039;True&#039; or the answer &#039;False&#039; is the correct answer. So &#039;true&#039; and &#039;false&#039; here refer to the statement in the question text, not to the correctness of the answer.&lt;br /&gt;
&lt;br /&gt;
The way Moodle stores which of the answers is the correct answer is via the &#039;fraction&#039; field in the quiz_answers table. The correct answer has &#039;fraction&#039; = 1, the wrong one has &#039;fraction&#039; = 0.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The response from the student in &amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt; is the id of the answer chosen by the student. This then also gets stored in the &#039;answer&#039; field in the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
$question-&amp;gt;options object holds the data from the quiz_truefalse table and the -&amp;gt;answers property which is an array with indices &#039;true&#039; and &#039;false&#039; and the values are the corresponding answer objects.&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2226</id>
		<title>True/False question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=True/False_question_type&amp;diff=2226"/>
		<updated>2006-02-21T21:39:30Z</updated>

		<summary type="html">&lt;p&gt;Delius: /* 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;
Each true/false question creates two records in the quiz_answers table, one for the &#039;true&#039; option, one for the &#039;false&#039; option. The ids of these answers are stored in the &#039;trueanswer&#039; and &#039;falseanswer&#039; field of the quiz_truefalse table.&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;
:id of the answer &#039;True&#039; (not necessarily the correct answer).&lt;br /&gt;
;falseanswer &lt;br /&gt;
:int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
:id of the answer &#039;False&#039; (not necessarily the wrong answer).&lt;br /&gt;
&lt;br /&gt;
It is important to distinguish between the answer &#039;True&#039; and the correct answer. When setting up a true/false question the teacher decides whether the answer &#039;True&#039; or the answer &#039;False&#039; is the correct answer. So &#039;true&#039; and &#039;false&#039; here refer to the statement in the question text, not to the correctness of the answer.&lt;br /&gt;
&lt;br /&gt;
The way Moodle stores which of the answers is the correct answer is via the &#039;fraction&#039; field in the quiz_answers table. The correct answer has &#039;fraction&#039; = 1, the wrong one has &#039;fraction&#039; = 0.&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
Each true/false question defines two answer records, one for the &#039;true&#039; option, one for the &#039;false&#039; option. The ids of these answers are stored in the &#039;trueanswer&#039; and &#039;falseanswer&#039; field of the quiz_truefalse table. &lt;br /&gt;
&lt;br /&gt;
The response from the student in &amp;lt;nowiki&amp;gt;$state-&amp;gt;responses[&#039;&#039;]&amp;lt;/nowiki&amp;gt; is the id of the answer chosen by the student. This then also gets stored in the &#039;answer&#039; field in the quiz_states table.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
$question-&amp;gt;options object holds the data from the quiz_truefalse table and the -&amp;gt;answers property which is an array with indices &#039;true&#039; and &#039;false&#039; and the values are the corresponding answer objects.&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Delius</name></author>
	</entry>
</feed>