<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/test/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Quen</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/test/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Quen"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/Special:Contributions/Quen"/>
	<updated>2026-04-28T12:55:01Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Useful_things_a_teacher_can_do_with_roles&amp;diff=45254</id>
		<title>Useful things a teacher can do with roles</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Useful_things_a_teacher_can_do_with_roles&amp;diff=45254"/>
		<updated>2008-10-13T10:01:01Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Requirements: New role created by an administrator */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Default role settings==&lt;br /&gt;
&lt;br /&gt;
* Give students [[Forum moderator role|forum moderator rights]]&lt;br /&gt;
* Enable students to grade assignment submissions&lt;br /&gt;
* Give students the rights to approve database entries (or glossary entries)&lt;br /&gt;
* Allow students to clean up saved chat sessions&lt;br /&gt;
&lt;br /&gt;
In each of the above cases, students are assigned the role of non-editing teacher in the module context (via the &amp;quot;Locally assigned roles&amp;quot; tab in the editing activity page).&lt;br /&gt;
&lt;br /&gt;
==Requirement: Teachers allowed to override permissions==&lt;br /&gt;
&lt;br /&gt;
* Create an [[Forum permissions|archive forum]] (or archive database, glossary or wiki)&lt;br /&gt;
* Enable students to [[Forum permissions|rate forum posts]]&lt;br /&gt;
* Allow students to [[Unenrolment|unenrol themselves from a course]]&lt;br /&gt;
* [[Block permissions|Hide a block]] from guests&lt;br /&gt;
&lt;br /&gt;
By default, only administrators are able to override permissions. Instructions on enabling teachers to override permissions can be found in [[Override permissions]].&lt;br /&gt;
&lt;br /&gt;
==Requirement: New role created by an administrator==&lt;br /&gt;
&lt;br /&gt;
* Give students [[Quiz user with unlimited time role|unlimited time to complete quizzes]]&lt;br /&gt;
* Enable students to [[Question creator role|create questions]]&lt;br /&gt;
* Assign a student the [[Calendar editor role|role of calendar editor]]&lt;br /&gt;
* Provide temporary read-only access to naughty students&lt;br /&gt;
&lt;br /&gt;
[[Category:Roles]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=OU_blog&amp;diff=44569</id>
		<title>OU blog</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=OU_blog&amp;diff=44569"/>
		<updated>2008-09-30T13:38:27Z</updated>

		<summary type="html">&lt;p&gt;Quen: New page: {{stub}} This contributed code module is an alternative blog system for Moodle. It can be used in place of, or in addition to, the standard Moodle blog system.  ==Features==  * Provides us...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
This contributed code module is an alternative blog system for Moodle. It can be used in place of, or in addition to, the standard Moodle blog system.&lt;br /&gt;
&lt;br /&gt;
==Features==&lt;br /&gt;
&lt;br /&gt;
* Provides user blogs (similar to Moodle ones; everyone has their own blog) and course blogs (add an instance of the module to a course, and students in the course can all contribute to a shared blog).&lt;br /&gt;
* Full support for comments. Comments can be turned off for a particular blog or post, but otherwise people can leave comments in both user and course blogs. In order to avoid spam, you currently have to be a logged-in user in order to leave comments, even if the post itself is open to the public.&lt;br /&gt;
* Access control levels: private (user only), course members, logged-in users, or worldwide.&lt;br /&gt;
* Group support for course blogs (so you can have per-group blogs).&lt;br /&gt;
* Blog-specific tags. Tags are not connected to the Moodle tag system but apply only within the blog. You click on a tag to see all posts in the current blog with that tag.&lt;br /&gt;
* User cosmetic options - change the name of your blog (from My Name&#039;s Blog to whatever you like) and add a description.&lt;br /&gt;
* Standard Moodle 1.9 role/permission support (eg if you want to make it so students can&#039;t post to course blogs, etc).&lt;br /&gt;
* Post and comment management. You can edit or delete posts and delete comments, but deleted or previous text remains available to administrator users. (This is necessary in various circumstances.)&lt;br /&gt;
* RSS and Atom feeds.&lt;br /&gt;
* Automatically integrates with the OU search system (if that is installed) to provide fulltext search of blog posts.&lt;br /&gt;
&lt;br /&gt;
There is no connection between this system and standard Moodle blog; installing this system doesn&#039;t do anything to your existing Moodle blogs. If you want to move over to this system entirely, you would use the Moodle admin option that lets you disable its internal blog feature, to avoid confusion. (There is no way at present to transfer actual content from Moodle blog to oublog.)&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
&lt;br /&gt;
* Requires PHP 5.&lt;br /&gt;
* Tested with Postgres 8.1 and MySQL 5. (Should work on other Moodle-supported databases.)&lt;br /&gt;
* Tested on current Moodle 1.9.2+ from CVS. (Probably works on any Moodle 1.9 though.)&lt;br /&gt;
&lt;br /&gt;
No complex installation is necessary, just drop the oublog folder into your Moodle mod folder and visit the admin notifications page to install.&lt;br /&gt;
&lt;br /&gt;
OU blog was specified by the Open University which funded the work. The actual development was done by Matt Clarkson of Catalyst, and further bugfixes and minor changes were then added by me (sam marshall) at the OU. &lt;br /&gt;
&lt;br /&gt;
==Development status==&lt;br /&gt;
&lt;br /&gt;
This blog is in active use at the Open University. We continue to maintain and develop it and plan to do public releases aligned with our internal release cycle. &lt;br /&gt;
&lt;br /&gt;
There are no major developments planned at present. &lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://moodle.org/mod/data/view.php?d=13&amp;amp;rid=1820 OU blog] is a Modules and plugins database page for downloads and more information.&lt;br /&gt;
*Discussions: please create or find a discussion topic in the [http://moodle.org/mod/forum/view.php?id=44 Contributed Code forum]&lt;br /&gt;
&lt;br /&gt;
[[Category:Contributed code]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Installing_and_upgrading_plugin_database_tables&amp;diff=42932</id>
		<title>Development:Installing and upgrading plugin database tables</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Installing_and_upgrading_plugin_database_tables&amp;diff=42932"/>
		<updated>2008-08-29T12:45:56Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* The files you need for the second release */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
&lt;br /&gt;
If you have done the right thing, Moodle will automatically create the database tables for your plugin when you visite the Admin notifications page (.../admin/index.php). This process is controlled by three files within your plugin:&lt;br /&gt;
;version.php : This records the version of the plugin code&lt;br /&gt;
;db/install.xml : This is used when someone installs your plugin for the first time.&lt;br /&gt;
;db/upgrade.php : This is used when someone who had an older version of your plugin installed upgrades to the latest version.&lt;br /&gt;
&lt;br /&gt;
In addition, Moodle also stores in the database the currently installed version of each plugin. This is normally stored in the mdl_config table, in a row with name something like &#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039;_version. For example qtype_myqtype_version. The exception to this rule are modules and blocks. Installed module version numbers are stored in the mdl_modules table. Block version numbers are in mdl_block.&lt;br /&gt;
&lt;br /&gt;
==A specific example==&lt;br /&gt;
&lt;br /&gt;
For the rest of this document, I will use a particular example, because it should make the explanation easier. You should be able to see how to generalise it.&lt;br /&gt;
&lt;br /&gt;
We will suppose you that you are making a new question type myqtype. This is plugin type qtype, and the code will be in the question/type/myqtype folder. The currently installed version number will be stored in the qtype_myqtype_version row of the mdl_config table.&lt;br /&gt;
&lt;br /&gt;
In addition, we will just consider the first two releases of the plugin. The first release will have version number 2008080100, and will just use one database table mdl_question_myqtype, with two columns col1 and col2. Then we will suppose that the second release is 2008080200, and that requires an extra column, newcol, to be added to the mdl_question_myqtype table.&lt;br /&gt;
&lt;br /&gt;
==The files you need for the first release==&lt;br /&gt;
&lt;br /&gt;
;version.php&lt;br /&gt;
 $plugin-&amp;gt;version  = 2008080100;&lt;br /&gt;
 $plugin-&amp;gt;requires = XXXXXXXXXX; // Copy the current value from the top-level version.php file.&lt;br /&gt;
;db/install.xml&lt;br /&gt;
:This file, which you should [[Development:XMLDB_defining_an_XML_structure#The_XMLDB_editor|create with the XMLDB editor]], should contain the definition for your mdl_question_myqtype table, with the two columns col1 and col2.&lt;br /&gt;
&lt;br /&gt;
At this stage, you do not need a db/upgrade.php file.&lt;br /&gt;
&lt;br /&gt;
==The files you need for the second release==&lt;br /&gt;
&lt;br /&gt;
;version.php&lt;br /&gt;
 $plugin-&amp;gt;version  = 2008080200;&lt;br /&gt;
 $plugin-&amp;gt;requires = XXXXXXXXXX; // Copy the current value from the top-level version.php file.&lt;br /&gt;
;db/install.xml : This file should now contain the updated definition for your mdl_question_myqtype table, with three columns col1, col2 and newcol. You modify this file using the XMLDB editor.&lt;br /&gt;
;db/upgrade.php&lt;br /&gt;
:This file should contain the code that people need to run to upgrade from version 2008080100 of your plugin. That is, the code to add a column newcol to the mdl_question_myqtype table. You don&#039;t have to write this code yourself as the XMLDB editor will generate it for you. The upgrade.php file should contain a single function xmldb_qtype_myqtype_upgrade that looks a bit like:&lt;br /&gt;
 function xmldb_qtype_myqtype_upgrade($oldversion = 0) {&lt;br /&gt;
     $result = true;&lt;br /&gt;
 &lt;br /&gt;
     /// Add a new column newcol to the mdl_question_myqtype&lt;br /&gt;
     if ($result &amp;amp;&amp;amp; $oldversion &amp;lt; 2008080200) {&lt;br /&gt;
         // Code to add the column, generated by the &#039;View PHP Code&#039; option of the XMLDB editor.&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return $result;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Hint: If you are modifying or adding a field/table, get the XMLDB editor to generate the PHP update code for you &#039;&#039;&#039;after&#039;&#039;&#039; making the changes in the editor. If you are deleting one, you need to generate the PHP code &#039;&#039;&#039;before&#039;&#039;&#039; making the change - or you won&#039;t be able to select the field/table to write the code for, because it no longer exists.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==What happens when a user installs or upgrades your plugin==&lt;br /&gt;
&lt;br /&gt;
The process is triggered when an administrator goes to the Admin notifications page (.../admin/index.php). The code that does the work is the upgrade_plugins function in lib/adminlib.php. In pseudo-code, what it does is:&lt;br /&gt;
&lt;br /&gt;
 For each plugin of this type (e.g. all qtype plugins) {&lt;br /&gt;
     // For the body of this loop, suppose the current plugin being processed is myqtype.&lt;br /&gt;
 &lt;br /&gt;
     Check that question/type/myqtype/version.php, .../db/upgrade.php and .../db/install.php exist.&lt;br /&gt;
 &lt;br /&gt;
     if ($CFG-&amp;gt;qtype_myqtype_version exists, and is less than the number in version.php) {&lt;br /&gt;
         Call the upgrade function xmldb_qtype_myqtype_upgrade from&lt;br /&gt;
                 upgrade.php, passing the old version number ($CFG-&amp;gt;qtype_myqtype_version)&lt;br /&gt;
                 which says what is currently installed&lt;br /&gt;
         Update $CFG-&amp;gt;qtype_myqtype_version to the latest number from version.php&lt;br /&gt;
                 to record what is currently installed&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     else if ($CFG-&amp;gt;qtype_myqtype_version does not exist) {&lt;br /&gt;
         Create the tables from the definitions in install.xml&lt;br /&gt;
         Update $CFG-&amp;gt;qtype_myqtype_version to the latest number from version.php&lt;br /&gt;
                 to record what is currently installed&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Of course, it is a bit more complex that than. However, the code in the upgrade_plugins is quite clear, and I encourage you to go and have a look at it so you can see all the details of how it works. That is the best way to really understand what is happening.&lt;br /&gt;
&lt;br /&gt;
Let us now look at some worked examples:&lt;br /&gt;
&lt;br /&gt;
===User installs version 2008080100 of myqtype===&lt;br /&gt;
&lt;br /&gt;
To start with, the mdl_question_myqtype does not exist, and there will not be a qtype_myqtype_version row in the mdl_config table.&lt;br /&gt;
&lt;br /&gt;
# The user will unzip myqtype.zip into the question/type folder.&lt;br /&gt;
# The user will visit the Admin notifications page.&lt;br /&gt;
# This will trigger Moodle to search for plugings to upgrade. It will find that the code for the qtype_myqtype plugin is now present, but there is no trace of it in the database, so it will install the plugin from the install.xml file.&lt;br /&gt;
&lt;br /&gt;
At the end of this process, the mdl_question_myqtype table will exist with the two columns col1 and col2; and the qtype_myqtype_version row in the mdl_config table will contain 2008080100.&lt;br /&gt;
&lt;br /&gt;
===User upgrades from version 2008080100 to version 2008080200 of myqtype===&lt;br /&gt;
&lt;br /&gt;
To start with, the mdl_question_myqtype table will exist with the two columns col1 and col2; and the qtype_myqtype_version row in the mdl_config table will contain 2008080100.&lt;br /&gt;
&lt;br /&gt;
# The user will delete the old question/type/myqtype folder.&lt;br /&gt;
# The user will unzip the new myqtype.zip into the question/type folder.&lt;br /&gt;
# The user will visit the Admin notifications page.&lt;br /&gt;
# This will trigger Moodle to search for plugings to upgrade. It will find that the code for version 2008080200 the qtype_myqtype plugin is now present, but the installed version of the the database tables (qtype_myqtype_version) is 2008080100. Therefore, it will call xmldb_qtype_myqtype_upgrade from upgrade.php, passing 2008080100 as the $oldversion argument.&lt;br /&gt;
&lt;br /&gt;
At the end of this process, the mdl_question_myqtype table will now have three columns col1, col2 and newcol; and the qtype_myqtype_version row in the mdl_config table will contain 2008080200.&lt;br /&gt;
&lt;br /&gt;
===User installs version 2008080200 of myqtype into a clean Moodle install===&lt;br /&gt;
&lt;br /&gt;
To start with, the mdl_question_myqtype does not exist, and there will not be a qtype_myqtype_version row in the mdl_config table.&lt;br /&gt;
&lt;br /&gt;
# The user will unzip the 2008080200 version of myqtype.zip into the question/type folder.&lt;br /&gt;
# The user will visit the Admin notifications page.&lt;br /&gt;
# This will trigger Moodle to search for plugings to upgrade. It will find that the code for the qtype_myqtype plugin is now present, but there is no trace of it in the database, so it will install the plugin from the install.xml file.&lt;br /&gt;
&lt;br /&gt;
At the end of this process, the mdl_question_myqtype table will exist with three columns col1, col2 and newcol; and the qtype_myqtype_version row in the mdl_config table will contain 2008080200.&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
&lt;br /&gt;
The first time a user installs any version of your plugin, the install.xml file will be used to create all the required database tables. Therefore install.xml should always contain the definition of the up-to-date database structure. Moodle recognises this situation because there is a version.php file on disc, but there is no &#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039;_version value in the mdl_config table.&lt;br /&gt;
&lt;br /&gt;
If the user already had a version of your plugin installed, and then upgrades to a newer version, Moodle will detect this because the version.php file will contain a newer version number than the &#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039;_version value in the mdl_config table. In this case, Moodle will run the code in the upgrade.php file, passing in the old version number, so that the correct bits of upgrade can be run, as controlled by the if ($oldversion &amp;lt; XXXXXXXXXX) blocks of code.&lt;br /&gt;
&lt;br /&gt;
The contents of the install.xml and upgrade.php files should be generated using the XMLDB editor.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Development:XMLDB_Documentation|XMLDB_Documentation]]&lt;br /&gt;
* [[Development:Coding|Coding guidelines]]&lt;br /&gt;
* [[Development:DDL functions|DDL functions]]&lt;br /&gt;
* [[Development:XMLDB defining an XML structure|install.xml file documentation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
[[Category:Installation]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=OU_wiki&amp;diff=42862</id>
		<title>OU wiki</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=OU_wiki&amp;diff=42862"/>
		<updated>2008-08-28T12:43:21Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Development status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
This contributed code module is a simple, easy to use, but reasonably full-featured alternative to standard Moodle wiki.&lt;br /&gt;
&lt;br /&gt;
==Features==&lt;br /&gt;
&lt;br /&gt;
*  Relies on HTML editor; does not use wiki markup except for links&lt;br /&gt;
* Can live alongside the existing wiki - does not make any attempt to convert content&lt;br /&gt;
* Includes integrated comments on pages or headings&lt;br /&gt;
* Supports most features of the old wiki &lt;br /&gt;
**Except for wiki markup (as above), attachments, and a few admin features&lt;br /&gt;
**If you want a search facility for the wiki, you must also install the ousearch block.&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
*This contributed code&#039;s [http://moodle.org/mod/data/view.php?d=13&amp;amp;rid=1015  Modules and plugins database page] for downloads and more information.&lt;br /&gt;
*Discussions: please create or find a discussion topic [http://moodle.org/mod/forum/view.php?id=44 The Contributed Code forum]&lt;br /&gt;
* Also the [http://moodle.org/mod/forum/view.php?f=366 Wiki forum] has some discussion about OU wiki features&lt;br /&gt;
&lt;br /&gt;
==Development status==&lt;br /&gt;
&lt;br /&gt;
This wiki is in active use at the Open University. We continue to maintain and develop it and plan to do public releases aligned with our internal release cycle. &lt;br /&gt;
&lt;br /&gt;
There are no major developments planned at present, but a number of minor enhancements should trickle in gradually. (Next planned features: way to easily revert to old page version, way for admins to hide page versions permanently.)&lt;br /&gt;
&lt;br /&gt;
[[Category: Administrator]]&lt;br /&gt;
[[Category:Contributed code]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Shared_activities_course_format&amp;diff=42861</id>
		<title>Shared activities course format</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Shared_activities_course_format&amp;diff=42861"/>
		<updated>2008-08-28T12:41:10Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Development status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
This contributed code module is a course format system that allows any Moodle user (for example, students) to create their own shared activities which they can invite a list of other people to join. When they invite people, those people receive an email with a link to the activity.&lt;br /&gt;
&lt;br /&gt;
==Features==&lt;br /&gt;
This system could be useful if users meet on a course and want to arrange social events between themselves, or to stay in touch after the course ends.&lt;br /&gt;
* Supports [[Forum module]]s&lt;br /&gt;
* Supports installed [[OU wiki]]s&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
*This contributed code&#039;s [PASTE http//: LINK HERE  Modules and plugins database page] for downloads and more information.&lt;br /&gt;
*Discussions: please create or find a discussion topic [http://moodle.org/mod/forum/view.php?id=44 The Contributed Code forum]&lt;br /&gt;
&lt;br /&gt;
==Development status==&lt;br /&gt;
&lt;br /&gt;
This code is currently in use at the Open University, but we don&#039;t have any plans to develop it further at present (except adding support for oublog when that is released). We&#039;re also not aware of any major problems. &lt;br /&gt;
&lt;br /&gt;
Please contact sam marshall if you find serious bugs. The public version may &#039;lag behind&#039; our internal one, and we may need prodding to update it for bugfixes.&lt;br /&gt;
&lt;br /&gt;
[[Category: Administrator]]&lt;br /&gt;
[[Category:Contributed code]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Resource_pages&amp;diff=42722</id>
		<title>Resource pages</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Resource_pages&amp;diff=42722"/>
		<updated>2008-08-26T09:16:42Z</updated>

		<summary type="html">&lt;p&gt;Quen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
This contributed code module shows a list of links, files, or text snippets on a single page. This requires 2 patches and does not work with MySQL, only with Postgres databases.&lt;br /&gt;
&lt;br /&gt;
==Features==&lt;br /&gt;
&lt;br /&gt;
* Make items appear/disappear on set dates.&lt;br /&gt;
* Include sections and subsections within a page.&lt;br /&gt;
* Include links from RSS feed within page.&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
*This contributed code&#039;s [http://moodle.org/mod/data/view.php?d=13&amp;amp;rid=1012 Modules and plugins database page] for downloads and more information.&lt;br /&gt;
*Discussions: please create or find a discussion topic [http://moodle.org/mod/forum/view.php?id=44 the contributed code&#039;s forum]&lt;br /&gt;
&lt;br /&gt;
==Development status==&lt;br /&gt;
&lt;br /&gt;
We (Open University) have not been updating the plugin code in line with our own local changes. If anyone actually uses it, you might want to request that we do so. Because this module is not very &#039;Moodle-like&#039;, is difficult to install, and requires a database which most people for some reason do not use, we don&#039;t anticipate that many other people will actually use it. (Please don&#039;t ask us for this update unless you have actually installed it, got it working, and wish to use it, as it will take us some work.)&lt;br /&gt;
&lt;br /&gt;
We are hopeful that there will be a significant update released for Moodle 2.0 which removes the requirement to apply code patches, and works on all databases, so that everyone can easily install it if they want.&lt;br /&gt;
&lt;br /&gt;
[[Category: Administrator]]&lt;br /&gt;
[[Category:Contributed code]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Study_calendar_course_format&amp;diff=42721</id>
		<title>Study calendar course format</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Study_calendar_course_format&amp;diff=42721"/>
		<updated>2008-08-26T09:11:37Z</updated>

		<summary type="html">&lt;p&gt;Quen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
This contributed code give a course format that has tick boxes next to each item so the student can check them off.&lt;br /&gt;
&lt;br /&gt;
==Features==&lt;br /&gt;
This is an enhanced version of the weekly course format. Key features:&lt;br /&gt;
&lt;br /&gt;
* You can combine, rename, and generally configure weeks. (E.g. group together 2 weeks, call it &#039;Easter break&#039;; or group together 6 weeks, call it &#039;Block 2&#039;.)&lt;br /&gt;
* Integrates Moodle calendar events into the main display.&lt;br /&gt;
* Students can use checkboxes to mark their progress by ticking activities and events.&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
*This contributed code&#039;s [http://moodle.org/mod/data/view.php?d=13&amp;amp;rid=1014 Modules and plugins database page] for downloads and more information.&lt;br /&gt;
*Discussions: please create or find a discussion topic [http://moodle.org/mod/forum/view.php?id=44 the contributed code&#039;s forum]&lt;br /&gt;
&lt;br /&gt;
==Development status==&lt;br /&gt;
&lt;br /&gt;
The current version is the final release for Moodle 1.x. If you find any serious bugs that need fixing, please get in touch with the developer (see contact details inside file); otherwise we are not expecting to make any changes.&lt;br /&gt;
&lt;br /&gt;
For Moodle 2.0 we will release a new version of this course format (renamed &#039;study planner&#039;) which integrates with Moodle 2.0 features. (An extended version of the checkbox feature is included in core Moodle 2 and available for all course formats, so we needed to change our course format to take account of this.)&lt;br /&gt;
&lt;br /&gt;
[[Category: Administrator]]&lt;br /&gt;
[[Category:Contributed code]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=41102</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=41102"/>
		<updated>2008-08-01T09:39:17Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Available conditions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
[[Development:Conditional activities_Adding module support]]&lt;br /&gt;
&lt;br /&gt;
= Design document =&lt;br /&gt;
&lt;br /&gt;
(This is a design document by sam marshall from the Open University. It is based on earlier discussion in this wiki, and then detailed discussion with moodle.com staff who contributed improvements and corrections.)&lt;br /&gt;
&lt;br /&gt;
See MDL-15497 for tasks and tracking.&lt;br /&gt;
&lt;br /&gt;
sam marshall, 21 May 2008; updated as of 26 June 2008. Exported to MediaWiki format using OpenOffice.org 3.0 beta (i.e. this page doesn&#039;t perfectly represent the word-processor version) and manually tweaked a bit to fix it where it was obviously wrong.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This design document describes in some detail a proposed method to add support for ‘conditional activities’ to Moodle. It is based on a [https://docs.moodle.org/en/Development:Conditional_activities discussion on the Moodle wiki], conversations with Moodle.com staff, and only the teeniest pinch of OU requirements. &lt;br /&gt;
&lt;br /&gt;
This is divided into two related, but separate, chunks of work.&lt;br /&gt;
&lt;br /&gt;
=== Completion tracking ===&lt;br /&gt;
Make the system store whether or not an activity has been ‘completed’. &lt;br /&gt;
&lt;br /&gt;
This may be according to an activity-specific definition of completion, or because the student has ticked a box saying they’ve finished it.&lt;br /&gt;
&lt;br /&gt;
When tracked automatically, completion could vary from formal requirements such as ‘scoring 90% on this quiz’ to informal requirements intended to ensure participation such as ‘post at least 3 times on this forum’.&lt;br /&gt;
&lt;br /&gt;
It should be possible for teachers to access progress information for their students, so that they can see if anyone is falling behind.&lt;br /&gt;
&lt;br /&gt;
=== Conditional availability ===&lt;br /&gt;
Allow or prevent access to an activity depending on various conditions.&lt;br /&gt;
&lt;br /&gt;
These conditions may include the completion of other activities; in the case of graded activities, also whether the grade was pass/fail, or a specific amount. It also may include date.&lt;br /&gt;
&lt;br /&gt;
=== Development process ===&lt;br /&gt;
I will do this work here. It is possible that time constraints might mean I only do the first part (completion tracking).&lt;br /&gt;
&lt;br /&gt;
Development will be against Moodle 1.9, because we need it here at the OU, but it will never actually be committed into Moodle 1.9. The code will instead be ported to Moodle 2.0, which will require various changes (particularly in the area of database access).&lt;br /&gt;
&lt;br /&gt;
Code will be PHP5. We will primarily test against Postgres here but intend using standard Moodle database API and only simple SQL where needed, so database compatibility is unlikely to be a problem.&lt;br /&gt;
&lt;br /&gt;
In some cases the OU have versions of these features. I will be coding automatic upgrade from the previous versions. This will not be included in the core Moodle 2.0 version.&lt;br /&gt;
&lt;br /&gt;
== Completion tracking ==&lt;br /&gt;
=== Completion options ===&lt;br /&gt;
The completion system can be enabled or disabled at site, course, and activity level.&lt;br /&gt;
&lt;br /&gt;
* At site level, the new admin variable $CFG-&amp;gt;enablecompletion (defaults to 1?).&lt;br /&gt;
* At course level, a new mdl_course field enablecompletion (defaults to 1).&lt;br /&gt;
* At activity level, a new mdl_course_modules field completion with values 0 = none, 1 = manual (student decides when they’ve completed something), 2 = automatic. Defaults to 1 but may be set by module e.g. a quiz module could default to automatic, label could set it to 0 so you don’t get checkboxes beside each label, etc.&lt;br /&gt;
&lt;br /&gt;
This table illustrates the effect of these options. (‘enablecompletion’ is abbreviated to ‘ec’.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;prettytable&amp;quot;&lt;br /&gt;
| &#039;&#039;&#039;Location&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Feature&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Appears if&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Admin settings&lt;br /&gt;
| On-off toggle for $CFG-&amp;gt;ec&lt;br /&gt;
| –&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Course settings&lt;br /&gt;
| On-off toggle for course ec&lt;br /&gt;
| $CFG-&amp;gt;ec&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Activity settings&lt;br /&gt;
| Off/manual/automatic option for course-module completion&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Course view&lt;br /&gt;
| Completion display/controls against activity&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec &amp;amp;&amp;amp; completion&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Admin block&lt;br /&gt;
| Link to progress report&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec &amp;amp;&amp;amp; user has permission&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
=== Completion states and conditions ===&lt;br /&gt;
Completion state is stored per-user for every activity. There are four states:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;Not completed [default – not stored in database]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Completed (pass/fail unspecified)&lt;br /&gt;
* Completed, passed&lt;br /&gt;
* Completed, failed&lt;br /&gt;
&lt;br /&gt;
The final two states only apply when completion is based on a specific grade result. These are used only in some situations. Here are the rules: &lt;br /&gt;
&lt;br /&gt;
* Grade visible, ‘grade to pass’ set: ‘completed, passed’ and ‘completed, failed’ states will be used.&lt;br /&gt;
* ‘Grade to pass’ not set &#039;&#039;or&#039;&#039;grade is hidden &#039;&#039;or&#039;&#039;grade is hidden-until (regardless of until date): only the standard ‘not completed’, ‘completed’ states are used.&lt;br /&gt;
&lt;br /&gt;
This is a ‘push’ system – the state is not computed live but is saved and that value used. When completion for the activity is set to manual, students can toggle this value between not completed and completed. When it is set to automatic, the system adjusts the value in certain cases.&lt;br /&gt;
&lt;br /&gt;
==== Standard conditions ====&lt;br /&gt;
There are two standard conditions which do not require (much) module-specific behaviour.&lt;br /&gt;
&lt;br /&gt;
* Graded – module has assigned grade for student.&lt;br /&gt;
** If there are multiple grades for this activity, you can select which one is used to determine completion. (We will not implement this selection in the user interface for the first release. It will always use the first grade.)&lt;br /&gt;
** This condition is implemented by a hook in gradebook that runs at the point where a grade is set.&lt;br /&gt;
* Viewed – student has viewed module.&lt;br /&gt;
** For this to be supported, the module must call a function completion_set_module_viewed($cm) when it thinks that the user has ‘viewed’ the activity. It also needs to indicate that it supports it via &#039;&#039;module&#039;&#039;_supports(FEATURE_COMPLETION_TRACKS_VIEWS).&lt;br /&gt;
&lt;br /&gt;
==== Custom conditions ====&lt;br /&gt;
Modules can support arbitrary custom conditions (with their own form components to configure these, and their own data storage to track them).&lt;br /&gt;
&lt;br /&gt;
Example conditions might be:&lt;br /&gt;
&lt;br /&gt;
* Forum&lt;br /&gt;
** User has made N posts.&lt;br /&gt;
** User has made N replies.&lt;br /&gt;
** Other people have posted N replies to discussions created by this user. (&#039;&#039;This an example of a more complex possibility, not necessarily something that would be a good idea.&#039;&#039;)&lt;br /&gt;
* Wiki&lt;br /&gt;
** User has edited N different pages.&lt;br /&gt;
** User has edited pages N times.&lt;br /&gt;
* Choice&lt;br /&gt;
** User has voted.&lt;br /&gt;
&lt;br /&gt;
It is up to the module to determine when a condition has been met and update the user’s completion. &lt;br /&gt;
&lt;br /&gt;
As part of this project I plan to create some custom conditions for one or a few modules (probably just forum), and implement view tracking for a wider range of modules.&lt;br /&gt;
&lt;br /&gt;
==== Combining conditions ====&lt;br /&gt;
If an activity has both the standard grade condition, and module conditions, these are currently combined via Boolean AND. Modules that support multiple conditions should usually also AND them as this will make life simpler for developer and users; however this is up to the module, as it creates its own form fields and data items.&lt;br /&gt;
&lt;br /&gt;
In the future we may (or may not!) provide the ability to choose boolean OR instead. Some of the API functions contain a parameter that indicates how results should be combined. At present this is always set to AND.&lt;br /&gt;
&lt;br /&gt;
=== Expected date ===&lt;br /&gt;
An activity can optionally have an expected completion date. This date currently has no effect and is not shown to students, but it appears to teachers when viewing progress. It&#039;s intended so that teachers can see when students are having problems and maybe offer assistance.&lt;br /&gt;
&lt;br /&gt;
In future it might be possible to export this data – e.g. the list of students who are &#039;late&#039; – to external systemss.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
(&#039;&#039;Prefix is shown as _. Constants are defined for all values here.&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* _course&lt;br /&gt;
** +Field enablecompletion, unsigned int (1) default 0 not null.1 = enable completion options for activities (if enabled at site level). This is the user-interface default that applies to new courses when completion is enabled for the site.0 = disable and hide options. This is the database default that will apply to existing courses.&lt;br /&gt;
* _course_modules&lt;br /&gt;
** +Field completion, unsigned int (1) default 0 not null.0 = No progress tracking for this activity.1 = Manual completion tracking.2 = Automatic completion tracking.&lt;br /&gt;
** +Field completiongradeitemnumber, unsigned int(10) default 0.NULL = Grade information not used for completion.0,1,… = Use first/second/N&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; grade item supplied by this activity.&lt;br /&gt;
** +Field completionview, unsigned int (1) default 0 not null.0 = View not required for completion.1 = View required for completion.&lt;br /&gt;
** +Field completionexpected, unsigned int (10) default 0 not null.0 = No particular date expected for completion&amp;lt;nowiki&amp;gt;* = time (seconds since epoch) by which activity is expected to be completed. &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* New table _course_modules_completion which stores completion state for a user on each activity.&lt;br /&gt;
** id.&lt;br /&gt;
** coursemoduleid&amp;lt;nowiki&amp;gt; [index].&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** userid&amp;lt;nowiki&amp;gt; [index]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
** completionstate, unsigned int(1) not null.(The absence of a row in the table counts the same as 0 here.)0 = not completed.1 = completed.2 = completed, passed.3 = completed, failed.&lt;br /&gt;
** viewed, unsigned int(1)null = not tracked0 = not viewed1 = viewedOnly stored if the activity is tracking viewed state.&lt;br /&gt;
** timemodified, unsigned int (10) not null.Last date the state changed, in seconds since epoch.&lt;br /&gt;
&lt;br /&gt;
=== Capabilities ===&lt;br /&gt;
* moodle/course:viewprogress&amp;lt;nowiki&amp;gt; [default Teacher, Editing Teacher, Course Creator]&amp;lt;/nowiki&amp;gt;Users with this permission can view progress of students on the course. If the course is set to visible groups mode, or the user also has accessallgroups, then they can see all groups. Otherwise they can only see groups they belong to.&lt;br /&gt;
&lt;br /&gt;
=== Admin ===&lt;br /&gt;
A new admin setting progresstrackedroles stores a list of the roles that are considered relevant when displaying progress. (Other roles can still use the completion system, but won’t be shown on the progress screen.) This setting is editable via standard admin screens.&lt;br /&gt;
&lt;br /&gt;
=== API ===&lt;br /&gt;
These functions will be included in a completionlib.php.&lt;br /&gt;
&lt;br /&gt;
* completion_is_enabled($course=null,$cm=null)Returns true if completion is enabled. With no parameters, returns the site value; when course is specified, checks course as well.If course-module is specified, the return value is the same as the value of completion from course_modules.&lt;br /&gt;
* completion_update_state($course,$cm, $possibleresult=COMPLETION_UNKNOWN,$userid=0)Called to update completion state on the activity $cm for the given or current user. This obtains grade/viewable information if necessary and then asks the module whether the activity has been completed.It is called whenever a grade is updated on an activity that uses grades for completion and, by modules, whenever a module-specific piece of data that might affect completion has changed. &lt;br /&gt;
* $possibleresult is included for performance reasons to avoid recalculating completion when not necessary. Set to COMPLETION_COMPLETE or COMPLETION_NOTCOMPLETE, it indicates that the change which necessitated calling this function can only result in that type of state. For example, if there is a condition that the user must make 5 forum posts, we would call this function in response to any new post. But if the state is already ‘complete’, there is no point going through counting posts, checking grades, etc. This hint allows the code to skip further work if the user’s state is already the target. Once retrieved we will cache the state in session so that frequently, no database queries are required.&lt;br /&gt;
* For performance reasons, modules should still only call this function when necessary. The forum should not call this function whenever a new post is made, unless the completion option for counting posts is actually turned on for that forum.&lt;br /&gt;
* When a module is set to manual completion, this function is used to directly toggle completion. The completion value is set to $possibleresult.&lt;br /&gt;
* completion_set_module_viewed($course,$cm,$userid=0)Called when a module is viewed. If view-based completion is enabled (in $cm) then it sets the &#039;viewed&#039; flag and calls update_completion_state.&lt;br /&gt;
* completion_count_user_data($cm)Called to determine whether any users have already completed an activity (if so, returns the number). This is used by the module settings form to determine whether completion settings should be &#039;locked&#039;.&lt;br /&gt;
* completion_delete_all_state($course,$cm)Called at the point where course-module entries are deleted. Deletes all completion state data for that course-module.&lt;br /&gt;
* completion_reset_all_state($course,$cm)Deletes existing completion state for all users in this activity, then recalculates it by calling update_completion_state a lot for (i) all state-tracked users (those with progresstrackedroles roles in this activity’s context), (ii) all users who have stored completion state for this activity.Needs to be called if completion conditions change.&lt;br /&gt;
* completion_get_data($course,$cm,$wholecourse=false,$userid=0)Obtains completion data for a particular user related to a given activity. User defaults to current user.The $wholecourse parameter is a hint that, if it isn&#039;t already available, the system should retrieve into cache the completion data for all course activities now (so that future requests for other activities can be satisfied from cache).&lt;br /&gt;
* completion_get_activities($course)Gets course-module objects for all activities on a course that have completion turned on. (&#039;&#039;Used by the progress report.&#039;&#039;)&lt;br /&gt;
* completion_get_progress_all($course,$sortfirstname=false,$groupid=0)Obtains progress of all users in a course (or group) across all activities in that course for which completion tracking is enabled. (&#039;&#039;Used by the progress report.&#039;&#039;)&lt;br /&gt;
* completion_inform_grade_changed($course,$cm,&amp;amp;$item,&amp;amp;$grade,$deleted)Called to notify the completion system when a user&#039;s grade changes. Does nothing (quickly) if completion is not enabled for the item; if completion is enabled and depends on grade, calls completion_update_state. (&#039;&#039;Provided only for use by the gradebook.&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== Module changes ===&lt;br /&gt;
There is no requirement for any module changes to support the completion system. Existing modules continue to work.&lt;br /&gt;
&lt;br /&gt;
If no changes are made to a module, then manual completion (where the user ticks the box themselves) is supported for activities of that type, and automatic completion is not offered as an option in the activity settings screen.&lt;br /&gt;
&lt;br /&gt;
Progressively more changes are required when implementing more detailed completion support for a module.&lt;br /&gt;
&lt;br /&gt;
==== View support ====&lt;br /&gt;
To support the &#039;complete when viewed&#039; feature, a module must do the following:&lt;br /&gt;
&lt;br /&gt;
* Implement &#039;&#039;module&#039;&#039;_supports() as follows:function &#039;&#039;module&#039;&#039;_supports($feature) { switch($feature) { case FEATURE_COMPLETION_TRACKS_VIEWS: return true; default:  return false; }}&lt;br /&gt;
* Add calls to completion_set_module_viewed whenever the module considers that it has been &#039;viewed&#039;.&lt;br /&gt;
** It is up to the module to determine what this means. However most modules might put this call in view.php, near print_footer once it is clear that no errors occurred.&lt;br /&gt;
** This function does not take a significant time to run if view-based completion is not enabled, so you don&#039;t need to put the call inside an if.&lt;br /&gt;
&lt;br /&gt;
==== Grade support ====&lt;br /&gt;
If a module provides grades, making &#039;&#039;module&#039;&#039;_supports() return true for FEATURE_GRADE_HAS_GRADES will make these accessible to the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Custom completion ====&lt;br /&gt;
Supporting module-specific custom completion conditions requires extra work:&lt;br /&gt;
&lt;br /&gt;
* Decide how to store the settings for these extra conditions (probably in your module&#039;s main table). Change your database tables to allow this.&lt;br /&gt;
* Add FEATURE_COMPLETION_HAS_RULES to your &#039;&#039;module&#039;&#039;_supports().&lt;br /&gt;
* Add the extra controls to your mod_form.php.&lt;br /&gt;
** Override the method completion_add_rules() so that it adds extra form elements for your controls (the method is called at the right point so that they are added in the &#039;completion&#039; box), and returns a list of the form elements (this is used to enable/disable them appropriately).&lt;br /&gt;
** Override the function completion_rule_enabled($data) so that it returns true if the supplied data means that at least one of the module&#039;s completion conditions is turned on. This is used to prevent the user from choosing &#039;automatic&#039; completion if they don&#039;t also enable at least one condition.&lt;br /&gt;
** You may need to modify other functions such as definition_after_data() and get_data to set up your form controls appropriately based on the data from the database, or vice versa.&lt;br /&gt;
* In your lib.php, implement the new function &#039;&#039;module&#039;&#039;_get_completion_state($course,$cm,$userid,$logic).&lt;br /&gt;
** If the specified module instance has completion requirements, this should return true (if they have been met) or false (if they haven&#039;t). The system will later combine this value with possible other completion requirements (view or grades).&lt;br /&gt;
** $logic is either COMPLETION_AND or COMPLETION_OR, indicating which type of Boolean logic should be used when there are multiple conditions. &lt;br /&gt;
** If completion conditions are not enabled for this particular instance, the function should return $logic (not false). &lt;br /&gt;
* In your module code, when something changes which might affect completion, call completion_update_state&lt;br /&gt;
&lt;br /&gt;
=== Example of system operation ===&lt;br /&gt;
Assume that the forum offers an option to check completion based on the number of posts (complete when you’ve made N posts).&lt;br /&gt;
&lt;br /&gt;
Every time a user makes a new post:&lt;br /&gt;
&lt;br /&gt;
* Forum checks if completion tracking based on the number of posts is enabled (this would probably be an option in $forum). If not, it does nothing (&#039;&#039;stop&#039;&#039;).&lt;br /&gt;
* Forum calls completion_update_state($cm,COMPLETION_COMPLETE).&lt;br /&gt;
* System looks up the user’s current completion state for $cm. If the current state is already COMPLETION_COMPLETE (or COMPLETE_PASS or COMPLETE_FAIL) then it returns with no further action (&#039;&#039;stop&#039;&#039;).&lt;br /&gt;
* If grade-based completion is enabled, system obtains grade and checks it. If viewed-completion is enabled, system checks whether the module has been viewed.&lt;br /&gt;
* If the forum has its own completion rules, then the system calls forum_get_completion_state().&lt;br /&gt;
* The forum checks its own rules, including the number of posts and anything else that’s enabled. It returns true if these rules are met and false if they’re not.&lt;br /&gt;
* Combining this data, the system decides whether to update the completion state. If an update is needed, it makes the change in the database.&lt;br /&gt;
&lt;br /&gt;
=== Activity UI (course page) ===&lt;br /&gt;
The user interface for students on the course view page needs to allow for displaying progress to students and, where completion is set to manual, allowing students to tick their own progress boxes. &lt;br /&gt;
&lt;br /&gt;
I have based this suggested interface on experience here at the OU. The interface will be implemented via changes to print_section and course view.php.&lt;br /&gt;
&lt;br /&gt;
* Completion displays alongside each activity for which completion is enabled, to the right of the section. (This conveniently separates it from the functional information at the left, and means that all the progress markers line up with each other.)&lt;br /&gt;
* Automatic completion displays as a tick or cross icon, by default coloured green and red (accessible colours will be chosen), or some kind of faint outline if something isn’t completed yet. The cross icon is used if completion state is 1.&lt;br /&gt;
* Manual completion displays using two more icons (‘manual tick’ and ‘manual blank’). Possible icons would be the same tick with a heavy dotted box around it, and an empty dotted box. The title of the icon is an interface clue to the user e.g. ‘Click to mark this activity completed’.When AJAX is not enabled, the manual icons link to a URL that toggles the completion value then redirects straight back to the course page.When AJAX is enabled, the manual icons use YUI to adjust the completion value without reloading the page. In this case some kind of animation – for example, the word ‘Saved’ appearing next to the icon for a second before fading away – will be used to indicate to users that their change has taken effect.&lt;br /&gt;
* If completion is not enabled for an activity (or for the course, site, etc) then the print_section display is the same as at present.&lt;br /&gt;
* When editing is turned on, completion information always displays as ticked regardless of the user’s actual completion setting. This makes it easy to see that completion is enabled for that activity.&lt;br /&gt;
&lt;br /&gt;
I will get a graphic designer to look at the icons to use. To reiterate, there are six icons:&lt;br /&gt;
&lt;br /&gt;
* automatic completion, not completed yet (above, not actually shown on its own, but would be a faint grey dotted box)&lt;br /&gt;
* automatic completion, completed (above, slightly grey tick, with faint grey dotted surround)&lt;br /&gt;
* automatic completion, pass (not shown, e.g. could be a green tick)&lt;br /&gt;
* automatic completion, fail (not shown, e.g. could be a red cross)&lt;br /&gt;
* manual completion, not completed (heavy black dotted outline)&lt;br /&gt;
* manual completion, completed (heavy black dotted outline with black tick)&lt;br /&gt;
&lt;br /&gt;
It may need some work to make the manual ones look clickable and the automatic ones look not clickable, but not irrelevant either. For example we might have to resort to crappy 3D button-style shading on the manual ones. This is what I&#039;ve done (badly) in the initial version of the icons which I have made.&lt;br /&gt;
&lt;br /&gt;
=== Configuration UI (activity settings page) ===&lt;br /&gt;
Each activity’s completion settings can be configured on the standard activity settings page. These settings only appear if completion is enabled for the course and site.&lt;br /&gt;
&lt;br /&gt;
The interface will be implemented via a change to the standard_coursemodule_elements function and a new optional form member function completion_add_rules(), as mentioned above, which is called (from within standard_coursemodule_elements) to add the activity-specific form elements.&lt;br /&gt;
&lt;br /&gt;
We also need to determine whether the activity supports grades. This will be determined via the new &#039;&#039;module_&#039;&#039;supports() function. (Note that there are existing functions for finding out whether a module &#039;&#039;instance&#039;&#039; has a grade, but not for finding out whether a module supports grades if it hasn&#039;t been created yet.)&lt;br /&gt;
&lt;br /&gt;
((TODO: Diagram needs redoing))&lt;br /&gt;
&lt;br /&gt;
* A dropdown allows choice of the three completion options – none, manual, automatic. (All three are shown in the diagrams below.) If the module does not support its own completion conditions, and does not support grades, then the ‘automatic’ option will not appear.&lt;br /&gt;
* A ‘view’ checkbox only appears if the module supports view tracking. If completion is not set to automatic, it will be greyed out. It allows you to mark something complete as soon as the user goes there once.&lt;br /&gt;
* A &#039;require grade&#039; checkbox only appears if the module supports grades. If completion is not set to automatic, it will be greyed out.&lt;br /&gt;
** At this point we could have a dropdown selector to choose which grade item to use if there is more than one. However, at least for the first release, I am not providing a user interface for that feature.&lt;br /&gt;
* Module-specific settings, if any, are included. These are also greyed out if completion is not set to automatic. The module can add any number of settings. It is responsible for storing the data from these as part of its normal form processing.&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;An expected completion date (default disabled) is given. This can be enabled for manual or automatic completion. It has no practical effect but displays on the progress screen. The intention is that those who design a course can set these dates at key points in the course. During the course, teachers can look at the progress report and use the dates as a guideline to check whether students are falling behind. [At a later date it might be possible to do other things with this data, such as export a list of &#039;late&#039; students to an external system.]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* If anybody already has stored completion state for this activity, completion settings will be locked: they appear, but read-only. A button allows you to unlock the settings (making those fields editable again); after you do that and save the form, existing completion data is wiped and recalculated against the new conditions. A warning by the button explains that changing completion conditions after students complete things is not a good idea.&lt;br /&gt;
&lt;br /&gt;
=== Progress tracking UI ===&lt;br /&gt;
Teachers wishing to track student progress can do so via the admin block. The existing course reports page will include a link to view student progress if the user has viewprogress capability.&lt;br /&gt;
&lt;br /&gt;
The resulting page shows a summary of progress either for a particular group, or for all students in the course, according to the normal rules for group selection. It may include a standard group dropdown too.&lt;br /&gt;
&lt;br /&gt;
# Progress is shown in a table. Students (everyone with a role in progresstrackedroles&amp;lt;nowiki&amp;gt;) are displayed down the left of the table and for activities that have completion enabled, the activity names [with expected completion dates, if set] are displayed across the top. Students can be sorted by first name or last name. The student names link to profiles and activity names link to the activities.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
# The cells in this grid show progress indicators using the same icons as used on the course view page, although these icons are not clickable in the report. For each cell, the title, which you can see by hovering over it, indicates the state of the cell and the time modified (‘Completed 12/9/08 13:47’) as well as the student&#039;s name and the activity name (in case you are scrolling around a table that doesn&#039;t fit on-screen).&lt;br /&gt;
# A link at the bottom allows this table to be downloaded in CSV format. The downloaded version contains the same data, using two columns (‘state’ and ‘date’) for each activity.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
==== Course view ====&lt;br /&gt;
When completion is enabled for a course, the course view page needs to obtain completion information. This will be cached in session and retrieved efficiently (hopefully 1 query) the first time.&lt;br /&gt;
&lt;br /&gt;
==== Module pages ====&lt;br /&gt;
There is no performance impact when using modules that do not support completion, or where completion is disabled.&lt;br /&gt;
&lt;br /&gt;
When you take an action that potentially involves completion (e.g. if you make a forum post to a forum that has enabled automatic completion when you reach N posts) the same completion state cache is used to read the current state of the data, so this should need no queries (you probably already saw the front page). &lt;br /&gt;
&lt;br /&gt;
If your action could potentially change that completion state (e.g. you have not already completed the activity and you just made an additional forum post) there will be an additional cost at that time, depending on the activity – in this case, the forum will do a query to find out how many posts you&#039;ve made. Because these actions occur relatively rarely, this should not cause a serious problem. (Once you have completed the activity, making another post will not incur the performance penalty.) &lt;br /&gt;
&lt;br /&gt;
View-related completion tracking, the part most potentially problematic, will behave similarly: the first time you view something that has a &#039;viewed&#039; requirement, it will make extra queries as it marks it viewed (or, if you viewed it in a previous session, loads up that information). After that the information will be cached in your session.&lt;br /&gt;
&lt;br /&gt;
=== Backup and restore ===&lt;br /&gt;
* When users are included in backup, course backup will include the contents of the _course_modules_completion table.&lt;br /&gt;
* Course and course-modules backup will be modified to include the new fields in those tables.&lt;br /&gt;
&lt;br /&gt;
= Conditional availability =&lt;br /&gt;
== Conditional options ==&lt;br /&gt;
There is no specific option to enable this part of the feature (?). The parts which depend on the completion system are enabled using the completion flag.&lt;br /&gt;
&lt;br /&gt;
== Available conditions ==&lt;br /&gt;
You can place conditions on any activity. Conditions are always combined with Boolean AND, i.e. all conditions must be met before the activity becomes available. Unlike completion, conditions are not module-dependent. There are two types of condition:&lt;br /&gt;
&lt;br /&gt;
# Conditional on date. You can have both of these conditions if required.&lt;br /&gt;
#* On or after date – activity becomes available on given date.&lt;br /&gt;
#* Before date – activity becomes unavailable on given date.&lt;br /&gt;
# Conditional on other activities. You can have as many of these conditions as desired.&lt;br /&gt;
#* Activity must be completed – any kind of completion will do.&lt;br /&gt;
#* Activity must be completed and passed – completion must have been graded and displayed with a pass mark (tick icon).&lt;br /&gt;
#* Activity must be graded at least/at most &#039;&#039;N&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Database ==&lt;br /&gt;
* _course_modules&lt;br /&gt;
** New field availablefrom, unsigned int (10) not null default 0.0 = Not conditional on date.&amp;lt;nowiki&amp;gt;* = Time (seconds since epoch&amp;lt;/nowiki&amp;gt;) after which activity becomes available.&lt;br /&gt;
** New field availableuntil, unsigned int(10) not null default 0.0 = Not conditional on date.&amp;lt;nowiki&amp;gt;* = Time (seconds since epoch) after which activity becomes unavailable.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** New field showavailability, unsigned int (1) not null default 0.0 = Activity does not appear at all if conditions are not met.1 = If conditions are not met, activity appears but greyed out (‘hidden’ style) with no link and a short explanation of when it will be available.&lt;br /&gt;
* New table _course_modules_avail(able?) which stores any per-module conditions.&lt;br /&gt;
** id.&lt;br /&gt;
** coursemoduleid&amp;lt;nowiki&amp;gt; [index]&amp;lt;/nowiki&amp;gt;.ID of the module that is being restricted.&lt;br /&gt;
** cmsourceid.ID of module that the restriction is based on.&lt;br /&gt;
** requiredcompletion, unsigned int(1) not null default 0.0 = no required completion.1 = required completed.2 = required completed and passed.3 = required completed and failed.&lt;br /&gt;
** gradesign, varchar(2).NULL = no required grade.&amp;lt;nowiki&amp;gt;‘&amp;lt;’, ‘&amp;lt;=&amp;lt;/nowiki&amp;gt;’, ‘&amp;gt;’, ‘&amp;gt;=’ = requirement for grade.&lt;br /&gt;
** requiredgrade, number(10,5 decimals).Grade boundary used together with the above sign. May be null.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
Two new functions:&lt;br /&gt;
&lt;br /&gt;
* availability_is_available($cm)Returns true if the module is available to students (it is visible, plus availability conditions, if any, are met). Does not include course access conditions, which it assumes have already been checked.This is a slot-in replacement where code checks for $cm-&amp;gt;visible at key points such as in require_login.&lt;br /&gt;
* availability_get_display_details($cm)Obtains information about the activity’s availability which is required in order to display (or not display) a link to the activity. Returns an object with the following fields:-&amp;gt;available – If true, activity is available; users should be allowed to access it / get links to it.-&amp;gt;show – If true, activity should be displayed (even to users who do not have viewhiddenactivities)-&amp;gt;info – Informational string. Blank if the activity is available.&lt;br /&gt;
&lt;br /&gt;
Other changes:&lt;br /&gt;
&lt;br /&gt;
* For performance reasons we need to cache the conditions in _course_modules_available. Best option is to use existing get_fast_modinfo infrastructure. This should not be hard. The above two functions will use this cache.&lt;br /&gt;
&lt;br /&gt;
== Configuration UI (activity settings page) ==&lt;br /&gt;
The configuration UI will be implemented as part of standard_coursemodule_elements in the module forms. The existing ‘visible to students’ option (not changed in database/code) is moved within this UI. &lt;br /&gt;
&lt;br /&gt;
This UI will appear even if completion is not enabled, but the parts related to completion will not show. So if completion is not enabled you will still be able to set available dates if you like, and the interface will remain consistent. The diagram below shows, first, the version that appears with completion not enabled, and then the one you get with completion enabled.&lt;br /&gt;
&lt;br /&gt;
((There should be a diagram here, not sure it will show in the wiki version))&lt;br /&gt;
&lt;br /&gt;
[[Image:]]&lt;br /&gt;
&lt;br /&gt;
* The actual ‘available from’ options should include time as well as date. ‘Available from’ should default to midnight tomorrow; ‘Available until’ should default to 23:59 today. (I got bored laying out combo boxes.)&lt;br /&gt;
* ‘Information display’ controls whether informational text is displayed to students when an activity is not available. (See below.) The default is not to show information.&lt;br /&gt;
* The list of other activities which might have conditions includes only those other activities on the course which either have completion information, or a grade. Anything which doesn’t have completion information or a grade is omitted.&lt;br /&gt;
* Only one condition is permitted per other activity. This isn’t a restriction of the back-end, it just makes the UI simpler.&lt;br /&gt;
* The condition type dropdown by each activity is adjusted dynamically to include only options that are valid for that activity:&lt;br /&gt;
** ‘Completed’ appears only if completion is enabled for the activity.&lt;br /&gt;
** ‘Completed with pass’ and ‘Completed with fail’ (which I missed off the diagram by accident) appear only if completion is enabled for the activity, and set to a grade item, and the grade item contains a pass mark.&lt;br /&gt;
** The grade conditions appear only if the activity has a grade item.&lt;br /&gt;
* The grade box is a text-entry field. Users type in the floating-point number version of the required grade.&lt;br /&gt;
&lt;br /&gt;
== Activity UI (course page) ==&lt;br /&gt;
(This will be accomplished via code changes to print_section. Logic is basically the same as for the current visible flag.) &lt;br /&gt;
&lt;br /&gt;
For available activities, the display obviously does not change. Unavailable activities will be displayed as follows:&lt;br /&gt;
&lt;br /&gt;
* If the current user has viewhiddenactivities:&lt;br /&gt;
** The activity displays using the CSS style for hidden activities.&lt;br /&gt;
** The informational message as to why the activity isn’t available is displayed (even if showinfo is not set).&lt;br /&gt;
* If the current user does not have viewhiddenactivities:&lt;br /&gt;
** If showavailability is not set, or if the activity is actually hidden (visibility 0), the activity does not display at all.&lt;br /&gt;
** If showavailability is set and the activity isn’t hidden but is unavailable for some other reason, the name of the activity displays using the CSS style for hidden activities, but does not include an actual link to the activity. The informational message as to why the activity isn’t available is displayed.&lt;br /&gt;
&lt;br /&gt;
Here are some examples of hidden activities with informational text:Assignment resources Available from 6 Oct 2008Assignment resources Available when Unit 1 Test grade is &amp;gt; 90Assignment resources Available when Tutor group forum is marked complete (+ other requirements)When there are multiple conditions, only one is shown. Date is considered first; the order after that is arbitrary.&lt;br /&gt;
&lt;br /&gt;
Behaviour is the same when editing is turned on except that the ‘availability’ string moves to the line below so as not to clash with all those icons.&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
This adds a single quick database query to the course view page for courses which have enabled conditional activities / completion.&lt;br /&gt;
&lt;br /&gt;
All other information is cached in modinfo&amp;lt;nowiki&amp;gt;, so does not have a performance penalty, save one problematic issue: the feature that allows arbitrary grade information to be considered. If you use pass/fail information, that’s fine, it’s there already in the completion data. But if you use a specific grade [and for example it could be different values for different activities] then the actual grade for the item needs to be retrieved on course view.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don’t believe this will pose a massive performance issue as it only applies when modules are used as source for this kind of information. We should review this once it’s developed and, if necessary, optimise performance then. There are various caching approaches we could use.&lt;br /&gt;
&lt;br /&gt;
== Module delete ==&lt;br /&gt;
If you try to delete a module, it will check to see if that module is referenced by any other module as a condition. If that’s the case, you will not be allowed to delete it. An error message will include a link to the module edit page for the other module (so you can go there and delete the condition if you like).&lt;br /&gt;
&lt;br /&gt;
== Backup and restore ==&lt;br /&gt;
* The new _course_modules_available table will be backed up and restored. &lt;br /&gt;
** Partial restore needs to be handled. If your backup includes module A but not module B, and module A had a condition on B, then that condition will not be restored.&lt;br /&gt;
* Backup will also be modified to include the fields added to _course_modules.&lt;br /&gt;
* If you restore a course with a startdateoffset, it will offset the dates from the new _course_modules date fields.&lt;br /&gt;
&lt;br /&gt;
= Module supported features =&lt;br /&gt;
As part of the completion system, I needed a way for modules to indicate support of certain features, so I propose a generic one which I have implemented:&lt;br /&gt;
&lt;br /&gt;
* A module API function &#039;&#039;module&#039;&#039;_supports($feature) which returns false if the feature is not available, and true (or an object with more information, if needed for specific features) if it is.&lt;br /&gt;
* A standard API function module_supports($modulename,$feature) which works as follows:&lt;br /&gt;
** If the $modulename_supports_feature function exists, it calls that function and returns the result.&lt;br /&gt;
** Otherwise it returns false – or, if features are added that correspond to ‘legacy’ ones that we can find out another way (e.g. by looking to see if a function exists) then this can be done.&lt;br /&gt;
* A set of FEATURE_&#039;&#039;xx&#039;&#039; constants. For this code, the following are necessary:&lt;br /&gt;
** FEATURE_GRADE_HAS_GRADE&lt;br /&gt;
** FEATURE_COMPLETION_TRACKS_VIEWS&lt;br /&gt;
** FEATURE_COMPLETION_HAS_RULES&lt;br /&gt;
* Other feature constants could be added as desired, e.g. FEATURE_CRON, etc. My initial implementation will include only the &#039;new&#039; ones needed for this work.&lt;br /&gt;
&lt;br /&gt;
Note that this implementation would not be appropriate if modules were changed to be fully object-oriented. However I don&#039;t expect that to happen in Moodle 2 so this is probably OK.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=41000</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=41000"/>
		<updated>2008-07-31T11:03:17Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Backup and restore for completion fields */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the &amp;lt;tt&amp;gt;print_footer()&amp;lt;/tt&amp;gt; call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add backup and restore code to back up these fields.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Backup and restore for completion fields ===&lt;br /&gt;
&lt;br /&gt;
Modules do not need to back up the generic completion options, which are handled by the system, but they do need to back up any custom options. You should add backup and restore logic for the fields mentioned above. &lt;br /&gt;
&lt;br /&gt;
Remember that your restore code should handle the case when these fields are not present, setting the fields to a suitable default value.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
I added the following code to forum &amp;lt;tt&amp;gt;backuplib.php&amp;lt;/tt&amp;gt; after a list of similar lines:&lt;br /&gt;
&lt;br /&gt;
 fwrite ($bf,full_tag(&amp;quot;COMPLETIONPOSTS&amp;quot;,4,false,$forum-&amp;gt;completionposts));&lt;br /&gt;
&lt;br /&gt;
And the following to &amp;lt;tt&amp;gt;restorelib.php&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $forum-&amp;gt;completionposts = isset($info[&#039;MOD&#039;][&#039;#&#039;][&#039;COMPLETIONPOSTS&#039;][&#039;0&#039;][&#039;#&#039;])?backup_todb($info[&#039;MOD&#039;][&#039;#&#039;][&#039;COMPLETIONPOSTS&#039;][&#039;0&#039;][&#039;#&#039;]):0;&lt;br /&gt;
&lt;br /&gt;
(This code followed the existing style set by other lines. I don&#039;t necessarily recommend this exact pattern.)&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039; &#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039; &#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
* If the user whose completion state would be updated is not the current user, then the optional &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; parameter must be included. For example, if a teacher deletes a student&#039;s forum post, then it is the student&#039;s completion state which may need updating, not the teacher&#039;s.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40999</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40999"/>
		<updated>2008-07-31T11:02:13Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Database fields for completion settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the &amp;lt;tt&amp;gt;print_footer()&amp;lt;/tt&amp;gt; call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add backup and restore code to back up these fields.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Backup and restore for completion fields ===&lt;br /&gt;
&lt;br /&gt;
Modules do not need to back up the generic completion options, which are handled by the system, but they do need to back up any custom options. You should add backup and restore logic for the fields mentioned above.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
I added the following code to forum &amp;lt;tt&amp;gt;backuplib.php&amp;lt;/tt&amp;gt; after a list of similar lines:&lt;br /&gt;
&lt;br /&gt;
 fwrite ($bf,full_tag(&amp;quot;COMPLETIONPOSTS&amp;quot;,4,false,$forum-&amp;gt;completionposts));&lt;br /&gt;
&lt;br /&gt;
And the following to &amp;lt;tt&amp;gt;restorelib.php&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 $forum-&amp;gt;completionposts = isset($info[&#039;MOD&#039;][&#039;#&#039;][&#039;COMPLETIONPOSTS&#039;][&#039;0&#039;][&#039;#&#039;])?backup_todb($info[&#039;MOD&#039;][&#039;#&#039;][&#039;COMPLETIONPOSTS&#039;][&#039;0&#039;][&#039;#&#039;]):0;&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039; &#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039; &#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
* If the user whose completion state would be updated is not the current user, then the optional &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; parameter must be included. For example, if a teacher deletes a student&#039;s forum post, then it is the student&#039;s completion state which may need updating, not the teacher&#039;s.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40998</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40998"/>
		<updated>2008-07-31T10:59:48Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Implementation overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the &amp;lt;tt&amp;gt;print_footer()&amp;lt;/tt&amp;gt; call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add backup and restore code to back up these fields.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039; &#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039; &#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
* If the user whose completion state would be updated is not the current user, then the optional &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; parameter must be included. For example, if a teacher deletes a student&#039;s forum post, then it is the student&#039;s completion state which may need updating, not the teacher&#039;s.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40936</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40936"/>
		<updated>2008-07-30T15:28:17Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Notifying the completion system */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the &amp;lt;tt&amp;gt;print_footer()&amp;lt;/tt&amp;gt; call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039; &#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039; &#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
* If the user whose completion state would be updated is not the current user, then the optional &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; parameter must be included. For example, if a teacher deletes a student&#039;s forum post, then it is the student&#039;s completion state which may need updating, not the teacher&#039;s.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40931</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40931"/>
		<updated>2008-07-30T12:23:03Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the &amp;lt;tt&amp;gt;print_footer()&amp;lt;/tt&amp;gt; call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039; &#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039; &#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40930</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40930"/>
		<updated>2008-07-30T12:21:21Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* How to implement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the &amp;lt;tt&amp;gt;print_footer()&amp;lt;/tt&amp;gt; call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40929</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40929"/>
		<updated>2008-07-30T12:20:15Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Feature support */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &#039;&#039;modulename&#039;&#039;&amp;lt;tt&amp;gt;_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40928</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40928"/>
		<updated>2008-07-30T12:19:38Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Notifying the completion system */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40927</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40927"/>
		<updated>2008-07-30T12:19:27Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Notifying the completion system */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;br /&gt;
&lt;br /&gt;
Finally you need to notify the completion system whenever these values might have changed for a user (in the case of the forum example, whenever somebody adds or deletes a post). The completion system will end up calling the function above - but only if it needs to. &lt;br /&gt;
&lt;br /&gt;
* To ensure performance is not compromised, you should notify the system only when the completion state might actually have changed. Don&#039;t notify the system unless your custom completion rule is actually enabled.&lt;br /&gt;
* You need to pass in the &#039;possible result&#039; of the change. This is used to significantly improve performance.  There are three values:&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_COMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it complete. The change cannot make a user&#039;s state &#039;&#039;in&#039;&#039;complete if it was complete previously. In the forum example, when you add a post, there is no way this can make the user&#039;s state incomplete, so this possible result applies.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_INCOMPLETE&#039;&#039;&#039; - this change will either have no effect on the user&#039;s completion state, or it will make it incomplete. The change cannot make a user&#039;s state complete if it was incomplete previously. Deleting a forum post would fall into this category.&lt;br /&gt;
** &#039;&#039;&#039;COMPLETION_UNKNOWN&#039;&#039; - this change might have either effect. Using this option is much slower than the others, so try to avoid using it in anything that might happen frequently.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code that runs when somebody makes a new forum post:&lt;br /&gt;
&lt;br /&gt;
 // Update completion state&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 if($completion-&amp;gt;is_enabled($cm) &amp;amp;&amp;amp; $forum-&amp;gt;completionposts)) {&lt;br /&gt;
     $completion-&amp;gt;update_state($cm,COMPLETION_COMPLETE);&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40925</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40925"/>
		<updated>2008-07-30T12:07:20Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40924</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40924"/>
		<updated>2008-07-30T12:06:54Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Completion value function */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion state function ===&lt;br /&gt;
&lt;br /&gt;
When you create completion conditions, you need to write a function &#039;&#039;module&#039;&#039;&amp;lt;tt&amp;gt;_get_completion_state&amp;lt;/tt&amp;gt; that checks the value of those conditions for a particular user. &lt;br /&gt;
&lt;br /&gt;
The function receives as parameters &amp;lt;tt&amp;gt;$course&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;$cm&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;$userid&amp;lt;/tt&amp;gt; - all self-explanatory, I hope - and &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt;. This has two values: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_AND&#039;&#039;&#039; - if multiple conditions are selected, the user must meet all of them.&lt;br /&gt;
* &#039;&#039;&#039;COMPLETION_OR&#039;&#039;&#039; (not currently used) - if multiple conditions are selected, any one of them is good enough to complete the activity.&lt;br /&gt;
&lt;br /&gt;
Your function should return:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;true&#039;&#039;&#039; if your custom completion options are enabled and the user meets the conditions.&lt;br /&gt;
* &#039;&#039;&#039;false&#039;&#039;&#039; if your custom completion options are enabled but the user does not yet meet the conditions.&lt;br /&gt;
* &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; (not false!) if none of your custom completion options are not enabled.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the function for forum (simplified to include only the one completion option):&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Obtains the automatic completion state for this forum based on any conditions&lt;br /&gt;
  * in forum settings.&lt;br /&gt;
  *&lt;br /&gt;
  * @param object $course Course&lt;br /&gt;
  * @param object $cm Course-module&lt;br /&gt;
  * @param int $userid User ID&lt;br /&gt;
  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)&lt;br /&gt;
  * @return bool True if completed, false if not, $type if conditions not set.&lt;br /&gt;
  */&lt;br /&gt;
 function forum_get_completion_state($course,$cm,$userid,$type) {&lt;br /&gt;
     global $CFG,$DB;&lt;br /&gt;
 &lt;br /&gt;
     // Get forum details&lt;br /&gt;
     if(!($forum=$DB-&amp;gt;get_record(&#039;forum&#039;,array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance)))) {&lt;br /&gt;
         throw new Exception(&amp;quot;Can&#039;t find forum {$cm-&amp;gt;instance}&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // If completion option is enabled, evaluate it and return true/false &lt;br /&gt;
     if($forum-&amp;gt;completionposts) {&lt;br /&gt;
         return $forum-&amp;gt;completionposts &amp;lt;= $DB-&amp;gt;get_field_sql(&amp;quot;&lt;br /&gt;
 SELECT &lt;br /&gt;
     COUNT(1) &lt;br /&gt;
 FROM &lt;br /&gt;
     {forum_posts} fp &lt;br /&gt;
     INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id&lt;br /&gt;
 WHERE&lt;br /&gt;
     fp.userid=:userid AND fd.forum=:forumid&amp;quot;,&lt;br /&gt;
             array(&#039;userid&#039;=&amp;gt;$userid,&#039;forumid&#039;=&amp;gt;$forum-&amp;gt;id));&lt;br /&gt;
     } else {&lt;br /&gt;
         // Completion option is not enabled so just return $type&lt;br /&gt;
         return $type;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40923</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40923"/>
		<updated>2008-07-30T11:55:41Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
 &lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion value function ===&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40922</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40922"/>
		<updated>2008-07-30T11:55:07Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Custom completion rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== Implementation overview ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
=== Database fields for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Form changes for completion settings ===&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
&lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
=== Completion value function ===&lt;br /&gt;
&lt;br /&gt;
=== Notifying the completion system ===&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40921</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40921"/>
		<updated>2008-07-30T11:53:51Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Database fields for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Form changes for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line, and we add a help button.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls become disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the edit field, but the checkbox is not ticked, the value counts as zero (the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
&lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
==== Completion value function ====&lt;br /&gt;
&lt;br /&gt;
==== Notifying the completion system ====&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40920</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40920"/>
		<updated>2008-07-30T11:52:12Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Database fields for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Form changes for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
 &lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
 &lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line.&lt;br /&gt;
* We add a help button for the control.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls are disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the editbox, but the checkbox is not ticked, the value counts as zero (so the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
&lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
==== Completion value function ====&lt;br /&gt;
&lt;br /&gt;
==== Notifying the completion system ====&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40919</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40919"/>
		<updated>2008-07-30T11:51:58Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Form changes for completion settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Database fields for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Form changes for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you have custom completion conditions, you need to add controls to your module&#039;s settings form &amp;lt;tt&amp;gt;mod_form.php&amp;lt;/tt&amp;gt; so that users can select these conditions. You can add any necessary controls.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;add_completion_rules&amp;lt;/tt&amp;gt; function which adds the form controls for your new rules.&lt;br /&gt;
&lt;br /&gt;
* Implement the &amp;lt;tt&amp;gt;completion_rule_enabled&amp;lt;/tt&amp;gt; function which is called during form validation to check whether one of your module&#039;s completion rules has been selected.&lt;br /&gt;
&lt;br /&gt;
* Implement other form changes if necessary to set up the form with your data. If your data is in the form of simple text boxes or dropdowns then this is not necessary, but you might want to have a checkbox that enables the rule with a separate control to set its value. This needs form tweaks.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
The forum offers a checkbox with a text input box beside it. You tick the checkbox to enable the rule, then type in the desired number of posts.&lt;br /&gt;
&lt;br /&gt;
First, the function that adds these controls:&lt;br /&gt;
&lt;br /&gt;
 function add_completion_rules() {&lt;br /&gt;
     $mform =&amp;amp; $this-&amp;gt;_form;&lt;br /&gt;
&lt;br /&gt;
     $group=array();&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;completionpostsenabled&#039;, &#039;&#039;, get_string(&#039;completionposts&#039;,&#039;forum&#039;));&lt;br /&gt;
     $group[] =&amp;amp; $mform-&amp;gt;createElement(&#039;text&#039;, &#039;completionposts&#039;, &#039;&#039;, array(&#039;size&#039;=&amp;gt;3));&lt;br /&gt;
     $mform-&amp;gt;setType(&#039;completionposts&#039;,PARAM_INT);&lt;br /&gt;
     $mform-&amp;gt;addGroup($group, &#039;completionpostsgroup&#039;, get_string(&#039;completionpostsgroup&#039;,&#039;forum&#039;), array(&#039; &#039;), false);&lt;br /&gt;
     $mform-&amp;gt;setHelpButton(&#039;completionpostsgroup&#039;, array(&#039;completion&#039;, get_string(&#039;completionpostshelp&#039;, &#039;forum&#039;), &#039;forum&#039;));&lt;br /&gt;
     $mform-&amp;gt;disabledIf(&#039;completionposts&#039;,&#039;completionpostsenabled&#039;,&#039;notchecked&#039;);&lt;br /&gt;
&lt;br /&gt;
     return array(&#039;completionpostsgroup&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The function creates a checkbox and a text input field, which is set to accept only numbers.&lt;br /&gt;
* These are grouped together so they appear on the same line.&lt;br /&gt;
* We add a help button for the control.&lt;br /&gt;
* The text input field is disabled if the checkbox isn&#039;t ticked.&lt;br /&gt;
* Note that this function must return the top-level element associated with the completion rule. (If there are multiple elements, you can return more than one.) &lt;br /&gt;
** This is used so that your controls are disabled if automatic completion is not selected.&lt;br /&gt;
&lt;br /&gt;
Next, a function for checking whether the user selected this option:&lt;br /&gt;
&lt;br /&gt;
 function completion_rule_enabled($data) {&lt;br /&gt;
     return (!empty($data[&#039;completionpostsenabled&#039;]) &amp;amp;&amp;amp; $data[&#039;completionposts&#039;]!=0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* The custom completion rule is enabled if the &#039;enabled&#039; checkbox is ticked and the text field value is something other than zero.&lt;br /&gt;
** This is used to give an error if the user selects automatic completion, but fails to select any conditions.&lt;br /&gt;
&lt;br /&gt;
That&#039;s all the &#039;required&#039; functions, but we need to add some extra code to support the checkbox behaviour. I overrode get_data so that if there is a value in the editbox, but the checkbox is not ticked, the value counts as zero (so the rule will not be enabled):&lt;br /&gt;
&lt;br /&gt;
 function get_data() {&lt;br /&gt;
     $data=parent::get_data();&lt;br /&gt;
     if(!$data) {&lt;br /&gt;
         return false;&lt;br /&gt;
     }&lt;br /&gt;
     // Turn off completion settings if the checkboxes aren&#039;t ticked&lt;br /&gt;
     $autocompletion=!empty($data-&amp;gt;completion) &amp;amp;&amp;amp; $data-&amp;gt;completion==COMPLETION_TRACKING_AUTOMATIC;&lt;br /&gt;
     if(empty($data-&amp;gt;completionpostsenabled) || !$autocompletion) {&lt;br /&gt;
         $data-&amp;gt;completionposts=0;&lt;br /&gt;
     }&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, forum already had a &amp;lt;tt&amp;gt;data_preprocessing&amp;lt;/tt&amp;gt; function but I added code to this to set up the checkboxes when the form is displayed, and to make the default value of the text fields 1 instead of 0:&lt;br /&gt;
&lt;br /&gt;
 function data_preprocessing(&amp;amp;$default_values){&lt;br /&gt;
     // [Existing code, not shown]&lt;br /&gt;
&lt;br /&gt;
     // Set up the completion checkboxes which aren&#039;t part of standard data.&lt;br /&gt;
     // We also make the default value (if you turn on the checkbox) for those&lt;br /&gt;
     // numbers to be 1, this will not apply unless checkbox is ticked.&lt;br /&gt;
     $default_values[&#039;completionpostsenabled&#039;]=&lt;br /&gt;
         !empty($default_values[&#039;completionposts&#039;]) ? 1 : 0;&lt;br /&gt;
     if(empty($default_values[&#039;completionposts&#039;])) {&lt;br /&gt;
         $default_values[&#039;completionposts&#039;]=1;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Phew! That&#039;s the form done.&lt;br /&gt;
&lt;br /&gt;
==== Completion value function ====&lt;br /&gt;
&lt;br /&gt;
==== Notifying the completion system ====&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40918</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40918"/>
		<updated>2008-07-30T11:37:33Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Database fields for completion settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Database fields for completion settings ====&lt;br /&gt;
&lt;br /&gt;
When you provide a custom completion rule for a module, that rule requires data to be stored with each module instance: whether the rule is enabled for that instance, and any options that apply to the rule.&lt;br /&gt;
&lt;br /&gt;
Usually the best place to store this information is your module&#039;s main table because:&lt;br /&gt;
&lt;br /&gt;
* The information in the relevant row of this table is likely to be available in most parts of your code, so code changes are minimised.&lt;br /&gt;
* You already read this row with most requests, so there is no need for additional database queries which would reduce performance.&lt;br /&gt;
* The main table is used for most other module options so it is a logical place for this information.&lt;br /&gt;
&lt;br /&gt;
If you are adding a basic completion condition you probably only need to add one field. To add a field to an existing module, you need to change the install.xml and then the update.php in the same way as adding any other field.&lt;br /&gt;
&lt;br /&gt;
===== Example =====&lt;br /&gt;
&lt;br /&gt;
Throughout this section I am using the forum as an example. The forum provides three completion options but because they all behave the same way, I am only showing one of them.&lt;br /&gt;
&lt;br /&gt;
The forum adds this field to store a completion option:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;completionposts&#039;&#039;&#039; - this may be 0 or an integer. If it&#039;s an integer, say 3, then the user needs to add 3 forum posts (either new discussions or replies) in order for the forum to count as &#039;completed&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Form changes for completion settings ====&lt;br /&gt;
&lt;br /&gt;
==== Completion value function ====&lt;br /&gt;
&lt;br /&gt;
==== Notifying the completion system ====&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40917</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40917"/>
		<updated>2008-07-30T11:29:30Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Custom completion rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;br /&gt;
&lt;br /&gt;
Custom completion rules allow for module-specific conditions. For example, the forum has custom rules so that you can make it mark a user completed when they make a certain number of posts to the forum.&lt;br /&gt;
&lt;br /&gt;
It is a lot harder to implement custom completion rules than it is to use the system-provided &#039;view&#039; or &#039;grade&#039; conditions, but the instructions below should help make it clear.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
To implement custom completion rules, you need to:&lt;br /&gt;
&lt;br /&gt;
# Return true for FEATURE_COMPLETION_HAS_RULES in your module&#039;s _supports function.&lt;br /&gt;
# Add database fields to your module&#039;s main table to store the custom completion settings.&lt;br /&gt;
# Add controls to your module&#039;s settings form so that users can select the custom rules, altering these database settings.&lt;br /&gt;
# Add a function that checks the value of these rules (if set).&lt;br /&gt;
# Add code so that whenever the value affecting a rule might change, you inform the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Database fields for completion settings ====&lt;br /&gt;
&lt;br /&gt;
==== Form changes for completion settings ====&lt;br /&gt;
&lt;br /&gt;
==== Completion value function ====&lt;br /&gt;
&lt;br /&gt;
==== Notifying the completion system ====&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40916</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40916"/>
		<updated>2008-07-30T11:15:21Z</updated>

		<summary type="html">&lt;p&gt;Quen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Feature support ==&lt;br /&gt;
&lt;br /&gt;
To support the completion system, your module must include a &amp;lt;tt&amp;gt;modulename_supports&amp;lt;/tt&amp;gt; function in its &amp;lt;tt&amp;gt;lib.php&amp;lt;/tt&amp;gt;. Here is an example:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Indicates API features that the forum supports.&lt;br /&gt;
  *&lt;br /&gt;
  * @param string $feature&lt;br /&gt;
  * @return mixed True if yes (some features may use other values)&lt;br /&gt;
  */&lt;br /&gt;
 function forum_supports($feature) {&lt;br /&gt;
     switch($feature) {&lt;br /&gt;
         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;&lt;br /&gt;
         case FEATURE_COMPLETION_HAS_RULES: return true;&lt;br /&gt;
         default: return null;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The relevant features for completion are:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_TRACKS_VIEWS&#039;&#039;&#039; - the module can support completion &#039;on view&#039;, meaning that an activity becomes marked complete as soon as a user clicks on it.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_GRADE_HAS_GRADE&#039;&#039;&#039; - the module provides (or may provide, depending on settings) a grade for students. When a module supports grades, it can support completion &#039;on grade&#039;, meaning that an activity becomes marked complete as soon as a user is assigned a grade.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;FEATURE_COMPLETION_HAS_RULES&#039;&#039;&#039; - the module has custom completion rules.&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
Completion on view means that, if selected, an activity is marked complete as soon as the user views it. &#039;View&#039; is usually defined as seeing the module&#039;s main page; if you click on the activity, and there isn&#039;t an error, you have probably viewed it. However it is up to each module precisely how they define &#039;view&#039;.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_COMPLETION_TRACKS_VIEWS.&lt;br /&gt;
&lt;br /&gt;
Then add this code to run whenever a user successfully views the activity (for example, near the print_footer() call in &amp;lt;tt&amp;gt;view.php&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 $completion=new completion_info($course);&lt;br /&gt;
 $completion-&amp;gt;set_module_viewed($cm);&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
Calling this method has no significant performance cost if &#039;on view&#039; completion is not enabled for the activity. If it is enabled, then the performance cost is kept low because the &#039;viewed&#039; state is cached; it doesn&#039;t add a database query to every request.&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
Completion on grade means that, if selected, an activity is marked complete as soon as the user receives a grade from that activity.&lt;br /&gt;
&lt;br /&gt;
=== How to implement ===&lt;br /&gt;
&lt;br /&gt;
In your module&#039;s _supports function, return true for FEATURE_GRADE_HAS_GRADE. No other action is necessary.&lt;br /&gt;
&lt;br /&gt;
=== Performance issues ===&lt;br /&gt;
&lt;br /&gt;
When &#039;on grade&#039; completion is enabled, there will be some additional database queries after a grade is assigned or changed. Unless your activity changes grades very frequently, this is unlikely to be an issue.&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40915</id>
		<title>Development:Conditional activities Adding module support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities_Adding_module_support&amp;diff=40915"/>
		<updated>2008-07-30T10:59:10Z</updated>

		<summary type="html">&lt;p&gt;Quen: New page: {{Moodle_2.0}}  Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system.   If you make no changes to a module what...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Modules do not need to be changed to support conditional availability, but they do need changing to support the completion system. &lt;br /&gt;
&lt;br /&gt;
If you make no changes to a module whatsoever, it can only support &#039;manual&#039; completion (where the user ticks a box).&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
== Completion on view ==&lt;br /&gt;
&lt;br /&gt;
== Completion on grade ==&lt;br /&gt;
&lt;br /&gt;
== Custom completion rules ==&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=40914</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=40914"/>
		<updated>2008-07-30T10:57:04Z</updated>

		<summary type="html">&lt;p&gt;Quen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
[[Development:Conditional activities_Adding module support]]&lt;br /&gt;
&lt;br /&gt;
= Design document =&lt;br /&gt;
&lt;br /&gt;
(This is a design document by sam marshall from the Open University. It is based on earlier discussion in this wiki, and then detailed discussion with moodle.com staff who contributed improvements and corrections.)&lt;br /&gt;
&lt;br /&gt;
See MDL-15497 for tasks and tracking.&lt;br /&gt;
&lt;br /&gt;
sam marshall, 21 May 2008; updated as of 26 June 2008. Exported to MediaWiki format using OpenOffice.org 3.0 beta (i.e. this page doesn&#039;t perfectly represent the word-processor version) and manually tweaked a bit to fix it where it was obviously wrong.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This design document describes in some detail a proposed method to add support for ‘conditional activities’ to Moodle. It is based on a [https://docs.moodle.org/en/Development:Conditional_activities discussion on the Moodle wiki], conversations with Moodle.com staff, and only the teeniest pinch of OU requirements. &lt;br /&gt;
&lt;br /&gt;
This is divided into two related, but separate, chunks of work.&lt;br /&gt;
&lt;br /&gt;
=== Completion tracking ===&lt;br /&gt;
Make the system store whether or not an activity has been ‘completed’. &lt;br /&gt;
&lt;br /&gt;
This may be according to an activity-specific definition of completion, or because the student has ticked a box saying they’ve finished it.&lt;br /&gt;
&lt;br /&gt;
When tracked automatically, completion could vary from formal requirements such as ‘scoring 90% on this quiz’ to informal requirements intended to ensure participation such as ‘post at least 3 times on this forum’.&lt;br /&gt;
&lt;br /&gt;
It should be possible for teachers to access progress information for their students, so that they can see if anyone is falling behind.&lt;br /&gt;
&lt;br /&gt;
=== Conditional availability ===&lt;br /&gt;
Allow or prevent access to an activity depending on various conditions.&lt;br /&gt;
&lt;br /&gt;
These conditions may include the completion of other activities; in the case of graded activities, also whether the grade was pass/fail, or a specific amount. It also may include date.&lt;br /&gt;
&lt;br /&gt;
=== Development process ===&lt;br /&gt;
I will do this work here. It is possible that time constraints might mean I only do the first part (completion tracking).&lt;br /&gt;
&lt;br /&gt;
Development will be against Moodle 1.9, because we need it here at the OU, but it will never actually be committed into Moodle 1.9. The code will instead be ported to Moodle 2.0, which will require various changes (particularly in the area of database access).&lt;br /&gt;
&lt;br /&gt;
Code will be PHP5. We will primarily test against Postgres here but intend using standard Moodle database API and only simple SQL where needed, so database compatibility is unlikely to be a problem.&lt;br /&gt;
&lt;br /&gt;
In some cases the OU have versions of these features. I will be coding automatic upgrade from the previous versions. This will not be included in the core Moodle 2.0 version.&lt;br /&gt;
&lt;br /&gt;
== Completion tracking ==&lt;br /&gt;
=== Completion options ===&lt;br /&gt;
The completion system can be enabled or disabled at site, course, and activity level.&lt;br /&gt;
&lt;br /&gt;
* At site level, the new admin variable $CFG-&amp;gt;enablecompletion (defaults to 1?).&lt;br /&gt;
* At course level, a new mdl_course field enablecompletion (defaults to 1).&lt;br /&gt;
* At activity level, a new mdl_course_modules field completion with values 0 = none, 1 = manual (student decides when they’ve completed something), 2 = automatic. Defaults to 1 but may be set by module e.g. a quiz module could default to automatic, label could set it to 0 so you don’t get checkboxes beside each label, etc.&lt;br /&gt;
&lt;br /&gt;
This table illustrates the effect of these options. (‘enablecompletion’ is abbreviated to ‘ec’.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;prettytable&amp;quot;&lt;br /&gt;
| &#039;&#039;&#039;Location&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Feature&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Appears if&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Admin settings&lt;br /&gt;
| On-off toggle for $CFG-&amp;gt;ec&lt;br /&gt;
| –&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Course settings&lt;br /&gt;
| On-off toggle for course ec&lt;br /&gt;
| $CFG-&amp;gt;ec&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Activity settings&lt;br /&gt;
| Off/manual/automatic option for course-module completion&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Course view&lt;br /&gt;
| Completion display/controls against activity&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec &amp;amp;&amp;amp; completion&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Admin block&lt;br /&gt;
| Link to progress report&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec &amp;amp;&amp;amp; user has permission&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
=== Completion states and conditions ===&lt;br /&gt;
Completion state is stored per-user for every activity. There are four states:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;Not completed [default – not stored in database]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Completed (pass/fail unspecified)&lt;br /&gt;
* Completed, passed&lt;br /&gt;
* Completed, failed&lt;br /&gt;
&lt;br /&gt;
The final two states only apply when completion is based on a specific grade result. These are used only in some situations. Here are the rules: &lt;br /&gt;
&lt;br /&gt;
* Grade visible, ‘grade to pass’ set: ‘completed, passed’ and ‘completed, failed’ states will be used.&lt;br /&gt;
* ‘Grade to pass’ not set &#039;&#039;or&#039;&#039;grade is hidden &#039;&#039;or&#039;&#039;grade is hidden-until (regardless of until date): only the standard ‘not completed’, ‘completed’ states are used.&lt;br /&gt;
&lt;br /&gt;
This is a ‘push’ system – the state is not computed live but is saved and that value used. When completion for the activity is set to manual, students can toggle this value between not completed and completed. When it is set to automatic, the system adjusts the value in certain cases.&lt;br /&gt;
&lt;br /&gt;
==== Standard conditions ====&lt;br /&gt;
There are two standard conditions which do not require (much) module-specific behaviour.&lt;br /&gt;
&lt;br /&gt;
* Graded – module has assigned grade for student.&lt;br /&gt;
** If there are multiple grades for this activity, you can select which one is used to determine completion. (We will not implement this selection in the user interface for the first release. It will always use the first grade.)&lt;br /&gt;
** This condition is implemented by a hook in gradebook that runs at the point where a grade is set.&lt;br /&gt;
* Viewed – student has viewed module.&lt;br /&gt;
** For this to be supported, the module must call a function completion_set_module_viewed($cm) when it thinks that the user has ‘viewed’ the activity. It also needs to indicate that it supports it via &#039;&#039;module&#039;&#039;_supports(FEATURE_COMPLETION_TRACKS_VIEWS).&lt;br /&gt;
&lt;br /&gt;
==== Custom conditions ====&lt;br /&gt;
Modules can support arbitrary custom conditions (with their own form components to configure these, and their own data storage to track them).&lt;br /&gt;
&lt;br /&gt;
Example conditions might be:&lt;br /&gt;
&lt;br /&gt;
* Forum&lt;br /&gt;
** User has made N posts.&lt;br /&gt;
** User has made N replies.&lt;br /&gt;
** Other people have posted N replies to discussions created by this user. (&#039;&#039;This an example of a more complex possibility, not necessarily something that would be a good idea.&#039;&#039;)&lt;br /&gt;
* Wiki&lt;br /&gt;
** User has edited N different pages.&lt;br /&gt;
** User has edited pages N times.&lt;br /&gt;
* Choice&lt;br /&gt;
** User has voted.&lt;br /&gt;
&lt;br /&gt;
It is up to the module to determine when a condition has been met and update the user’s completion. &lt;br /&gt;
&lt;br /&gt;
As part of this project I plan to create some custom conditions for one or a few modules (probably just forum), and implement view tracking for a wider range of modules.&lt;br /&gt;
&lt;br /&gt;
==== Combining conditions ====&lt;br /&gt;
If an activity has both the standard grade condition, and module conditions, these are currently combined via Boolean AND. Modules that support multiple conditions should usually also AND them as this will make life simpler for developer and users; however this is up to the module, as it creates its own form fields and data items.&lt;br /&gt;
&lt;br /&gt;
In the future we may (or may not!) provide the ability to choose boolean OR instead. Some of the API functions contain a parameter that indicates how results should be combined. At present this is always set to AND.&lt;br /&gt;
&lt;br /&gt;
=== Expected date ===&lt;br /&gt;
An activity can optionally have an expected completion date. This date currently has no effect and is not shown to students, but it appears to teachers when viewing progress. It&#039;s intended so that teachers can see when students are having problems and maybe offer assistance.&lt;br /&gt;
&lt;br /&gt;
In future it might be possible to export this data – e.g. the list of students who are &#039;late&#039; – to external systemss.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
(&#039;&#039;Prefix is shown as _. Constants are defined for all values here.&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* _course&lt;br /&gt;
** +Field enablecompletion, unsigned int (1) default 0 not null.1 = enable completion options for activities (if enabled at site level). This is the user-interface default that applies to new courses when completion is enabled for the site.0 = disable and hide options. This is the database default that will apply to existing courses.&lt;br /&gt;
* _course_modules&lt;br /&gt;
** +Field completion, unsigned int (1) default 0 not null.0 = No progress tracking for this activity.1 = Manual completion tracking.2 = Automatic completion tracking.&lt;br /&gt;
** +Field completiongradeitemnumber, unsigned int(10) default 0.NULL = Grade information not used for completion.0,1,… = Use first/second/N&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; grade item supplied by this activity.&lt;br /&gt;
** +Field completionview, unsigned int (1) default 0 not null.0 = View not required for completion.1 = View required for completion.&lt;br /&gt;
** +Field completionexpected, unsigned int (10) default 0 not null.0 = No particular date expected for completion&amp;lt;nowiki&amp;gt;* = time (seconds since epoch) by which activity is expected to be completed. &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* New table _course_modules_completion which stores completion state for a user on each activity.&lt;br /&gt;
** id.&lt;br /&gt;
** coursemoduleid&amp;lt;nowiki&amp;gt; [index].&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** userid&amp;lt;nowiki&amp;gt; [index]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
** completionstate, unsigned int(1) not null.(The absence of a row in the table counts the same as 0 here.)0 = not completed.1 = completed.2 = completed, passed.3 = completed, failed.&lt;br /&gt;
** viewed, unsigned int(1)null = not tracked0 = not viewed1 = viewedOnly stored if the activity is tracking viewed state.&lt;br /&gt;
** timemodified, unsigned int (10) not null.Last date the state changed, in seconds since epoch.&lt;br /&gt;
&lt;br /&gt;
=== Capabilities ===&lt;br /&gt;
* moodle/course:viewprogress&amp;lt;nowiki&amp;gt; [default Teacher, Editing Teacher, Course Creator]&amp;lt;/nowiki&amp;gt;Users with this permission can view progress of students on the course. If the course is set to visible groups mode, or the user also has accessallgroups, then they can see all groups. Otherwise they can only see groups they belong to.&lt;br /&gt;
&lt;br /&gt;
=== Admin ===&lt;br /&gt;
A new admin setting progresstrackedroles stores a list of the roles that are considered relevant when displaying progress. (Other roles can still use the completion system, but won’t be shown on the progress screen.) This setting is editable via standard admin screens.&lt;br /&gt;
&lt;br /&gt;
=== API ===&lt;br /&gt;
These functions will be included in a completionlib.php.&lt;br /&gt;
&lt;br /&gt;
* completion_is_enabled($course=null,$cm=null)Returns true if completion is enabled. With no parameters, returns the site value; when course is specified, checks course as well.If course-module is specified, the return value is the same as the value of completion from course_modules.&lt;br /&gt;
* completion_update_state($course,$cm, $possibleresult=COMPLETION_UNKNOWN,$userid=0)Called to update completion state on the activity $cm for the given or current user. This obtains grade/viewable information if necessary and then asks the module whether the activity has been completed.It is called whenever a grade is updated on an activity that uses grades for completion and, by modules, whenever a module-specific piece of data that might affect completion has changed. &lt;br /&gt;
* $possibleresult is included for performance reasons to avoid recalculating completion when not necessary. Set to COMPLETION_COMPLETE or COMPLETION_NOTCOMPLETE, it indicates that the change which necessitated calling this function can only result in that type of state. For example, if there is a condition that the user must make 5 forum posts, we would call this function in response to any new post. But if the state is already ‘complete’, there is no point going through counting posts, checking grades, etc. This hint allows the code to skip further work if the user’s state is already the target. Once retrieved we will cache the state in session so that frequently, no database queries are required.&lt;br /&gt;
* For performance reasons, modules should still only call this function when necessary. The forum should not call this function whenever a new post is made, unless the completion option for counting posts is actually turned on for that forum.&lt;br /&gt;
* When a module is set to manual completion, this function is used to directly toggle completion. The completion value is set to $possibleresult.&lt;br /&gt;
* completion_set_module_viewed($course,$cm,$userid=0)Called when a module is viewed. If view-based completion is enabled (in $cm) then it sets the &#039;viewed&#039; flag and calls update_completion_state.&lt;br /&gt;
* completion_count_user_data($cm)Called to determine whether any users have already completed an activity (if so, returns the number). This is used by the module settings form to determine whether completion settings should be &#039;locked&#039;.&lt;br /&gt;
* completion_delete_all_state($course,$cm)Called at the point where course-module entries are deleted. Deletes all completion state data for that course-module.&lt;br /&gt;
* completion_reset_all_state($course,$cm)Deletes existing completion state for all users in this activity, then recalculates it by calling update_completion_state a lot for (i) all state-tracked users (those with progresstrackedroles roles in this activity’s context), (ii) all users who have stored completion state for this activity.Needs to be called if completion conditions change.&lt;br /&gt;
* completion_get_data($course,$cm,$wholecourse=false,$userid=0)Obtains completion data for a particular user related to a given activity. User defaults to current user.The $wholecourse parameter is a hint that, if it isn&#039;t already available, the system should retrieve into cache the completion data for all course activities now (so that future requests for other activities can be satisfied from cache).&lt;br /&gt;
* completion_get_activities($course)Gets course-module objects for all activities on a course that have completion turned on. (&#039;&#039;Used by the progress report.&#039;&#039;)&lt;br /&gt;
* completion_get_progress_all($course,$sortfirstname=false,$groupid=0)Obtains progress of all users in a course (or group) across all activities in that course for which completion tracking is enabled. (&#039;&#039;Used by the progress report.&#039;&#039;)&lt;br /&gt;
* completion_inform_grade_changed($course,$cm,&amp;amp;$item,&amp;amp;$grade,$deleted)Called to notify the completion system when a user&#039;s grade changes. Does nothing (quickly) if completion is not enabled for the item; if completion is enabled and depends on grade, calls completion_update_state. (&#039;&#039;Provided only for use by the gradebook.&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== Module changes ===&lt;br /&gt;
There is no requirement for any module changes to support the completion system. Existing modules continue to work.&lt;br /&gt;
&lt;br /&gt;
If no changes are made to a module, then manual completion (where the user ticks the box themselves) is supported for activities of that type, and automatic completion is not offered as an option in the activity settings screen.&lt;br /&gt;
&lt;br /&gt;
Progressively more changes are required when implementing more detailed completion support for a module.&lt;br /&gt;
&lt;br /&gt;
==== View support ====&lt;br /&gt;
To support the &#039;complete when viewed&#039; feature, a module must do the following:&lt;br /&gt;
&lt;br /&gt;
* Implement &#039;&#039;module&#039;&#039;_supports() as follows:function &#039;&#039;module&#039;&#039;_supports($feature) { switch($feature) { case FEATURE_COMPLETION_TRACKS_VIEWS: return true; default:  return false; }}&lt;br /&gt;
* Add calls to completion_set_module_viewed whenever the module considers that it has been &#039;viewed&#039;.&lt;br /&gt;
** It is up to the module to determine what this means. However most modules might put this call in view.php, near print_footer once it is clear that no errors occurred.&lt;br /&gt;
** This function does not take a significant time to run if view-based completion is not enabled, so you don&#039;t need to put the call inside an if.&lt;br /&gt;
&lt;br /&gt;
==== Grade support ====&lt;br /&gt;
If a module provides grades, making &#039;&#039;module&#039;&#039;_supports() return true for FEATURE_GRADE_HAS_GRADES will make these accessible to the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Custom completion ====&lt;br /&gt;
Supporting module-specific custom completion conditions requires extra work:&lt;br /&gt;
&lt;br /&gt;
* Decide how to store the settings for these extra conditions (probably in your module&#039;s main table). Change your database tables to allow this.&lt;br /&gt;
* Add FEATURE_COMPLETION_HAS_RULES to your &#039;&#039;module&#039;&#039;_supports().&lt;br /&gt;
* Add the extra controls to your mod_form.php.&lt;br /&gt;
** Override the method completion_add_rules() so that it adds extra form elements for your controls (the method is called at the right point so that they are added in the &#039;completion&#039; box), and returns a list of the form elements (this is used to enable/disable them appropriately).&lt;br /&gt;
** Override the function completion_rule_enabled($data) so that it returns true if the supplied data means that at least one of the module&#039;s completion conditions is turned on. This is used to prevent the user from choosing &#039;automatic&#039; completion if they don&#039;t also enable at least one condition.&lt;br /&gt;
** You may need to modify other functions such as definition_after_data() and get_data to set up your form controls appropriately based on the data from the database, or vice versa.&lt;br /&gt;
* In your lib.php, implement the new function &#039;&#039;module&#039;&#039;_get_completion_state($course,$cm,$userid,$logic).&lt;br /&gt;
** If the specified module instance has completion requirements, this should return true (if they have been met) or false (if they haven&#039;t). The system will later combine this value with possible other completion requirements (view or grades).&lt;br /&gt;
** $logic is either COMPLETION_AND or COMPLETION_OR, indicating which type of Boolean logic should be used when there are multiple conditions. &lt;br /&gt;
** If completion conditions are not enabled for this particular instance, the function should return $logic (not false). &lt;br /&gt;
* In your module code, when something changes which might affect completion, call completion_update_state&lt;br /&gt;
&lt;br /&gt;
=== Example of system operation ===&lt;br /&gt;
Assume that the forum offers an option to check completion based on the number of posts (complete when you’ve made N posts).&lt;br /&gt;
&lt;br /&gt;
Every time a user makes a new post:&lt;br /&gt;
&lt;br /&gt;
* Forum checks if completion tracking based on the number of posts is enabled (this would probably be an option in $forum). If not, it does nothing (&#039;&#039;stop&#039;&#039;).&lt;br /&gt;
* Forum calls completion_update_state($cm,COMPLETION_COMPLETE).&lt;br /&gt;
* System looks up the user’s current completion state for $cm. If the current state is already COMPLETION_COMPLETE (or COMPLETE_PASS or COMPLETE_FAIL) then it returns with no further action (&#039;&#039;stop&#039;&#039;).&lt;br /&gt;
* If grade-based completion is enabled, system obtains grade and checks it. If viewed-completion is enabled, system checks whether the module has been viewed.&lt;br /&gt;
* If the forum has its own completion rules, then the system calls forum_get_completion_state().&lt;br /&gt;
* The forum checks its own rules, including the number of posts and anything else that’s enabled. It returns true if these rules are met and false if they’re not.&lt;br /&gt;
* Combining this data, the system decides whether to update the completion state. If an update is needed, it makes the change in the database.&lt;br /&gt;
&lt;br /&gt;
=== Activity UI (course page) ===&lt;br /&gt;
The user interface for students on the course view page needs to allow for displaying progress to students and, where completion is set to manual, allowing students to tick their own progress boxes. &lt;br /&gt;
&lt;br /&gt;
I have based this suggested interface on experience here at the OU. The interface will be implemented via changes to print_section and course view.php.&lt;br /&gt;
&lt;br /&gt;
* Completion displays alongside each activity for which completion is enabled, to the right of the section. (This conveniently separates it from the functional information at the left, and means that all the progress markers line up with each other.)&lt;br /&gt;
* Automatic completion displays as a tick or cross icon, by default coloured green and red (accessible colours will be chosen), or some kind of faint outline if something isn’t completed yet. The cross icon is used if completion state is 1.&lt;br /&gt;
* Manual completion displays using two more icons (‘manual tick’ and ‘manual blank’). Possible icons would be the same tick with a heavy dotted box around it, and an empty dotted box. The title of the icon is an interface clue to the user e.g. ‘Click to mark this activity completed’.When AJAX is not enabled, the manual icons link to a URL that toggles the completion value then redirects straight back to the course page.When AJAX is enabled, the manual icons use YUI to adjust the completion value without reloading the page. In this case some kind of animation – for example, the word ‘Saved’ appearing next to the icon for a second before fading away – will be used to indicate to users that their change has taken effect.&lt;br /&gt;
* If completion is not enabled for an activity (or for the course, site, etc) then the print_section display is the same as at present.&lt;br /&gt;
* When editing is turned on, completion information always displays as ticked regardless of the user’s actual completion setting. This makes it easy to see that completion is enabled for that activity.&lt;br /&gt;
&lt;br /&gt;
I will get a graphic designer to look at the icons to use. To reiterate, there are six icons:&lt;br /&gt;
&lt;br /&gt;
* automatic completion, not completed yet (above, not actually shown on its own, but would be a faint grey dotted box)&lt;br /&gt;
* automatic completion, completed (above, slightly grey tick, with faint grey dotted surround)&lt;br /&gt;
* automatic completion, pass (not shown, e.g. could be a green tick)&lt;br /&gt;
* automatic completion, fail (not shown, e.g. could be a red cross)&lt;br /&gt;
* manual completion, not completed (heavy black dotted outline)&lt;br /&gt;
* manual completion, completed (heavy black dotted outline with black tick)&lt;br /&gt;
&lt;br /&gt;
It may need some work to make the manual ones look clickable and the automatic ones look not clickable, but not irrelevant either. For example we might have to resort to crappy 3D button-style shading on the manual ones. This is what I&#039;ve done (badly) in the initial version of the icons which I have made.&lt;br /&gt;
&lt;br /&gt;
=== Configuration UI (activity settings page) ===&lt;br /&gt;
Each activity’s completion settings can be configured on the standard activity settings page. These settings only appear if completion is enabled for the course and site.&lt;br /&gt;
&lt;br /&gt;
The interface will be implemented via a change to the standard_coursemodule_elements function and a new optional form member function completion_add_rules(), as mentioned above, which is called (from within standard_coursemodule_elements) to add the activity-specific form elements.&lt;br /&gt;
&lt;br /&gt;
We also need to determine whether the activity supports grades. This will be determined via the new &#039;&#039;module_&#039;&#039;supports() function. (Note that there are existing functions for finding out whether a module &#039;&#039;instance&#039;&#039; has a grade, but not for finding out whether a module supports grades if it hasn&#039;t been created yet.)&lt;br /&gt;
&lt;br /&gt;
((TODO: Diagram needs redoing))&lt;br /&gt;
&lt;br /&gt;
* A dropdown allows choice of the three completion options – none, manual, automatic. (All three are shown in the diagrams below.) If the module does not support its own completion conditions, and does not support grades, then the ‘automatic’ option will not appear.&lt;br /&gt;
* A ‘view’ checkbox only appears if the module supports view tracking. If completion is not set to automatic, it will be greyed out. It allows you to mark something complete as soon as the user goes there once.&lt;br /&gt;
* A &#039;require grade&#039; checkbox only appears if the module supports grades. If completion is not set to automatic, it will be greyed out.&lt;br /&gt;
** At this point we could have a dropdown selector to choose which grade item to use if there is more than one. However, at least for the first release, I am not providing a user interface for that feature.&lt;br /&gt;
* Module-specific settings, if any, are included. These are also greyed out if completion is not set to automatic. The module can add any number of settings. It is responsible for storing the data from these as part of its normal form processing.&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;An expected completion date (default disabled) is given. This can be enabled for manual or automatic completion. It has no practical effect but displays on the progress screen. The intention is that those who design a course can set these dates at key points in the course. During the course, teachers can look at the progress report and use the dates as a guideline to check whether students are falling behind. [At a later date it might be possible to do other things with this data, such as export a list of &#039;late&#039; students to an external system.]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* If anybody already has stored completion state for this activity, completion settings will be locked: they appear, but read-only. A button allows you to unlock the settings (making those fields editable again); after you do that and save the form, existing completion data is wiped and recalculated against the new conditions. A warning by the button explains that changing completion conditions after students complete things is not a good idea.&lt;br /&gt;
&lt;br /&gt;
=== Progress tracking UI ===&lt;br /&gt;
Teachers wishing to track student progress can do so via the admin block. The existing course reports page will include a link to view student progress if the user has viewprogress capability.&lt;br /&gt;
&lt;br /&gt;
The resulting page shows a summary of progress either for a particular group, or for all students in the course, according to the normal rules for group selection. It may include a standard group dropdown too.&lt;br /&gt;
&lt;br /&gt;
# Progress is shown in a table. Students (everyone with a role in progresstrackedroles&amp;lt;nowiki&amp;gt;) are displayed down the left of the table and for activities that have completion enabled, the activity names [with expected completion dates, if set] are displayed across the top. Students can be sorted by first name or last name. The student names link to profiles and activity names link to the activities.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
# The cells in this grid show progress indicators using the same icons as used on the course view page, although these icons are not clickable in the report. For each cell, the title, which you can see by hovering over it, indicates the state of the cell and the time modified (‘Completed 12/9/08 13:47’) as well as the student&#039;s name and the activity name (in case you are scrolling around a table that doesn&#039;t fit on-screen).&lt;br /&gt;
# A link at the bottom allows this table to be downloaded in CSV format. The downloaded version contains the same data, using two columns (‘state’ and ‘date’) for each activity.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
==== Course view ====&lt;br /&gt;
When completion is enabled for a course, the course view page needs to obtain completion information. This will be cached in session and retrieved efficiently (hopefully 1 query) the first time.&lt;br /&gt;
&lt;br /&gt;
==== Module pages ====&lt;br /&gt;
There is no performance impact when using modules that do not support completion, or where completion is disabled.&lt;br /&gt;
&lt;br /&gt;
When you take an action that potentially involves completion (e.g. if you make a forum post to a forum that has enabled automatic completion when you reach N posts) the same completion state cache is used to read the current state of the data, so this should need no queries (you probably already saw the front page). &lt;br /&gt;
&lt;br /&gt;
If your action could potentially change that completion state (e.g. you have not already completed the activity and you just made an additional forum post) there will be an additional cost at that time, depending on the activity – in this case, the forum will do a query to find out how many posts you&#039;ve made. Because these actions occur relatively rarely, this should not cause a serious problem. (Once you have completed the activity, making another post will not incur the performance penalty.) &lt;br /&gt;
&lt;br /&gt;
View-related completion tracking, the part most potentially problematic, will behave similarly: the first time you view something that has a &#039;viewed&#039; requirement, it will make extra queries as it marks it viewed (or, if you viewed it in a previous session, loads up that information). After that the information will be cached in your session.&lt;br /&gt;
&lt;br /&gt;
=== Backup and restore ===&lt;br /&gt;
* When users are included in backup, course backup will include the contents of the _course_modules_completion table.&lt;br /&gt;
* Course and course-modules backup will be modified to include the new fields in those tables.&lt;br /&gt;
&lt;br /&gt;
= Conditional availability =&lt;br /&gt;
== Conditional options ==&lt;br /&gt;
There is no specific option to enable this part of the feature (?). The parts which depend on the completion system are enabled using the completion flag.&lt;br /&gt;
&lt;br /&gt;
== Available conditions ==&lt;br /&gt;
You can place conditions on any activity. Conditions are always combined with Boolean AND, i.e. all conditions must be met before the activity becomes available. Unlike completion, conditions are not module-dependent. There are two types of condition:&lt;br /&gt;
&lt;br /&gt;
# Conditional on date. You can have both of these conditions if required.&lt;br /&gt;
&lt;br /&gt;
# &lt;br /&gt;
#* On or after date – activity becomes available on given date.&lt;br /&gt;
#* Before date – activity becomes unavailable on given date.&lt;br /&gt;
&lt;br /&gt;
# Conditional on other activities. You can have as many of these conditions as desired.&lt;br /&gt;
&lt;br /&gt;
# &lt;br /&gt;
#* Activity must be completed – any kind of completion will do.&lt;br /&gt;
#* Activity must be completed and passed – completion must have been graded and displayed with a pass mark (tick icon).&lt;br /&gt;
#* Activity must be graded at least/at most &#039;&#039;N&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Database ==&lt;br /&gt;
* _course_modules&lt;br /&gt;
** New field availablefrom, unsigned int (10) not null default 0.0 = Not conditional on date.&amp;lt;nowiki&amp;gt;* = Time (seconds since epoch&amp;lt;/nowiki&amp;gt;) after which activity becomes available.&lt;br /&gt;
** New field availableuntil, unsigned int(10) not null default 0.0 = Not conditional on date.&amp;lt;nowiki&amp;gt;* = Time (seconds since epoch) after which activity becomes unavailable.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** New field showavailability, unsigned int (1) not null default 0.0 = Activity does not appear at all if conditions are not met.1 = If conditions are not met, activity appears but greyed out (‘hidden’ style) with no link and a short explanation of when it will be available.&lt;br /&gt;
* New table _course_modules_avail(able?) which stores any per-module conditions.&lt;br /&gt;
** id.&lt;br /&gt;
** coursemoduleid&amp;lt;nowiki&amp;gt; [index]&amp;lt;/nowiki&amp;gt;.ID of the module that is being restricted.&lt;br /&gt;
** cmsourceid.ID of module that the restriction is based on.&lt;br /&gt;
** requiredcompletion, unsigned int(1) not null default 0.0 = no required completion.1 = required completed.2 = required completed and passed.3 = required completed and failed.&lt;br /&gt;
** gradesign, varchar(2).NULL = no required grade.&amp;lt;nowiki&amp;gt;‘&amp;lt;’, ‘&amp;lt;=&amp;lt;/nowiki&amp;gt;’, ‘&amp;gt;’, ‘&amp;gt;=’ = requirement for grade.&lt;br /&gt;
** requiredgrade, number(10,5 decimals).Grade boundary used together with the above sign. May be null.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
Two new functions:&lt;br /&gt;
&lt;br /&gt;
* availability_is_available($cm)Returns true if the module is available to students (it is visible, plus availability conditions, if any, are met). Does not include course access conditions, which it assumes have already been checked.This is a slot-in replacement where code checks for $cm-&amp;gt;visible at key points such as in require_login.&lt;br /&gt;
* availability_get_display_details($cm)Obtains information about the activity’s availability which is required in order to display (or not display) a link to the activity. Returns an object with the following fields:-&amp;gt;available – If true, activity is available; users should be allowed to access it / get links to it.-&amp;gt;show – If true, activity should be displayed (even to users who do not have viewhiddenactivities)-&amp;gt;info – Informational string. Blank if the activity is available.&lt;br /&gt;
&lt;br /&gt;
Other changes:&lt;br /&gt;
&lt;br /&gt;
* For performance reasons we need to cache the conditions in _course_modules_available. Best option is to use existing get_fast_modinfo infrastructure. This should not be hard. The above two functions will use this cache.&lt;br /&gt;
&lt;br /&gt;
== Configuration UI (activity settings page) ==&lt;br /&gt;
The configuration UI will be implemented as part of standard_coursemodule_elements in the module forms. The existing ‘visible to students’ option (not changed in database/code) is moved within this UI. &lt;br /&gt;
&lt;br /&gt;
This UI will appear even if completion is not enabled, but the parts related to completion will not show. So if completion is not enabled you will still be able to set available dates if you like, and the interface will remain consistent. The diagram below shows, first, the version that appears with completion not enabled, and then the one you get with completion enabled.&lt;br /&gt;
&lt;br /&gt;
((There should be a diagram here, not sure it will show in the wiki version))&lt;br /&gt;
&lt;br /&gt;
[[Image:]]&lt;br /&gt;
&lt;br /&gt;
* The actual ‘available from’ options should include time as well as date. ‘Available from’ should default to midnight tomorrow; ‘Available until’ should default to 23:59 today. (I got bored laying out combo boxes.)&lt;br /&gt;
* ‘Information display’ controls whether informational text is displayed to students when an activity is not available. (See below.) The default is not to show information.&lt;br /&gt;
* The list of other activities which might have conditions includes only those other activities on the course which either have completion information, or a grade. Anything which doesn’t have completion information or a grade is omitted.&lt;br /&gt;
* Only one condition is permitted per other activity. This isn’t a restriction of the back-end, it just makes the UI simpler.&lt;br /&gt;
* The condition type dropdown by each activity is adjusted dynamically to include only options that are valid for that activity:&lt;br /&gt;
** ‘Completed’ appears only if completion is enabled for the activity.&lt;br /&gt;
** ‘Completed with pass’ and ‘Completed with fail’ (which I missed off the diagram by accident) appear only if completion is enabled for the activity, and set to a grade item, and the grade item contains a pass mark.&lt;br /&gt;
** The grade conditions appear only if the activity has a grade item.&lt;br /&gt;
* The grade box is a text-entry field. Users type in the floating-point number version of the required grade.&lt;br /&gt;
&lt;br /&gt;
== Activity UI (course page) ==&lt;br /&gt;
(This will be accomplished via code changes to print_section. Logic is basically the same as for the current visible flag.) &lt;br /&gt;
&lt;br /&gt;
For available activities, the display obviously does not change. Unavailable activities will be displayed as follows:&lt;br /&gt;
&lt;br /&gt;
* If the current user has viewhiddenactivities:&lt;br /&gt;
** The activity displays using the CSS style for hidden activities.&lt;br /&gt;
** The informational message as to why the activity isn’t available is displayed (even if showinfo is not set).&lt;br /&gt;
* If the current user does not have viewhiddenactivities:&lt;br /&gt;
** If showavailability is not set, or if the activity is actually hidden (visibility 0), the activity does not display at all.&lt;br /&gt;
** If showavailability is set and the activity isn’t hidden but is unavailable for some other reason, the name of the activity displays using the CSS style for hidden activities, but does not include an actual link to the activity. The informational message as to why the activity isn’t available is displayed.&lt;br /&gt;
&lt;br /&gt;
Here are some examples of hidden activities with informational text:Assignment resources Available from 6 Oct 2008Assignment resources Available when Unit 1 Test grade is &amp;gt; 90Assignment resources Available when Tutor group forum is marked complete (+ other requirements)When there are multiple conditions, only one is shown. Date is considered first; the order after that is arbitrary.&lt;br /&gt;
&lt;br /&gt;
Behaviour is the same when editing is turned on except that the ‘availability’ string moves to the line below so as not to clash with all those icons.&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
This adds a single quick database query to the course view page for courses which have enabled conditional activities / completion.&lt;br /&gt;
&lt;br /&gt;
All other information is cached in modinfo&amp;lt;nowiki&amp;gt;, so does not have a performance penalty, save one problematic issue: the feature that allows arbitrary grade information to be considered. If you use pass/fail information, that’s fine, it’s there already in the completion data. But if you use a specific grade [and for example it could be different values for different activities] then the actual grade for the item needs to be retrieved on course view.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don’t believe this will pose a massive performance issue as it only applies when modules are used as source for this kind of information. We should review this once it’s developed and, if necessary, optimise performance then. There are various caching approaches we could use.&lt;br /&gt;
&lt;br /&gt;
== Module delete ==&lt;br /&gt;
If you try to delete a module, it will check to see if that module is referenced by any other module as a condition. If that’s the case, you will not be allowed to delete it. An error message will include a link to the module edit page for the other module (so you can go there and delete the condition if you like).&lt;br /&gt;
&lt;br /&gt;
== Backup and restore ==&lt;br /&gt;
* The new _course_modules_available table will be backed up and restored. &lt;br /&gt;
** Partial restore needs to be handled. If your backup includes module A but not module B, and module A had a condition on B, then that condition will not be restored.&lt;br /&gt;
* Backup will also be modified to include the fields added to _course_modules.&lt;br /&gt;
* If you restore a course with a startdateoffset, it will offset the dates from the new _course_modules date fields.&lt;br /&gt;
&lt;br /&gt;
= Module supported features =&lt;br /&gt;
As part of the completion system, I needed a way for modules to indicate support of certain features, so I propose a generic one which I have implemented:&lt;br /&gt;
&lt;br /&gt;
* A module API function &#039;&#039;module&#039;&#039;_supports($feature) which returns false if the feature is not available, and true (or an object with more information, if needed for specific features) if it is.&lt;br /&gt;
* A standard API function module_supports($modulename,$feature) which works as follows:&lt;br /&gt;
** If the $modulename_supports_feature function exists, it calls that function and returns the result.&lt;br /&gt;
** Otherwise it returns false – or, if features are added that correspond to ‘legacy’ ones that we can find out another way (e.g. by looking to see if a function exists) then this can be done.&lt;br /&gt;
* A set of FEATURE_&#039;&#039;xx&#039;&#039; constants. For this code, the following are necessary:&lt;br /&gt;
** FEATURE_GRADE_HAS_GRADE&lt;br /&gt;
** FEATURE_COMPLETION_TRACKS_VIEWS&lt;br /&gt;
** FEATURE_COMPLETION_HAS_RULES&lt;br /&gt;
* Other feature constants could be added as desired, e.g. FEATURE_CRON, etc. My initial implementation will include only the &#039;new&#039; ones needed for this work.&lt;br /&gt;
&lt;br /&gt;
Note that this implementation would not be appropriate if modules were changed to be fully object-oriented. However I don&#039;t expect that to happen in Moodle 2 so this is probably OK.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=38506</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=38506"/>
		<updated>2008-06-26T16:37:45Z</updated>

		<summary type="html">&lt;p&gt;Quen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;(This is a design document by sam marshall from the Open University. It is based on earlier discussion in this wiki, and then detailed discussion with moodle.com staff who contributed improvements and corrections.)&lt;br /&gt;
&lt;br /&gt;
= Conditional activities =&lt;br /&gt;
sam marshall, 21 May 2008; updated as of 26 June 2008. Exported to MediaWiki format using OpenOffice.org 3.0 beta (i.e. this page doesn&#039;t perfectly represent the word-processor version) and manually tweaked a bit to fix it where it was obviously wrong.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This design document describes in some detail a proposed method to add support for ‘conditional activities’ to Moodle. It is based on a [https://docs.moodle.org/en/Development:Conditional_activities discussion on the Moodle wiki], conversations with Moodle.com staff, and only the teeniest pinch of OU requirements. &lt;br /&gt;
&lt;br /&gt;
This is divided into two related, but separate, chunks of work.&lt;br /&gt;
&lt;br /&gt;
=== Completion tracking ===&lt;br /&gt;
Make the system store whether or not an activity has been ‘completed’. &lt;br /&gt;
&lt;br /&gt;
This may be according to an activity-specific definition of completion, or because the student has ticked a box saying they’ve finished it.&lt;br /&gt;
&lt;br /&gt;
When tracked automatically, completion could vary from formal requirements such as ‘scoring 90% on this quiz’ to informal requirements intended to ensure participation such as ‘post at least 3 times on this forum’.&lt;br /&gt;
&lt;br /&gt;
It should be possible for teachers to access progress information for their students, so that they can see if anyone is falling behind.&lt;br /&gt;
&lt;br /&gt;
=== Conditional availability ===&lt;br /&gt;
Allow or prevent access to an activity depending on various conditions.&lt;br /&gt;
&lt;br /&gt;
These conditions may include the completion of other activities; in the case of graded activities, also whether the grade was pass/fail, or a specific amount. It also may include date.&lt;br /&gt;
&lt;br /&gt;
=== Development process ===&lt;br /&gt;
I will do this work here. It is possible that time constraints might mean I only do the first part (completion tracking).&lt;br /&gt;
&lt;br /&gt;
Development will be against Moodle 1.9, because we need it here at the OU, but it will never actually be committed into Moodle 1.9. The code will instead be ported to Moodle 2.0, which will require various changes (particularly in the area of database access).&lt;br /&gt;
&lt;br /&gt;
Code will be PHP5. We will primarily test against Postgres here but intend using standard Moodle database API and only simple SQL where needed, so database compatibility is unlikely to be a problem.&lt;br /&gt;
&lt;br /&gt;
In some cases the OU have versions of these features. I will be coding automatic upgrade from the previous versions. This will not be included in the core Moodle 2.0 version.&lt;br /&gt;
&lt;br /&gt;
== Completion tracking ==&lt;br /&gt;
=== Completion options ===&lt;br /&gt;
The completion system can be enabled or disabled at site, course, and activity level.&lt;br /&gt;
&lt;br /&gt;
* At site level, the new admin variable $CFG-&amp;gt;enablecompletion (defaults to 1?).&lt;br /&gt;
* At course level, a new mdl_course field enablecompletion (defaults to 1).&lt;br /&gt;
* At activity level, a new mdl_course_modules field completion with values 0 = none, 1 = manual (student decides when they’ve completed something), 2 = automatic. Defaults to 1 but may be set by module e.g. a quiz module could default to automatic, label could set it to 0 so you don’t get checkboxes beside each label, etc.&lt;br /&gt;
&lt;br /&gt;
This table illustrates the effect of these options. (‘enablecompletion’ is abbreviated to ‘ec’.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;prettytable&amp;quot;&lt;br /&gt;
| &#039;&#039;&#039;Location&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Feature&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Appears if&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Admin settings&lt;br /&gt;
| On-off toggle for $CFG-&amp;gt;ec&lt;br /&gt;
| –&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Course settings&lt;br /&gt;
| On-off toggle for course ec&lt;br /&gt;
| $CFG-&amp;gt;ec&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Activity settings&lt;br /&gt;
| Off/manual/automatic option for course-module completion&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Course view&lt;br /&gt;
| Completion display/controls against activity&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec &amp;amp;&amp;amp; completion&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| Admin block&lt;br /&gt;
| Link to progress report&lt;br /&gt;
| $CFG-&amp;gt;ec &amp;amp;&amp;amp; course ec &amp;amp;&amp;amp; user has permission&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
=== Completion states and conditions ===&lt;br /&gt;
Completion state is stored per-user for every activity. There are four states:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;Not completed [default – not stored in database]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Completed (pass/fail unspecified)&lt;br /&gt;
* Completed, passed&lt;br /&gt;
* Completed, failed&lt;br /&gt;
&lt;br /&gt;
The final two states only apply when completion is based on a specific grade result. These are used only in some situations. Here are the rules: &lt;br /&gt;
&lt;br /&gt;
* Grade visible, ‘grade to pass’ set: ‘completed, passed’ and ‘completed, failed’ states will be used.&lt;br /&gt;
* ‘Grade to pass’ not set &#039;&#039;or&#039;&#039;grade is hidden &#039;&#039;or&#039;&#039;grade is hidden-until (regardless of until date): only the standard ‘not completed’, ‘completed’ states are used.&lt;br /&gt;
&lt;br /&gt;
This is a ‘push’ system – the state is not computed live but is saved and that value used. When completion for the activity is set to manual, students can toggle this value between not completed and completed. When it is set to automatic, the system adjusts the value in certain cases.&lt;br /&gt;
&lt;br /&gt;
==== Standard conditions ====&lt;br /&gt;
There are two standard conditions which do not require (much) module-specific behaviour.&lt;br /&gt;
&lt;br /&gt;
* Graded – module has assigned grade for student.&lt;br /&gt;
** If there are multiple grades for this activity, you can select which one is used to determine completion. (We will not implement this selection in the user interface for the first release. It will always use the first grade.)&lt;br /&gt;
** This condition is implemented by a hook in gradebook that runs at the point where a grade is set.&lt;br /&gt;
* Viewed – student has viewed module.&lt;br /&gt;
** For this to be supported, the module must call a function completion_set_module_viewed($cm) when it thinks that the user has ‘viewed’ the activity. It also needs to indicate that it supports it via &#039;&#039;module&#039;&#039;_supports(FEATURE_COMPLETION_TRACKS_VIEWS).&lt;br /&gt;
&lt;br /&gt;
==== Custom conditions ====&lt;br /&gt;
Modules can support arbitrary custom conditions (with their own form components to configure these, and their own data storage to track them).&lt;br /&gt;
&lt;br /&gt;
Example conditions might be:&lt;br /&gt;
&lt;br /&gt;
* Forum&lt;br /&gt;
** User has made N posts.&lt;br /&gt;
** User has made N replies.&lt;br /&gt;
** Other people have posted N replies to discussions created by this user. (&#039;&#039;This an example of a more complex possibility, not necessarily something that would be a good idea.&#039;&#039;)&lt;br /&gt;
* Wiki&lt;br /&gt;
** User has edited N different pages.&lt;br /&gt;
** User has edited pages N times.&lt;br /&gt;
* Choice&lt;br /&gt;
** User has voted.&lt;br /&gt;
&lt;br /&gt;
It is up to the module to determine when a condition has been met and update the user’s completion. &lt;br /&gt;
&lt;br /&gt;
As part of this project I plan to create some custom conditions for one or a few modules (probably just forum), and implement view tracking for a wider range of modules.&lt;br /&gt;
&lt;br /&gt;
==== Combining conditions ====&lt;br /&gt;
If an activity has both the standard grade condition, and module conditions, these are currently combined via Boolean AND. Modules that support multiple conditions should usually also AND them as this will make life simpler for developer and users; however this is up to the module, as it creates its own form fields and data items.&lt;br /&gt;
&lt;br /&gt;
In the future we may (or may not!) provide the ability to choose boolean OR instead. Some of the API functions contain a parameter that indicates how results should be combined. At present this is always set to AND.&lt;br /&gt;
&lt;br /&gt;
=== Expected date ===&lt;br /&gt;
An activity can optionally have an expected completion date. This date currently has no effect and is not shown to students, but it appears to teachers when viewing progress. It&#039;s intended so that teachers can see when students are having problems and maybe offer assistance.&lt;br /&gt;
&lt;br /&gt;
In future it might be possible to export this data – e.g. the list of students who are &#039;late&#039; – to external systemss.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
(&#039;&#039;Prefix is shown as _. Constants are defined for all values here.&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
* _course&lt;br /&gt;
** +Field enablecompletion, unsigned int (1) default 0 not null.1 = enable completion options for activities (if enabled at site level). This is the user-interface default that applies to new courses when completion is enabled for the site.0 = disable and hide options. This is the database default that will apply to existing courses.&lt;br /&gt;
* _course_modules&lt;br /&gt;
** +Field completion, unsigned int (1) default 0 not null.0 = No progress tracking for this activity.1 = Manual completion tracking.2 = Automatic completion tracking.&lt;br /&gt;
** +Field completiongradeitemnumber, unsigned int(10) default 0.NULL = Grade information not used for completion.0,1,… = Use first/second/N&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; grade item supplied by this activity.&lt;br /&gt;
** +Field completionview, unsigned int (1) default 0 not null.0 = View not required for completion.1 = View required for completion.&lt;br /&gt;
** +Field completionexpected, unsigned int (10) default 0 not null.0 = No particular date expected for completion&amp;lt;nowiki&amp;gt;* = time (seconds since epoch) by which activity is expected to be completed. &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* New table _course_modules_completion which stores completion state for a user on each activity.&lt;br /&gt;
** id.&lt;br /&gt;
** coursemoduleid&amp;lt;nowiki&amp;gt; [index].&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** userid&amp;lt;nowiki&amp;gt; [index]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
** completionstate, unsigned int(1) not null.(The absence of a row in the table counts the same as 0 here.)0 = not completed.1 = completed.2 = completed, passed.3 = completed, failed.&lt;br /&gt;
** viewed, unsigned int(1)null = not tracked0 = not viewed1 = viewedOnly stored if the activity is tracking viewed state.&lt;br /&gt;
** timemodified, unsigned int (10) not null.Last date the state changed, in seconds since epoch.&lt;br /&gt;
&lt;br /&gt;
=== Capabilities ===&lt;br /&gt;
* moodle/course:viewprogress&amp;lt;nowiki&amp;gt; [default Teacher, Editing Teacher, Course Creator]&amp;lt;/nowiki&amp;gt;Users with this permission can view progress of students on the course. If the course is set to visible groups mode, or the user also has accessallgroups, then they can see all groups. Otherwise they can only see groups they belong to.&lt;br /&gt;
&lt;br /&gt;
=== Admin ===&lt;br /&gt;
A new admin setting progresstrackedroles stores a list of the roles that are considered relevant when displaying progress. (Other roles can still use the completion system, but won’t be shown on the progress screen.) This setting is editable via standard admin screens.&lt;br /&gt;
&lt;br /&gt;
=== API ===&lt;br /&gt;
These functions will be included in a completionlib.php.&lt;br /&gt;
&lt;br /&gt;
* completion_is_enabled($course=null,$cm=null)Returns true if completion is enabled. With no parameters, returns the site value; when course is specified, checks course as well.If course-module is specified, the return value is the same as the value of completion from course_modules.&lt;br /&gt;
* completion_update_state($course,$cm, $possibleresult=COMPLETION_UNKNOWN,$userid=0)Called to update completion state on the activity $cm for the given or current user. This obtains grade/viewable information if necessary and then asks the module whether the activity has been completed.It is called whenever a grade is updated on an activity that uses grades for completion and, by modules, whenever a module-specific piece of data that might affect completion has changed. &lt;br /&gt;
* $possibleresult is included for performance reasons to avoid recalculating completion when not necessary. Set to COMPLETION_COMPLETE or COMPLETION_NOTCOMPLETE, it indicates that the change which necessitated calling this function can only result in that type of state. For example, if there is a condition that the user must make 5 forum posts, we would call this function in response to any new post. But if the state is already ‘complete’, there is no point going through counting posts, checking grades, etc. This hint allows the code to skip further work if the user’s state is already the target. Once retrieved we will cache the state in session so that frequently, no database queries are required.&lt;br /&gt;
* For performance reasons, modules should still only call this function when necessary. The forum should not call this function whenever a new post is made, unless the completion option for counting posts is actually turned on for that forum.&lt;br /&gt;
* When a module is set to manual completion, this function is used to directly toggle completion. The completion value is set to $possibleresult.&lt;br /&gt;
* completion_set_module_viewed($course,$cm,$userid=0)Called when a module is viewed. If view-based completion is enabled (in $cm) then it sets the &#039;viewed&#039; flag and calls update_completion_state.&lt;br /&gt;
* completion_count_user_data($cm)Called to determine whether any users have already completed an activity (if so, returns the number). This is used by the module settings form to determine whether completion settings should be &#039;locked&#039;.&lt;br /&gt;
* completion_delete_all_state($course,$cm)Called at the point where course-module entries are deleted. Deletes all completion state data for that course-module.&lt;br /&gt;
* completion_reset_all_state($course,$cm)Deletes existing completion state for all users in this activity, then recalculates it by calling update_completion_state a lot for (i) all state-tracked users (those with progresstrackedroles roles in this activity’s context), (ii) all users who have stored completion state for this activity.Needs to be called if completion conditions change.&lt;br /&gt;
* completion_get_data($course,$cm,$wholecourse=false,$userid=0)Obtains completion data for a particular user related to a given activity. User defaults to current user.The $wholecourse parameter is a hint that, if it isn&#039;t already available, the system should retrieve into cache the completion data for all course activities now (so that future requests for other activities can be satisfied from cache).&lt;br /&gt;
* completion_get_activities($course)Gets course-module objects for all activities on a course that have completion turned on. (&#039;&#039;Used by the progress report.&#039;&#039;)&lt;br /&gt;
* completion_get_progress_all($course,$sortfirstname=false,$groupid=0)Obtains progress of all users in a course (or group) across all activities in that course for which completion tracking is enabled. (&#039;&#039;Used by the progress report.&#039;&#039;)&lt;br /&gt;
* completion_inform_grade_changed($course,$cm,&amp;amp;$item,&amp;amp;$grade,$deleted)Called to notify the completion system when a user&#039;s grade changes. Does nothing (quickly) if completion is not enabled for the item; if completion is enabled and depends on grade, calls completion_update_state. (&#039;&#039;Provided only for use by the gradebook.&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== Module changes ===&lt;br /&gt;
There is no requirement for any module changes to support the completion system. Existing modules continue to work.&lt;br /&gt;
&lt;br /&gt;
If no changes are made to a module, then manual completion (where the user ticks the box themselves) is supported for activities of that type, and automatic completion is not offered as an option in the activity settings screen.&lt;br /&gt;
&lt;br /&gt;
Progressively more changes are required when implementing more detailed completion support for a module.&lt;br /&gt;
&lt;br /&gt;
==== View support ====&lt;br /&gt;
To support the &#039;complete when viewed&#039; feature, a module must do the following:&lt;br /&gt;
&lt;br /&gt;
* Implement &#039;&#039;module&#039;&#039;_supports() as follows:function &#039;&#039;module&#039;&#039;_supports($feature) { switch($feature) { case FEATURE_COMPLETION_TRACKS_VIEWS: return true; default:  return false; }}&lt;br /&gt;
* Add calls to completion_set_module_viewed whenever the module considers that it has been &#039;viewed&#039;.&lt;br /&gt;
** It is up to the module to determine what this means. However most modules might put this call in view.php, near print_footer once it is clear that no errors occurred.&lt;br /&gt;
** This function does not take a significant time to run if view-based completion is not enabled, so you don&#039;t need to put the call inside an if.&lt;br /&gt;
&lt;br /&gt;
==== Grade support ====&lt;br /&gt;
If a module provides grades, making &#039;&#039;module&#039;&#039;_supports() return true for FEATURE_GRADE_HAS_GRADES will make these accessible to the completion system.&lt;br /&gt;
&lt;br /&gt;
==== Custom completion ====&lt;br /&gt;
Supporting module-specific custom completion conditions requires extra work:&lt;br /&gt;
&lt;br /&gt;
* Decide how to store the settings for these extra conditions (probably in your module&#039;s main table). Change your database tables to allow this.&lt;br /&gt;
* Add FEATURE_COMPLETION_HAS_RULES to your &#039;&#039;module&#039;&#039;_supports().&lt;br /&gt;
* Add the extra controls to your mod_form.php.&lt;br /&gt;
** Override the method completion_add_rules() so that it adds extra form elements for your controls (the method is called at the right point so that they are added in the &#039;completion&#039; box), and returns a list of the form elements (this is used to enable/disable them appropriately).&lt;br /&gt;
** Override the function completion_rule_enabled($data) so that it returns true if the supplied data means that at least one of the module&#039;s completion conditions is turned on. This is used to prevent the user from choosing &#039;automatic&#039; completion if they don&#039;t also enable at least one condition.&lt;br /&gt;
** You may need to modify other functions such as definition_after_data() and get_data to set up your form controls appropriately based on the data from the database, or vice versa.&lt;br /&gt;
* In your lib.php, implement the new function &#039;&#039;module&#039;&#039;_get_completion_state($course,$cm,$userid,$logic).&lt;br /&gt;
** If the specified module instance has completion requirements, this should return true (if they have been met) or false (if they haven&#039;t). The system will later combine this value with possible other completion requirements (view or grades).&lt;br /&gt;
** $logic is either COMPLETION_AND or COMPLETION_OR, indicating which type of Boolean logic should be used when there are multiple conditions. &lt;br /&gt;
** If completion conditions are not enabled for this particular instance, the function should return $logic (not false). &lt;br /&gt;
* In your module code, when something changes which might affect completion, call completion_update_state&lt;br /&gt;
&lt;br /&gt;
=== Example of system operation ===&lt;br /&gt;
Assume that the forum offers an option to check completion based on the number of posts (complete when you’ve made N posts).&lt;br /&gt;
&lt;br /&gt;
Every time a user makes a new post:&lt;br /&gt;
&lt;br /&gt;
* Forum checks if completion tracking based on the number of posts is enabled (this would probably be an option in $forum). If not, it does nothing (&#039;&#039;stop&#039;&#039;).&lt;br /&gt;
* Forum calls completion_update_state($cm,COMPLETION_COMPLETE).&lt;br /&gt;
* System looks up the user’s current completion state for $cm. If the current state is already COMPLETION_COMPLETE (or COMPLETE_PASS or COMPLETE_FAIL) then it returns with no further action (&#039;&#039;stop&#039;&#039;).&lt;br /&gt;
* If grade-based completion is enabled, system obtains grade and checks it. If viewed-completion is enabled, system checks whether the module has been viewed.&lt;br /&gt;
* If the forum has its own completion rules, then the system calls forum_get_completion_state().&lt;br /&gt;
* The forum checks its own rules, including the number of posts and anything else that’s enabled. It returns true if these rules are met and false if they’re not.&lt;br /&gt;
* Combining this data, the system decides whether to update the completion state. If an update is needed, it makes the change in the database.&lt;br /&gt;
&lt;br /&gt;
=== Activity UI (course page) ===&lt;br /&gt;
The user interface for students on the course view page needs to allow for displaying progress to students and, where completion is set to manual, allowing students to tick their own progress boxes. &lt;br /&gt;
&lt;br /&gt;
I have based this suggested interface on experience here at the OU. The interface will be implemented via changes to print_section and course view.php.&lt;br /&gt;
&lt;br /&gt;
* Completion displays alongside each activity for which completion is enabled, to the right of the section. (This conveniently separates it from the functional information at the left, and means that all the progress markers line up with each other.)&lt;br /&gt;
* Automatic completion displays as a tick or cross icon, by default coloured green and red (accessible colours will be chosen), or some kind of faint outline if something isn’t completed yet. The cross icon is used if completion state is 1.&lt;br /&gt;
* Manual completion displays using two more icons (‘manual tick’ and ‘manual blank’). Possible icons would be the same tick with a heavy dotted box around it, and an empty dotted box. The title of the icon is an interface clue to the user e.g. ‘Click to mark this activity completed’.When AJAX is not enabled, the manual icons link to a URL that toggles the completion value then redirects straight back to the course page.When AJAX is enabled, the manual icons use YUI to adjust the completion value without reloading the page. In this case some kind of animation – for example, the word ‘Saved’ appearing next to the icon for a second before fading away – will be used to indicate to users that their change has taken effect.&lt;br /&gt;
* If completion is not enabled for an activity (or for the course, site, etc) then the print_section display is the same as at present.&lt;br /&gt;
* When editing is turned on, completion information always displays as ticked regardless of the user’s actual completion setting. This makes it easy to see that completion is enabled for that activity.&lt;br /&gt;
&lt;br /&gt;
I will get a graphic designer to look at the icons to use. To reiterate, there are six icons:&lt;br /&gt;
&lt;br /&gt;
* automatic completion, not completed yet (above, not actually shown on its own, but would be a faint grey dotted box)&lt;br /&gt;
* automatic completion, completed (above, slightly grey tick, with faint grey dotted surround)&lt;br /&gt;
* automatic completion, pass (not shown, e.g. could be a green tick)&lt;br /&gt;
* automatic completion, fail (not shown, e.g. could be a red cross)&lt;br /&gt;
* manual completion, not completed (heavy black dotted outline)&lt;br /&gt;
* manual completion, completed (heavy black dotted outline with black tick)&lt;br /&gt;
&lt;br /&gt;
It may need some work to make the manual ones look clickable and the automatic ones look not clickable, but not irrelevant either. For example we might have to resort to crappy 3D button-style shading on the manual ones. This is what I&#039;ve done (badly) in the initial version of the icons which I have made.&lt;br /&gt;
&lt;br /&gt;
=== Configuration UI (activity settings page) ===&lt;br /&gt;
Each activity’s completion settings can be configured on the standard activity settings page. These settings only appear if completion is enabled for the course and site.&lt;br /&gt;
&lt;br /&gt;
The interface will be implemented via a change to the standard_coursemodule_elements function and a new optional form member function completion_add_rules(), as mentioned above, which is called (from within standard_coursemodule_elements) to add the activity-specific form elements.&lt;br /&gt;
&lt;br /&gt;
We also need to determine whether the activity supports grades. This will be determined via the new &#039;&#039;module_&#039;&#039;supports() function. (Note that there are existing functions for finding out whether a module &#039;&#039;instance&#039;&#039; has a grade, but not for finding out whether a module supports grades if it hasn&#039;t been created yet.)&lt;br /&gt;
&lt;br /&gt;
((TODO: Diagram needs redoing))&lt;br /&gt;
&lt;br /&gt;
* A dropdown allows choice of the three completion options – none, manual, automatic. (All three are shown in the diagrams below.) If the module does not support its own completion conditions, and does not support grades, then the ‘automatic’ option will not appear.&lt;br /&gt;
* A ‘view’ checkbox only appears if the module supports view tracking. If completion is not set to automatic, it will be greyed out. It allows you to mark something complete as soon as the user goes there once.&lt;br /&gt;
* A &#039;require grade&#039; checkbox only appears if the module supports grades. If completion is not set to automatic, it will be greyed out.&lt;br /&gt;
** At this point we could have a dropdown selector to choose which grade item to use if there is more than one. However, at least for the first release, I am not providing a user interface for that feature.&lt;br /&gt;
* Module-specific settings, if any, are included. These are also greyed out if completion is not set to automatic. The module can add any number of settings. It is responsible for storing the data from these as part of its normal form processing.&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;An expected completion date (default disabled) is given. This can be enabled for manual or automatic completion. It has no practical effect but displays on the progress screen. The intention is that those who design a course can set these dates at key points in the course. During the course, teachers can look at the progress report and use the dates as a guideline to check whether students are falling behind. [At a later date it might be possible to do other things with this data, such as export a list of &#039;late&#039; students to an external system.]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* If anybody already has stored completion state for this activity, completion settings will be locked: they appear, but read-only. A button allows you to unlock the settings (making those fields editable again); after you do that and save the form, existing completion data is wiped and recalculated against the new conditions. A warning by the button explains that changing completion conditions after students complete things is not a good idea.&lt;br /&gt;
&lt;br /&gt;
=== Progress tracking UI ===&lt;br /&gt;
Teachers wishing to track student progress can do so via the admin block. The existing course reports page will include a link to view student progress if the user has viewprogress capability.&lt;br /&gt;
&lt;br /&gt;
The resulting page shows a summary of progress either for a particular group, or for all students in the course, according to the normal rules for group selection. It may include a standard group dropdown too.&lt;br /&gt;
&lt;br /&gt;
# Progress is shown in a table. Students (everyone with a role in progresstrackedroles&amp;lt;nowiki&amp;gt;) are displayed down the left of the table and for activities that have completion enabled, the activity names [with expected completion dates, if set] are displayed across the top. Students can be sorted by first name or last name. The student names link to profiles and activity names link to the activities.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
# The cells in this grid show progress indicators using the same icons as used on the course view page, although these icons are not clickable in the report. For each cell, the title, which you can see by hovering over it, indicates the state of the cell and the time modified (‘Completed 12/9/08 13:47’) as well as the student&#039;s name and the activity name (in case you are scrolling around a table that doesn&#039;t fit on-screen).&lt;br /&gt;
# A link at the bottom allows this table to be downloaded in CSV format. The downloaded version contains the same data, using two columns (‘state’ and ‘date’) for each activity.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
==== Course view ====&lt;br /&gt;
When completion is enabled for a course, the course view page needs to obtain completion information. This will be cached in session and retrieved efficiently (hopefully 1 query) the first time.&lt;br /&gt;
&lt;br /&gt;
==== Module pages ====&lt;br /&gt;
There is no performance impact when using modules that do not support completion, or where completion is disabled.&lt;br /&gt;
&lt;br /&gt;
When you take an action that potentially involves completion (e.g. if you make a forum post to a forum that has enabled automatic completion when you reach N posts) the same completion state cache is used to read the current state of the data, so this should need no queries (you probably already saw the front page). &lt;br /&gt;
&lt;br /&gt;
If your action could potentially change that completion state (e.g. you have not already completed the activity and you just made an additional forum post) there will be an additional cost at that time, depending on the activity – in this case, the forum will do a query to find out how many posts you&#039;ve made. Because these actions occur relatively rarely, this should not cause a serious problem. (Once you have completed the activity, making another post will not incur the performance penalty.) &lt;br /&gt;
&lt;br /&gt;
View-related completion tracking, the part most potentially problematic, will behave similarly: the first time you view something that has a &#039;viewed&#039; requirement, it will make extra queries as it marks it viewed (or, if you viewed it in a previous session, loads up that information). After that the information will be cached in your session.&lt;br /&gt;
&lt;br /&gt;
=== Backup and restore ===&lt;br /&gt;
* When users are included in backup, course backup will include the contents of the _course_modules_completion table.&lt;br /&gt;
* Course and course-modules backup will be modified to include the new fields in those tables.&lt;br /&gt;
&lt;br /&gt;
= Conditional availability =&lt;br /&gt;
== Conditional options ==&lt;br /&gt;
There is no specific option to enable this part of the feature (?). The parts which depend on the completion system are enabled using the completion flag.&lt;br /&gt;
&lt;br /&gt;
== Available conditions ==&lt;br /&gt;
You can place conditions on any activity. Conditions are always combined with Boolean AND, i.e. all conditions must be met before the activity becomes available. Unlike completion, conditions are not module-dependent. There are two types of condition:&lt;br /&gt;
&lt;br /&gt;
# Conditional on date. You can have both of these conditions if required.&lt;br /&gt;
&lt;br /&gt;
# &lt;br /&gt;
#* On or after date – activity becomes available on given date.&lt;br /&gt;
#* Before date – activity becomes unavailable on given date.&lt;br /&gt;
&lt;br /&gt;
# Conditional on other activities. You can have as many of these conditions as desired.&lt;br /&gt;
&lt;br /&gt;
# &lt;br /&gt;
#* Activity must be completed – any kind of completion will do.&lt;br /&gt;
#* Activity must be completed and passed – completion must have been graded and displayed with a pass mark (tick icon).&lt;br /&gt;
#* Activity must be graded at least/at most &#039;&#039;N&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Database ==&lt;br /&gt;
* _course_modules&lt;br /&gt;
** New field availablefrom, unsigned int (10) not null default 0.0 = Not conditional on date.&amp;lt;nowiki&amp;gt;* = Time (seconds since epoch&amp;lt;/nowiki&amp;gt;) after which activity becomes available.&lt;br /&gt;
** New field availableuntil, unsigned int(10) not null default 0.0 = Not conditional on date.&amp;lt;nowiki&amp;gt;* = Time (seconds since epoch) after which activity becomes unavailable.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** New field showavailability, unsigned int (1) not null default 0.0 = Activity does not appear at all if conditions are not met.1 = If conditions are not met, activity appears but greyed out (‘hidden’ style) with no link and a short explanation of when it will be available.&lt;br /&gt;
* New table _course_modules_avail(able?) which stores any per-module conditions.&lt;br /&gt;
** id.&lt;br /&gt;
** coursemoduleid&amp;lt;nowiki&amp;gt; [index]&amp;lt;/nowiki&amp;gt;.ID of the module that is being restricted.&lt;br /&gt;
** cmsourceid.ID of module that the restriction is based on.&lt;br /&gt;
** requiredcompletion, unsigned int(1) not null default 0.0 = no required completion.1 = required completed.2 = required completed and passed.3 = required completed and failed.&lt;br /&gt;
** gradesign, varchar(2).NULL = no required grade.&amp;lt;nowiki&amp;gt;‘&amp;lt;’, ‘&amp;lt;=&amp;lt;/nowiki&amp;gt;’, ‘&amp;gt;’, ‘&amp;gt;=’ = requirement for grade.&lt;br /&gt;
** requiredgrade, number(10,5 decimals).Grade boundary used together with the above sign. May be null.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
Two new functions:&lt;br /&gt;
&lt;br /&gt;
* availability_is_available($cm)Returns true if the module is available to students (it is visible, plus availability conditions, if any, are met). Does not include course access conditions, which it assumes have already been checked.This is a slot-in replacement where code checks for $cm-&amp;gt;visible at key points such as in require_login.&lt;br /&gt;
* availability_get_display_details($cm)Obtains information about the activity’s availability which is required in order to display (or not display) a link to the activity. Returns an object with the following fields:-&amp;gt;available – If true, activity is available; users should be allowed to access it / get links to it.-&amp;gt;show – If true, activity should be displayed (even to users who do not have viewhiddenactivities)-&amp;gt;info – Informational string. Blank if the activity is available.&lt;br /&gt;
&lt;br /&gt;
Other changes:&lt;br /&gt;
&lt;br /&gt;
* For performance reasons we need to cache the conditions in _course_modules_available. Best option is to use existing get_fast_modinfo infrastructure. This should not be hard. The above two functions will use this cache.&lt;br /&gt;
&lt;br /&gt;
== Configuration UI (activity settings page) ==&lt;br /&gt;
The configuration UI will be implemented as part of standard_coursemodule_elements in the module forms. The existing ‘visible to students’ option (not changed in database/code) is moved within this UI. &lt;br /&gt;
&lt;br /&gt;
This UI will appear even if completion is not enabled, but the parts related to completion will not show. So if completion is not enabled you will still be able to set available dates if you like, and the interface will remain consistent. The diagram below shows, first, the version that appears with completion not enabled, and then the one you get with completion enabled.&lt;br /&gt;
&lt;br /&gt;
((There should be a diagram here, not sure it will show in the wiki version))&lt;br /&gt;
&lt;br /&gt;
[[Image:]]&lt;br /&gt;
&lt;br /&gt;
* The actual ‘available from’ options should include time as well as date. ‘Available from’ should default to midnight tomorrow; ‘Available until’ should default to 23:59 today. (I got bored laying out combo boxes.)&lt;br /&gt;
* ‘Information display’ controls whether informational text is displayed to students when an activity is not available. (See below.) The default is not to show information.&lt;br /&gt;
* The list of other activities which might have conditions includes only those other activities on the course which either have completion information, or a grade. Anything which doesn’t have completion information or a grade is omitted.&lt;br /&gt;
* Only one condition is permitted per other activity. This isn’t a restriction of the back-end, it just makes the UI simpler.&lt;br /&gt;
* The condition type dropdown by each activity is adjusted dynamically to include only options that are valid for that activity:&lt;br /&gt;
** ‘Completed’ appears only if completion is enabled for the activity.&lt;br /&gt;
** ‘Completed with pass’ and ‘Completed with fail’ (which I missed off the diagram by accident) appear only if completion is enabled for the activity, and set to a grade item, and the grade item contains a pass mark.&lt;br /&gt;
** The grade conditions appear only if the activity has a grade item.&lt;br /&gt;
* The grade box is a text-entry field. Users type in the floating-point number version of the required grade.&lt;br /&gt;
&lt;br /&gt;
== Activity UI (course page) ==&lt;br /&gt;
(This will be accomplished via code changes to print_section. Logic is basically the same as for the current visible flag.) &lt;br /&gt;
&lt;br /&gt;
For available activities, the display obviously does not change. Unavailable activities will be displayed as follows:&lt;br /&gt;
&lt;br /&gt;
* If the current user has viewhiddenactivities:&lt;br /&gt;
** The activity displays using the CSS style for hidden activities.&lt;br /&gt;
** The informational message as to why the activity isn’t available is displayed (even if showinfo is not set).&lt;br /&gt;
* If the current user does not have viewhiddenactivities:&lt;br /&gt;
** If showavailability is not set, or if the activity is actually hidden (visibility 0), the activity does not display at all.&lt;br /&gt;
** If showavailability is set and the activity isn’t hidden but is unavailable for some other reason, the name of the activity displays using the CSS style for hidden activities, but does not include an actual link to the activity. The informational message as to why the activity isn’t available is displayed.&lt;br /&gt;
&lt;br /&gt;
Here are some examples of hidden activities with informational text:Assignment resources Available from 6 Oct 2008Assignment resources Available when Unit 1 Test grade is &amp;gt; 90Assignment resources Available when Tutor group forum is marked complete (+ other requirements)When there are multiple conditions, only one is shown. Date is considered first; the order after that is arbitrary.&lt;br /&gt;
&lt;br /&gt;
Behaviour is the same when editing is turned on except that the ‘availability’ string moves to the line below so as not to clash with all those icons.&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
This adds a single quick database query to the course view page for courses which have enabled conditional activities / completion.&lt;br /&gt;
&lt;br /&gt;
All other information is cached in modinfo&amp;lt;nowiki&amp;gt;, so does not have a performance penalty, save one problematic issue: the feature that allows arbitrary grade information to be considered. If you use pass/fail information, that’s fine, it’s there already in the completion data. But if you use a specific grade [and for example it could be different values for different activities] then the actual grade for the item needs to be retrieved on course view.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I don’t believe this will pose a massive performance issue as it only applies when modules are used as source for this kind of information. We should review this once it’s developed and, if necessary, optimise performance then. There are various caching approaches we could use.&lt;br /&gt;
&lt;br /&gt;
== Module delete ==&lt;br /&gt;
If you try to delete a module, it will check to see if that module is referenced by any other module as a condition. If that’s the case, you will not be allowed to delete it. An error message will include a link to the module edit page for the other module (so you can go there and delete the condition if you like).&lt;br /&gt;
&lt;br /&gt;
== Backup and restore ==&lt;br /&gt;
* The new _course_modules_available table will be backed up and restored. &lt;br /&gt;
** Partial restore needs to be handled. If your backup includes module A but not module B, and module A had a condition on B, then that condition will not be restored.&lt;br /&gt;
* Backup will also be modified to include the fields added to _course_modules.&lt;br /&gt;
* If you restore a course with a startdateoffset, it will offset the dates from the new _course_modules date fields.&lt;br /&gt;
&lt;br /&gt;
= Module supported features =&lt;br /&gt;
As part of the completion system, I needed a way for modules to indicate support of certain features, so I propose a generic one which I have implemented:&lt;br /&gt;
&lt;br /&gt;
* A module API function &#039;&#039;module&#039;&#039;_supports($feature) which returns false if the feature is not available, and true (or an object with more information, if needed for specific features) if it is.&lt;br /&gt;
* A standard API function module_supports($modulename,$feature) which works as follows:&lt;br /&gt;
** If the $modulename_supports_feature function exists, it calls that function and returns the result.&lt;br /&gt;
** Otherwise it returns false – or, if features are added that correspond to ‘legacy’ ones that we can find out another way (e.g. by looking to see if a function exists) then this can be done.&lt;br /&gt;
* A set of FEATURE_&#039;&#039;xx&#039;&#039; constants. For this code, the following are necessary:&lt;br /&gt;
** FEATURE_GRADE_HAS_GRADE&lt;br /&gt;
** FEATURE_COMPLETION_TRACKS_VIEWS&lt;br /&gt;
** FEATURE_COMPLETION_HAS_RULES&lt;br /&gt;
* Other feature constants could be added as desired, e.g. FEATURE_CRON, etc. My initial implementation will include only the &#039;new&#039; ones needed for this work.&lt;br /&gt;
&lt;br /&gt;
Note that this implementation would not be appropriate if modules were changed to be fully object-oriented. However I don&#039;t expect that to happen in Moodle 2 so this is probably OK.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Git_Migration&amp;diff=38161</id>
		<title>Development:Git Migration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Git_Migration&amp;diff=38161"/>
		<updated>2008-06-24T10:30:03Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* The way to go for developers who want it now */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Proposal to move Moodle development from CVS to Git =&lt;br /&gt;
&lt;br /&gt;
There have been discussions to abandon CVS as the main version tracking system, to move to a distributed system instead. Many developers have expressed their interest for [http://git.or.cz Git]. A [http://moodle.org/mod/forum/discuss.php?d=99763 discussion] is taking place in moodle.org forums about a possible move to Git and contains a lot of information.&lt;br /&gt;
&lt;br /&gt;
Some other systems have also been mentioned, such as [http://www.selenic.com/mercurial/wiki/ Mercurial].&lt;br /&gt;
&lt;br /&gt;
= Git and human usage =&lt;br /&gt;
&lt;br /&gt;
* A lot of people need an easy interface to the revision system.  Most of them are currently using TortoiseCVS (a lot of translators, it seems). There is no tool (as of late June 2008) for Git that is equivalent in ease of use to TortoiseCVS, though [http://digilander.libero.it/mcostalba/ qgit] (said to be running flawlessly on Windows) and [http://cola.tuxfamily.org/ git-cola] are improving. In the meantime, people could use a CVS gateway, which would need to work both ways (read &amp;amp; write), to give people time to change over once proper tools become available.&lt;br /&gt;
* Developers using Eclipse, NetBeans, and most other major IDEs need to wait for plugins. There is a [http://wiki.eclipse.org/EGit/Proposal proposal], which is aiming to provide a pure-Java implementation along with an Eclipse plugin and should lead to support at least in the Java-based IDEs, but this is still not ready for prime time (June 2008).&lt;br /&gt;
* [http://vim.sourceforge.net/scripts/script.php?script_id=90 VCSCommand] plugin for Vim now supports Git.&lt;br /&gt;
* Some users are using CVS mirrors to deploy (and update) their site. Can&#039;t break this. A read-only CVS gateway could be a good working solution to this.&lt;br /&gt;
&lt;br /&gt;
= Git and server-side tool integration =&lt;br /&gt;
&lt;br /&gt;
* Web interface to the repository: Git provides a web interface. Alternatively, Trac now provides a [http://trac-hacks.org/wiki/GitPlugin GitPlugin] that could be used.&lt;br /&gt;
* Bug tracking: see [http://forums.atlassian.com/thread.jspa?threadID=24671&amp;amp;tstart=0] and [http://jira.atlassian.com/browse/FE-337] (support still uncomplete, on June 24 2008).  Martín Langhoff says: &amp;quot;[http://moodle.org/mod/forum/discuss.php?d=99763#p441057 looks like there is a mercurial plugin we can quickly grab and, ahem, repurpose...]&amp;quot;. We could also use a CVS gateway, though there could be problems with this workaround, as &amp;quot;[http://moodle.org/mod/forum/discuss.php?d=99763#p440831 the rev numbers don&#039;t line up]&amp;quot;.&lt;br /&gt;
* The module managing [http://moodle.org/cvs moodle.org/cvs] would need to be rewritten to use Git. The user-access control would need to be managed [http://moodle.org/mod/forum/discuss.php?d=99763#p441030 using the pre-received hook].&lt;br /&gt;
* Need to see if cvsspam (for the cvs-commits list) would still work&lt;br /&gt;
* Moving cvs.moodle.org to git.moodle.org? Or keep both?&lt;br /&gt;
&lt;br /&gt;
= The way to go for developers who want it now =&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use Git right now, to track &lt;br /&gt;
* Follow instructions on the &amp;quot;[[Tracking Moodle CVS with git]]&amp;quot; page&lt;br /&gt;
* Use git-cvsexportcommit to commit to Moodle CVS&lt;br /&gt;
* Wait until the next refresh (5h30 am, New Zealand time) to get the patch back into your local Git repository&lt;br /&gt;
&lt;br /&gt;
= Other interesting links =&lt;br /&gt;
&lt;br /&gt;
* [http://garrys-brain.blogspot.com/2008/04/git-for-windows-msysgit.html Garry Bodsworth] says some good of the MinGW port of Git (for Windows)&lt;br /&gt;
* Installation reports - Git growth amongst DSCMs: [http://tinyurl.com/4uemg2 http://tinyurl.com/4uemg2]&lt;br /&gt;
* Usage reports - With a longer timeframe, and counting CVS/SVN: [http://tinyurl.com/4hu2cn http://tinyurl.com/4hu2cn]&lt;br /&gt;
* Get a free personal public git repo with some cool tools: [http://github.com/ http://github.com/]&lt;br /&gt;
* Free screencasts by Scott Chacon on using Git: [http://gitcasts.com/ http://gitcasts.com/]&lt;br /&gt;
* [http://pragprog.com/titles/tsgit/pragmatic-version-control-using-git Pragmatic Version Control using Git] will come out on November 1st, 2008.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Developer tools]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Git_Migration&amp;diff=38160</id>
		<title>Development:Git Migration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Git_Migration&amp;diff=38160"/>
		<updated>2008-06-24T10:28:36Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Git and human usage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Proposal to move Moodle development from CVS to Git =&lt;br /&gt;
&lt;br /&gt;
There have been discussions to abandon CVS as the main version tracking system, to move to a distributed system instead. Many developers have expressed their interest for [http://git.or.cz Git]. A [http://moodle.org/mod/forum/discuss.php?d=99763 discussion] is taking place in moodle.org forums about a possible move to Git and contains a lot of information.&lt;br /&gt;
&lt;br /&gt;
Some other systems have also been mentioned, such as [http://www.selenic.com/mercurial/wiki/ Mercurial].&lt;br /&gt;
&lt;br /&gt;
= Git and human usage =&lt;br /&gt;
&lt;br /&gt;
* A lot of people need an easy interface to the revision system.  Most of them are currently using TortoiseCVS (a lot of translators, it seems). There is no tool (as of late June 2008) for Git that is equivalent in ease of use to TortoiseCVS, though [http://digilander.libero.it/mcostalba/ qgit] (said to be running flawlessly on Windows) and [http://cola.tuxfamily.org/ git-cola] are improving. In the meantime, people could use a CVS gateway, which would need to work both ways (read &amp;amp; write), to give people time to change over once proper tools become available.&lt;br /&gt;
* Developers using Eclipse, NetBeans, and most other major IDEs need to wait for plugins. There is a [http://wiki.eclipse.org/EGit/Proposal proposal], which is aiming to provide a pure-Java implementation along with an Eclipse plugin and should lead to support at least in the Java-based IDEs, but this is still not ready for prime time (June 2008).&lt;br /&gt;
* [http://vim.sourceforge.net/scripts/script.php?script_id=90 VCSCommand] plugin for Vim now supports Git.&lt;br /&gt;
* Some users are using CVS mirrors to deploy (and update) their site. Can&#039;t break this. A read-only CVS gateway could be a good working solution to this.&lt;br /&gt;
&lt;br /&gt;
= Git and server-side tool integration =&lt;br /&gt;
&lt;br /&gt;
* Web interface to the repository: Git provides a web interface. Alternatively, Trac now provides a [http://trac-hacks.org/wiki/GitPlugin GitPlugin] that could be used.&lt;br /&gt;
* Bug tracking: see [http://forums.atlassian.com/thread.jspa?threadID=24671&amp;amp;tstart=0] and [http://jira.atlassian.com/browse/FE-337] (support still uncomplete, on June 24 2008).  Martín Langhoff says: &amp;quot;[http://moodle.org/mod/forum/discuss.php?d=99763#p441057 looks like there is a mercurial plugin we can quickly grab and, ahem, repurpose...]&amp;quot;. We could also use a CVS gateway, though there could be problems with this workaround, as &amp;quot;[http://moodle.org/mod/forum/discuss.php?d=99763#p440831 the rev numbers don&#039;t line up]&amp;quot;.&lt;br /&gt;
* The module managing [http://moodle.org/cvs moodle.org/cvs] would need to be rewritten to use Git. The user-access control would need to be managed [http://moodle.org/mod/forum/discuss.php?d=99763#p441030 using the pre-received hook].&lt;br /&gt;
* Need to see if cvsspam (for the cvs-commits list) would still work&lt;br /&gt;
* Moving cvs.moodle.org to git.moodle.org? Or keep both?&lt;br /&gt;
&lt;br /&gt;
= The way to go for developers who want it now =&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to use Git right now, to track &lt;br /&gt;
* Follow instructions on the &amp;quot;[Tracking Moodle CVS with git]&amp;quot; page&lt;br /&gt;
* Use git-cvsexportcommit to commit to Moodle CVS&lt;br /&gt;
* Wait until the next refresh (5h30 am, New Zealand time) to get the patch back into your local Git repository&lt;br /&gt;
&lt;br /&gt;
= Other interesting links =&lt;br /&gt;
&lt;br /&gt;
* [http://garrys-brain.blogspot.com/2008/04/git-for-windows-msysgit.html Garry Bodsworth] says some good of the MinGW port of Git (for Windows)&lt;br /&gt;
* Installation reports - Git growth amongst DSCMs: [http://tinyurl.com/4uemg2 http://tinyurl.com/4uemg2]&lt;br /&gt;
* Usage reports - With a longer timeframe, and counting CVS/SVN: [http://tinyurl.com/4hu2cn http://tinyurl.com/4hu2cn]&lt;br /&gt;
* Get a free personal public git repo with some cool tools: [http://github.com/ http://github.com/]&lt;br /&gt;
* Free screencasts by Scott Chacon on using Git: [http://gitcasts.com/ http://gitcasts.com/]&lt;br /&gt;
* [http://pragprog.com/titles/tsgit/pragmatic-version-control-using-git Pragmatic Version Control using Git] will come out on November 1st, 2008.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Developer tools]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=37097</id>
		<title>Development:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=37097"/>
		<updated>2008-06-06T13:03:01Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* The golden changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}{{Template:Development:dmllib 2.0}}__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Much of the following documentation will not make much sense unless you first read [[Development:XMLDB_Documentation|the XMLDB documentation]]. Please read it first if you would like to join the effort to convert Moodle&#039;s code to the new dmllib.&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to read the whole [[wikipedia:Data_Definition_Language|DDL]] and [[wikipedia:Data_Manipulation_Language|DML]] documentation before start with the migration. That will allow you to have some initial knowledge about the new architecture.&lt;br /&gt;
&lt;br /&gt;
This article defines all the changes that need to be performed in Moodle 1.9 code in order to make it run properly under new Moodle 2.0 DB layer. Changes below are grouped into 2 main blocks ([[Development:XMLDB_Documentation|xmldb]] and [[wikipedia:Data_Manipulation_Language|dml]]) to have them organised. Additional minor changes may be required in the [[wikipedia:Data_Definition_Language|ddl]] code, but won&#039;t be documented here.&lt;br /&gt;
&lt;br /&gt;
Although the order of changes showed in this page isn&#039;t mandatory at all, it can be interesting to follow it in the migration progress to be able to understand and learn a bit more about all them. That way, you&#039;ll end up knowing not only what to change but how and why those changes are required.&lt;br /&gt;
&lt;br /&gt;
Each change will be as simple as possible, representing one easy rule to follow to adapt the code. When anything become too complex to be explained as one simple rule, it will contain one link to the [[Development:dmllib_2.0_examples|examples page]].&lt;br /&gt;
&lt;br /&gt;
For any problem in the migration of code, it&#039;s recommended to use the [http://moodle.org/mod/forum/view.php?id=45 Databases forum] at [http://moodle.org moodle.org]. Also if you find any bug in the process, please report it in the [http://tracker.moodle.org/browse/MDL-14679 Moodle Tracker], that way developers will be able to fix it ASAP.&lt;br /&gt;
&lt;br /&gt;
The Glossary module was used as the basis for many of the examples below.&lt;br /&gt;
&lt;br /&gt;
And finally, feel free to complete/fix the list below with the changes you find in the progress of migration, that will certainly help many developers. Thanks!&lt;br /&gt;
&lt;br /&gt;
== XMLDB changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* When changing DB structures it&#039;s highly recommended to use the XMLDB Editor (Admin-&amp;gt;Misc-&amp;gt;XMLDB Editor). It is a safe way to edit install.xml files and to get correct PHP code to be used in upgrade.php scripts.&lt;br /&gt;
* If you have some doubts about the list of changes below, it&#039;s highly recommended to take a look at some code in core modules, blocks... whatever you need. They are a good reference.&lt;br /&gt;
&lt;br /&gt;
=== The changes ===&lt;br /&gt;
&lt;br /&gt;
* No changes are required in install.xml files at all (that&#039;s good news!).&lt;br /&gt;
* All upgrade.php scripts, within the main xxxx_upgrade function must have &#039;&#039;&#039;$DB&#039;&#039;&#039; (uppercase) in the globals declaration (along with others if needed). Example (from glossary module):&lt;br /&gt;
    function xmldb_glossary_upgrade($oldversion=0) {&lt;br /&gt;
    &lt;br /&gt;
        global $CFG, $THEME, $DB;&lt;br /&gt;
* All upgrade.php scripts, must NOT have &#039;&#039;&#039;$db&#039;&#039;&#039; (lowercase) in the globals declaration. Delete it if present.&lt;br /&gt;
* After the global declaration in the points above, this line must be present (we&#039;ll need it later):&lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager(); /// loads ddl manager and xmldb classes&lt;br /&gt;
* All XMLDBTable instances in your upgrade code must be replaced by xmldb_table (parameters are the same, no change with them required)&lt;br /&gt;
* All XMLDBField instances in your upgrade code must be replaced by xmldb_field (no change in parameters)&lt;br /&gt;
* All XMLDBIndex instances in your upgrade code must be replaced by xmldb_index (no change in parameters)&lt;br /&gt;
* All XMLDBKey instances in your upgrade code must be replaced by xmldb_key (no change in parameters)&lt;br /&gt;
* All the addFieldInfo() methods must be replaced by add_field() (no change in parameters)&lt;br /&gt;
* All the addIndexInfo() methods must be replaced by add_index() (no change in parameters)&lt;br /&gt;
* All the addKeyInfo() methods must be replaced by add_key() (no change in parameters)&lt;br /&gt;
* All the setAttributes() methods must be replaced by set_attributes() (no change in parameters)&lt;br /&gt;
* All the DDL functions used in upgrade code, must be transformed as detailed below (it&#039;s only about to add &#039;&#039;&#039;&amp;quot;$dbman-&amp;gt;&amp;quot;&#039;&#039;&#039; - without the quotes - before each function call). No changes in parameters are required:&lt;br /&gt;
    table_exists ==&amp;gt; $dbman-&amp;gt;table_exists&lt;br /&gt;
    field_exists ==&amp;gt; $dbman-&amp;gt;field_exists&lt;br /&gt;
    index_exists ==&amp;gt; $dbman-&amp;gt;index_exists&lt;br /&gt;
    find_index_name ==&amp;gt; $dbman-&amp;gt;find_index_name&lt;br /&gt;
    find_check_constraint_name ==&amp;gt; $dbman-&amp;gt;find_check_constraint_name&lt;br /&gt;
    check_constraint_exists ==&amp;gt; $dbman-&amp;gt;check_constraint_exists&lt;br /&gt;
    find_sequence_name ==&amp;gt; $dbman-&amp;gt;find_sequence_name&lt;br /&gt;
    create_table ==&amp;gt; $dbman-&amp;gt;create_table&lt;br /&gt;
    drop_table ==&amp;gt; $dbman-&amp;gt;drop_table&lt;br /&gt;
    rename_table ==&amp;gt; $dbman-&amp;gt;rename_table&lt;br /&gt;
    add_field ==&amp;gt; $dbman-&amp;gt;add_field&lt;br /&gt;
    drop_field ==&amp;gt; $dbman-&amp;gt;drop field&lt;br /&gt;
    rename_field ==&amp;gt; $dbman-&amp;gt;rename_field&lt;br /&gt;
    change_field_type ==&amp;gt; $dbman-&amp;gt;change_field_type&lt;br /&gt;
    change_field_precision =&amp;gt; $dbman-&amp;gt;change_field_precision&lt;br /&gt;
    change_field_unsigned ==&amp;gt; $dbman-&amp;gt;change_field_unsigned&lt;br /&gt;
    change_field_notnull ==&amp;gt; $dbman-&amp;gt;change_field_notnull&lt;br /&gt;
    change_field_enum ==&amp;gt; $dbman-&amp;gt;change_field_enum&lt;br /&gt;
    change_field_default ==&amp;gt; $dbman-&amp;gt;change_field_default&lt;br /&gt;
    add_key ==&amp;gt; $dbman-&amp;gt;add_key&lt;br /&gt;
    drop_key ==&amp;gt; $dbman-&amp;gt;drop_key&lt;br /&gt;
    add_index ==&amp;gt; $dbman-&amp;gt;add_index&lt;br /&gt;
    drop_index ==&amp;gt; $dbman-&amp;gt;drop_index&lt;br /&gt;
&lt;br /&gt;
== DML changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
* The ENTIRE CODEBASE requires an update of ALL database query function calls. Expect most moodle files to be affected by this change.&lt;br /&gt;
&lt;br /&gt;
* This is the more complex part to migrate to have the code working under Moodle 2.0, not because of the complexity of the changes themselves (90% of them will be really easy), but because you&#039;ll need to triple-check everything works as expected after changes.&lt;br /&gt;
&lt;br /&gt;
* Along the changes below, you&#039;ll find links to some examples that will try to make things easier. Anyway, if you are blocked at any point, please ask in forums or tracker (see links at the beginning of the page). Sure it has a good enough solution.&lt;br /&gt;
&lt;br /&gt;
* Once more it&#039;s highly recommended to take a look to Moodle core code, searching for similar examples. Of course, new meaningful examples are welcome, and also any clarification in the list of changes below. Feel free to do it, this is a wiki!&lt;br /&gt;
&lt;br /&gt;
* Finally, one more explanation: The changes below have been split into two sections. First one, (called &#039;&#039;&#039;&amp;quot;The golden changes&amp;quot;&#039;&#039;&#039;) are modifications that must be applied to ALL the transformations defined in the second section (&#039;&#039;&#039;&amp;quot;The iron changes&amp;quot;&#039;&#039;&#039;). Sure you&#039;ll understand that after reading them (it&#039;s basically a matter of not repeating the golden ones within each iron one, just imagine they are everywhere).&lt;br /&gt;
&lt;br /&gt;
=== The golden changes ===&lt;br /&gt;
&#039;&#039;PLEASE read the API before going crazy with search &amp;amp; replace&#039;&#039;! You can find all the new methods in lib/dml/moodle_database.php. This is essential because some method signatures have changed (params are different), and some method names have even changed (execute_sql() is now execute()).&lt;br /&gt;
&lt;br /&gt;
*Wherever old functions are used (get_record*, get_field*, set_field, insert_record, update_record), the global $DB must be used as the object on which these functions are called (e.g. get_record_select() becomes $DB-&amp;gt;get_record_select()).&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  get_record_select($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  $DB-&amp;gt;get_record_select($sql);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Careful: for some functions, the $params array is not the second function parameter. For example, set_field:&#039;&#039;&#039;&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  set_field(&#039;user&#039;, &#039;firstname&#039;, &#039;Eloy&#039;, &#039;id&#039;, 1);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $DB-&amp;gt;set_field(&#039;user&#039;, &#039;firstname&#039;, &#039;Eloy&#039;, array(&#039;id&#039; =&amp;gt; 1));&lt;br /&gt;
&lt;br /&gt;
*All the functions that used to accept a list of string params in the form &amp;quot;param1, value1, param2, value2&amp;quot; now need to be given an array of key=&amp;gt;value pairs as a replacement for these params. Other params remain as before. Check the new API for any exceptions. &lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $user = get_record(&amp;quot;user&amp;quot;, &amp;quot;firstname&amp;quot;, &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot;, &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax:&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $conditions = array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  $user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, $conditions);&lt;br /&gt;
**Note:  The example above has been written out in full for clarity. You can use the array() directly within the function call, without using a temporary variable, if you prefer:&#039;&#039;&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Lafuente&amp;quot;) );&lt;br /&gt;
&lt;br /&gt;
*rs_fetch_next_record($rs) is deprecated, in favour of the simple foreach($rs as $var). Calls to rs_close() must be replaced by $rs-&amp;gt;close();&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  while($result = rs_fetch_next_record($rs)) {&lt;br /&gt;
      ...&lt;br /&gt;
  }&lt;br /&gt;
  rs_close();&lt;br /&gt;
     &lt;br /&gt;
  // New syntax&lt;br /&gt;
  foreach ($rs as $result) {&lt;br /&gt;
       ....&lt;br /&gt;
  }&lt;br /&gt;
  $rs-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
*All uses of addslashes() must be removed. They are no longer needed&lt;br /&gt;
*Placeholders must be used for table names. Instead of {$CFG-&amp;gt;prefix}tablename, use {tablename}.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {$CFG-&amp;gt;prefix}user&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {user}&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
*When PHP variables are used in SQL queries, they must be replaced by parameters. You have the choice between two approaches: ordered parameters, or named parameters.&lt;br /&gt;
**Ordered parameters use a simple array of values, which are given to the DML function as $params. The values in the SQL code are simply question marks (?) replacing the values. They are replaced by the DML code one by one, substituting each question mark (?) with the next value in the $params array.&lt;br /&gt;
**Named parameters use an associative array of name =&amp;gt; value pairs as the $params array. The values in the SQL code are replaced with a colon (:) followed by the key associated with the value, in the $params array.&lt;br /&gt;
&lt;br /&gt;
  Examples:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {$CFG-&amp;gt;prefix}user WHERE firstname = &#039;Eloy&#039; AND lastname = &#039;Lafuente&#039;&amp;quot;;&lt;br /&gt;
  $user = get_record_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: ordered params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;Eloy&#039;, &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = ? AND lastname = ?&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: named params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;firstname&#039; =&amp;gt; &#039;Eloy&#039;, &#039;lastname&#039; =&amp;gt; &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = :firstname AND lastname = :lastname&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
*Replacement of the IN(...) syntax: We no longer hard-code this in our SQL queries, we use a function which determines whether the IN() syntax is needed, or, if there is only one value to compare, the equal (=) sign can be used.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  $gis = implode(&#039;,&#039;, $depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {$CFG-&amp;gt;prefix}grade_items&lt;br /&gt;
           WHERE id IN ($gis)&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // new syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  list($usql, $params) = $DB-&amp;gt;get_in_or_equal($depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {grade_items}&lt;br /&gt;
           WHERE id $usql&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
=== The iron changes ===&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Development:XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[Development:DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[Development:DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development_talk:DB_layer_2.0_migration_docs&amp;diff=37096</id>
		<title>Development talk:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development_talk:DB_layer_2.0_migration_docs&amp;diff=37096"/>
		<updated>2008-06-06T11:24:15Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* random things */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* The developer reading this article MUST read XMLDB Documentation (at least Introduction + three first Developing section pages) otherwise he&#039;s going to ask plenty of questions :) It could be very good that the first line of this article be: &amp;quot;In order to understand this article you need to know how works the database abstraction layer in Moodle (previous to 2.0)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* API link is broken (=&amp;gt; http://php.moodle.org/ &amp;quot;Server not found&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* We know that some changes need to be done on 2.0. But on what? &lt;br /&gt;
All these examples concerns the glossary module. It would be good to indicate it first. When I read it first, I didn&#039;t really know what was going to be explained in XMLDB changes. In fact all this section is about &amp;quot;Updating your upgrade.php file for Moodle 2.0&amp;quot;. Conclusion: we really need a clear first sentence for the all &amp;quot;XMLDB changes&amp;quot; section. So we know what we are going to read. Once I knew what is about, all was very clear.&lt;br /&gt;
&lt;br /&gt;
* If we don&#039;t make any change on DDL code we shouldn&#039;t make it as a section/block. The DDL section should be a note. If you remove this section don&#039;t forget to update: &amp;quot;Changes below are grouped into 3 main blocks&amp;quot; =&amp;gt; &amp;quot;Changes below are grouped into 2 main blocks&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* DML section:&lt;br /&gt;
this is about to change all DML code, in all Moodle files? I think it miss an introduction line as well.&lt;br /&gt;
&lt;br /&gt;
* Maybe you should use more the word: YOU should do that, YOU do this, YOU ... The developer will feel more guided.&lt;br /&gt;
&lt;br /&gt;
Note: I wrote this comment on first read.&lt;br /&gt;
&lt;br /&gt;
Note 2: I&#039;m new as dev in Moodle, and I&#039;ve just discover all the power of Moodle XMLDB reading. All the current XMLDB looks awesome, I don&#039;t even talk about the coming 2.0 :)&lt;br /&gt;
&lt;br /&gt;
[[User:jerome mouneyrac|jerome mouneyrac]] 22:22, 22 May 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
== random things ==&lt;br /&gt;
&lt;br /&gt;
1 I added a marker re add_index or somesuch, is it really renamed add_key or is that just a copy/paste error? If it is correct, needs changing to emphasise that the function has really changed.&lt;br /&gt;
&lt;br /&gt;
2 The section with nothing in it (DDL) should probably be removed :)&lt;br /&gt;
&lt;br /&gt;
3 &#039;Golden&#039; and &#039;iron&#039; makes no sense at all to me, nor did the explanation. Could we rename these in some way?&lt;br /&gt;
&lt;br /&gt;
4 The example using named params should probably be changed to use better names for the params eg fn, ln - if you&#039;re using &#039;param1&#039; and &#039;param2&#039; you should use use the ordered one.&lt;br /&gt;
&lt;br /&gt;
5 Some of the examples are unnecessarily wordy - for example, why put the array into a variable then call the function? It only has two elements, you can do it in the same line no problem.&lt;br /&gt;
:Wordiness in code samples is perfectly OK, Sam, but you&#039;re free to be more terse in your implementations ;) [[User:Nicolas Connault|Nicolas Connault]] 06:59, 3 June 2008 (CDT)&lt;br /&gt;
::Yes, but my point is that it makes it look bad for people who are having to change. It&#039;s like, OMG! this was one line before and now it&#039;s four! wtf I have to define a separate array every time I scratch my backside! why are you making my life a misery, you unfeeling b****rds!!! That kind of thing. :) I don&#039;t think it makes it easier to understand to show use of a mostly-unnecessary separate variable. [[User:sam marshall|sam marshall]] 06:24, 6 June 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
6 Wow this new system is a fantastic improvement (except for the new IN function which is kind of nasty)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] 04:32, 3 June 2008 (CDT)&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development_talk:DB_layer_2.0_migration_docs&amp;diff=36976</id>
		<title>Development talk:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development_talk:DB_layer_2.0_migration_docs&amp;diff=36976"/>
		<updated>2008-06-03T09:33:41Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* random things */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* The developer reading this article MUST read XMLDB Documentation (at least Introduction + three first Developing section pages) otherwise he&#039;s going to ask plenty of questions :) It could be very good that the first line of this article be: &amp;quot;In order to understand this article you need to know how works the database abstraction layer in Moodle (previous to 2.0)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* API link is broken (=&amp;gt; http://php.moodle.org/ &amp;quot;Server not found&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* We know that some changes need to be done on 2.0. But on what? &lt;br /&gt;
All these examples concerns the glossary module. It would be good to indicate it first. When I read it first, I didn&#039;t really know what was going to be explained in XMLDB changes. In fact all this section is about &amp;quot;Updating your upgrade.php file for Moodle 2.0&amp;quot;. Conclusion: we really need a clear first sentence for the all &amp;quot;XMLDB changes&amp;quot; section. So we know what we are going to read. Once I knew what is about, all was very clear.&lt;br /&gt;
&lt;br /&gt;
* If we don&#039;t make any change on DDL code we shouldn&#039;t make it as a section/block. The DDL section should be a note. If you remove this section don&#039;t forget to update: &amp;quot;Changes below are grouped into 3 main blocks&amp;quot; =&amp;gt; &amp;quot;Changes below are grouped into 2 main blocks&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* DML section:&lt;br /&gt;
this is about to change all DML code, in all Moodle files? I think it miss an introduction line as well.&lt;br /&gt;
&lt;br /&gt;
* Maybe you should use more the word: YOU should do that, YOU do this, YOU ... The developer will feel more guided.&lt;br /&gt;
&lt;br /&gt;
Note: I wrote this comment on first read.&lt;br /&gt;
&lt;br /&gt;
Note 2: I&#039;m new as dev in Moodle, and I&#039;ve just discover all the power of Moodle XMLDB reading. All the current XMLDB looks awesome, I don&#039;t even talk about the coming 2.0 :)&lt;br /&gt;
&lt;br /&gt;
[[User:jerome mouneyrac|jerome mouneyrac]] 22:22, 22 May 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
== random things ==&lt;br /&gt;
&lt;br /&gt;
1 I added a marker re add_index or somesuch, is it really renamed add_key or is that just a copy/paste error? If it is correct, needs changing to emphasise that the function has really changed.&lt;br /&gt;
&lt;br /&gt;
2 The section with nothing in it (DDL) should probably be removed :)&lt;br /&gt;
&lt;br /&gt;
3 &#039;Golden&#039; and &#039;iron&#039; makes no sense at all to me, nor did the explanation. Could we rename these in some way?&lt;br /&gt;
&lt;br /&gt;
4 The example using named params should probably be changed to use better names for the params eg fn, ln - if you&#039;re using &#039;param1&#039; and &#039;param2&#039; you should use use the ordered one.&lt;br /&gt;
&lt;br /&gt;
5 Some of the examples are unnecessarily wordy - for example, why put the array into a variable then call the function? It only has two elements, you can do it in the same line no problem.&lt;br /&gt;
&lt;br /&gt;
6 Wow this new system is a fantastic improvement (except for the new IN function which is kind of nasty)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] 04:32, 3 June 2008 (CDT)&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development_talk:DB_layer_2.0_migration_docs&amp;diff=36973</id>
		<title>Development talk:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development_talk:DB_layer_2.0_migration_docs&amp;diff=36973"/>
		<updated>2008-06-03T09:32:04Z</updated>

		<summary type="html">&lt;p&gt;Quen: random things&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* The developer reading this article MUST read XMLDB Documentation (at least Introduction + three first Developing section pages) otherwise he&#039;s going to ask plenty of questions :) It could be very good that the first line of this article be: &amp;quot;In order to understand this article you need to know how works the database abstraction layer in Moodle (previous to 2.0)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* API link is broken (=&amp;gt; http://php.moodle.org/ &amp;quot;Server not found&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* We know that some changes need to be done on 2.0. But on what? &lt;br /&gt;
All these examples concerns the glossary module. It would be good to indicate it first. When I read it first, I didn&#039;t really know what was going to be explained in XMLDB changes. In fact all this section is about &amp;quot;Updating your upgrade.php file for Moodle 2.0&amp;quot;. Conclusion: we really need a clear first sentence for the all &amp;quot;XMLDB changes&amp;quot; section. So we know what we are going to read. Once I knew what is about, all was very clear.&lt;br /&gt;
&lt;br /&gt;
* If we don&#039;t make any change on DDL code we shouldn&#039;t make it as a section/block. The DDL section should be a note. If you remove this section don&#039;t forget to update: &amp;quot;Changes below are grouped into 3 main blocks&amp;quot; =&amp;gt; &amp;quot;Changes below are grouped into 2 main blocks&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* DML section:&lt;br /&gt;
this is about to change all DML code, in all Moodle files? I think it miss an introduction line as well.&lt;br /&gt;
&lt;br /&gt;
* Maybe you should use more the word: YOU should do that, YOU do this, YOU ... The developer will feel more guided.&lt;br /&gt;
&lt;br /&gt;
Note: I wrote this comment on first read.&lt;br /&gt;
&lt;br /&gt;
Note 2: I&#039;m new as dev in Moodle, and I&#039;ve just discover all the power of Moodle XMLDB reading. All the current XMLDB looks awesome, I don&#039;t even talk about the coming 2.0 :)&lt;br /&gt;
&lt;br /&gt;
[[User:jerome mouneyrac|jerome mouneyrac]] 22:22, 22 May 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
== random things ==&lt;br /&gt;
&lt;br /&gt;
1 I added a marker re add_index or somesuch, is it really renamed add_key or is that just a copy/paste error? If it is correct, needs changing to emphasise that the function has really changed.&lt;br /&gt;
&lt;br /&gt;
2 The section with nothing in it (DDL) should probably be removed :)&lt;br /&gt;
&lt;br /&gt;
3 &#039;Golden&#039; and &#039;iron&#039; makes no sense at all to me, nor did the explanation. Could we rename these in some way?&lt;br /&gt;
&lt;br /&gt;
4 The example using named params should probably be changed to use better names for the params eg fn, ln - if you&#039;re using &#039;param1&#039; and &#039;param2&#039; you should use use the ordered one.&lt;br /&gt;
&lt;br /&gt;
5 Wow this new system is a fantastic improvement (except for the new IN syntax which is horrid)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] 04:32, 3 June 2008 (CDT)&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=36971</id>
		<title>Development:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=36971"/>
		<updated>2008-06-03T09:22:50Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* The changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}{{Template:Development:dmllib 2.0}}__NOTOC__&lt;br /&gt;
This article defines all the changes that need to be performed in Moodle 1.9 code in order to make it run properly under new Moodle 2.0 DB layer. Changes below are grouped into 3 main blocks ([[Development:XMLDB_Documentation|xmldb]], [[wikipedia:Data_Definition_Language|ddl]] and [[wikipedia:Data_Manipulation_Language|dml]]) to have them organised.&lt;br /&gt;
&lt;br /&gt;
Although the order of changes showed in this page isn&#039;t mandatory at all, it can be interesting to follow it in the migration progress to be able to understand and learn a bit more about all them. That way, you&#039;ll end knowing not only what to change but how and why those changes are required.&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to read the whole [[Development:XMLDB_Documentation|XMLDB]], [[wikipedia:Data_Definition_Language|DDL]] and [[wikipedia:Data_Manipulation_Language|DML]] documentation and [http://php.moodle.org APIs] before start with the migration. That will allow you to have some initial knowledge about the new architecture.&lt;br /&gt;
&lt;br /&gt;
Each change will be as simple as possible, representing one easy rule to follow to adapt the code. When anything become too much complex to be explained as one simple rule, it will contain one link to the [[Development:dmllib_2.0_examples|examples page]].&lt;br /&gt;
&lt;br /&gt;
For any problem in the migration of code, it&#039;s recommended to use the [http://moodle.org/mod/forum/view.php?id=45 Databases forum] at [http://moodle.org moodle.org]. Also if you find any bug in the process, pleas report it in the [http://tracker.moodle.org/browse/MDL-14679 Moodle Tracker], that way developers will be able to fix it ASAP.&lt;br /&gt;
&lt;br /&gt;
And finally, feel free to complete/fix the list below with the changes you find in the progress of migration, for sure that will help a lot of developers. Thanks!&lt;br /&gt;
&lt;br /&gt;
== XMLDB changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* When changing DB structures it&#039;s highly recommended to use the XMLDB Editor (Admin-&amp;gt;Misc-&amp;gt;XMLDB Editor). It is a safe way to edit install.xml files and to get correct PHP code to be used in upgrade.php scripts.&lt;br /&gt;
* If you have some doubts about the list of changes below, it&#039;s highly recommended to take a look to some code in core modules, blocks... whatever you need. They are a good reference.&lt;br /&gt;
&lt;br /&gt;
=== The changes ===&lt;br /&gt;
&lt;br /&gt;
* No changes required in install.xml files at all (that&#039;s good news!).&lt;br /&gt;
* All upgrade.php scripts, within the main xxxx_upgrade function must have &#039;&#039;&#039;$DB&#039;&#039;&#039; (uppercase) in the globals declaration (along with others if needed). Example (from glossary module):&lt;br /&gt;
    function xmldb_glossary_upgrade($oldversion=0) {&lt;br /&gt;
    &lt;br /&gt;
        global $CFG, $THEME, $DB;&lt;br /&gt;
* All upgrade.php scripts, must NOT have &#039;&#039;&#039;$db&#039;&#039;&#039; (lowercase) in the globals declaration. Delete it if present.&lt;br /&gt;
* After the global declaration in the points above, this line must be present (we&#039;ll need it later):&lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager(); /// loads ddl manager and xmldb classes&lt;br /&gt;
* All XMLDBTable instances in your upgrade code must be replaced by xmldb_table (parameters are the same, no change with them required)&lt;br /&gt;
* All XMLDBField instances in your upgrade code must be replaced by xmldb_field (no change in parameters)&lt;br /&gt;
* All XMLDBIndex instances in your upgrade code must be replaced by xmldb_index (no change in parameters)&lt;br /&gt;
* All XMLDBKey instances in your upgrade code must be replaced by xmldb_key (no change in parameters)&lt;br /&gt;
* All the addFieldInfo() methods must be replaced by add_field() (no change in parameters)&lt;br /&gt;
* All the addIndexInfo() methods must be replaced by add_key() (no change in parameters) [[User:sam marshall|sam marshall]] I&#039;m guessing this is supposed to be add_index()? Or are indexes the same as keys now?&lt;br /&gt;
* All the addKeyInfo() methods must be replaced by add_key() (no change in parameters)&lt;br /&gt;
* All the setAttributes() methods must be replaced by set_attributes() (no change in parameters)&lt;br /&gt;
* All the DDL functions used in upgrade code, must be transformed as detailed below (it&#039;s only about to add &#039;&#039;&#039;&amp;quot;$dbman-&amp;gt;&amp;quot;&#039;&#039;&#039; - without the quotes - before each function call). No changes in parameters are required:&lt;br /&gt;
    table_exists ==&amp;gt; $dbman-&amp;gt;table_exists&lt;br /&gt;
    field_exists ==&amp;gt; $dbman-&amp;gt;field_exists&lt;br /&gt;
    index_exists ==&amp;gt; $dbman-&amp;gt;index_exists&lt;br /&gt;
    find_index_name ==&amp;gt; $dbman-&amp;gt;find_index_name&lt;br /&gt;
    find_check_constraint_name ==&amp;gt; $dbman-&amp;gt;find_check_constraint_name&lt;br /&gt;
    check_constraint_exists ==&amp;gt; $dbman-&amp;gt;check_constraint_exists&lt;br /&gt;
    find_sequence_name ==&amp;gt; $dbman-&amp;gt;find_sequence_name&lt;br /&gt;
    create_table ==&amp;gt; $dbman-&amp;gt;create_table&lt;br /&gt;
    drop_table ==&amp;gt; $dbman-&amp;gt;drop_table&lt;br /&gt;
    rename_table ==&amp;gt; $dbman-&amp;gt;rename_table&lt;br /&gt;
    add_field ==&amp;gt; $dbman-&amp;gt;add_field&lt;br /&gt;
    drop_field ==&amp;gt; $dbman-&amp;gt;drop field&lt;br /&gt;
    rename_field ==&amp;gt; $dbman-&amp;gt;rename_field&lt;br /&gt;
    change_field_type ==&amp;gt; $dbman-&amp;gt;change_field_type&lt;br /&gt;
    change_field_precision =&amp;gt; $dbman-&amp;gt;change_field_precision&lt;br /&gt;
    change_field_unsigned ==&amp;gt; $dbman-&amp;gt;change_field_unsigned&lt;br /&gt;
    change_field_notnull ==&amp;gt; $dbman-&amp;gt;change_field_notnull&lt;br /&gt;
    change_field_enum ==&amp;gt; $dbman-&amp;gt;change_field_enum&lt;br /&gt;
    change_field_default ==&amp;gt; $dbman-&amp;gt;change_field_default&lt;br /&gt;
    add_key ==&amp;gt; $dbman-&amp;gt;add_key&lt;br /&gt;
    drop_key ==&amp;gt; $dbman-&amp;gt;drop_key&lt;br /&gt;
    add_index ==&amp;gt; $dbman-&amp;gt;add_index&lt;br /&gt;
    drop_index ==&amp;gt; $dbman-&amp;gt;drop_index&lt;br /&gt;
&lt;br /&gt;
== DDL changes ==&lt;br /&gt;
&lt;br /&gt;
You are really lucky! If you&#039;ve performed all the changes above, then all your DDL code has been upgraded successfully! Congrats!&lt;br /&gt;
&lt;br /&gt;
== DML changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* This is, with difference, the complexer part to migrate to have the code working under Moodle 2.0, not because of the complexity of the changes themselves (90% of them will be really easy), but because you&#039;ll need to triple-check everything works as expected after changes.&lt;br /&gt;
&lt;br /&gt;
* Along the changes below, you&#039;ll find links to some examples that will try to make things easier. Anyway, if you are blocked at any point, please ask in forums or tracker (see links at the beginning of the page). Sure it has a good enough solution.&lt;br /&gt;
&lt;br /&gt;
* Once more it&#039;s highly recommended to take a look to Moodle core code, searching for similar examples. Of course, new meaningful examples are welcome, and also any clarification in the list of changes below. Feel free to do it, this is a wiki!&lt;br /&gt;
&lt;br /&gt;
* Finally, one more explanation: The changes below have been split into two sections. First one, (called &#039;&#039;&#039;&amp;quot;The golden changes&amp;quot;&#039;&#039;&#039;) are modifications that must be applied to ALL the transformations defined in the second section (&#039;&#039;&#039;&amp;quot;The iron changes&amp;quot;&#039;&#039;&#039;). Sure you&#039;ll understand that after reading them (it&#039;s basically a matter of not repeating the golden ones within each iron one, just imagine they are everywhere).&lt;br /&gt;
&lt;br /&gt;
=== The golden changes ===&lt;br /&gt;
*Wherever old functions are used (get_record*, get_field*, set_field, insert_record, update_record), the global $DB must be used as the object on which these functions are called (e.g. get_record_select() becomes $DB-&amp;gt;get_record_select()).&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  get_record_select($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  $DB-&amp;gt;get_record_select($sql);&lt;br /&gt;
&lt;br /&gt;
*All the functions that used to accept a list of string params in the form &amp;quot;param1, value1, param2, value2&amp;quot; now need to be given an array of key=&amp;gt;value pairs as a replacement for these params. Other params remain as before. Check the new API for any exceptions. &lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $user = get_record(&amp;quot;user&amp;quot;, &amp;quot;firstname&amp;quot;, &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot;, &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax:&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $conditions = array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  $user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, $conditions);&lt;br /&gt;
&lt;br /&gt;
*rs_fetch_next_record($rs) is deprecated, in favour of the simple foreach($rs as $var). Calls to rs_close() must be replaced by $rs-&amp;gt;close();&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  while($result = rs_fetch_next_record($rs)) {&lt;br /&gt;
      ...&lt;br /&gt;
  }&lt;br /&gt;
  rs_close();&lt;br /&gt;
     &lt;br /&gt;
  // New syntax&lt;br /&gt;
  foreach ($rs as $result) {&lt;br /&gt;
       ....&lt;br /&gt;
  }&lt;br /&gt;
  $rs-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
*All uses of addslashes() must be removed. They are no longer needed&lt;br /&gt;
*Placeholders must be used for table names. Instead of {$CFG-&amp;gt;prefix}tablename, use {tablename}.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {$CFG-&amp;gt;prefix}user&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {user}&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
*When PHP variables are used in SQL queries, they must be replaced by parameters. You have the choice between two approaches: ordered parameters, or named parameters.&lt;br /&gt;
**Ordered parameters use a simple array of values, which are given to the DML function as $params. The values in the SQL code are simply question marks (?) replacing the values. They are replaced by the DML code one by one, substituting each question mark (?) with the next value in the $params array.&lt;br /&gt;
**Named parameters use an associative array of name =&amp;gt; value pairs as the $params array. The values in the SQL code are replaced with a colon (:) followed by the key associated with the value, in the $params array.&lt;br /&gt;
&lt;br /&gt;
  Examples:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {$CFG-&amp;gt;prefix}user WHERE firstname = &#039;Eloy&#039; AND lastname = &#039;Lafuente&#039;&amp;quot;;&lt;br /&gt;
  $user = get_record_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: ordered params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;Eloy&#039;, &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = ? AND lastname = ?&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: named params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;param1&#039; =&amp;gt; &#039;Eloy&#039;, &#039;param2&#039; =&amp;gt; &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = :param1 AND lastname = :param2&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
*Replacement of the IN(...) syntax: We no longer hard-code this in our SQL queries, we use a function which determines whether the IN() syntax is needed, or, if there is only one value to compare, the equal (=) sign can be used.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  $gis = implode(&#039;,&#039;, $depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {$CFG-&amp;gt;prefix}grade_items&lt;br /&gt;
           WHERE id IN ($gis)&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // new syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  list($usql, $params) = $DB-&amp;gt;get_in_or_equal($depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {grade_items}&lt;br /&gt;
           WHERE id $usql&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
=== The iron changes ===&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Development:XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[Development:DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[Development:DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=36970</id>
		<title>Development:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=36970"/>
		<updated>2008-06-03T09:22:34Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* The changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}{{Template:Development:dmllib 2.0}}__NOTOC__&lt;br /&gt;
This article defines all the changes that need to be performed in Moodle 1.9 code in order to make it run properly under new Moodle 2.0 DB layer. Changes below are grouped into 3 main blocks ([[Development:XMLDB_Documentation|xmldb]], [[wikipedia:Data_Definition_Language|ddl]] and [[wikipedia:Data_Manipulation_Language|dml]]) to have them organised.&lt;br /&gt;
&lt;br /&gt;
Although the order of changes showed in this page isn&#039;t mandatory at all, it can be interesting to follow it in the migration progress to be able to understand and learn a bit more about all them. That way, you&#039;ll end knowing not only what to change but how and why those changes are required.&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to read the whole [[Development:XMLDB_Documentation|XMLDB]], [[wikipedia:Data_Definition_Language|DDL]] and [[wikipedia:Data_Manipulation_Language|DML]] documentation and [http://php.moodle.org APIs] before start with the migration. That will allow you to have some initial knowledge about the new architecture.&lt;br /&gt;
&lt;br /&gt;
Each change will be as simple as possible, representing one easy rule to follow to adapt the code. When anything become too much complex to be explained as one simple rule, it will contain one link to the [[Development:dmllib_2.0_examples|examples page]].&lt;br /&gt;
&lt;br /&gt;
For any problem in the migration of code, it&#039;s recommended to use the [http://moodle.org/mod/forum/view.php?id=45 Databases forum] at [http://moodle.org moodle.org]. Also if you find any bug in the process, pleas report it in the [http://tracker.moodle.org/browse/MDL-14679 Moodle Tracker], that way developers will be able to fix it ASAP.&lt;br /&gt;
&lt;br /&gt;
And finally, feel free to complete/fix the list below with the changes you find in the progress of migration, for sure that will help a lot of developers. Thanks!&lt;br /&gt;
&lt;br /&gt;
== XMLDB changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* When changing DB structures it&#039;s highly recommended to use the XMLDB Editor (Admin-&amp;gt;Misc-&amp;gt;XMLDB Editor). It is a safe way to edit install.xml files and to get correct PHP code to be used in upgrade.php scripts.&lt;br /&gt;
* If you have some doubts about the list of changes below, it&#039;s highly recommended to take a look to some code in core modules, blocks... whatever you need. They are a good reference.&lt;br /&gt;
&lt;br /&gt;
=== The changes ===&lt;br /&gt;
&lt;br /&gt;
* No changes required in install.xml files at all (that&#039;s good news!).&lt;br /&gt;
* All upgrade.php scripts, within the main xxxx_upgrade function must have &#039;&#039;&#039;$DB&#039;&#039;&#039; (uppercase) in the globals declaration (along with others if needed). Example (from glossary module):&lt;br /&gt;
    function xmldb_glossary_upgrade($oldversion=0) {&lt;br /&gt;
    &lt;br /&gt;
        global $CFG, $THEME, $DB;&lt;br /&gt;
* All upgrade.php scripts, must NOT have &#039;&#039;&#039;$db&#039;&#039;&#039; (lowercase) in the globals declaration. Delete it if present.&lt;br /&gt;
* After the global declaration in the points above, this line must be present (we&#039;ll need it later):&lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager(); /// loads ddl manager and xmldb classes&lt;br /&gt;
* All XMLDBTable instances in your upgrade code must be replaced by xmldb_table (parameters are the same, no change with them required)&lt;br /&gt;
* All XMLDBField instances in your upgrade code must be replaced by xmldb_field (no change in parameters)&lt;br /&gt;
* All XMLDBIndex instances in your upgrade code must be replaced by xmldb_index (no change in parameters)&lt;br /&gt;
* All XMLDBKey instances in your upgrade code must be replaced by xmldb_key (no change in parameters)&lt;br /&gt;
* All the addFieldInfo() methods must be replaced by add_field() (no change in parameters)&lt;br /&gt;
* All the addIndexInfo() methods must be replaced by add_key() (no change in parameters) ~~ I&#039;m guessing this is supposed to be add_index()? Or are indexes the same as keys now?&lt;br /&gt;
* All the addKeyInfo() methods must be replaced by add_key() (no change in parameters)&lt;br /&gt;
* All the setAttributes() methods must be replaced by set_attributes() (no change in parameters)&lt;br /&gt;
* All the DDL functions used in upgrade code, must be transformed as detailed below (it&#039;s only about to add &#039;&#039;&#039;&amp;quot;$dbman-&amp;gt;&amp;quot;&#039;&#039;&#039; - without the quotes - before each function call). No changes in parameters are required:&lt;br /&gt;
    table_exists ==&amp;gt; $dbman-&amp;gt;table_exists&lt;br /&gt;
    field_exists ==&amp;gt; $dbman-&amp;gt;field_exists&lt;br /&gt;
    index_exists ==&amp;gt; $dbman-&amp;gt;index_exists&lt;br /&gt;
    find_index_name ==&amp;gt; $dbman-&amp;gt;find_index_name&lt;br /&gt;
    find_check_constraint_name ==&amp;gt; $dbman-&amp;gt;find_check_constraint_name&lt;br /&gt;
    check_constraint_exists ==&amp;gt; $dbman-&amp;gt;check_constraint_exists&lt;br /&gt;
    find_sequence_name ==&amp;gt; $dbman-&amp;gt;find_sequence_name&lt;br /&gt;
    create_table ==&amp;gt; $dbman-&amp;gt;create_table&lt;br /&gt;
    drop_table ==&amp;gt; $dbman-&amp;gt;drop_table&lt;br /&gt;
    rename_table ==&amp;gt; $dbman-&amp;gt;rename_table&lt;br /&gt;
    add_field ==&amp;gt; $dbman-&amp;gt;add_field&lt;br /&gt;
    drop_field ==&amp;gt; $dbman-&amp;gt;drop field&lt;br /&gt;
    rename_field ==&amp;gt; $dbman-&amp;gt;rename_field&lt;br /&gt;
    change_field_type ==&amp;gt; $dbman-&amp;gt;change_field_type&lt;br /&gt;
    change_field_precision =&amp;gt; $dbman-&amp;gt;change_field_precision&lt;br /&gt;
    change_field_unsigned ==&amp;gt; $dbman-&amp;gt;change_field_unsigned&lt;br /&gt;
    change_field_notnull ==&amp;gt; $dbman-&amp;gt;change_field_notnull&lt;br /&gt;
    change_field_enum ==&amp;gt; $dbman-&amp;gt;change_field_enum&lt;br /&gt;
    change_field_default ==&amp;gt; $dbman-&amp;gt;change_field_default&lt;br /&gt;
    add_key ==&amp;gt; $dbman-&amp;gt;add_key&lt;br /&gt;
    drop_key ==&amp;gt; $dbman-&amp;gt;drop_key&lt;br /&gt;
    add_index ==&amp;gt; $dbman-&amp;gt;add_index&lt;br /&gt;
    drop_index ==&amp;gt; $dbman-&amp;gt;drop_index&lt;br /&gt;
&lt;br /&gt;
== DDL changes ==&lt;br /&gt;
&lt;br /&gt;
You are really lucky! If you&#039;ve performed all the changes above, then all your DDL code has been upgraded successfully! Congrats!&lt;br /&gt;
&lt;br /&gt;
== DML changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* This is, with difference, the complexer part to migrate to have the code working under Moodle 2.0, not because of the complexity of the changes themselves (90% of them will be really easy), but because you&#039;ll need to triple-check everything works as expected after changes.&lt;br /&gt;
&lt;br /&gt;
* Along the changes below, you&#039;ll find links to some examples that will try to make things easier. Anyway, if you are blocked at any point, please ask in forums or tracker (see links at the beginning of the page). Sure it has a good enough solution.&lt;br /&gt;
&lt;br /&gt;
* Once more it&#039;s highly recommended to take a look to Moodle core code, searching for similar examples. Of course, new meaningful examples are welcome, and also any clarification in the list of changes below. Feel free to do it, this is a wiki!&lt;br /&gt;
&lt;br /&gt;
* Finally, one more explanation: The changes below have been split into two sections. First one, (called &#039;&#039;&#039;&amp;quot;The golden changes&amp;quot;&#039;&#039;&#039;) are modifications that must be applied to ALL the transformations defined in the second section (&#039;&#039;&#039;&amp;quot;The iron changes&amp;quot;&#039;&#039;&#039;). Sure you&#039;ll understand that after reading them (it&#039;s basically a matter of not repeating the golden ones within each iron one, just imagine they are everywhere).&lt;br /&gt;
&lt;br /&gt;
=== The golden changes ===&lt;br /&gt;
*Wherever old functions are used (get_record*, get_field*, set_field, insert_record, update_record), the global $DB must be used as the object on which these functions are called (e.g. get_record_select() becomes $DB-&amp;gt;get_record_select()).&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  get_record_select($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  $DB-&amp;gt;get_record_select($sql);&lt;br /&gt;
&lt;br /&gt;
*All the functions that used to accept a list of string params in the form &amp;quot;param1, value1, param2, value2&amp;quot; now need to be given an array of key=&amp;gt;value pairs as a replacement for these params. Other params remain as before. Check the new API for any exceptions. &lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $user = get_record(&amp;quot;user&amp;quot;, &amp;quot;firstname&amp;quot;, &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot;, &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax:&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $conditions = array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  $user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, $conditions);&lt;br /&gt;
&lt;br /&gt;
*rs_fetch_next_record($rs) is deprecated, in favour of the simple foreach($rs as $var). Calls to rs_close() must be replaced by $rs-&amp;gt;close();&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  while($result = rs_fetch_next_record($rs)) {&lt;br /&gt;
      ...&lt;br /&gt;
  }&lt;br /&gt;
  rs_close();&lt;br /&gt;
     &lt;br /&gt;
  // New syntax&lt;br /&gt;
  foreach ($rs as $result) {&lt;br /&gt;
       ....&lt;br /&gt;
  }&lt;br /&gt;
  $rs-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
*All uses of addslashes() must be removed. They are no longer needed&lt;br /&gt;
*Placeholders must be used for table names. Instead of {$CFG-&amp;gt;prefix}tablename, use {tablename}.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {$CFG-&amp;gt;prefix}user&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {user}&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
*When PHP variables are used in SQL queries, they must be replaced by parameters. You have the choice between two approaches: ordered parameters, or named parameters.&lt;br /&gt;
**Ordered parameters use a simple array of values, which are given to the DML function as $params. The values in the SQL code are simply question marks (?) replacing the values. They are replaced by the DML code one by one, substituting each question mark (?) with the next value in the $params array.&lt;br /&gt;
**Named parameters use an associative array of name =&amp;gt; value pairs as the $params array. The values in the SQL code are replaced with a colon (:) followed by the key associated with the value, in the $params array.&lt;br /&gt;
&lt;br /&gt;
  Examples:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {$CFG-&amp;gt;prefix}user WHERE firstname = &#039;Eloy&#039; AND lastname = &#039;Lafuente&#039;&amp;quot;;&lt;br /&gt;
  $user = get_record_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: ordered params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;Eloy&#039;, &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = ? AND lastname = ?&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: named params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;param1&#039; =&amp;gt; &#039;Eloy&#039;, &#039;param2&#039; =&amp;gt; &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = :param1 AND lastname = :param2&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
*Replacement of the IN(...) syntax: We no longer hard-code this in our SQL queries, we use a function which determines whether the IN() syntax is needed, or, if there is only one value to compare, the equal (=) sign can be used.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  $gis = implode(&#039;,&#039;, $depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {$CFG-&amp;gt;prefix}grade_items&lt;br /&gt;
           WHERE id IN ($gis)&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // new syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  list($usql, $params) = $DB-&amp;gt;get_in_or_equal($depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {grade_items}&lt;br /&gt;
           WHERE id $usql&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
=== The iron changes ===&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Development:XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[Development:DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[Development:DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=36969</id>
		<title>Development:DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:DB_layer_2.0_migration_docs&amp;diff=36969"/>
		<updated>2008-06-03T09:20:52Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Some comments */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}{{Template:Development:dmllib 2.0}}__NOTOC__&lt;br /&gt;
This article defines all the changes that need to be performed in Moodle 1.9 code in order to make it run properly under new Moodle 2.0 DB layer. Changes below are grouped into 3 main blocks ([[Development:XMLDB_Documentation|xmldb]], [[wikipedia:Data_Definition_Language|ddl]] and [[wikipedia:Data_Manipulation_Language|dml]]) to have them organised.&lt;br /&gt;
&lt;br /&gt;
Although the order of changes showed in this page isn&#039;t mandatory at all, it can be interesting to follow it in the migration progress to be able to understand and learn a bit more about all them. That way, you&#039;ll end knowing not only what to change but how and why those changes are required.&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to read the whole [[Development:XMLDB_Documentation|XMLDB]], [[wikipedia:Data_Definition_Language|DDL]] and [[wikipedia:Data_Manipulation_Language|DML]] documentation and [http://php.moodle.org APIs] before start with the migration. That will allow you to have some initial knowledge about the new architecture.&lt;br /&gt;
&lt;br /&gt;
Each change will be as simple as possible, representing one easy rule to follow to adapt the code. When anything become too much complex to be explained as one simple rule, it will contain one link to the [[Development:dmllib_2.0_examples|examples page]].&lt;br /&gt;
&lt;br /&gt;
For any problem in the migration of code, it&#039;s recommended to use the [http://moodle.org/mod/forum/view.php?id=45 Databases forum] at [http://moodle.org moodle.org]. Also if you find any bug in the process, pleas report it in the [http://tracker.moodle.org/browse/MDL-14679 Moodle Tracker], that way developers will be able to fix it ASAP.&lt;br /&gt;
&lt;br /&gt;
And finally, feel free to complete/fix the list below with the changes you find in the progress of migration, for sure that will help a lot of developers. Thanks!&lt;br /&gt;
&lt;br /&gt;
== XMLDB changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* When changing DB structures it&#039;s highly recommended to use the XMLDB Editor (Admin-&amp;gt;Misc-&amp;gt;XMLDB Editor). It is a safe way to edit install.xml files and to get correct PHP code to be used in upgrade.php scripts.&lt;br /&gt;
* If you have some doubts about the list of changes below, it&#039;s highly recommended to take a look to some code in core modules, blocks... whatever you need. They are a good reference.&lt;br /&gt;
&lt;br /&gt;
=== The changes ===&lt;br /&gt;
&lt;br /&gt;
* No changes required in install.xml files at all (that&#039;s good news!).&lt;br /&gt;
* All upgrade.php scripts, within the main xxxx_upgrade function must have &#039;&#039;&#039;$DB&#039;&#039;&#039; (uppercase) in the globals declaration (along with others if needed). Example (from glossary module):&lt;br /&gt;
    function xmldb_glossary_upgrade($oldversion=0) {&lt;br /&gt;
    &lt;br /&gt;
        global $CFG, $THEME, $DB;&lt;br /&gt;
* All upgrade.php scripts, must NOT have &#039;&#039;&#039;$db&#039;&#039;&#039; (lowercase) in the globals declaration. Delete it if present.&lt;br /&gt;
* After the global declaration in the points above, this line must be present (we&#039;ll need it later):&lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager(); /// loads ddl manager and xmldb classes&lt;br /&gt;
* All XMLDBTable instances in your upgrade code must be replaced by xmldb_table (parameters are the same, no change with them required)&lt;br /&gt;
* All XMLDBField instances in your upgrade code must be replaced by xmldb_field (no change in parameters)&lt;br /&gt;
* All XMLDBIndex instances in your upgrade code must be replaced by xmldb_index (no change in parameters)&lt;br /&gt;
* All XMLDBKey instances in your upgrade code must be replaced by xmldb_key (no change in parameters)&lt;br /&gt;
* All the addFieldInfo() methods must be replaced by add_field() (no change in parameters)&lt;br /&gt;
* All the addIndexInfo() methods must be replaced by add_key() (no change in parameters)&lt;br /&gt;
* All the addKeyInfo() methods must be replaced by add_key() (no change in parameters)&lt;br /&gt;
* All the setAttributes() methods must be replaced by set_attributes() (no change in parameters)&lt;br /&gt;
* All the DDL functions used in upgrade code, must be transformed as detailed below (it&#039;s only about to add &#039;&#039;&#039;&amp;quot;$dbman-&amp;gt;&amp;quot;&#039;&#039;&#039; - without the quotes - before each function call). No changes in parameters are required:&lt;br /&gt;
    table_exists ==&amp;gt; $dbman-&amp;gt;table_exists&lt;br /&gt;
    field_exists ==&amp;gt; $dbman-&amp;gt;field_exists&lt;br /&gt;
    index_exists ==&amp;gt; $dbman-&amp;gt;index_exists&lt;br /&gt;
    find_index_name ==&amp;gt; $dbman-&amp;gt;find_index_name&lt;br /&gt;
    find_check_constraint_name ==&amp;gt; $dbman-&amp;gt;find_check_constraint_name&lt;br /&gt;
    check_constraint_exists ==&amp;gt; $dbman-&amp;gt;check_constraint_exists&lt;br /&gt;
    find_sequence_name ==&amp;gt; $dbman-&amp;gt;find_sequence_name&lt;br /&gt;
    create_table ==&amp;gt; $dbman-&amp;gt;create_table&lt;br /&gt;
    drop_table ==&amp;gt; $dbman-&amp;gt;drop_table&lt;br /&gt;
    rename_table ==&amp;gt; $dbman-&amp;gt;rename_table&lt;br /&gt;
    add_field ==&amp;gt; $dbman-&amp;gt;add_field&lt;br /&gt;
    drop_field ==&amp;gt; $dbman-&amp;gt;drop field&lt;br /&gt;
    rename_field ==&amp;gt; $dbman-&amp;gt;rename_field&lt;br /&gt;
    change_field_type ==&amp;gt; $dbman-&amp;gt;change_field_type&lt;br /&gt;
    change_field_precision =&amp;gt; $dbman-&amp;gt;change_field_precision&lt;br /&gt;
    change_field_unsigned ==&amp;gt; $dbman-&amp;gt;change_field_unsigned&lt;br /&gt;
    change_field_notnull ==&amp;gt; $dbman-&amp;gt;change_field_notnull&lt;br /&gt;
    change_field_enum ==&amp;gt; $dbman-&amp;gt;change_field_enum&lt;br /&gt;
    change_field_default ==&amp;gt; $dbman-&amp;gt;change_field_default&lt;br /&gt;
    add_key ==&amp;gt; $dbman-&amp;gt;add_key&lt;br /&gt;
    drop_key ==&amp;gt; $dbman-&amp;gt;drop_key&lt;br /&gt;
    add_index ==&amp;gt; $dbman-&amp;gt;add_index&lt;br /&gt;
    drop_index ==&amp;gt; $dbman-&amp;gt;drop_index&lt;br /&gt;
&lt;br /&gt;
== DDL changes ==&lt;br /&gt;
&lt;br /&gt;
You are really lucky! If you&#039;ve performed all the changes above, then all your DDL code has been upgraded successfully! Congrats!&lt;br /&gt;
&lt;br /&gt;
== DML changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* This is, with difference, the complexer part to migrate to have the code working under Moodle 2.0, not because of the complexity of the changes themselves (90% of them will be really easy), but because you&#039;ll need to triple-check everything works as expected after changes.&lt;br /&gt;
&lt;br /&gt;
* Along the changes below, you&#039;ll find links to some examples that will try to make things easier. Anyway, if you are blocked at any point, please ask in forums or tracker (see links at the beginning of the page). Sure it has a good enough solution.&lt;br /&gt;
&lt;br /&gt;
* Once more it&#039;s highly recommended to take a look to Moodle core code, searching for similar examples. Of course, new meaningful examples are welcome, and also any clarification in the list of changes below. Feel free to do it, this is a wiki!&lt;br /&gt;
&lt;br /&gt;
* Finally, one more explanation: The changes below have been split into two sections. First one, (called &#039;&#039;&#039;&amp;quot;The golden changes&amp;quot;&#039;&#039;&#039;) are modifications that must be applied to ALL the transformations defined in the second section (&#039;&#039;&#039;&amp;quot;The iron changes&amp;quot;&#039;&#039;&#039;). Sure you&#039;ll understand that after reading them (it&#039;s basically a matter of not repeating the golden ones within each iron one, just imagine they are everywhere).&lt;br /&gt;
&lt;br /&gt;
=== The golden changes ===&lt;br /&gt;
*Wherever old functions are used (get_record*, get_field*, set_field, insert_record, update_record), the global $DB must be used as the object on which these functions are called (e.g. get_record_select() becomes $DB-&amp;gt;get_record_select()).&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  get_record_select($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
  $DB-&amp;gt;get_record_select($sql);&lt;br /&gt;
&lt;br /&gt;
*All the functions that used to accept a list of string params in the form &amp;quot;param1, value1, param2, value2&amp;quot; now need to be given an array of key=&amp;gt;value pairs as a replacement for these params. Other params remain as before. Check the new API for any exceptions. &lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $user = get_record(&amp;quot;user&amp;quot;, &amp;quot;firstname&amp;quot;, &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot;, &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax:&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $conditions = array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Eloy&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Lafuente&amp;quot;);&lt;br /&gt;
  $user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, $conditions);&lt;br /&gt;
&lt;br /&gt;
*rs_fetch_next_record($rs) is deprecated, in favour of the simple foreach($rs as $var). Calls to rs_close() must be replaced by $rs-&amp;gt;close();&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  while($result = rs_fetch_next_record($rs)) {&lt;br /&gt;
      ...&lt;br /&gt;
  }&lt;br /&gt;
  rs_close();&lt;br /&gt;
     &lt;br /&gt;
  // New syntax&lt;br /&gt;
  foreach ($rs as $result) {&lt;br /&gt;
       ....&lt;br /&gt;
  }&lt;br /&gt;
  $rs-&amp;gt;close();&lt;br /&gt;
&lt;br /&gt;
*All uses of addslashes() must be removed. They are no longer needed&lt;br /&gt;
*Placeholders must be used for table names. Instead of {$CFG-&amp;gt;prefix}tablename, use {tablename}.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {$CFG-&amp;gt;prefix}user&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
  // New syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT * FROM {user}&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
*When PHP variables are used in SQL queries, they must be replaced by parameters. You have the choice between two approaches: ordered parameters, or named parameters.&lt;br /&gt;
**Ordered parameters use a simple array of values, which are given to the DML function as $params. The values in the SQL code are simply question marks (?) replacing the values. They are replaced by the DML code one by one, substituting each question mark (?) with the next value in the $params array.&lt;br /&gt;
**Named parameters use an associative array of name =&amp;gt; value pairs as the $params array. The values in the SQL code are replaced with a colon (:) followed by the key associated with the value, in the $params array.&lt;br /&gt;
&lt;br /&gt;
  Examples:&lt;br /&gt;
  // Old syntax&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {$CFG-&amp;gt;prefix}user WHERE firstname = &#039;Eloy&#039; AND lastname = &#039;Lafuente&#039;&amp;quot;;&lt;br /&gt;
  $user = get_record_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: ordered params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;Eloy&#039;, &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = ? AND lastname = ?&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
  &lt;br /&gt;
  // New syntax: named params&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $params = array(&#039;param1&#039; =&amp;gt; &#039;Eloy&#039;, &#039;param2&#039; =&amp;gt; &#039;Lafuente&#039;);&lt;br /&gt;
  $sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = :param1 AND lastname = :param2&amp;quot;;&lt;br /&gt;
  $user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
*Replacement of the IN(...) syntax: We no longer hard-code this in our SQL queries, we use a function which determines whether the IN() syntax is needed, or, if there is only one value to compare, the equal (=) sign can be used.&lt;br /&gt;
&lt;br /&gt;
  Example:&lt;br /&gt;
  // Old syntax:&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  $gis = implode(&#039;,&#039;, $depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {$CFG-&amp;gt;prefix}grade_items&lt;br /&gt;
           WHERE id IN ($gis)&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
  // new syntax&lt;br /&gt;
  global $DB;&lt;br /&gt;
  $depends_on = array(1, 43, 553);&lt;br /&gt;
  list($usql, $params) = $DB-&amp;gt;get_in_or_equal($depends_on);&lt;br /&gt;
  $sql = &amp;quot;SELECT *&lt;br /&gt;
            FROM {grade_items}&lt;br /&gt;
           WHERE id $usql&amp;quot;;&lt;br /&gt;
  $items = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
=== The iron changes ===&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Development:XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[Development:DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[Development:DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34926</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34926"/>
		<updated>2008-04-17T15:57:10Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* sam&amp;#039;s picture */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] For us and no doubt other places, the &#039;activity completion&#039; part of the system is still useful even if we are not using conditional activities for a course. We would then want a reporting interface so that tutors can see which tracked activities their students have/haven&#039;t completed. (And for course staff, obviously they would be able to see all students on the course in the same manner.)&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. Would be stored in course_modules_avail&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] How is this defined? I think it probably needs a way to specify conditions for the course.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status&lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] I think modulespecific is difficult to handle here because it probably needs to be set per module (i.e. typically in the module settings page and stored in the module&#039;s main table). Suggest moving to the _done table.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Eloy suggested we should only store conditions in one place (as opposed to the A/B above) but I see the possible need for several e.g. a quiz, you want one activity that shows if you get &amp;gt; 80% and another one that shows only if you get &amp;lt;80%. However I think this could still be simplified - how about putting the &#039;grade&#039; stuff ONLY in this &#039;avail&#039; table (so your choice for avail is basically always &#039;require the activity to think it&#039;s done, however it likes&#039; but then you can additionally require a grade as well). So done = completed regardless of grade or anything else, but avail could be conditional on grade.&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
==sam&#039;s picture==&lt;br /&gt;
&lt;br /&gt;
This diagram shows sam&#039;s idea of how it should look/work, which is not quite the same as the original description above. It definitely isn&#039;t intended to be final in any way as features might need to be removed (or added or changed) etc. - I just did a diagram to illustrate my thinking.&lt;br /&gt;
&lt;br /&gt;
[[Image:conditional.png|Possible interface diagram]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34925</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34925"/>
		<updated>2008-04-17T15:54:11Z</updated>

		<summary type="html">&lt;p&gt;Quen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] For us and no doubt other places, the &#039;activity completion&#039; part of the system is still useful even if we are not using conditional activities for a course. We would then want a reporting interface so that tutors can see which tracked activities their students have/haven&#039;t completed. (And for course staff, obviously they would be able to see all students on the course in the same manner.)&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. Would be stored in course_modules_avail&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] How is this defined? I think it probably needs a way to specify conditions for the course.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status&lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] I think modulespecific is difficult to handle here because it probably needs to be set per module (i.e. typically in the module settings page and stored in the module&#039;s main table). Suggest moving to the _done table.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Eloy suggested we should only store conditions in one place (as opposed to the A/B above) but I see the possible need for several e.g. a quiz, you want one activity that shows if you get &amp;gt; 80% and another one that shows only if you get &amp;lt;80%. However I think this could still be simplified - how about putting the &#039;grade&#039; stuff ONLY in this &#039;avail&#039; table (so your choice for avail is basically always &#039;require the activity to think it&#039;s done, however it likes&#039; but then you can additionally require a grade as well). So done = completed regardless of grade or anything else, but avail could be conditional on grade.&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
==sam&#039;s picture==&lt;br /&gt;
&lt;br /&gt;
This diagram shows sam&#039;s idea of how it should look/work, which is not quite the same as the original description above. It definitely isn&#039;t intended to be final in any way as features might need to be removed (or added) etc.&lt;br /&gt;
&lt;br /&gt;
[[Image:conditional.png|Possible interface diagram]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=File:conditional.png&amp;diff=34924</id>
		<title>File:conditional.png</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=File:conditional.png&amp;diff=34924"/>
		<updated>2008-04-17T15:51:22Z</updated>

		<summary type="html">&lt;p&gt;Quen: Diagram of possible interface for conditional activities options (very early draft)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of possible interface for conditional activities options (very early draft)&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34913</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34913"/>
		<updated>2008-04-17T12:11:34Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* course_modules_avail */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] For us and no doubt other places, the &#039;activity completion&#039; part of the system is still useful even if we are not using conditional activities for a course. We would then want a reporting interface so that tutors can see which tracked activities their students have/haven&#039;t completed. (And for course staff, obviously they would be able to see all students on the course in the same manner.)&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. Would be stored in course_modules_avail&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] How is this defined? I think it probably needs a way to specify conditions for the course.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status&lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] I think modulespecific is difficult to handle here because it probably needs to be set per module (i.e. typically in the module settings page and stored in the module&#039;s main table). Suggest moving to the _done table.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Eloy suggested we should only store conditions in one place (as opposed to the A/B above) but I see the possible need for several e.g. a quiz, you want one activity that shows if you get &amp;gt; 80% and another one that shows only if you get &amp;lt;80%. However I think this could still be simplified - how about putting the &#039;grade&#039; stuff ONLY in this &#039;avail&#039; table (so your choice for avail is basically always &#039;require the activity to think it&#039;s done, however it likes&#039; but then you can additionally require a grade as well). So done = completed regardless of grade or anything else, but avail could be conditional on grade.&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34912</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34912"/>
		<updated>2008-04-17T12:06:37Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* course_completion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] For us and no doubt other places, the &#039;activity completion&#039; part of the system is still useful even if we are not using conditional activities for a course. We would then want a reporting interface so that tutors can see which tracked activities their students have/haven&#039;t completed. (And for course staff, obviously they would be able to see all students on the course in the same manner.)&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. Would be stored in course_modules_avail&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] How is this defined? I think it probably needs a way to specify conditions for the course.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status&lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34909</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34909"/>
		<updated>2008-04-17T11:51:11Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* This activity will be available when ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] For us and no doubt other places, the &#039;activity completion&#039; part of the system is still useful even if we are not using conditional activities for a course. We would then want a reporting interface so that tutors can see which tracked activities their students have/haven&#039;t completed. (And for course staff, obviously they would be able to see all students on the course in the same manner.)&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. Would be stored in course_modules_avail&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status &lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34908</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34908"/>
		<updated>2008-04-17T11:43:44Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Objectives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] For us and no doubt other places, the &#039;activity completion&#039; part of the system is still useful even if we are not using conditional activities for a course. We would then want a reporting interface so that tutors can see which tracked activities their students have/haven&#039;t completed. (And for course staff, obviously they would be able to see all students on the course in the same manner.)&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. This may complicate the design slightly as obviously date is not a per-other-activity option&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status &lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34900</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34900"/>
		<updated>2008-04-17T10:02:15Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* This activity will be completed when ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. This may complicate the design slightly as obviously date is not a per-other-activity option&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status &lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34899</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34899"/>
		<updated>2008-04-17T10:01:38Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* This activity will be available when ... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. This may complicate the design slightly as obviously date is not a per-other-activity option&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Maybe consider also an option for whether the activity is visible before it is available, greyed out with a &#039;This activity will be available when...&#039; note, or not displayed at all.&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Just wondering, how are you going to track &#039;viewed&#039;? Modules don&#039;t store this in a sensible way, only in the log table.&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status &lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34898</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34898"/>
		<updated>2008-04-17T10:00:32Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Course page */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] At the OU we use an option that controls who sees the checkbox. Remember course:participate? YES IT&#039;S THAT AGAIN. Not that it is really really desperately needed or anything. Ahem. But anyhow, we have a specific permission for who the progress system applies to, and this is checked with doanything=false. You might need something similar.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. This may complicate the design slightly as obviously date is not a per-other-activity option&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Just wondering, how are you going to track &#039;viewed&#039;? Modules don&#039;t store this in a sensible way, only in the log table.&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status &lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34897</id>
		<title>Development:Conditional activities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Development:Conditional_activities&amp;diff=34897"/>
		<updated>2008-04-17T09:59:20Z</updated>

		<summary type="html">&lt;p&gt;Quen: /* Course page */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a developer&#039;s page for Moodle Version 2.0, describing an evolving specification.  UNDER CONSTRUCTION!&lt;br /&gt;
&lt;br /&gt;
Conditional activities allow the course editor to hide certain activities until conditions on other activities have been met.  &lt;br /&gt;
&lt;br /&gt;
For example, a student will not see Assignment B until they have scored 80% or higher on Quiz A. &lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# We want to know when activities are finished (for each user independently)&lt;br /&gt;
# We want to have this calculated automatically, but also manually if required.&lt;br /&gt;
# We want other some activities to be hidden until other activities are done.&lt;br /&gt;
# We want to &amp;quot;chain&amp;quot; these things into learning paths.&lt;br /&gt;
# We want the course page to remain fast.&lt;br /&gt;
# We want conditional activities to be optional.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
There are two main approaches to this.  For the discussion below let&#039;s use A to mean a source activity, and B and C to mean two activities that are only available when A is done.&lt;br /&gt;
&lt;br /&gt;
Approach 1: The one used by activity locking is to place the UI to choose the conditions in B, so that it specifies the passing grades etc that are needed for A so that B is unlocked.  This has advantages in that B can specify a different passing grade that C (both on the same A).&lt;br /&gt;
&lt;br /&gt;
Approach 2: This places the logic in A, so that it defines when it is &amp;quot;done&amp;quot; any way it likes and B can just say &amp;quot;I&#039;m available when A is done&amp;quot;.  The advantages here are that A can define &amp;quot;done&amp;quot; in any way it likes, and the configuration can be more subtle if the module wants it.&lt;br /&gt;
&lt;br /&gt;
The approach described below actually combines BOTH these approaches so it should please everyone and allow the maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
==Interfaces== &lt;br /&gt;
&lt;br /&gt;
===Site settings===&lt;br /&gt;
&lt;br /&gt;
Admins can turn Conditional Activities on/off for the whole site.&lt;br /&gt;
&lt;br /&gt;
===Course settings===&lt;br /&gt;
&lt;br /&gt;
Teachers can choose between three states for a course:&lt;br /&gt;
# Conditional Activities off&lt;br /&gt;
# Conditional Activities Manual&lt;br /&gt;
# Conditional Activities Auto &lt;br /&gt;
&lt;br /&gt;
===Course page===&lt;br /&gt;
&lt;br /&gt;
For teachers&lt;br /&gt;
* Each activity will have an icon indicating the status, and clicking on it takes you to the activity settings (see below).  These are also available as a tab from the main activity pages.&lt;br /&gt;
&lt;br /&gt;
For students&lt;br /&gt;
* Colour icons (checkboxes) in red/orange/green down the side of the course format indicate the status of each activity&lt;br /&gt;
* In manual mode, these can be clicked on to toggle the status as required (so that students can manually keep track of what they&#039;ve done).&lt;br /&gt;
* In auto mode, these icons are fixed&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Be very careful with colours. You mustn&#039;t use colour as only way of displaying information (accessibility). I&#039;d suggest something like: For manual mode, use straightforward checkbox as above; For auto mode, use an icon as described but make these look different as well as different colour (I&#039;d suggest grey crosshatching for unavailable, white (hollow w/black outline) for available but not done, green tick inside box for done-pass, red cross inside box for done-fail) and of course include alt text&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] &#039;Manual&#039; and &#039;Auto&#039; modes maybe needs rethinking. I think this should be actually be a choice of &#039;disable system&#039; (why? well, anyway), &#039;enable system&#039;, and &#039;enable system plus student progress&#039;. These are equiv to off, auto, and auto+manual. The reason for this is that if you specify conditions for something you always want it to be &#039;auto&#039; obviously. But, anything you didn&#039;t specify conditions for, it could be &#039;manual&#039; (i.e. you want students to track progress on some things that are not trackable automatically, e.g. &#039;go and read this web link&#039; (a link) or &#039;go and read the book we sent you&#039; (a label)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] If this approach is adopted (or anyway for standard manual), it needs a way to turn off progress support per-activity, this could be in course_modules or whatever. For example you don&#039;t want to include a &#039;progress&#039; box on something like a generic course forum that is available for the life of the course, or a course resources page that&#039;s similar, or a page about how to contact student support. We do this because in editing mode, our checkboxes include a tiny little eye icon next to them so you can hide them where they aren&#039;t needed. Maybe also appropriate to set defaults i.e. labels default to not having progress.&lt;br /&gt;
&lt;br /&gt;
===Activity settings===&lt;br /&gt;
&lt;br /&gt;
When the teacher is editing the activity settings for each activity, they see two parts to the page:&lt;br /&gt;
&lt;br /&gt;
====This activity will be available when ...====&lt;br /&gt;
&lt;br /&gt;
The UI here is standard for all modules. (Settings are stored in the &#039;&#039;&#039;course_modules_avail&#039;&#039;&#039; table.)  It shows all the other activities in the course, and beside each of them are menus to choose from:&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Completed (as defined by that activity)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Should also include date as a condition. This may complicate the design slightly as obviously date is not a per-other-activity option&lt;br /&gt;
&lt;br /&gt;
====This activity will be completed when ...====&lt;br /&gt;
&lt;br /&gt;
This UI shows optional settings for this activity to define when it thinks it is finished.  (Settings are stored in &#039;&#039;&#039;course_modules_done&#039;&#039;&#039; table):&lt;br /&gt;
* Grade &amp;gt;= X  (&amp;lt;, &amp;lt;=, &amp;gt;= and &amp;gt;)&lt;br /&gt;
* Viewed&lt;br /&gt;
* Something else (interface defined by module)&lt;br /&gt;
&lt;br /&gt;
[[User:sam marshall|sam marshall]] Just wondering, how are you going to track &#039;viewed&#039;? Modules don&#039;t store this in a sensible way, only in the log table.&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
===course_modules_completion===&lt;br /&gt;
This table records the status of each user completing each activity module.  It represents current state and is used to make the display of course pages very fast.  It is updated whenever grades or modules change etc.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* courseid  - just here for speed&lt;br /&gt;
* cmid  - FK to course_modules&lt;br /&gt;
* userid &lt;br /&gt;
* status - hide / not done / in progress / done fail / done pass&lt;br /&gt;
* timemodified &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===course_completion===&lt;br /&gt;
This table records when whole courses are completed.&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* userid&lt;br /&gt;
* courseid&lt;br /&gt;
* status &lt;br /&gt;
&lt;br /&gt;
===course_modules_avail===&lt;br /&gt;
Records settings for availability &lt;br /&gt;
* id &lt;br /&gt;
* cmid  - the activity that is defining the condition&lt;br /&gt;
* cmsourceid - the activity we are checking&lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
* modulespecific - boolean&lt;br /&gt;
&lt;br /&gt;
===course_modules_done===&lt;br /&gt;
Records settings for whether something is done&lt;br /&gt;
* id &lt;br /&gt;
* cmid &lt;br /&gt;
* gradesign  - &amp;lt;, &amp;gt;, &amp;lt;=, =&amp;gt; etc&lt;br /&gt;
* gradecutoff &lt;br /&gt;
* views - boolean&lt;br /&gt;
&lt;br /&gt;
==Process==&lt;br /&gt;
&lt;br /&gt;
Coming soon&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Issues to think about==&lt;br /&gt;
&lt;br /&gt;
* How do we cope with circular references?&lt;br /&gt;
* We should remove conditions when activities are deleted - how does that affect things downstream?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*Take a look at the [http://moodle.org/mod/forum/view.php?f=678 Conditional activities forum] at [http://moodle.org http://moodle.org].&lt;br /&gt;
*[[Activity_Locking]], a MoodleDoc page with table and descriptions of different conditional activity modules&lt;br /&gt;
*[[Score Lock]] a MoodleDoc page for another conditional activity module for 1.6&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=35488 forum discussion about Stuart Mayor&#039;s Conditional Activities], including Moodle 1.6 version &lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=36697 Conditional activities at CICEI], running demo included as student, teacher and designer.&lt;br /&gt;
*[[Adding/editing_a_lesson#Dependent_on]] MoodleDoc page . The lesson activity settings in V 1.6 has a specialized dependency setting. Entering the lesson can be made dependent on the % (lesson questions) correct, time spent or completion of one other specific lesson. &lt;br /&gt;
&lt;br /&gt;
*Tracker reference(s) for conditional development _____________&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer|Conditional activities]]&lt;/div&gt;</summary>
		<author><name>Quen</name></author>
	</entry>
</feed>