<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Moodlebot</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Moodlebot"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Moodlebot"/>
	<updated>2026-06-07T14:20:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=QA_testing&amp;diff=61090</id>
		<title>QA testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=QA_testing&amp;diff=61090"/>
		<updated>2021-08-11T14:54:55Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Quality Assurance&#039;&#039;&#039; tests look at the functionality of Moodle from a user&#039;s point of view.  &lt;br /&gt;
&lt;br /&gt;
Real users systematically try each feature in Moodle and test that it works in the current version of the Moodle code. These tests are repeated in series of cycles, usually 4 weeks before a major release, once all major features have landed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;QA testing latest&#039;&#039;&#039;:  &#039;&#039;A 100% pass rate was obtained in Moodle 3.11 QA testing. Many thanks to all our [[Testing credits|QA testers]].&#039;&#039;&amp;lt;/p&amp;gt;&lt;br /&gt;
==Getting involved==&lt;br /&gt;
&lt;br /&gt;
Would you like to help with QA testing?  If so, please make sure you have created an account in the [[Tracker_introduction|Moodle tracker]] and you&#039;re subscribed to the [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum] in order to receive QA testing news updates.&lt;br /&gt;
&lt;br /&gt;
==Running tests==&lt;br /&gt;
&lt;br /&gt;
# Go to the [https://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11454 Moodle QA testing dashboard] and choose a test from the list of current QA cycle open issues. When viewing a test, if you wish, you can click the &#039;Assign to me&#039; link on the right, so that nobody else chooses the same test to run. (If you then find you are unable to run the test, you can click the Assign button and set the assignee as &#039;Unassigned&#039;.) Please note:&lt;br /&gt;
#* Only assign an issue to yourself which no one else is testing (Assignee = Unassigned).&lt;br /&gt;
#* Only assign one issue at a time unless you plan to test a number of related issues within the next 24 hours. In other words, don&#039;t assign several issues to yourself then do nothing for several days. ;-)&lt;br /&gt;
#* The label &#039;&#039;test_server_required&#039;&#039; indicates issues that can&#039;t be tested on the QA testing site. The label &#039;&#039;credentials_required&#039;&#039; indicates that credentials such as an OAuth 2 service client ID and secret are required.&lt;br /&gt;
# Using either the [https://qa.moodledemo.net/ Moodle QA Testing Site] or your own test site running the latest Moodle 4.0dev (available from Git on the integration/MOODLE_400_STABLE branch &#039;&#039;&amp;lt;nowiki&amp;gt;git://git.moodle.org/integration.git&amp;lt;/nowiki&amp;gt;&#039;&#039;) with [[:en:Debugging|debugging]] set to developer, perform each of the steps listed in the test.&lt;br /&gt;
# &#039;&#039;Please attach screenshots of the steps where you verify or check something.&#039;&#039;&lt;br /&gt;
# If it makes sense, please test using the currently supported themes, Boost and Classic.&lt;br /&gt;
# Choose an appropriate workflow action:&lt;br /&gt;
#* &#039;&#039;Pass&#039;&#039; - Test runs perfectly. Add comment such as feedback about a new feature, browsers used for testing (if applicable; example: &amp;quot;This test passes on Q&amp;amp;A site with Teacher role using Boost theme&amp;quot;), or simply &amp;quot;This test passes - yippee!&amp;quot;&lt;br /&gt;
#* &#039;&#039;Fail&#039;&#039; - Something doesn&#039;t work, or you obtain debugging messages. Add comment describing the step that doesn&#039;t work. If in doubt whether to pass a test, give it a fail and add a comment describing your doubts.&lt;br /&gt;
#* &#039;&#039;Obsolete&#039;&#039; - Test is no longer relevant in the current Moodle version. Add comment explaining why.&lt;br /&gt;
&lt;br /&gt;
If you notice that the test description is out-of-date, add a comment mentioning that it needs updating. Alternatively, if you&#039;d like to help with updating the test yourself, see below.&lt;br /&gt;
&lt;br /&gt;
==Any questions?==&lt;br /&gt;
&lt;br /&gt;
If there is anything you are unsure of, such as whether to mark a test as failed, or you have any other questions, please ask in one of the following places:&lt;br /&gt;
&lt;br /&gt;
* [https://t.me/moodleqa Moodle QA Telegram chat room] *new*&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum]&lt;br /&gt;
&lt;br /&gt;
==Moodle QA Testing Site==&lt;br /&gt;
&lt;br /&gt;
The [https://qa.moodledemo.net/ Moodle QA Testing Site] is updated daily at around 13:00 UTC with the latest bug fixes to enable you to re-run QA tests.&lt;br /&gt;
&lt;br /&gt;
To prevent the site being used for sending spam, no emails are sent from it. Thus, tests involving email cannot be run using the Moodle QA Testing Site. (If such tests are attempted, an email debug message is displayed. This is not a bug but rather expected behaviour.)&lt;br /&gt;
&lt;br /&gt;
Teacher and student accounts are provided. Please contact [https://moodle.org/user/profile.php?id=24152&amp;amp;course=1 Helen] if you would like admin or manager access to the Moodle QA Testing Site for running certain tests.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;div id=&amp;quot;failedTests&amp;quot;&amp;gt;Failed tests&amp;lt;/div&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
So you ran a test and it failed? Congratulations on finding a bug! Please do the following.&lt;br /&gt;
&lt;br /&gt;
# Click the Fail button at the top of the page.&lt;br /&gt;
# Add a comment to the QA test stating that there was a problem and that you will report it as a Moodle bug.&lt;br /&gt;
# Note the MDLQA number; it will be something like &amp;lt;nowiki&amp;gt;MDLQA-448&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
# Try searching for whether the bug has been reported previously, and if not create a new issue for it (as described in [[Tracker introduction]]).&lt;br /&gt;
# In the new Moodle (MDL) issue select &#039;Link&#039; from the &#039;More actions&#039; dropdown menu. &amp;lt;br /&amp;gt;[[Image:LinkIssue.png|150px|Linking to the QA issue in the tracker]]&lt;br /&gt;
# Link to the QA test by selecting &#039;blocks&#039; as the link type, entering the MDLQA number that you noted earlier, and optionally adding a comment. &amp;lt;br /&amp;gt;[[Image:LinkDetails.png|150px|Adding details for a link to the QA issue]]&lt;br /&gt;
# Give the issue the label &#039;mdlqa&#039;. &lt;br /&gt;
# (Optional) Add yourself as a watcher to the MDL issue so that you receive email notification when the issue is fixed.&lt;br /&gt;
# When the MDL issue is fixed, hopefully within a day or two, the QA test can be reset and can then be run again.&lt;br /&gt;
&lt;br /&gt;
==Resetting tests==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note for integrators:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After integrating a fix, &lt;br /&gt;
&lt;br /&gt;
# Reset the MDLQA test, adding a comment.&lt;br /&gt;
# Remove the &#039;mdlqa&#039; label from the MDL issue.&lt;br /&gt;
# If the issue doesn&#039;t have testing instructions, pass it with message &amp;quot;Will be tested by MDLQA-XXXX&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The tester will then receive email notification that the bug is fixed and will hopefully decide to run the test again soon.&lt;br /&gt;
&lt;br /&gt;
==Fixing existing bugs==&lt;br /&gt;
&lt;br /&gt;
At the beginning of the QA cycle, all bugs identified (both new and existing) are investigated promptly and hopefully fixed. &lt;br /&gt;
&lt;br /&gt;
When we are close to the scheduled release date (1-2 weeks prior), developers must focus on fixing new bugs (which affect the upcoming release version) only.&lt;br /&gt;
&lt;br /&gt;
Thus, at this point in the QA cycle, any bugs which also affect existing versions of Moodle are labelled qa_identified (and the label mdlqa removed) for investigation after the release.&lt;br /&gt;
&lt;br /&gt;
==Testing tips==&lt;br /&gt;
&lt;br /&gt;
When entering text into a form, try things like:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;amp;&amp;lt;/syntaxhighlight&amp;gt; (ampersand), &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;gt;&amp;lt;/syntaxhighlight&amp;gt; (greater than) or &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;lt;&amp;lt;/syntaxhighlight&amp;gt; (less than) e.g. &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;x &amp;lt; 1 &amp;amp;&amp;amp; x &amp;gt; 0&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;0&amp;lt;/syntaxhighlight&amp;gt; (the single digit 0) &lt;br /&gt;
* &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&#039;&amp;lt;/syntaxhighlight&amp;gt; (single quote) e.g. &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;Fergal.O&#039;Brien@example.com&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* special characters e.g. &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;café&amp;lt;/syntaxhighlight&amp;gt; or &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;囲碁&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* very long strings&lt;br /&gt;
* different languages, such as a RTL language&lt;br /&gt;
&lt;br /&gt;
==New QA tests required==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note for developers:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If an issue fix cannot be covered by automated tests, &lt;br /&gt;
&lt;br /&gt;
# Add the label &#039;qa_test_required&#039; to the issue.&lt;br /&gt;
# Add a comment explaining why it can&#039;t be covered by automated tests and suggesting which steps of the testing instructions should be included in a QA test e.g. steps 6-10 or all steps.&lt;br /&gt;
&lt;br /&gt;
QA tests will then be written and included in the next QA cycle. For issues with long testing instructions, several QA tests will be written to cover the issue. If appropriate, activities etc. will be set up on the [https://qa.moodledemo.net/ Moodle QA Testing Site] to enable the issue to be easily tested in future. &lt;br /&gt;
&lt;br /&gt;
Similarly, for new features and improvements which would benefit from exploratory testing,&lt;br /&gt;
&lt;br /&gt;
# Add the label &#039;qa_test_required&#039; to the issue.&lt;br /&gt;
# Add a comment mentioning that exploratory testing is required.&lt;br /&gt;
&lt;br /&gt;
Exploratory QA tests will then be written and included in the next QA cycle and then removed.&lt;br /&gt;
&lt;br /&gt;
==Updating tests==&lt;br /&gt;
&lt;br /&gt;
QA tests often become out-of-date due to new developments. If you would like to help with updating tests, you&#039;ll need to be a member of the test writers group in the Tracker. Please contact Helen about being added.&lt;br /&gt;
&lt;br /&gt;
To update a QA test:&lt;br /&gt;
&lt;br /&gt;
# Search for the master copy of the test - with affects version as &#039;Master copy&#039; and MDLQA-1 as parent.&lt;br /&gt;
# Edit the test description.&lt;br /&gt;
# Optional: Add a comment describing your edit.&lt;br /&gt;
&lt;br /&gt;
==Writing new tests==&lt;br /&gt;
&lt;br /&gt;
Would you like to help with writing new QA tests? If so, as for updating tests, you&#039;ll need to be a member of the test writers group in the Tracker. Please contact Helen about being added.&lt;br /&gt;
&lt;br /&gt;
To create a new QA test:&lt;br /&gt;
&lt;br /&gt;
# Choose an issue from the  [https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_test_required%20AND%20status%20%3D%20Closed closed qa_test_required-labelled issues] &lt;br /&gt;
# Do a quick search of MDLQA-1 to check if there is an existing test which can be updated&lt;br /&gt;
# If not, create a sub-task of MDLQA-1&lt;br /&gt;
# Select &#039;Original&#039; as affected version&lt;br /&gt;
# Select appropriate components&lt;br /&gt;
# Set assignee as unassigned&lt;br /&gt;
# Write the test (usually between 3 and 10 steps). It&#039;s a good idea to try doing the steps yourself as you write the test.&lt;br /&gt;
# Add the label &#039;&#039;new&#039;&#039;&lt;br /&gt;
# For tests which can’t be run on the QA site, label &#039;&#039;test_server_required&#039;&#039;. For OAuth 2 tests and any other tests which require a client ID or secret to be entered, label &#039;&#039;credentials_required&#039;&#039;.&lt;br /&gt;
# For issues which specifically mention in the testing instructions to test in different browsers, use the phrase &amp;quot;Test in as many browsers as possible and mention in a comment which ones you’ve used.&amp;quot;&lt;br /&gt;
# For an exploratory test, begin the test description with &amp;quot;This is an exploratory test of a new feature or improvement, so please feel free to try anything you like and not just the test steps!&amp;quot;&lt;br /&gt;
# For a test requiring admin access which can be run on the QA site, add:&lt;br /&gt;
 This test requires admin access. If you would like to use the [QA testing site|https://qa.moodledemo.net/] for running it, please see the [QA testing guide|https://docs.moodle.org/dev/QA_testing] for details of how to request admin access. Begin just after the hourly reset to give yourself plenty of time to complete the test!&lt;br /&gt;
&lt;br /&gt;
13. Go to the MDL issue and create a ‘has a QA test’ link to the new QA test, adding a comment “Thanks for this improvement which is now covered by the QA test MDLQA....”, and remove the qa_test_required label. &#039;&#039;Make sure that all QA tests are linked back to a corresponding MDL issue.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
New tests will be included in the next QA cycle.&lt;br /&gt;
&lt;br /&gt;
==Feedback==&lt;br /&gt;
&lt;br /&gt;
Feedback on all aspects of our QA testing process is welcome. If you have any questions or comments, please post in the [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [https://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11454 QA testing dashboard]&lt;br /&gt;
* [[Testing credits]]&lt;br /&gt;
* [[MDLQA-features]]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=351302 Useful tips for QA testing]&lt;br /&gt;
&lt;br /&gt;
Comments on tests from previous QA cycles:&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-150 Moodle 2.0 QA Cycle 1]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-328 Moodle 2.0 QA Cycle 2]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-540 Moodle 2.0.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-944 Moodle 2.1 QA Cycle 1]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-1190 Moodle 2.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-1814 Moodle 2.3 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-4602 Moodle 2.4 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-5267 Moodle 2.5 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-5740 Moodle 2.6 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-6693 Moodle 2.7 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-7170 Moodle 2.8 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-7660 Moodle 2.9 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-8205 Moodle 3.0 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-9267 Moodle 3.1 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-9827 Moodle 3.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-10403 Moodle 3.3 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-10999 Moodle 3.4 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-11698 Moodle 3.5 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-12282 Moodle 3.6 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-12911 Moodle 3.7 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-13517 Moodle 3.8 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-14131 Moodle 3.9 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-14813 Moodle 3.10 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-15457 Moodle 3.11 QA]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Languages_subsystem_improvements_2.0&amp;diff=61089</id>
		<title>Languages subsystem improvements 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Languages_subsystem_improvements_2.0&amp;diff=61089"/>
		<updated>2021-08-11T14:54:53Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Languages subsystem improvements&lt;br /&gt;
|state = Complete&lt;br /&gt;
|tracker = MDL-18797 MDL-15252&lt;br /&gt;
|discussion = [http://moodle.org/mod/forum/discuss.php?d=118707]&lt;br /&gt;
|assignee = [[User:David Mudrak|David Mudrak]]&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
{{Warning|This page was once used as an initial specification of the project. Only parts of it were finally implemented. It is kept for archive purposes only.}}&lt;br /&gt;
&lt;br /&gt;
This is a specification of changes to the language strings processing in Moodle 2.0 and 2.1. You should start looking at the [http://www.mindmeister.com/41382366/proposed-changes-for-moodle-2-x-languages-machinery overview of proposed changes] mindmap.&lt;br /&gt;
&lt;br /&gt;
== Current issues ==&lt;br /&gt;
&lt;br /&gt;
Why the changes in the current tools and process are needed:&lt;br /&gt;
&lt;br /&gt;
; String files are not branched : We must keep all strings from all branches in place for backwards compatibility and we are unable to easily clean up language packs. Some say the branching and merging is too much work for our translators (see MDL-15252).&lt;br /&gt;
; Plural forms, gender forms and other grammar : We are unable to handle plurals at all. For example, handling [http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html plural forms in gettext] is traditional, well tested and robust way (see MDL-4790). MDL-12433 by Sam Marshall shows alternative approach based on logical expressions.&lt;br /&gt;
; Strings can&#039;t be modified : It is difficult to notify translators that some string was modified (expanded, fixed, changed) - as in [http://git.moodle.org/gw?p=moodle.git;a=commit;h=d033b1288713625a733ce5fcbce5e7b5a1f6d5d1 this case], for example. The current work around is the policy of adding another string with the same suffixed name (like &#039;license2&#039;). It would be nice if such strings were tagged/highlighted in the translation UI.&lt;br /&gt;
; We do not use standard formats : Translators can&#039;t use specialized tools for translation (PO/gettext editors, community translation portals). Also, I (David) am not aware of any benchmarking showing the performance differences between out native $string[] format compared to, for example, standard .po format.&lt;br /&gt;
; More syntax checks are required : So the translators do not brake Moodle functionality (see MDL-12433)&lt;br /&gt;
; Language packs are PHP code, but stored in moodledata : This increases the severity of some security exploits. It means that any exploit that lets you write files to an arbitrary location in moodledata suddenly lets you execute arbitrary PHP code on the server. On the other hand, it would be nice to be able to allow complex logic when evaluating dynamic strings (ie such containing $a param/params).&lt;br /&gt;
; Right-to-left languages : There are problems reported in RTL languages when using online tools (including the our current one) which lead to putting placeholders like a$ and a$-&amp;gt;lastname into the string definition.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
# Fix all the issues listed above&lt;br /&gt;
# Do not reinvent the wheel&lt;br /&gt;
# Keep &amp;quot;do one thing and do it well&amp;quot; principle&lt;br /&gt;
# Keep it simple and stupid.&lt;br /&gt;
# Have the translation process as simple as possible - translators are not geeks&lt;br /&gt;
# Make simple things easy and hard things possible&lt;br /&gt;
# Make most of this available for Moodle 2.0&lt;br /&gt;
&lt;br /&gt;
== Key design questions ==&lt;br /&gt;
&lt;br /&gt;
When working on the specification, these were the key questions to keep in mind:&lt;br /&gt;
&lt;br /&gt;
; What is the data structure for storing the master copies of the lang packs : At the moment, strings are defined in plain PHP associative arrays, editable via translation UI or directly. These arrays are stored in PHP files in Moodle CVS. We are going to change it. According to the original Petr Skoda&#039;s proposal, the primary place for keeping all translated strings will be a central database at one of moodle.org servers. Together with the translation itself, usefule meta-data are kept in the database: the timestamp of the last modifications, links to the revision of the English string that the translation is based on, the author name, proposed alternatives, comments etc (see rosetta translation tool at launchpad for the example of possible metadata).&lt;br /&gt;
; What is the UI for translators, what are the processes of contributing and how the translations are redistributed to Moodle sites : Thanks to storing all strings in a database, we will be able to produce their list in various standardised formats (like PO or XLIFF). Therefore, the translators will not be forced to use the only one possible tool but can use their favourite advanced tool with its own translation memory, connected with dictionaries, i18n portals etc. Our central strings repository will support data export and import from/into various formats.&lt;br /&gt;
; What is the data structure that get_string() uses at runtime : This is just a performance optimization (implementation detail), should be independent on the native format that humans work with so it could be modified anytime in the future. For example, see the system proposed by Tim based on calling class methods (inspired by Perl&#039;s Maketext).&lt;br /&gt;
; What is the format of a lang string, and how are placeholders substituted : It is strongly tied together with the runtime format, it can be changed any time. On the other hand, both the UI and storage format must support it.&lt;br /&gt;
&lt;br /&gt;
== Use cases ==&lt;br /&gt;
&lt;br /&gt;
# Developers add new strings to the code and commit their work into CVS (core or contrib)&lt;br /&gt;
# Developers can add a comment to the string, eg. &amp;quot;this string is used for ...&amp;quot;&lt;br /&gt;
# Developers add new string and link it with a current one with an explanation eg &amp;quot;this string replaces ...&amp;quot;. Such links are available to translators and help them to decide the correct translation.&lt;br /&gt;
# Developers moves the string from one component (like enrol.php) into another (like enrol_manual.php). The current translations are re-used.&lt;br /&gt;
# Developers change the string identificator, for example from configfoobar to foobar_desc.&lt;br /&gt;
# Translators translate strings on several Moodle branches and do not need to worry about branching, commiting and merging&lt;br /&gt;
# Translators can see the list of untranslated strings and translate them&lt;br /&gt;
# Translators can see the list of outdated translated strings (aka English string was changed) and update the translation&lt;br /&gt;
# Admins can locally modify the language pack for their site&lt;br /&gt;
# Community members can propose alternative translations. They are reviewed by the lang pack maintainer and may be approved.&lt;br /&gt;
&lt;br /&gt;
== Research ==&lt;br /&gt;
&lt;br /&gt;
This is the list of projects, resources and tools that were explored before writing this spec&lt;br /&gt;
&lt;br /&gt;
* [http://search.cpan.org/~ferreira/Locale-Maketext-1.13_82/lib/Locale/Maketext/TPJ13.pod Great CPAN article about software localization]. Plain string based lexicon is not enough. Strings can be translated by functions only. &amp;quot;A phrase is a function; a phrasebook is a bunch of functions.&amp;quot;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/XLIFF XLIFF] - XML Localization Interchange File Format&lt;br /&gt;
* [http://translate.sourceforge.net/wiki/virtaal/index Virtaal] - promising, we could have XLIFF &amp;lt;-&amp;gt; .php conversion&lt;br /&gt;
* [http://launchpad.net/+tour/translation Launchpad] - translation portal used by Ubuntu and many other projects. Would require BSD licensing, therefore IMO not suitable as we could not import our current GPL&#039;ed translation. Seems to be quite slow during the process.&lt;br /&gt;
* [http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html Plural forms in gettext]&lt;br /&gt;
* [http://framework.zend.com/manual/en/zend.translate.html Zend_Translate reference guide]&lt;br /&gt;
* MDL-12433 - Sam Marshal&#039;s proposal&lt;br /&gt;
* MediaWiki approach: [http://www.mediawiki.org/wiki/Manual:$wgGrammarForms Grammar forms] and plurals: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;{{plural:1|is|are}} {{plural:2|is|are}}&amp;lt;/syntaxhighlight&amp;gt; (Example of how mediawiki outputs the correct given pluralization form depending on the count. Plural transformations are used for languages like Russian based on &amp;quot;count mod 10&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Functional proposals ==&lt;br /&gt;
&lt;br /&gt;
=== Overall strings processing flow ===&lt;br /&gt;
&lt;br /&gt;
(Follow the attached UML flow diagram) [[Image:languages20_overview1.png|thumb|right|UML: Overall string processing flow]]&lt;br /&gt;
&lt;br /&gt;
* All string definitions are kept in a central database togeteher with other all meta-data (branch, where does the string come from, what was its history etc.). Officially maintained language packs are referred to as &#039;&#039;master&#039;&#039; in this proposal. Every language pack can have its &#039;&#039;parent&#039;&#039; defined. The English language pack can be seen as the greatest common parent of all language packs.&lt;br /&gt;
* During upgrade or on demand, the relevant branch of master language packs are fetched (downloaded) automatically from the central database. Together with the selected language, all its parents, grandparent, great-grandparents, ... etc are downloaded, too.&lt;br /&gt;
* Administrators can keep local modifications (customizations) of any master pack. We call them &#039;&#039;local&#039;&#039; language packs.&lt;br /&gt;
* Immediately after upgrade (or again, on demand), the string definitions are merged from all available sources. The merge logic is so that the sources for any given string are evaluated in the order like: fr_ca_local, fr_ca, fr_local, fr, en_local, en. Strings are merged for the performance reasons so that the searching for the string to use (local, parent, master, English etc.) is done just once and we do not need to load all possible sources on runtime. After the merge, we have a single place to look for the string definition for every installed language. By default, the location for these merged strings will be $CFG-&amp;gt;dataroot/cache/lang/XX/component.php where XX is the language code (fr_ca, fr, en in this example). The benefit is that get_string() can rely on always having the string defined in this file, no other seeking and I/O is needed in runtime.&lt;br /&gt;
* Together with the merge, strings are compiled into a runtime format that may be optimised in the future. Humans do not modify the compiled format. Strings must be re-merged and re-compiled after any update of master or local packs. During the compilation, syntax checks are performed.&lt;br /&gt;
* The runtime format we will start with will be very similar with the current one. Strings are defined as array elements indexed by the string identifier. The arrays are defined in separate files for every module. We can, however, modify this in the future. For example, we can divide string definitions into files not by the module name but by the real usage frequency. Strings that are used very often (like at every page) would go into common file which can be loaded during bootstrap. This would reduce memory usage and number of I/O operations.&lt;br /&gt;
* There will be a way how to let get_string() call a PHP function/method to actually return the translated string instead of a static string definition. This will allow advanced translators to deal with many grammar issues they have in their languages (notably singular v plural forms).&lt;br /&gt;
&lt;br /&gt;
=== Naming and locations ===&lt;br /&gt;
&lt;br /&gt;
* Languages will be reffered to as &amp;quot;en&amp;quot;, &amp;quot;cs&amp;quot;, &amp;quot;en_us&amp;quot; or &amp;quot;fr_local&amp;quot; etc. Directories will be renamed.&lt;br /&gt;
* Downloaded lang packs are stored in $CFG-&amp;gt;langpacks, which is by default $CFG-&amp;gt;datadir/lang. Paranoid admins can change this to a different location that is normally read-only for the web server. Then they will manually switch to read-write when they are performing an upgrade, doing lang editing, or installing a lang pack. The UI should therefore check whether $CFG-&amp;gt;langpacks is writable before starting any of these operations, and explain the situation to admins if it is not.&lt;br /&gt;
* After mergin and compiling, the strings in runtime format are stored in $CFG-&amp;gt;dataroot/cache/lang/ (see above).&lt;br /&gt;
* All core plugins will have their language files in their own scope as the contrib plugins have. So for example workshop strings will be defined in &#039;/mod/workshop/lang/en/workshop.php&#039; instead of legacy &#039;/lang/en_utf8/workshop.php&#039;&lt;br /&gt;
&lt;br /&gt;
=== HTML help files replaced with ordinary strings ===&lt;br /&gt;
&lt;br /&gt;
Help should consist of a paragraph or two of a static HTML only, the rest goes to wiki. We will drop help files indices (index of all help files) as well as other dynamically generated helps in favour of wiki. This will make the translation easier as we do not need to have other tools to translate help files.&lt;br /&gt;
&lt;br /&gt;
Help strings are kept together with other workshop strings as in &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$string[&#039;intro&#039;] = &#039;Workshop intro&#039;; $string[&#039;intro_help&#039;] = &#039;This is the ...&#039;;&amp;lt;/syntaxhighlight&amp;gt;. It allows to keep the string and their help together which helps translators to keep translation consistency.&lt;br /&gt;
&lt;br /&gt;
See [[Help strings]] for further information.&lt;br /&gt;
&lt;br /&gt;
=== Other changes ===&lt;br /&gt;
&lt;br /&gt;
* The only valid placeholder in runtime format is &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;{$a}&amp;lt;/syntaxhighlight&amp;gt; for strings and numbers and &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;{$a-&amp;gt;foobar}&amp;lt;/syntaxhighlight&amp;gt; for objects MDL-18841.&lt;br /&gt;
* Around 90% of our strings do not contain any placeholder and they will be immediately returned by get_string().&lt;br /&gt;
* If the string contains one or more placeholders, they are replaced with their eval()-uated result. We can safely eval() the whole string definition because the string compiler makes sure that the placeholders are the only executable/evaluable code. All other malicious code and $variables are properly quoted/escaped/htmlentitled.&lt;br /&gt;
* Valid format of string identifier must be defined. These identifiers may be used as associative array keys (as in &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$string[&#039;identifier&#039;]&amp;lt;/syntaxhighlight&amp;gt;), function names, HTML form field names, file names etc. No characters like &#039;*&#039; can be used (as happened in MDL-21375).&lt;br /&gt;
* Some string identifiers are not hardcoded (explicitly referenced) in the code but computed, eg. &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;get_string(&#039;level&#039; . $level, &#039;arcade&#039;)&amp;lt;/syntaxhighlight&amp;gt; with strings &#039;level1&#039;, &#039;level2&#039;, &#039;level3&#039; etc being defined. It is difficult to automatically search for the usage of such strings. Therefore, I (David) propose the following guideline (rule):&amp;lt;br /&amp;gt;String identifiers must follow our convention for naming $variables: single lowercase word, no underscore. The colon (:) sign can be used only in strings with the names of capabilities and nowhere else. The minus sign (-) can be used only in string identifiers witch are partially computed, as in &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;get_string(&#039;region-&#039; . $regionid, &#039;theme_example&#039;)&amp;lt;/syntaxhighlight&amp;gt; so that is a sign that we should be careful when trying to find an usage of such string in the code. The underscore is reserved for special _help and _desc suffixes.&lt;br /&gt;
&lt;br /&gt;
=== Central web-based translation tool ===&lt;br /&gt;
&lt;br /&gt;
See [[Automated_Manipulation_of_Strings_2.0]]&lt;br /&gt;
&lt;br /&gt;
== Implementation proposals ==&lt;br /&gt;
&lt;br /&gt;
Read [http://moodle.org/mod/forum/discuss.php?d=118707#p542197 Petr&#039;s proposal] to store strings in one central database and to disable direct commits. That is roughly valid with the exception that the &amp;quot;no change meaning&amp;quot; rule is not forced. AMOS is able to track changes and inform translators that their translation is outdated. So we will be able to fix/update/extend English string as needed. Together with branching, this will lead to a nice &amp;quot;reduced&amp;quot; packs without redundancy.&lt;br /&gt;
&lt;br /&gt;
=== Translation tools and the process ===&lt;br /&gt;
&lt;br /&gt;
See MDL-15252 (Cleanup of English language pack) and the discussion at http://moodle.org/mod/forum/discuss.php?d=118707 for Koen&#039;s proposition. Branching issue, the translation process and other aspects discussed there.&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
From Martin in Dev chat:  &#039;&#039;if you want crazy ideas, how about get_string returns some special tags and those tags get converted to ajax on the GUI so that translators can translate directly in the main Moodle GUI?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
What a cool idea. Could be a special mode you have to turn on in the admin screens. Perhaps even if you turned this mode on, it would still only be active for people with certain roles, or perhaps when it was turned on, it would have to apply to all roles, so that you could edit strings for not-logged-in users. Anyway, when this mode was on, it would:&lt;br /&gt;
&lt;br /&gt;
# Adds &amp;amp;lt;span class=&amp;quot;moodle-lang-string&amp;quot; id=&amp;quot;lang_string|admin|langedit&amp;quot;&amp;gt;Language editing&amp;lt;/span&amp;gt; around each string on the page - to use one example.&lt;br /&gt;
# $PAGE-&amp;gt;requires-&amp;gt;js an extra JS file that adds an on-click handler to all such spans, so that when you click on it, it pops up the language editing UI in a YUI dialogue.&lt;br /&gt;
&lt;br /&gt;
:: [[User:David Mudrak|David Mudrak]] 14:07, 23 November 2009 (UTC): the solution based on wrapping &amp;amp;lt;span&amp;amp;gt; around every string was already considered and dropped. It may badly break XHTML as the string itself may appear as a value of an HTML tag&#039;s attribute: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;amp;lt;img title=&amp;quot;&amp;amp;lt;span class=&amp;quot;moodle-lang-string&amp;quot; ...&amp;lt;/syntaxhighlight&amp;gt;. We are unable to say the scope where the string will appear.&lt;br /&gt;
:: David&#039;s contra-proposal: get_string() could track all strings used at the current page and the AJAX form to edit them all could be rendered before the footer(). Or &#039;Edit system text on this page&#039; link would appear there.&lt;br /&gt;
&lt;br /&gt;
=== Getting the history of strings into database ===&lt;br /&gt;
&lt;br /&gt;
Source code management systems can&#039;t show us how the given string evolved during the time. Translators on the other hand need to know &amp;quot;personal history&amp;quot; of any given string, each with the author of the change, date, comment etc. String timeline will be populated from DB. To let it work, we will need to load all the strings history into DB. That can be done using our git mirror. This conversion is done:&lt;br /&gt;
&lt;br /&gt;
# Regularly for the master English strings that are part of Moodle source code. David already has a prototype of script to track commits into languages files and updates the database.&lt;br /&gt;
# Once for all other languages. When we have the new translation portal prepared, we will stop supporting direct CVS commits into languages. The history of all commits into all lang packs will be transferred into the database and further translations will be recorded there.&lt;br /&gt;
&lt;br /&gt;
David is writing these migration script as a part of his [[Languages/AMOS]] tool.&lt;br /&gt;
&lt;br /&gt;
== Design decisions and voting ==&lt;br /&gt;
&lt;br /&gt;
* MDL-21690 Central master database of all strings and their translations&lt;br /&gt;
* MDL-21635 Decide how to implement information in langconfig.php in AMOS&lt;br /&gt;
* MDL-21693 Drop _utf8 suffix from language codes and folder names&lt;br /&gt;
* MDL-21694 Move language files to the plugin space&lt;br /&gt;
* MDL-21695 Replace built-in HTML help files with proper strings&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [http://live.gnome.org/TranslationProject/GitHowTo How to use Git for GNOME translators]&lt;br /&gt;
* [http://translate.sourceforge.net/wiki/ Nice site with tools, localisation problems and alternatives...]&lt;br /&gt;
* [[Languages:Tim&#039;s crazy proposal based on maketext]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Language]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Global_search_(GSoC2013)&amp;diff=61088</id>
		<title>Global search (GSoC2013)</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Global_search_(GSoC2013)&amp;diff=61088"/>
		<updated>2021-08-11T14:54:49Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{obsolete}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Global search&lt;br /&gt;
|state = Coding period&lt;br /&gt;
|tracker = MDL-31989&lt;br /&gt;
|discussion = [https://moodle.org/mod/forum/discuss.php?d=227805 Writing Moodle&#039;s Global Search]&lt;br /&gt;
|assignee = [https://moodle.org/user/view.php?id=1565904&amp;amp;course=5 Prateek Sachan]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;GSOC&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt; &#039;13&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Global Search will have the feature of searching keywords within the entire Moodle site across modules keeping the security intact having full-text advance search capabilities.&lt;br /&gt;
*It will display results based on relevance weightage.&lt;br /&gt;
*Security will be preserved throughout the search.&lt;br /&gt;
*Search Modules will enable chosen search engine integration with ease. Admins will have the option for selecting the modules that could be made &amp;quot;searchable&amp;quot;&lt;br /&gt;
*It will include keywords from other files types (like PDFs, PPTs, HTML content and others).&lt;br /&gt;
*Following are the features that I&#039;m considering in implementing in the first version of Global Search:&lt;br /&gt;
# Groupings of boolean operators:&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;AND&amp;lt;/syntaxhighlight&amp;gt;, &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;OR&amp;lt;/syntaxhighlight&amp;gt;, &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;NOT&amp;lt;/syntaxhighlight&amp;gt;. Eg.: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;(&amp;quot;query1&amp;quot; AND &amp;quot;query2&amp;quot;) OR (&amp;quot;query3&amp;quot; NOT &amp;quot;query4&amp;quot;)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Highlighting: All matched keywords will be highlighted. For long content, only a short part will be displayed alongwith the highlighted keyword.&lt;br /&gt;
# Searching for phrases. Results with matched phrase will have higher priority and hence will be shown higher in the results.&lt;br /&gt;
# Wildcard (&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;*&amp;lt;/syntaxhighlight&amp;gt;) (&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;?&amp;lt;/syntaxhighlight&amp;gt;) feature.&lt;br /&gt;
# Stemming. Eg.: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;bag&amp;lt;/syntaxhighlight&amp;gt; will return results both from &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;bag&amp;lt;/syntaxhighlight&amp;gt; and &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;bags&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Proximity Searches: &lt;br /&gt;
:*&amp;quot;mood&amp;quot;~2 returns &amp;quot;moodle&amp;quot;. (2 alphabets away from the searched term).&lt;br /&gt;
:*&amp;quot;moodle australia&amp;quot;~3 returns results containing &amp;quot;moodle hq at perth australia&amp;quot; (the queried terms were within 3 words of each other)&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
*Moodle 2.5 and above.&lt;br /&gt;
*PHP Solr extension.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&#039;&#039;&#039;Adding a Global Search Block&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Add_Global_Search_Block.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Search through Global Search Block&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Block.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Results UI&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Results_UI.png|900px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Admin Solr settings&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Admin_Solr_Settings.png|900px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Admin Modules Activation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Admin_Module_Activation.png|900px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Admin Indexing Statistics&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Admin_Indexing_Statistics.png|900px]]&lt;br /&gt;
&lt;br /&gt;
== Admin Controls ==&lt;br /&gt;
These controls appear under Site Administration &amp;gt; Global Search. (Please refer the screenshots above).&lt;br /&gt;
=== Search Engine ===&lt;br /&gt;
This will enable you to choose your preferred Search Engine. Currently, Global Search only supports Apache Solr.&lt;br /&gt;
=== Solr Settings ===&lt;br /&gt;
This section lists down the various server connection settings that you&#039;ll need to configure for your server.&lt;br /&gt;
=== Activated Modules ===&lt;br /&gt;
This section lists down the modules that are enabled in Global Search for indexing and searching of the content within them. You may activate/deactivate modules.&lt;br /&gt;
=== Indexing Statistics ===&lt;br /&gt;
*This lists down the indexing statistics of Global Search.&lt;br /&gt;
*It also gives you the control for deleting index from specific modules or deleting the entire index in one go. (Deleting &amp;quot;Entire Index&amp;quot; deletes the entire Solr index irrespective of whether a module is activated/deactivated).&lt;br /&gt;
*The content will have to be re-indexed through cron.&lt;br /&gt;
&lt;br /&gt;
== Installing PHP Solr extension==&lt;br /&gt;
=== UNIX ===&lt;br /&gt;
*You may download pecl-php-solr extension version &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;1.0.3-alpha&amp;lt;/syntaxhighlight&amp;gt; by &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;git clone https://github.com/lukaszkujawa/php-pecl-solr.git&amp;lt;/syntaxhighlight&amp;gt; or official versions &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;lt;=1.0.2&amp;lt;/syntaxhighlight&amp;gt; from http://pecl.php.net/package/solr. (Extract the contents in a directory)&lt;br /&gt;
*Install the extension dependencies by executing &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;apt-get install libxml2-dev libcurl4-openssl-dev libpcre3-dev&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*Restart apache server. &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;sudo service apache2 restart&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*Assuming you cloned or downloaded the extension in a directory, you&#039;ll have to compile the downloaded extension.&lt;br /&gt;
*&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;cd /your-downloaded-or-cloned-php-solr-extension-directory/&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;phpize&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
**This a shell script used to prepare the build environment for a php extension to be compiled. If you don&#039;t have &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;phpize&amp;lt;/syntaxhighlight&amp;gt;, you can install it by executing &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;sudo apt-get install php5-dev&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;sudo ./configure&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*sudo make&lt;br /&gt;
*sudo make install&lt;br /&gt;
&lt;br /&gt;
The above procedure will compile and install it in the &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;extension_dir&amp;lt;/syntaxhighlight&amp;gt; directory in the &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;php.ini&amp;lt;/syntaxhighlight&amp;gt; file. To enable, the installed extension, you could follow any of the following two steps:&lt;br /&gt;
&lt;br /&gt;
1. Navigate to the directory &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;/etc/php5/conf.d&amp;lt;/syntaxhighlight&amp;gt; and create a new &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;solr.ini&amp;lt;/syntaxhighlight&amp;gt; file with the following line:&lt;br /&gt;
 extension=solr.so&lt;br /&gt;
&lt;br /&gt;
OR&lt;br /&gt;
&lt;br /&gt;
2. Open your &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;php.ini&amp;lt;/syntaxhighlight&amp;gt; file and include the following line:&lt;br /&gt;
 extension=solr.so&lt;br /&gt;
&lt;br /&gt;
You may follow any of the above two steps. You will need to restart your apache server after that by executing &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;sudo service apache2 restart&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now view the &#039;&#039;&#039;solr&#039;&#039;&#039; extension details by clicking &#039;&#039;&#039;PHP info&#039;&#039;&#039; from Site administration &amp;gt; Server in browser or &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;php -m&amp;lt;/syntaxhighlight&amp;gt; in Terminal (&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;Ctrl+Alt+T&amp;lt;/syntaxhighlight&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== OSX using macports ===&lt;br /&gt;
This method provides an easy install of php solr extension without any downloads.(php solr extension version: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;lt;=1.0.2&amp;lt;/syntaxhighlight&amp;gt;)&lt;br /&gt;
 - sudo port install apache-solr4&lt;br /&gt;
 - sudo port install php54-solr&lt;br /&gt;
&lt;br /&gt;
you can choose your relevant available versions @ http://www.macports.org/ports.php?by=name&amp;amp;substr=solr&lt;br /&gt;
&lt;br /&gt;
== Setting up Global Search for Moodle ==&lt;br /&gt;
&lt;br /&gt;
After installing the php-pecl-solr extension, users will have to download the required [http://lucene.apache.org/solr/ Apache Solr] release (version 4.x for solr-php extension &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;1.0.3-alpha&amp;lt;/syntaxhighlight&amp;gt; or 3.x for solr-php extension version &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;lt;=1.0.2&amp;lt;/syntaxhighlight&amp;gt;), unzip it and keep it in an external directory of Moodle.&lt;br /&gt;
&lt;br /&gt;
Users will have to replace &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;solconfig.xml&amp;lt;/syntaxhighlight&amp;gt; and &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;schema.xml&amp;lt;/syntaxhighlight&amp;gt; inside the downloaded directory &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;example/solr/collection1/conf/&amp;lt;/syntaxhighlight&amp;gt; with the ones that Global Search will provide in &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;/search/solr/conf/&amp;lt;/syntaxhighlight&amp;gt; directory. &lt;br /&gt;
&lt;br /&gt;
Once the files have been copied and replaced, users will have to start the java jetty server &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;start.jar&amp;lt;/syntaxhighlight&amp;gt; located in &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;/example/&amp;lt;/syntaxhighlight&amp;gt; directory by executing &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;java -jar start.jar&amp;lt;/syntaxhighlight&amp;gt;. For the production setup you may prefert to [http://jmuras.com/blog/2012/setup-solr-4-tomcat-ubuntu-server-12-04-lts run solr on tomcat 6 or 7] and Ubuntu server.&lt;br /&gt;
&lt;br /&gt;
Admins will then have to Enable Global Search in Site Administration &amp;gt; Plugins &amp;gt; Global Search &amp;gt; Manage Global Search&lt;br /&gt;
&lt;br /&gt;
== Searchable content in Global Search==&lt;br /&gt;
Following are the modules/resources covered so far in Global Search. I&#039;ll be continuing my work, including other modules shortly as well.&lt;br /&gt;
&lt;br /&gt;
All the contents of the following modules including all uploaded rich document media(PDFs, PPTXs, .TXTs, etc.) will be indexed and made searchable taking proper care of security through Moodle capabilities.&lt;br /&gt;
 &lt;br /&gt;
*Book Resource&lt;br /&gt;
*Forum Module&lt;br /&gt;
*Glossary Module&lt;br /&gt;
*Label Resource&lt;br /&gt;
*Lesson Module&lt;br /&gt;
*Page Resource&lt;br /&gt;
*File Resource&lt;br /&gt;
*Url Resource&lt;br /&gt;
*Wiki Module&lt;br /&gt;
&lt;br /&gt;
The search results will display highlighted matched queries alongwith context links/direct links to the corresponding record.&lt;br /&gt;
&lt;br /&gt;
== Implementation and Milestones ==&lt;br /&gt;
*Writing cron jobs:(17th June - 21st June)&lt;br /&gt;
**Addition of records.&lt;br /&gt;
**Deletion of records.[shouldn&#039;t be focused upon just now]&lt;br /&gt;
**Update of records.&lt;br /&gt;
*Design the solr schema and solconfig files. (22nd June - 26th June)&lt;br /&gt;
**These files will be embedded in the in a separate directory under the Global Search directory. Users will have to copy these two files to the Apache Solr example directory that they will download which will run the Solr jetty server. See Installation for more. &lt;br /&gt;
**&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;schema.xml&amp;lt;/syntaxhighlight&amp;gt; contains all the properties about the documents fields which are being indexed. There may be different fields pertaining to different modules. &lt;br /&gt;
**&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;solrconfig.xml&amp;lt;/syntaxhighlight&amp;gt; contains the configurational parameters for solr.&lt;br /&gt;
*Writing the core search API for all searchable modules. (27th June - 3rd July)&lt;br /&gt;
**_SEARCH_ITERATOR($from=0)&lt;br /&gt;
**_SEARCH_DOCUMENTS($id)&lt;br /&gt;
*Adding proper security to the search API.(4th July - 8th July)&lt;br /&gt;
**_SEARCH_ACCESS($id)&lt;br /&gt;
***Use of Access API&lt;br /&gt;
****ACCESS_DENIED&lt;br /&gt;
****ACCESS_GRANTED&lt;br /&gt;
***ACCESS_DELETED: Situations where the records may have been deleted-hence not viewable.&lt;br /&gt;
*Reviewing all the above once. (9th July - 10th July)&lt;br /&gt;
*Integrating Apache Tika to handle indexing from external files (&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;PDFs&amp;lt;/syntaxhighlight&amp;gt;, &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;PPTX&amp;lt;/syntaxhighlight&amp;gt; etc.) (11th July - 13th July)&lt;br /&gt;
*Writing the search functions for querying. (Just a basic search UI to be used at this moment). (14th July - 17th July)&lt;br /&gt;
**Input for query.&lt;br /&gt;
**Input for filter fields for filtering the search results.&lt;br /&gt;
**Input for AND/OR.&lt;br /&gt;
**Phrase searches.&lt;br /&gt;
**Stemming.&lt;br /&gt;
**Support for wildcards.&lt;br /&gt;
*Admin page for search configuration options. (18th July - 21st July) (The UI page here will be the default type as being currently used. For example, Site Administration&amp;gt;Advance features)&lt;br /&gt;
**Deletion of index.&lt;br /&gt;
***Deletion of entire index in one go.&lt;br /&gt;
***Deletion of index by specific modules only.(For example, only the index of records belonging to &#039;forum&#039; module is to be deleted).&lt;br /&gt;
**configurational options for cron&lt;br /&gt;
***Time of cron run.&lt;br /&gt;
*Implementing and releasing the first prototype &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;version: 1.0&amp;lt;/syntaxhighlight&amp;gt; for developers&#039; feedback. (22nd July - 28th July)&lt;br /&gt;
**See the &#039;&#039;&#039;Prototype&#039;&#039;&#039; section.&lt;br /&gt;
*Preparing for mid-term evaluation. (29th July - 1st August)&lt;br /&gt;
*MID_TERM EVALUATION (2nd August)&lt;br /&gt;
*Re-designing the search page. (2nd August - 7th August) (Taking ideas from community+discussion in [https://moodle.org/mod/forum/discuss.php?d=227805 forum])&lt;br /&gt;
*Improving the prototype after feedback from developers.(8th August - 15th August)&lt;br /&gt;
**Bug-fixing.&lt;br /&gt;
**Fixing security leaks.&lt;br /&gt;
**Improving relevance &amp;amp; speed of search results.&lt;br /&gt;
*Running Test cases and performance testing. (16th August - 21st August) (Performance testing will be good at this point as the code would have been optimized to some level as instructed by the developers above)&lt;br /&gt;
*Debugging. (22nd August - 29th August)&lt;br /&gt;
*Finalizing the Global Search documentation. (30th August - 6th September)&lt;br /&gt;
**Discussing it with my mentors whether everything has been properly covered or not.&lt;br /&gt;
*Buffer Period. (7th September - 8th September)&lt;br /&gt;
**Making sure everything above has been implemented correctly and efficiently. &lt;br /&gt;
*Submitting my code to Moodle and Google. (9th September - 15th September)&lt;br /&gt;
*Suggested Pencils Down Period. (16th September)&lt;br /&gt;
*Performing edits to the documentation after feedback from the Moodle community. (17th September - 22nd September)&lt;br /&gt;
*Firm Pencils Down and Final Evaluation. (23rd September)&lt;br /&gt;
&lt;br /&gt;
== Quick setup for testing ==&lt;br /&gt;
This covers the features and procedure to install Global Search plugin. It would be very good if developers may come forward to test it and give their feedback which would be very crucial for improving it.&lt;br /&gt;
Developers may check out the cases in the &#039;&#039;&#039;Testing&#039;&#039;&#039; section. Developers may add their own preferred test cases and results (pass/fail) in that section which would be helpful for the other developers or you may comment on [https://moodle.org/mod/forum/discuss.php?d=227805 Global Search] discussion on Developer Forum. &lt;br /&gt;
*Here are some things that I&#039;ve summarized that may be focused upon:&lt;br /&gt;
**Finding out any security leaks that I may have missed out.&lt;br /&gt;
**Relevance/speed of displaying search results.&lt;br /&gt;
**Taking ideas to optimize the [https://github.com/prateeksachan/moodle/tree/gs2rebased source code] wherever possible.&lt;br /&gt;
**Getting feedback.&lt;br /&gt;
**Addition/deletion of any search features that you may feel would be useful.&lt;br /&gt;
*Features included in this prototype:&lt;br /&gt;
**Indexing/Searching of content in all the above mentioned modules/resources.&lt;br /&gt;
**Support for indexing/searching rich documents.&lt;br /&gt;
**Admin configuration options.&lt;br /&gt;
**Support for advanced search queries as stated above.&lt;br /&gt;
*Steps to install and test Global Search plugin:&lt;br /&gt;
**Make sure you&#039;ve installed your preferred PHP Solr extension (see sections above).&lt;br /&gt;
**You can simply clone my Github branch and checkout &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;gs2rebased&amp;lt;/syntaxhighlight&amp;gt; branch.&lt;br /&gt;
:&amp;lt;code language=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/prateeksachan/moodle.git&lt;br /&gt;
git checkout gs2rebased&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
**Go to &#039;&#039;&#039;Setting up Global Search in Moodle after installing PHP Solr extension&#039;&#039;&#039; section above.&lt;br /&gt;
**Open &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;../moodle/admin&amp;lt;/syntaxhighlight&amp;gt; in your browser, and update the admin Global Search settings.&lt;br /&gt;
**Indexing is through cron. You will have to run the cron script to index content.&lt;br /&gt;
&lt;br /&gt;
==Search workflow==&lt;br /&gt;
===Simple version===&lt;br /&gt;
# Moodle sends a query to standard solr handler.&lt;br /&gt;
# solr returns 1000 results. Results include all fields required to render search result row. Results are ordered by relevancy.&lt;br /&gt;
# Moodle checks each result in order to establish if it should be visible for current user or not&lt;br /&gt;
# Once 100 visible results are found, Moodle stops checking the rest and displays 100 results&lt;br /&gt;
&lt;br /&gt;
The best case scenario is that Moodle needs to check only 100 returned results (first 100 are accessible for the current user).&lt;br /&gt;
The worst case scenario is that out of 1000 returned documents, none of them is available for the current user. In this case Moodle performs 1000 checks and displays &amp;quot;no results found&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
===Advanced version===&lt;br /&gt;
More advanced version will use a logic on solr side to pre-filter some of the results.&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
A list of test cases.&lt;br /&gt;
===New content===&lt;br /&gt;
* index&lt;br /&gt;
* add new forum post&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure new content is searchable&lt;br /&gt;
&lt;br /&gt;
===Updated content===&lt;br /&gt;
* index&lt;br /&gt;
* edit existing forum post&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure new content is searchable&lt;br /&gt;
* make sure old content is not searchable&lt;br /&gt;
&lt;br /&gt;
===Deleted content===&lt;br /&gt;
* index&lt;br /&gt;
* delete existing forum post&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure deleted content is not searchable&lt;br /&gt;
&lt;br /&gt;
===Backup restored===&lt;br /&gt;
* index&lt;br /&gt;
* restore whole course from a backup&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure restored content is searchable&lt;br /&gt;
&lt;br /&gt;
===Access Tests===&lt;br /&gt;
====Common Access====&lt;br /&gt;
*Add courses.&lt;br /&gt;
*Create activity modules/resources that are supported by Global Search (See section &#039;&#039;&#039;Searchable content in Global Search&#039;&#039;&#039;).&lt;br /&gt;
*Insert content or attach files (wherever possible)&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure the results are visible only to those who have access to the respective course&#039;s activity/resource.&lt;br /&gt;
*Set Common Module Settings of activities/resources as Hidden.&lt;br /&gt;
*Make sure those activities/resources do not appear in search results.&lt;br /&gt;
&lt;br /&gt;
====Forum Activity Module Access====&lt;br /&gt;
*Create a course.&lt;br /&gt;
*Create groups in it.&lt;br /&gt;
*Create a Forum Activity.&lt;br /&gt;
*Post in the forum discussions from members of different groups. (+you may also attach files)&lt;br /&gt;
*Index.&lt;br /&gt;
*Make sure members see posts only from those groups which they are a member of.&lt;br /&gt;
&lt;br /&gt;
====Lesson Activity Module Access====&lt;br /&gt;
*Create a course.&lt;br /&gt;
*Create a Lesson Activity.&lt;br /&gt;
1. Type 1&lt;br /&gt;
*Assign Availability &lt;br /&gt;
**Available From only&lt;br /&gt;
**Deadline only&lt;br /&gt;
**Time limit&lt;br /&gt;
**Password Protection&lt;br /&gt;
**Combinations of the above&lt;br /&gt;
*Index.&lt;br /&gt;
*Make sure there are no access leaks when searching as a student.&lt;br /&gt;
*Make sure the teacher, manager are able to see the searches.&lt;br /&gt;
&lt;br /&gt;
2. Type 2&lt;br /&gt;
*Assign Prerequisite Lesson&lt;br /&gt;
**Set Dependent On Prerequisite feature.&lt;br /&gt;
**Set Time spent Prerequisite feature.&lt;br /&gt;
**Toggle completed Prerequisite feature.&lt;br /&gt;
**Set Grade Prerequisite feature.&lt;br /&gt;
**Combinations of the above.&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure there are no access leaks when searching as a student.&lt;br /&gt;
*Make sure the teacher, manager are able to see the searches.&lt;br /&gt;
&lt;br /&gt;
====Wiki Activity Module Access====&lt;br /&gt;
*Create a course.&lt;br /&gt;
*Create Groups.&lt;br /&gt;
*Create a Wiki Activity.&lt;br /&gt;
*Set Group Mode On&lt;br /&gt;
1. Type 1&lt;br /&gt;
*Group Mode: Separate Groups&lt;br /&gt;
*Add Wikipages. (+you may also attach files)&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure there are no access leaks: A group shouldn&#039;t see results from other groups.&lt;br /&gt;
2. Type 2&lt;br /&gt;
*Group Mode: Visible Groups&lt;br /&gt;
*Add Wikipages.(+you may also attach files)&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure there are no access leaks: A group shouldn&#039;t see results from other groups.&lt;br /&gt;
&lt;br /&gt;
====Results====&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
*My Mentors:[https://moodle.org/user/view.php?id=353008&amp;amp;course=5 Tomasz Muras] &amp;amp; [https://moodle.org/user/view.php?id=1146834&amp;amp;course=5 Aparup Banerjee]&lt;br /&gt;
*[http://lucene.apache.org/solr/ Apache Solr Community]&lt;br /&gt;
*[https://github.com/ecaron/php-pecl-solr PHP-Solr extension for Solr 4.x]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[GSOC/2013|Moodle GSoC projects for 2013]]&lt;br /&gt;
* [[GSOC|Moodle GSoC Overview page]]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=227805 Writing Moodle&#039;s Global Search Discussion]&lt;br /&gt;
&lt;br /&gt;
[[Category:GSOC]]&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=CodeSniffer&amp;diff=61087</id>
		<title>CodeSniffer</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=CodeSniffer&amp;diff=61087"/>
		<updated>2021-08-11T14:54:45Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
===Scope===&lt;br /&gt;
This document describes the CodeSniffing/Code checker tools their purpose and usage.&lt;br /&gt;
&lt;br /&gt;
===Function===&lt;br /&gt;
The function of the CodeSniffer tool is to analyse PHP5 (only) code, apply a set of rules that match the [[Coding_style | Moodle Coding Style]], and output a report showing which parts of the code do not conform to this style.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
===Using codechecker===&lt;br /&gt;
&lt;br /&gt;
codechecker is a local plugin that creates a web based interface for checking the syntax of a given file. It can be found at&lt;br /&gt;
https://github.com/moodlehq/moodle-local_codechecker&lt;br /&gt;
&lt;br /&gt;
Once installed a new codechecker option will appear in site administration\development page.&lt;br /&gt;
&lt;br /&gt;
This page allows for the code in a specified directory to be checked, e.g. if you wanted to check the code for the shortanswer question type you would enter&lt;br /&gt;
/question/type/shortanswer&lt;br /&gt;
&lt;br /&gt;
You would then be presented with a list of the count of files processed and any warnings or errors.&lt;br /&gt;
&lt;br /&gt;
===Installing codechecker===&lt;br /&gt;
&lt;br /&gt;
To install using git, type this command in the root of your Moodle install&lt;br /&gt;
    git clone git://github.com/moodlehq/moodle-local_codechecker.git local/codechecker&lt;br /&gt;
&lt;br /&gt;
Then edit .gitignore in your development folder eg: &lt;br /&gt;
    gedit /var/www/moodle/.gitignore&lt;br /&gt;
&lt;br /&gt;
And add /local/codechecker/ - including the slash at the end&lt;br /&gt;
&lt;br /&gt;
Alternatively, download the zip from &lt;br /&gt;
&lt;br /&gt;
https://github.com/moodlehq/moodle-local_codechecker/zipball/master&lt;br /&gt;
&lt;br /&gt;
unzip it into the local folder, and then rename the new folder to codechecker.&lt;br /&gt;
&lt;br /&gt;
===Installing PHP CS===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Using pear installer&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. Install the Pear package for PHP CS, pear install PHP_CodeSniffer&lt;br /&gt;
&lt;br /&gt;
2. Download the standard: PHPCompatibility and moodle directories from https://github.com/moodlehq/moodle-local_codechecker&lt;br /&gt;
&lt;br /&gt;
3.  Copy the previous directories to the PHP CS standard path:&lt;br /&gt;
* in Mac with Macports is /opt/local/lib/php/PHP/CodeSniffer/Standards/&lt;br /&gt;
* In Mac with Homebrew is /usr/local/share/pear\@7.0/PHP/CodeSniffer/Standards/&lt;br /&gt;
* in Linux is /usr/share/php/PHP/CodeSniffer/Standards/ or /usr/share/php/PHP/CodeSniffer/src/Standards&lt;br /&gt;
&lt;br /&gt;
4.  If they are installed properly, moodle and PHPCompatibility will show up in the output of `phpcs -i`. Here is a typical example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
The installed coding standards are MySource, PHPCompatibility, Squiz, PSR2, moodle, PEAR, PSR1, PSR12 and Zend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Optionally, you can set the default standard in a configuration file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    phpcs --config-set default_standard moodle&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Install using composer&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. Run the following in your terminal from your moodle folder:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
composer global require &amp;quot;squizlabs/php_codesniffer=3.*&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Download the standard: PHPCompatibility and moodle directories from https://github.com/moodlehq/moodle-local_codechecker&lt;br /&gt;
to an accessible location on your computer - it doesn&#039;t have to be your project folder.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;quot;blackboard-open-source/moodle-coding-standard&amp;quot; is no longer being maintained.&lt;br /&gt;
&lt;br /&gt;
3. Tell phpcs about where to find the Moodle code checker&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
phpcs  --config-set  installed_paths /path/to/moodle-local_codechecker # adds moodle&#039;s standard to phpcs&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4.  If they are installed properly, moodle and PHPCompatibility will show up in the output of `phpcs -i`. Here is a typical example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
The installed coding standards are MySource, PHPCompatibility, Squiz, PSR2, moodle, PEAR, PSR1, PSR12 and Zend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Optionally, you can set the default standard in a configuration file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    phpcs --config-set default_standard moodle&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Codechecker output===&lt;br /&gt;
&lt;br /&gt;
The output is similar to the following &lt;br /&gt;
&lt;br /&gt;
Files found: 21&lt;br /&gt;
&lt;br /&gt;
question\type\calculated\backup\moodle1\lib.php - 1 error(s) and 10 warning(s)&lt;br /&gt;
then a list of all files checked with a count of errors and warnings..followed by a summary&lt;br /&gt;
Total: 31 error(s) and 262 warning(s)&lt;br /&gt;
&lt;br /&gt;
Then a list describing the exact issue in each file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;question\type\calculated\backup\moodle1\lib.php&lt;br /&gt;
&lt;br /&gt;
2: The opening &amp;lt;?php tag must be followed by exactly one newline.&lt;br /&gt;
········//·convert·and·write·the·answers·first&lt;br /&gt;
50: Inline comments must start with a capital letter, digit or 3-dots sequence&lt;br /&gt;
etc etc&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;You can then edit the files to attempt to remove each issue.&lt;br /&gt;
&lt;br /&gt;
===IDE plugin alternatives===&lt;br /&gt;
&lt;br /&gt;
Using the web based interface means switching between the browser and the editing environment. You may find it easier to use a plugin that allows you to check your code against the standards as you go along. &lt;br /&gt;
&lt;br /&gt;
For Eclipse users&lt;br /&gt;
http://www.phpsrc.org/&lt;br /&gt;
&lt;br /&gt;
For Netbeans users&lt;br /&gt;
&lt;br /&gt;
Make sure you have the PEAR php Codesniffer code installed, you can find instructions at &lt;br /&gt;
http://pear.php.net/package/PHP_CodeSniffer/download/All&lt;br /&gt;
&lt;br /&gt;
Then install the netbeans plugin which can be found at &lt;br /&gt;
&lt;br /&gt;
https://github.com/beberlei/netbeans-php-enhancements/downloads&lt;br /&gt;
&lt;br /&gt;
Once installed you can check it within Netbeans by going to &lt;br /&gt;
Tools/Options/PHP and click on the codesniffer tab.&lt;br /&gt;
&lt;br /&gt;
====Windows set up====&lt;br /&gt;
&lt;br /&gt;
There is an option for the codesniffer script. On my windows xampp install this needs to point to &lt;br /&gt;
&lt;br /&gt;
C:\xampp\php\phpcs.bat&lt;br /&gt;
&lt;br /&gt;
Underneath this should be a list of some of the coding standards available, but by default this will not include Moodle. To install the moodle standard, copy the&amp;quot;moodle&amp;quot; and &amp;quot;phpcompatibility&amp;quot; folders from local\codechecker into your standards directory which for me was under&lt;br /&gt;
&lt;br /&gt;
php\PEAR\PHP\CodeSniffer\Standards&lt;br /&gt;
&lt;br /&gt;
[[Image:codesniffer.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now when you restart your Netbeans you should see a new moodle coding standard. Right clicking on a file name should present you with a new option of &amp;quot;Show Code Standard Violations&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Linux set up====&lt;br /&gt;
&lt;br /&gt;
After installing codesniffer and codechecker, copy the moodle and phpcompatibility standard folders from (assuming you have the code in /local/codechecker)&lt;br /&gt;
&lt;br /&gt;
/var/www/moodle/local/codechecker/&lt;br /&gt;
&lt;br /&gt;
to &lt;br /&gt;
&lt;br /&gt;
/usr/share/pear/PHP/CodeSniffer/Standards/&lt;br /&gt;
&lt;br /&gt;
There is an option to set the default standard in a configuration file:&lt;br /&gt;
&lt;br /&gt;
    phpcs --config-set default_standard moodle&lt;br /&gt;
&lt;br /&gt;
Then restart Netbeans and it should now work. You can also switch between coding standards.&lt;br /&gt;
&lt;br /&gt;
===Simple example===&lt;br /&gt;
The script is located in lib/pear/PHP and is called runsniffer. To check the syntax of a given file (e.g. index.php), run:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer index.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will get a report that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FOUND 139 ERROR(S) AND 24 WARNING(S) AFFECTING 130 LINE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
     1 | WARNING | $Id$ tag is no longer required, please remove.&lt;br /&gt;
    28 | ERROR   | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
    50 | ERROR   | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
    50 | ERROR   | A cast statement must be followed by a single space&lt;br /&gt;
    55 | ERROR   | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
  ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first column shows the line at which the ERROR or WARNING was found. The CodeSniffer uses a set of rules which are still being defined, so that what is currently defined as ERROR or WARNING is likely to change in the near future. &lt;br /&gt;
&lt;br /&gt;
You should fix all ERRORs, but may safely ignore the WARNINGs. Fixing warnings will help your code be even more readable and consistent with other code that follow this standard.&lt;br /&gt;
&lt;br /&gt;
===Advanced Usage===&lt;br /&gt;
====Ignoring warnings====&lt;br /&gt;
You can run the CodeSniffer with the -n flag to ignore warnings:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer -n index.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Resulting output:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FOUND 139 ERROR(S) AFFECTING 125 LINE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
    28 | ERROR | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
    50 | ERROR | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Recursive analysis====&lt;br /&gt;
If you give the name of a folder instead of a file, it will search, analyse and report on all PHP files found in this folder and all its subfolders. This will produce a full report for each PHP file. Since this is likely to be too much information, you may want to print only a summary report, by using the following syntax (search the files/ folder as an example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer --report=summary files&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Report:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  PHP CODE SNIFFER REPORT SUMMARY&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FILE                                                            ERRORS  WARNINGS&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  /web/htdocs/moodle_blog2/files/index.php                        11      58&lt;br /&gt;
  /web/htdocs/moodle_blog2/files/draftfiles.php                   6       22&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  A TOTAL OF 17 ERROR(S) AND 80 WARNING(S) WERE FOUND IN 2 FILE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use the -n flag to ignore warnings.&lt;br /&gt;
&lt;br /&gt;
====Several files in one folder====&lt;br /&gt;
If you want to search all files under a folder, but not recurse through the subfolders, you can use the -l flag (local files only):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer --report=summary -l grade&lt;br /&gt;
&lt;br /&gt;
  PHP CODE SNIFFER REPORT SUMMARY&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FILE                                                            ERRORS  WARNINGS&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  /web/htdocs/moodle_blog2/grade/index.php                        0       2&lt;br /&gt;
  /web/htdocs/moodle_blog2/grade/lib.php                          6       210&lt;br /&gt;
  /web/htdocs/moodle_blog2/grade/querylib.php                     5       39&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  A TOTAL OF 11 ERROR(S) AND 251 WARNING(S) WERE FOUND IN 3 FILE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can pass as many files and folders to the script as you want, the analysis and flags will apply to all of them.&lt;br /&gt;
&lt;br /&gt;
===Special rules===&lt;br /&gt;
&lt;br /&gt;
When recursing through folders, the CodeSniffer script looks for a file called thirdpartylibs.xml. Currently there is only one, found under lib/. It lists directories and files which are meant to stay &#039;as-is&#039; in Moodle core, in order to ensure minimum hassle when upgrading these libraries. You can use this file as a template to create your own list of exceptions.&lt;br /&gt;
&lt;br /&gt;
For using the thirdpartylibs.xml in your plugins, please see [[Plugin files#thirdpartylibs.xml]].&lt;br /&gt;
&lt;br /&gt;
===Other report formats===&lt;br /&gt;
CodeSniffer can export its reports in the following formats:&lt;br /&gt;
#full: default, shown first above&lt;br /&gt;
#summary: also shown above&lt;br /&gt;
#xml: Simple XML format&lt;br /&gt;
#csv: Comma-separated list&lt;br /&gt;
#checkstyle: XML format intended for use with CruiseControl&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
#[[Coding]]&lt;br /&gt;
#[[Coding style]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Bug_triage&amp;diff=61086</id>
		<title>Bug triage</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Bug_triage&amp;diff=61086"/>
		<updated>2021-08-11T14:54:42Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Triage.png|200px|right|alt Triage image]]&lt;br /&gt;
Triage is medical term referring to the process of prioritising patients based on the severity of their condition so as to maximise benefit (help as many as possible) when resources are limited.&lt;br /&gt;
&lt;br /&gt;
Bug triage is a process where tracker issues are screened and prioritised. Triage should help ensure we appropriately manage all reported issues - bugs as well as improvements and feature requests.&lt;br /&gt;
&lt;br /&gt;
Triage initially happens shortly after the issue was reported but it can be repeated later if the initial assumptions were wrong, issue was resolved otherwise, affected versions need updating or there are other reasons to review the issue.&lt;br /&gt;
&lt;br /&gt;
==Get involved==&lt;br /&gt;
&lt;br /&gt;
Anybody can do triage in form of correcting the components and/or affected versions, linking to related issues, and of course commenting asking for clarification, confirming bug, redirecting to forum, etc. Users in &#039;&#039;jira-developers&#039;&#039; and &#039;&#039;moodle-triage&#039;&#039; groups can edit any issue, &#039;&#039;jira-users&#039;&#039; can comment on any issue or edit issues they reported. Please see MDLSITE-3592 if you are not a developer but would like to help with triage process.&lt;br /&gt;
&lt;br /&gt;
Adding &#039;&#039;triaged&#039;&#039; label and placing the issue on the backlog should only be done by component lead or HQ developer. At the same time other users can remove &#039;&#039;triaged&#039;&#039; label from the old issues or replace it with &#039;&#039;triaging_in_progress&#039;&#039; if they want to request an additional triage.&lt;br /&gt;
&lt;br /&gt;
==The triage process==&lt;br /&gt;
&lt;br /&gt;
===Initial screening===&lt;br /&gt;
&lt;br /&gt;
First of all, identify the issues that should be closed or placed under investigation. Ask the following questions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Is the issue a request for support/help?&#039;&#039;&#039; If so, the reporter should be directed to the forums to seek help and the issue should be closed as &amp;quot;Not a bug&amp;quot;. Sometimes improvement requests can be phrased as a question, though; if this is the case, ask the reporter to reword the description to describe an improvement.&lt;br /&gt;
* &#039;&#039;&#039;Have the reporter mistaken the Moodle Tracker with their own support desk?&#039;&#039;&#039; Sometimes people mistake the Moodle Tracker as a place to request help about their own Moodle instance, often about logging in. We need to refer the user to their instance administrators and close the issue as &amp;quot;Not a bug&amp;quot;. &lt;br /&gt;
* &#039;&#039;&#039;Has the issue been reported previously?&#039;&#039;&#039; If so, link to a duplicate issue and close the newly reported issue as a &amp;quot;Duplicate&amp;quot; with no fix version set. Encourage the reporter to search before reporting. If a newer issue has a patch or more voters/watchers, consider closing the older issue. Checking for duplicates first will save you having to check the rest of the issue. See [[Tracker tips]] for help with effective search of tracker.&lt;br /&gt;
* &#039;&#039;&#039;Does the problem affect only unsupported versions?&#039;&#039;&#039; If so, the issue should be closed using &amp;quot;Fixed&amp;quot; (preferred as it sounds better) when the issue is resolved in current versions or &amp;quot;Not a bug&amp;quot; when the issue has disappeared due to changes leading to current versions. See [Releases] to find currently supported versions&lt;br /&gt;
* &#039;&#039;&#039;Did the problem arise because of mistake in documentation or lack thereof?&#039;&#039;&#039; If it appears that the reporter does not understand a particular feature in Moodle and the documentation is lacking, ask the reporter where would he expect to find documentation about it. Then simply edit the relevant pages in the documentation wiki and close the issue. If required change is significant, add &#039;&#039;Documentation&#039;&#039; component and &#039;&#039;docs_required&#039;&#039; label.&lt;br /&gt;
* &#039;&#039;&#039;Is the problem a language string change?&#039;&#039;&#039; Language string problems can be corrected by [[Contributing a translation|contributing a translation]] or by contacting the language pack maintainer as listed in the [https://lang.moodle.org/local/amos/credits.php Translation credits]. English language string typo fixes and suggested improvements can be [[Improving English language strings|contributed to the English (fixes) (en_fix) language pack]] or given the component &#039;Language&#039; for fixing by the Language component lead. Such issues should be closed in the Tracker using &amp;quot;Deferred&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Is it a usability issue?&#039;&#039;&#039; If so, add the component &amp;quot;Usability&amp;quot; in addition to the component(s) specifying the area of Moodle. &lt;br /&gt;
* &#039;&#039;&#039;Was the problem caused by additional code or 3rd party plugins?&#039;&#039;&#039; If you can identify the plugin, move the issue to the respective component of CONTRIB project. Otherwise comment and close as &amp;quot;Not a bug&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Can this be implemented as a plugin?&#039;&#039;&#039; And maybe the plugin already exists in the plugins directory. Explanation should be given to the reporter that Moodle provides the framework but does not work on any possible plugin. Add label &amp;quot;addon_candidate&amp;quot; but do not close the issue. This can also apply to the requests to significantly redesign existing plugins and it would be more preferable to create a new alternative plugin.&lt;br /&gt;
* &#039;&#039;&#039;Does the problem seem rational?&#039;&#039;&#039; If not, then the problem may simply be an misunderstanding on the part of the reporter. It might be a problem exclusive to the reporter&#039;s server set-up. If you can replicate the problem quickly, do so. If you can&#039;t replicate the problem, ask the reporter to attempt to replicate the problem on http://demo.moodle.net. If the problem seems persistent but strange, consider asking a developer with experience working in the area to consider the problem and determine if it could be a real problem.&lt;br /&gt;
* &#039;&#039;&#039;Can the problem be replicated?&#039;&#039;&#039; If not, or information on the issue is insufficient, ask the reporter to add error messages, screenshots, environment information (OS, web server, browser) and exact replication instructions&lt;br /&gt;
&lt;br /&gt;
As a result of initial screening up to 20% of new issues may be closed. When closing the issues make sure to set the correct resolution and write a polite comment with explanation, refer to the templates below. If you have doubts, ask the questions and always add label [https://tracker.moodle.org/issues/?jql=labels%20in%20%28triaging_in_progress%29 triaging_in_progress]. Subscribe to the filter [https://tracker.moodle.org/issues/?jql=labels%20in%20%28triaging_in_progress%29%20AND%20project%20%3D%20MDL%20AND%20resolution%20%3D%20Unresolved%20AND%20Participants%20%3D%20currentUser%28%29%20AND%20updatedDate%20%3C%20-30d My old issues in triage] and you will receive notifications after 30 days of inactivity on such issues. See [[Tracker tips]] about how to subscribe to filter. Very often the reporter never follows up on their own issues and this is a good way to find such issues and ping reporter again or make a final decision about closing.&lt;br /&gt;
&lt;br /&gt;
===Confirming the issue===&lt;br /&gt;
&lt;br /&gt;
When you confirm that issue is indeed a bug or a reasonable improvement request that was not reported previously, make sure that the following is accurate:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Security level.&#039;&#039;&#039; Security level must be set as soon as possible if the reported bug discloses vulnerability in Moodle that can be exploited to access information without appropriate level, create an attack on the site, embed XSS or forge a request. In some rare cases Improvements may be also marked as security&lt;br /&gt;
* &#039;&#039;&#039;Summary.&#039;&#039;&#039; Summary of the issue should clearly describe the problem or improvement area, rephrase such summaries as &amp;quot;Some improvements in xxx&amp;quot; or &amp;quot;Error in Moodle&amp;quot;, etc.&lt;br /&gt;
* &#039;&#039;&#039;Issue Type.&#039;&#039;&#039; The following issue types are used in Moodle:&lt;br /&gt;
** Bug - represents an actual bug and should be fixed in all supported versions. Very often when reporter expects something to be better than it actually is they call it a bug when it&#039;s in fact an improvement.&lt;br /&gt;
** Improvement - improvement to existing functionality. If addressed, will be integrated in the following major release only&lt;br /&gt;
** New feature - completely new feature, also will not be applied to the released versions (unless implemented as a plugin and submitted to plugins directory)&lt;br /&gt;
** Task - usually created by developers themselves and can not be classified as Bug or Improvement, for example, adding automated tests, improving documentation, etc.&lt;br /&gt;
** Epic - created by HQ developers or component leads to collect together issues that represents parts of one project. META issues and sub-tasks should not be used any more&lt;br /&gt;
* &#039;&#039;&#039;Priority.&#039;&#039;&#039; Some reporters over-state an issue&#039;s priority. Some reporters don&#039;t know they can set a priority. Priority is used as one of the criteria when sorting issues in the backlog, so it should reflect the position of this issue comparing to the others. Usually Improvements have Minor or Major priority and Bugs can have any priority up to Blocker. Priority levels have specific criteria. Please see [https://docs.moodle.org/dev/Tracker_guide#When_editing_an_issue the Tracker guide]&lt;br /&gt;
* &#039;&#039;&#039;Component/s.&#039;&#039;&#039; Listing components correctly is important as they are the primary variable used for searching for issues, also adding a component automatically include the component lead as a watcher. Issue may have several components when needed&lt;br /&gt;
* &#039;&#039;&#039;Affects version.&#039;&#039;&#039; This field should include one or more released *and supported* versions of Moodle that are affected by the issue, with the following exceptions:&lt;br /&gt;
** The issue is a bug in code that is present in the Master branch only, in which case the next major version should be used. (The next major version should not be used in conjunction with previous released versions, this won&#039;t make sense later.)&lt;br /&gt;
** The issue is a new feature and is unrelated to any existing code in Moodle, in which case the &#039;Future dev&#039; version should be used.&lt;br /&gt;
* &#039;&#039;&#039;Labels.&#039;&#039;&#039; &lt;br /&gt;
** Remove functionality tags that some reporters add as labels, only  [https://docs.moodle.org/dev/Tracker_issue_labels standard] labels or partner-specific labels are used in Moodle&lt;br /&gt;
** Issues with proposed fixes are labelled &#039;&#039;patch&#039;&#039; so that they can be found easily and given attention. When this is the case, consider whether moving the issue to the &#039;Waiting for peer review&#039; state in the workflow might be more appropriate&lt;br /&gt;
** Add &#039;&#039;addon_candidate&#039;&#039; label if the functionality can be implemented as a plugin;&lt;br /&gt;
** If you are component lead or HQ developer you may also add &#039;&#039;triaged&#039;&#039; label to indicate that triage process is completed. Use it only when the issue has actually been added to the backlog&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that &amp;quot;Fix version&amp;quot; is no longer used during triage. If you are in &amp;quot;moodle-triage&amp;quot; group, you can use the &#039;&#039;&#039;Triage screen&#039;&#039;&#039; to edit only aforementioned fields, see MDLSITE-3592.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When commenting on the issue give more details on replication, environment or testing. Ask questions, add watchers, modify description if needed. Link to as many related issues as possible. Do everything that will make the issues scope more clear and attract opinions, discussions and patches.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to show &#039;&#039;&#039;Gratitude and encouragement&#039;&#039;&#039;.  After triaging many issues, it&#039;s easy to lose sight of the fact that the reporter has contributed their time and energy to report an issue for the benefit of the community.&lt;br /&gt;
&lt;br /&gt;
It is easy to become defensive of Moodle if reports are seen as criticism (and sometimes reporters may use phrasing that suggests this), however the triagers response must always be one of sincere gratitude.&lt;br /&gt;
&lt;br /&gt;
It is also important to encourage reporters to continue being involved with the issue after it is triaged. We must not give the sense that we are taking the issue ownership away from the reporter. Instead the reporter should be encouraged to discover the cause of the problem and present a solution; this is appropriate in an open-source project. It is amazing that such a challenge can lead to a sense of purpose for the reporters.&lt;br /&gt;
&lt;br /&gt;
=== Following up on issues ===&lt;br /&gt;
&lt;br /&gt;
Tracker is set up by default so as soon as you comment on any issue or edit it, you become an automatic watcher and any following change on the issue will be emailed to you. &lt;br /&gt;
&lt;br /&gt;
If you have encouraged the reporter well, they may &#039;&#039;&#039;submit a patch&#039;&#039;&#039; or somebody else may do it. Make sure that the &#039;&#039;patch&#039;&#039; label is added or issue is sent to peer review. On the contrary, if &#039;&#039;patch&#039;&#039; label was added by somebody else but you clearly see that patch is far from ready, remove the label and leave a comment explaining it.&lt;br /&gt;
&lt;br /&gt;
Users may also comment with additional details, screenshots, replicating instructions. It may happen that the issue gets re-evaluated and priority or summary changed.&lt;br /&gt;
&lt;br /&gt;
=== Revisiting old issues ===&lt;br /&gt;
&lt;br /&gt;
While searching the tracker you may come over issues that were reported long time ago but still remain open. Again, ask the following questions&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Is this still an issue?&#039;&#039;&#039; If it is not applicable any more either close it or comment about it on the issue and recommend to close. Very few tracker users actually have permission to close issues but the component lead or watchers will see your comment and revisit issue. Another good practice is to replace &#039;&#039;triaged&#039;&#039; label with &#039;&#039;triaging_in_progress&#039;&#039; and add a comment asking if the issue can be closed. If users confirm that it was resolved or nobody replies in 30 days, issue should be closed.&lt;br /&gt;
* &#039;&#039;&#039;Do affected versions need correction?&#039;&#039;&#039; If the issue is still applicable, make sure to add missing current affected versions or comment about it on the issue if you can&#039;t edit it.&lt;br /&gt;
* &#039;&#039;&#039;Does the issue have patch and if yes, is it still applicable?&#039;&#039;&#039; If the issue has patch that still works but &#039;&#039;patch&#039;&#039; label is missing, look through comments or history to see if the &#039;&#039;patch&#039;&#039; label was removed after reviewing the current patch. If you find that label was never added, do it yourself. On contrary if the issue has &#039;&#039;patch&#039;&#039; label but the patch is no longer applicable or not sufficient, remove the label.&lt;br /&gt;
* &#039;&#039;&#039;Are there any duplicating issues?&#039;&#039;&#039; When finding duplicates among the old issues it might not be obvious which issue to close as a duplicate. Usually we should leave the first reported issue but if the later issues have more watchers, better description, more votes, useful comments, attached patch, etc. you may decide to close the earlier issue and leave the later. Sometimes both issues have lots of watchers and they both remain open. In any case, always create links between duplicates or related issues.&lt;br /&gt;
* &#039;&#039;&#039;Does the issue have assignee who forgot about it or misleading status &amp;quot;Development in process&amp;quot;?&#039;&#039;&#039; Due to some  [[Changes_to_issue_assignment|process changes]] in May 2013 some issues still have a real user in the &#039;&#039;Assignee&#039;&#039; field but this user actually does not work on the issue. Sometimes &#039;&#039;Assignee&#039;&#039; remains filled after failing peer review, sometimes developers simply forget that the issue was assigned to them. If you suspect that &#039;&#039;Assignee&#039;&#039; does not actually work on the issue, comment asking they about it and in some cases remove the &#039;&#039;Assignee&#039;&#039; completely. Allow somebody else to work on the issue without feeling that the issue is &amp;quot;taken&amp;quot;. Please also note that for some time tracker had a restriction that &#039;&#039;Assignee&#039;&#039; could not be empty so you can find lots of issues assigned to &#039;&#039;moodle.com&#039;&#039; or &#039;&#039;Nobody&#039;&#039;. Do not modify such issues as this creates unnecessary activity, emails to watchers and irrelevant change in the &amp;quot;Last update date&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Comments templates ===&lt;br /&gt;
====Redirecting someone with a support request====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for taking the time to create an issue. However, the problem you describe seems to be specific to your site, since I am unable to reproduce it on http://demo.moodle.net/. Thus I suggest you post asking for help in one of our community forums https://moodle.org/community/.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
I&#039;m going to close this issue now. If you find that your problem can indeed be reproduced on http://demo.moodle.net/ or you have a suggestion for an improvement, please create a new issue providing as much detail as you can.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Redirecting someone making a &#039;feature request&#039; that is actually already possible====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thank you for taking the time to request a new feature / suggest an improvement. However, what you ask for is already possible. I suggest you post asking for help about how to set up what you want in one of our community forums https://moodle.org/community/.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
I&#039;m going to close this issue now.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refer the user to their instance administrators====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;You have posted an issue on the Moodle Tracker, which relates to the improvement of Moodle code, not the Moodle site you are using at your institution. I recommend you contact the administrators of your Moodle site.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Closing duplicate====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for your report.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
It seems you&#039;re not the only one to have come across this bug, as it&#039;s been reported previously - see MDL-xyz. I&#039;m going to close this issue now so we can focus on MDL-xyz. Please watch, vote or comment on MDL-xyz if there is any additional information you can provide.&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Issue affects only unsupported versions====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for your report and apologies for it not being looked at before now. I tried but couldn&#039;t reproduce the problem in the latest stable version of Moodle. Thus, it seems it has been fixed as part of another issue and so I am closing this issue with resolution &#039;Cannot Reproduce&#039;. If you find that the problem can indeed be reproduced in the latest stable version of Moodle (for example on the [Moodle sandbox demo|https://sandbox.moodledemo.net]) please create a new issue with clear steps to reproduce and link it to this one.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Requesting more information====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for reporting this.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Could you please add more information to your report such as replication instructions, error messages and screenshots. If you are able to suggest a workaround, that would be immediately helpful to others experiencing this problem. If you can determine the cause of the problem or even determine a solution, that will be very valuable.&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Request to correct translation====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for reporting this.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;The problem that you are describing refers to the translation in another language. Language string problems can be corrected by [Contributing a translation|https://docs.moodle.org/dev/Contributing_a_translation] or by contacting the language pack maintainer as listed in the [Translation credits|http://lang.moodle.org/local/amos/credits.php]. I&#039;m going to close this issue because Moodle does not include translations in the standard download package.&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Correction to English language strings====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for reporting this.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Please note that English language string typo fixes and suggested improvements can be &amp;lt;nowiki&amp;gt;[contributed to the English (fixes) (en_fix) language pack|https://docs.moodle.org/dev/Improving_English_language_strings]&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Bug in contributed plugin (plugin can be identified)====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
You have created an issue under MDL project in the tracker. However the problem that you are describing refers to contributed plugin xxx. &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;I have moved your issue in the appropriate component of the CONTRIB project in tracker. I will also recommend you to leave a comment on the plugin page in the [Moodle plugins directory|https://moodle.org/plugins/]&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Triaging a bug report====&lt;br /&gt;
Thanks for reporting this issue.&lt;br /&gt;
&lt;br /&gt;
You can help us resolve it as quickly as possible by:&lt;br /&gt;
&lt;br /&gt;
* Adding further information in a comment or attaching a screenshot if requested by a developer investigating the issue.&lt;br /&gt;
* Posting the issue number in a moodle.org forum discussion about it.&lt;br /&gt;
* If you are able to provide a patch or links to your Git repository branch, please add a patch label so we will spot it.&lt;br /&gt;
&lt;br /&gt;
====Triaging an improvement or new feature====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for suggesting an improvement or new feature. &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;Please try [searching moodle.org|http://moodle.org/public/search/] to check whether someone else has had the same idea, then either join an existing discussion or start a new discussion in [Moodle in English|http://moodle.org/course/view.php?id=5]. Comment here with the link to the discussion, and mention this issue number in the discussion to encourage others to watch, vote or comment on it.&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;If you can propose a code solution, please [create a patch|https://docs.moodle.org/dev/How_to_create_a_patch] or provide links to your Git repository branch, then add the patch label to the issue. &amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;For more ways to maximize the chance of your idea being implemented, see the guide [New feature ideas|https://docs.moodle.org/dev/New_feature_ideas].&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating a filter and gadget for triaging==&lt;br /&gt;
&lt;br /&gt;
If you are a component lead you are responsible for triaging issues that involve your component. A good way to monitor newly created issues is to create a filter in the Tracker and add a gadget on your dashboard to show the results of the filter.&lt;br /&gt;
&lt;br /&gt;
===Adding a filter===&lt;br /&gt;
&lt;br /&gt;
In Tracker...&lt;br /&gt;
# Select &#039;&#039;Issues&#039;&#039; &amp;gt; &#039;&#039;Search for Issues&#039;&#039;.&lt;br /&gt;
# Create a search for untriaged issues in your component, for example...&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;component in (Assignment) AND resolution = Unresolved AND (labels is EMPTY OR labels not in (triaged)) ORDER BY created DESC&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Run the search query by pressing &#039;&#039;Enter&#039;&#039; or clicking the magnifying glass icon to the right of the search box.&lt;br /&gt;
# When the search query results are displayed, click the &#039;&#039;Save as&#039;&#039; button.&lt;br /&gt;
# Save the search query with an appropriate name, like &amp;quot;Untriaged Assignment issues&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Adding a filter in a gadget to your dashboard===&lt;br /&gt;
&lt;br /&gt;
In Tracker...&lt;br /&gt;
# Click &#039;&#039;Dashboards&#039;&#039; &amp;gt; &#039;&#039;Dashboard for XXX&#039;&#039; (where &#039;&#039;XXX&#039;&#039; is your name).&lt;br /&gt;
# Click &#039;&#039;+ Add Gadget&#039;&#039;.&lt;br /&gt;
# Find the &#039;&#039;Filter Results&#039;&#039; gadget.&lt;br /&gt;
# Click &#039;&#039;Add it Now&#039;&#039;.&lt;br /&gt;
# Click &#039;&#039;Finished&#039;&#039;.&lt;br /&gt;
# In the &#039;&#039;Saved Filter&#039;&#039; input, search for and select your newly created filter.&lt;br /&gt;
# Click &#039;&#039;Save&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The most recent untriaged issues should appear in reverse-date order.&lt;br /&gt;
&lt;br /&gt;
==Triaging priorities and the Triaging Dashboard==&lt;br /&gt;
&lt;br /&gt;
The following are the priorities for ordering issues to be triaged that are reflected on the [http://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11153 Triaging dashboard].&lt;br /&gt;
&lt;br /&gt;
# Security issues - should always be reduced to 0&lt;br /&gt;
# High-priority issue - aim for blockers and critical issues to be reduced to 0&lt;br /&gt;
# Partner issues - aim for partner issues to be reduced to 0&lt;br /&gt;
# Patched issues - aim to triage as soon as possible&lt;br /&gt;
# Developer-reported issues (HQ and non-HQ) - should be quick to triage&lt;br /&gt;
# Recent community bugs - should be triaged last-in-first-out&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Tracker guide]]&lt;br /&gt;
*[[Process]]&lt;br /&gt;
*[[Talk:Bug triage]]&lt;br /&gt;
*[[Tracker tips]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Processes]]&lt;br /&gt;
[[Category:Quality Assurance]]&lt;br /&gt;
[[Category:Tracker]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=QA_testing&amp;diff=61084</id>
		<title>QA testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=QA_testing&amp;diff=61084"/>
		<updated>2021-08-11T14:54:19Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Quality Assurance&#039;&#039;&#039; tests look at the functionality of Moodle from a user&#039;s point of view.  &lt;br /&gt;
&lt;br /&gt;
Real users systematically try each feature in Moodle and test that it works in the current version of the Moodle code. These tests are repeated in series of cycles, usually 4 weeks before a major release, once all major features have landed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;QA testing latest&#039;&#039;&#039;:  &#039;&#039;A 100% pass rate was obtained in Moodle 3.11 QA testing. Many thanks to all our [[Testing credits|QA testers]].&#039;&#039;&amp;lt;/p&amp;gt;&lt;br /&gt;
==Getting involved==&lt;br /&gt;
&lt;br /&gt;
Would you like to help with QA testing?  If so, please make sure you have created an account in the [[Tracker_introduction|Moodle tracker]] and you&#039;re subscribed to the [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum] in order to receive QA testing news updates.&lt;br /&gt;
&lt;br /&gt;
==Running tests==&lt;br /&gt;
&lt;br /&gt;
# Go to the [https://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11454 Moodle QA testing dashboard] and choose a test from the list of current QA cycle open issues. When viewing a test, if you wish, you can click the &#039;Assign to me&#039; link on the right, so that nobody else chooses the same test to run. (If you then find you are unable to run the test, you can click the Assign button and set the assignee as &#039;Unassigned&#039;.) Please note:&lt;br /&gt;
#* Only assign an issue to yourself which no one else is testing (Assignee = Unassigned).&lt;br /&gt;
#* Only assign one issue at a time unless you plan to test a number of related issues within the next 24 hours. In other words, don&#039;t assign several issues to yourself then do nothing for several days. ;-)&lt;br /&gt;
#* The label &#039;&#039;test_server_required&#039;&#039; indicates issues that can&#039;t be tested on the QA testing site. The label &#039;&#039;credentials_required&#039;&#039; indicates that credentials such as an OAuth 2 service client ID and secret are required.&lt;br /&gt;
# Using either the [https://qa.moodledemo.net/ Moodle QA Testing Site] or your own test site running the latest Moodle 4.0dev (available from Git on the integration/MOODLE_400_STABLE branch &#039;&#039;&amp;lt;nowiki&amp;gt;git://git.moodle.org/integration.git&amp;lt;/nowiki&amp;gt;&#039;&#039;) with [[:en:Debugging|debugging]] set to developer, perform each of the steps listed in the test.&lt;br /&gt;
# &#039;&#039;Please attach screenshots of the steps where you verify or check something.&#039;&#039;&lt;br /&gt;
# If it makes sense, please test using the currently supported themes, Boost and Classic.&lt;br /&gt;
# Choose an appropriate workflow action:&lt;br /&gt;
#* &#039;&#039;Pass&#039;&#039; - Test runs perfectly. Add comment such as feedback about a new feature, browsers used for testing (if applicable; example: &amp;quot;This test passes on Q&amp;amp;A site with Teacher role using Boost theme&amp;quot;), or simply &amp;quot;This test passes - yippee!&amp;quot;&lt;br /&gt;
#* &#039;&#039;Fail&#039;&#039; - Something doesn&#039;t work, or you obtain debugging messages. Add comment describing the step that doesn&#039;t work. If in doubt whether to pass a test, give it a fail and add a comment describing your doubts.&lt;br /&gt;
#* &#039;&#039;Obsolete&#039;&#039; - Test is no longer relevant in the current Moodle version. Add comment explaining why.&lt;br /&gt;
&lt;br /&gt;
If you notice that the test description is out-of-date, add a comment mentioning that it needs updating. Alternatively, if you&#039;d like to help with updating the test yourself, see below.&lt;br /&gt;
&lt;br /&gt;
==Any questions?==&lt;br /&gt;
&lt;br /&gt;
If there is anything you are unsure of, such as whether to mark a test as failed, or you have any other questions, please ask in one of the following places:&lt;br /&gt;
&lt;br /&gt;
* [https://t.me/moodleqa Moodle QA Telegram chat room] *new*&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum]&lt;br /&gt;
&lt;br /&gt;
==Moodle QA Testing Site==&lt;br /&gt;
&lt;br /&gt;
The [https://qa.moodledemo.net/ Moodle QA Testing Site] is updated daily at around 13:00 UTC with the latest bug fixes to enable you to re-run QA tests.&lt;br /&gt;
&lt;br /&gt;
To prevent the site being used for sending spam, no emails are sent from it. Thus, tests involving email cannot be run using the Moodle QA Testing Site. (If such tests are attempted, an email debug message is displayed. This is not a bug but rather expected behaviour.)&lt;br /&gt;
&lt;br /&gt;
Teacher and student accounts are provided. Please contact [https://moodle.org/user/profile.php?id=24152&amp;amp;course=1 Helen] if you would like admin or manager access to the Moodle QA Testing Site for running certain tests.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;div id=&amp;quot;failedTests&amp;quot;&amp;gt;Failed tests&amp;lt;/div&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
So you ran a test and it failed? Congratulations on finding a bug! Please do the following.&lt;br /&gt;
&lt;br /&gt;
# Click the Fail button at the top of the page.&lt;br /&gt;
# Add a comment to the QA test stating that there was a problem and that you will report it as a Moodle bug.&lt;br /&gt;
# Note the MDLQA number; it will be something like &amp;lt;nowiki&amp;gt;MDLQA-448&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
# Try searching for whether the bug has been reported previously, and if not create a new issue for it (as described in [[Tracker introduction]]).&lt;br /&gt;
# In the new Moodle (MDL) issue select &#039;Link&#039; from the &#039;More actions&#039; dropdown menu. &amp;lt;br /&amp;gt;[[Image:LinkIssue.png|150px|Linking to the QA issue in the tracker]]&lt;br /&gt;
# Link to the QA test by selecting &#039;blocks&#039; as the link type, entering the MDLQA number that you noted earlier, and optionally adding a comment. &amp;lt;br /&amp;gt;[[Image:LinkDetails.png|150px|Adding details for a link to the QA issue]]&lt;br /&gt;
# Give the issue the label &#039;mdlqa&#039;. &lt;br /&gt;
# (Optional) Add yourself as a watcher to the MDL issue so that you receive email notification when the issue is fixed.&lt;br /&gt;
# When the MDL issue is fixed, hopefully within a day or two, the QA test can be reset and can then be run again.&lt;br /&gt;
&lt;br /&gt;
==Resetting tests==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note for integrators:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After integrating a fix, &lt;br /&gt;
&lt;br /&gt;
# Reset the MDLQA test, adding a comment.&lt;br /&gt;
# Remove the &#039;mdlqa&#039; label from the MDL issue.&lt;br /&gt;
# If the issue doesn&#039;t have testing instructions, pass it with message &amp;quot;Will be tested by MDLQA-XXXX&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The tester will then receive email notification that the bug is fixed and will hopefully decide to run the test again soon.&lt;br /&gt;
&lt;br /&gt;
==Fixing existing bugs==&lt;br /&gt;
&lt;br /&gt;
At the beginning of the QA cycle, all bugs identified (both new and existing) are investigated promptly and hopefully fixed. &lt;br /&gt;
&lt;br /&gt;
When we are close to the scheduled release date (1-2 weeks prior), developers must focus on fixing new bugs (which affect the upcoming release version) only.&lt;br /&gt;
&lt;br /&gt;
Thus, at this point in the QA cycle, any bugs which also affect existing versions of Moodle are labelled qa_identified (and the label mdlqa removed) for investigation after the release.&lt;br /&gt;
&lt;br /&gt;
==Testing tips==&lt;br /&gt;
&lt;br /&gt;
When entering text into a form, try things like:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;amp;&amp;lt;/syntaxhighlight&amp;gt; (ampersand), &amp;lt;code&amp;gt;&amp;gt;&amp;lt;/syntaxhighlight&amp;gt; (greater than) or &amp;lt;code&amp;gt;&amp;lt;&amp;lt;/syntaxhighlight&amp;gt; (less than) e.g. &amp;lt;code&amp;gt;x &amp;lt; 1 &amp;amp;&amp;amp; x &amp;gt; 0&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;0&amp;lt;/syntaxhighlight&amp;gt; (the single digit 0) &lt;br /&gt;
* &amp;lt;code&amp;gt;&#039;&amp;lt;/syntaxhighlight&amp;gt; (single quote) e.g. &amp;lt;code&amp;gt;Fergal.O&#039;Brien@example.com&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* special characters e.g. &amp;lt;code&amp;gt;café&amp;lt;/syntaxhighlight&amp;gt; or &amp;lt;code&amp;gt;囲碁&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* very long strings&lt;br /&gt;
* different languages, such as a RTL language&lt;br /&gt;
&lt;br /&gt;
==New QA tests required==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note for developers:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If an issue fix cannot be covered by automated tests, &lt;br /&gt;
&lt;br /&gt;
# Add the label &#039;qa_test_required&#039; to the issue.&lt;br /&gt;
# Add a comment explaining why it can&#039;t be covered by automated tests and suggesting which steps of the testing instructions should be included in a QA test e.g. steps 6-10 or all steps.&lt;br /&gt;
&lt;br /&gt;
QA tests will then be written and included in the next QA cycle. For issues with long testing instructions, several QA tests will be written to cover the issue. If appropriate, activities etc. will be set up on the [https://qa.moodledemo.net/ Moodle QA Testing Site] to enable the issue to be easily tested in future. &lt;br /&gt;
&lt;br /&gt;
Similarly, for new features and improvements which would benefit from exploratory testing,&lt;br /&gt;
&lt;br /&gt;
# Add the label &#039;qa_test_required&#039; to the issue.&lt;br /&gt;
# Add a comment mentioning that exploratory testing is required.&lt;br /&gt;
&lt;br /&gt;
Exploratory QA tests will then be written and included in the next QA cycle and then removed.&lt;br /&gt;
&lt;br /&gt;
==Updating tests==&lt;br /&gt;
&lt;br /&gt;
QA tests often become out-of-date due to new developments. If you would like to help with updating tests, you&#039;ll need to be a member of the test writers group in the Tracker. Please contact Helen about being added.&lt;br /&gt;
&lt;br /&gt;
To update a QA test:&lt;br /&gt;
&lt;br /&gt;
# Search for the master copy of the test - with affects version as &#039;Master copy&#039; and MDLQA-1 as parent.&lt;br /&gt;
# Edit the test description.&lt;br /&gt;
# Optional: Add a comment describing your edit.&lt;br /&gt;
&lt;br /&gt;
==Writing new tests==&lt;br /&gt;
&lt;br /&gt;
Would you like to help with writing new QA tests? If so, as for updating tests, you&#039;ll need to be a member of the test writers group in the Tracker. Please contact Helen about being added.&lt;br /&gt;
&lt;br /&gt;
To create a new QA test:&lt;br /&gt;
&lt;br /&gt;
# Choose an issue from the  [https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_test_required%20AND%20status%20%3D%20Closed closed qa_test_required-labelled issues] &lt;br /&gt;
# Do a quick search of MDLQA-1 to check if there is an existing test which can be updated&lt;br /&gt;
# If not, create a sub-task of MDLQA-1&lt;br /&gt;
# Select &#039;Original&#039; as affected version&lt;br /&gt;
# Select appropriate components&lt;br /&gt;
# Set assignee as unassigned&lt;br /&gt;
# Write the test (usually between 3 and 10 steps). It&#039;s a good idea to try doing the steps yourself as you write the test.&lt;br /&gt;
# Add the label &#039;&#039;new&#039;&#039;&lt;br /&gt;
# For tests which can’t be run on the QA site, label &#039;&#039;test_server_required&#039;&#039;. For OAuth 2 tests and any other tests which require a client ID or secret to be entered, label &#039;&#039;credentials_required&#039;&#039;.&lt;br /&gt;
# For issues which specifically mention in the testing instructions to test in different browsers, use the phrase &amp;quot;Test in as many browsers as possible and mention in a comment which ones you’ve used.&amp;quot;&lt;br /&gt;
# For an exploratory test, begin the test description with &amp;quot;This is an exploratory test of a new feature or improvement, so please feel free to try anything you like and not just the test steps!&amp;quot;&lt;br /&gt;
# For a test requiring admin access which can be run on the QA site, add:&lt;br /&gt;
 This test requires admin access. If you would like to use the [QA testing site|https://qa.moodledemo.net/] for running it, please see the [QA testing guide|https://docs.moodle.org/dev/QA_testing] for details of how to request admin access. Begin just after the hourly reset to give yourself plenty of time to complete the test!&lt;br /&gt;
&lt;br /&gt;
13. Go to the MDL issue and create a ‘has a QA test’ link to the new QA test, adding a comment “Thanks for this improvement which is now covered by the QA test MDLQA....”, and remove the qa_test_required label. &#039;&#039;Make sure that all QA tests are linked back to a corresponding MDL issue.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
New tests will be included in the next QA cycle.&lt;br /&gt;
&lt;br /&gt;
==Feedback==&lt;br /&gt;
&lt;br /&gt;
Feedback on all aspects of our QA testing process is welcome. If you have any questions or comments, please post in the [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [https://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11454 QA testing dashboard]&lt;br /&gt;
* [[Testing credits]]&lt;br /&gt;
* [[MDLQA-features]]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=351302 Useful tips for QA testing]&lt;br /&gt;
&lt;br /&gt;
Comments on tests from previous QA cycles:&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-150 Moodle 2.0 QA Cycle 1]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-328 Moodle 2.0 QA Cycle 2]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-540 Moodle 2.0.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-944 Moodle 2.1 QA Cycle 1]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-1190 Moodle 2.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-1814 Moodle 2.3 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-4602 Moodle 2.4 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-5267 Moodle 2.5 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-5740 Moodle 2.6 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-6693 Moodle 2.7 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-7170 Moodle 2.8 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-7660 Moodle 2.9 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-8205 Moodle 3.0 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-9267 Moodle 3.1 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-9827 Moodle 3.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-10403 Moodle 3.3 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-10999 Moodle 3.4 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-11698 Moodle 3.5 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-12282 Moodle 3.6 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-12911 Moodle 3.7 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-13517 Moodle 3.8 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-14131 Moodle 3.9 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-14813 Moodle 3.10 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-15457 Moodle 3.11 QA]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Languages_subsystem_improvements_2.0&amp;diff=61083</id>
		<title>Languages subsystem improvements 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Languages_subsystem_improvements_2.0&amp;diff=61083"/>
		<updated>2021-08-11T14:54:19Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Languages subsystem improvements&lt;br /&gt;
|state = Complete&lt;br /&gt;
|tracker = MDL-18797 MDL-15252&lt;br /&gt;
|discussion = [http://moodle.org/mod/forum/discuss.php?d=118707]&lt;br /&gt;
|assignee = [[User:David Mudrak|David Mudrak]]&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
{{Warning|This page was once used as an initial specification of the project. Only parts of it were finally implemented. It is kept for archive purposes only.}}&lt;br /&gt;
&lt;br /&gt;
This is a specification of changes to the language strings processing in Moodle 2.0 and 2.1. You should start looking at the [http://www.mindmeister.com/41382366/proposed-changes-for-moodle-2-x-languages-machinery overview of proposed changes] mindmap.&lt;br /&gt;
&lt;br /&gt;
== Current issues ==&lt;br /&gt;
&lt;br /&gt;
Why the changes in the current tools and process are needed:&lt;br /&gt;
&lt;br /&gt;
; String files are not branched : We must keep all strings from all branches in place for backwards compatibility and we are unable to easily clean up language packs. Some say the branching and merging is too much work for our translators (see MDL-15252).&lt;br /&gt;
; Plural forms, gender forms and other grammar : We are unable to handle plurals at all. For example, handling [http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html plural forms in gettext] is traditional, well tested and robust way (see MDL-4790). MDL-12433 by Sam Marshall shows alternative approach based on logical expressions.&lt;br /&gt;
; Strings can&#039;t be modified : It is difficult to notify translators that some string was modified (expanded, fixed, changed) - as in [http://git.moodle.org/gw?p=moodle.git;a=commit;h=d033b1288713625a733ce5fcbce5e7b5a1f6d5d1 this case], for example. The current work around is the policy of adding another string with the same suffixed name (like &#039;license2&#039;). It would be nice if such strings were tagged/highlighted in the translation UI.&lt;br /&gt;
; We do not use standard formats : Translators can&#039;t use specialized tools for translation (PO/gettext editors, community translation portals). Also, I (David) am not aware of any benchmarking showing the performance differences between out native $string[] format compared to, for example, standard .po format.&lt;br /&gt;
; More syntax checks are required : So the translators do not brake Moodle functionality (see MDL-12433)&lt;br /&gt;
; Language packs are PHP code, but stored in moodledata : This increases the severity of some security exploits. It means that any exploit that lets you write files to an arbitrary location in moodledata suddenly lets you execute arbitrary PHP code on the server. On the other hand, it would be nice to be able to allow complex logic when evaluating dynamic strings (ie such containing $a param/params).&lt;br /&gt;
; Right-to-left languages : There are problems reported in RTL languages when using online tools (including the our current one) which lead to putting placeholders like a$ and a$-&amp;gt;lastname into the string definition.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
# Fix all the issues listed above&lt;br /&gt;
# Do not reinvent the wheel&lt;br /&gt;
# Keep &amp;quot;do one thing and do it well&amp;quot; principle&lt;br /&gt;
# Keep it simple and stupid.&lt;br /&gt;
# Have the translation process as simple as possible - translators are not geeks&lt;br /&gt;
# Make simple things easy and hard things possible&lt;br /&gt;
# Make most of this available for Moodle 2.0&lt;br /&gt;
&lt;br /&gt;
== Key design questions ==&lt;br /&gt;
&lt;br /&gt;
When working on the specification, these were the key questions to keep in mind:&lt;br /&gt;
&lt;br /&gt;
; What is the data structure for storing the master copies of the lang packs : At the moment, strings are defined in plain PHP associative arrays, editable via translation UI or directly. These arrays are stored in PHP files in Moodle CVS. We are going to change it. According to the original Petr Skoda&#039;s proposal, the primary place for keeping all translated strings will be a central database at one of moodle.org servers. Together with the translation itself, usefule meta-data are kept in the database: the timestamp of the last modifications, links to the revision of the English string that the translation is based on, the author name, proposed alternatives, comments etc (see rosetta translation tool at launchpad for the example of possible metadata).&lt;br /&gt;
; What is the UI for translators, what are the processes of contributing and how the translations are redistributed to Moodle sites : Thanks to storing all strings in a database, we will be able to produce their list in various standardised formats (like PO or XLIFF). Therefore, the translators will not be forced to use the only one possible tool but can use their favourite advanced tool with its own translation memory, connected with dictionaries, i18n portals etc. Our central strings repository will support data export and import from/into various formats.&lt;br /&gt;
; What is the data structure that get_string() uses at runtime : This is just a performance optimization (implementation detail), should be independent on the native format that humans work with so it could be modified anytime in the future. For example, see the system proposed by Tim based on calling class methods (inspired by Perl&#039;s Maketext).&lt;br /&gt;
; What is the format of a lang string, and how are placeholders substituted : It is strongly tied together with the runtime format, it can be changed any time. On the other hand, both the UI and storage format must support it.&lt;br /&gt;
&lt;br /&gt;
== Use cases ==&lt;br /&gt;
&lt;br /&gt;
# Developers add new strings to the code and commit their work into CVS (core or contrib)&lt;br /&gt;
# Developers can add a comment to the string, eg. &amp;quot;this string is used for ...&amp;quot;&lt;br /&gt;
# Developers add new string and link it with a current one with an explanation eg &amp;quot;this string replaces ...&amp;quot;. Such links are available to translators and help them to decide the correct translation.&lt;br /&gt;
# Developers moves the string from one component (like enrol.php) into another (like enrol_manual.php). The current translations are re-used.&lt;br /&gt;
# Developers change the string identificator, for example from configfoobar to foobar_desc.&lt;br /&gt;
# Translators translate strings on several Moodle branches and do not need to worry about branching, commiting and merging&lt;br /&gt;
# Translators can see the list of untranslated strings and translate them&lt;br /&gt;
# Translators can see the list of outdated translated strings (aka English string was changed) and update the translation&lt;br /&gt;
# Admins can locally modify the language pack for their site&lt;br /&gt;
# Community members can propose alternative translations. They are reviewed by the lang pack maintainer and may be approved.&lt;br /&gt;
&lt;br /&gt;
== Research ==&lt;br /&gt;
&lt;br /&gt;
This is the list of projects, resources and tools that were explored before writing this spec&lt;br /&gt;
&lt;br /&gt;
* [http://search.cpan.org/~ferreira/Locale-Maketext-1.13_82/lib/Locale/Maketext/TPJ13.pod Great CPAN article about software localization]. Plain string based lexicon is not enough. Strings can be translated by functions only. &amp;quot;A phrase is a function; a phrasebook is a bunch of functions.&amp;quot;&lt;br /&gt;
* [http://en.wikipedia.org/wiki/XLIFF XLIFF] - XML Localization Interchange File Format&lt;br /&gt;
* [http://translate.sourceforge.net/wiki/virtaal/index Virtaal] - promising, we could have XLIFF &amp;lt;-&amp;gt; .php conversion&lt;br /&gt;
* [http://launchpad.net/+tour/translation Launchpad] - translation portal used by Ubuntu and many other projects. Would require BSD licensing, therefore IMO not suitable as we could not import our current GPL&#039;ed translation. Seems to be quite slow during the process.&lt;br /&gt;
* [http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html Plural forms in gettext]&lt;br /&gt;
* [http://framework.zend.com/manual/en/zend.translate.html Zend_Translate reference guide]&lt;br /&gt;
* MDL-12433 - Sam Marshal&#039;s proposal&lt;br /&gt;
* MediaWiki approach: [http://www.mediawiki.org/wiki/Manual:$wgGrammarForms Grammar forms] and plurals: &amp;lt;code&amp;gt;{{plural:1|is|are}} {{plural:2|is|are}}&amp;lt;/syntaxhighlight&amp;gt; (Example of how mediawiki outputs the correct given pluralization form depending on the count. Plural transformations are used for languages like Russian based on &amp;quot;count mod 10&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Functional proposals ==&lt;br /&gt;
&lt;br /&gt;
=== Overall strings processing flow ===&lt;br /&gt;
&lt;br /&gt;
(Follow the attached UML flow diagram) [[Image:languages20_overview1.png|thumb|right|UML: Overall string processing flow]]&lt;br /&gt;
&lt;br /&gt;
* All string definitions are kept in a central database togeteher with other all meta-data (branch, where does the string come from, what was its history etc.). Officially maintained language packs are referred to as &#039;&#039;master&#039;&#039; in this proposal. Every language pack can have its &#039;&#039;parent&#039;&#039; defined. The English language pack can be seen as the greatest common parent of all language packs.&lt;br /&gt;
* During upgrade or on demand, the relevant branch of master language packs are fetched (downloaded) automatically from the central database. Together with the selected language, all its parents, grandparent, great-grandparents, ... etc are downloaded, too.&lt;br /&gt;
* Administrators can keep local modifications (customizations) of any master pack. We call them &#039;&#039;local&#039;&#039; language packs.&lt;br /&gt;
* Immediately after upgrade (or again, on demand), the string definitions are merged from all available sources. The merge logic is so that the sources for any given string are evaluated in the order like: fr_ca_local, fr_ca, fr_local, fr, en_local, en. Strings are merged for the performance reasons so that the searching for the string to use (local, parent, master, English etc.) is done just once and we do not need to load all possible sources on runtime. After the merge, we have a single place to look for the string definition for every installed language. By default, the location for these merged strings will be $CFG-&amp;gt;dataroot/cache/lang/XX/component.php where XX is the language code (fr_ca, fr, en in this example). The benefit is that get_string() can rely on always having the string defined in this file, no other seeking and I/O is needed in runtime.&lt;br /&gt;
* Together with the merge, strings are compiled into a runtime format that may be optimised in the future. Humans do not modify the compiled format. Strings must be re-merged and re-compiled after any update of master or local packs. During the compilation, syntax checks are performed.&lt;br /&gt;
* The runtime format we will start with will be very similar with the current one. Strings are defined as array elements indexed by the string identifier. The arrays are defined in separate files for every module. We can, however, modify this in the future. For example, we can divide string definitions into files not by the module name but by the real usage frequency. Strings that are used very often (like at every page) would go into common file which can be loaded during bootstrap. This would reduce memory usage and number of I/O operations.&lt;br /&gt;
* There will be a way how to let get_string() call a PHP function/method to actually return the translated string instead of a static string definition. This will allow advanced translators to deal with many grammar issues they have in their languages (notably singular v plural forms).&lt;br /&gt;
&lt;br /&gt;
=== Naming and locations ===&lt;br /&gt;
&lt;br /&gt;
* Languages will be reffered to as &amp;quot;en&amp;quot;, &amp;quot;cs&amp;quot;, &amp;quot;en_us&amp;quot; or &amp;quot;fr_local&amp;quot; etc. Directories will be renamed.&lt;br /&gt;
* Downloaded lang packs are stored in $CFG-&amp;gt;langpacks, which is by default $CFG-&amp;gt;datadir/lang. Paranoid admins can change this to a different location that is normally read-only for the web server. Then they will manually switch to read-write when they are performing an upgrade, doing lang editing, or installing a lang pack. The UI should therefore check whether $CFG-&amp;gt;langpacks is writable before starting any of these operations, and explain the situation to admins if it is not.&lt;br /&gt;
* After mergin and compiling, the strings in runtime format are stored in $CFG-&amp;gt;dataroot/cache/lang/ (see above).&lt;br /&gt;
* All core plugins will have their language files in their own scope as the contrib plugins have. So for example workshop strings will be defined in &#039;/mod/workshop/lang/en/workshop.php&#039; instead of legacy &#039;/lang/en_utf8/workshop.php&#039;&lt;br /&gt;
&lt;br /&gt;
=== HTML help files replaced with ordinary strings ===&lt;br /&gt;
&lt;br /&gt;
Help should consist of a paragraph or two of a static HTML only, the rest goes to wiki. We will drop help files indices (index of all help files) as well as other dynamically generated helps in favour of wiki. This will make the translation easier as we do not need to have other tools to translate help files.&lt;br /&gt;
&lt;br /&gt;
Help strings are kept together with other workshop strings as in &amp;lt;code&amp;gt;$string[&#039;intro&#039;] = &#039;Workshop intro&#039;; $string[&#039;intro_help&#039;] = &#039;This is the ...&#039;;&amp;lt;/syntaxhighlight&amp;gt;. It allows to keep the string and their help together which helps translators to keep translation consistency.&lt;br /&gt;
&lt;br /&gt;
See [[Help strings]] for further information.&lt;br /&gt;
&lt;br /&gt;
=== Other changes ===&lt;br /&gt;
&lt;br /&gt;
* The only valid placeholder in runtime format is &amp;lt;code&amp;gt;{$a}&amp;lt;/syntaxhighlight&amp;gt; for strings and numbers and &amp;lt;code&amp;gt;{$a-&amp;gt;foobar}&amp;lt;/syntaxhighlight&amp;gt; for objects MDL-18841.&lt;br /&gt;
* Around 90% of our strings do not contain any placeholder and they will be immediately returned by get_string().&lt;br /&gt;
* If the string contains one or more placeholders, they are replaced with their eval()-uated result. We can safely eval() the whole string definition because the string compiler makes sure that the placeholders are the only executable/evaluable code. All other malicious code and $variables are properly quoted/escaped/htmlentitled.&lt;br /&gt;
* Valid format of string identifier must be defined. These identifiers may be used as associative array keys (as in &amp;lt;code&amp;gt;$string[&#039;identifier&#039;]&amp;lt;/syntaxhighlight&amp;gt;), function names, HTML form field names, file names etc. No characters like &#039;*&#039; can be used (as happened in MDL-21375).&lt;br /&gt;
* Some string identifiers are not hardcoded (explicitly referenced) in the code but computed, eg. &amp;lt;code&amp;gt;get_string(&#039;level&#039; . $level, &#039;arcade&#039;)&amp;lt;/syntaxhighlight&amp;gt; with strings &#039;level1&#039;, &#039;level2&#039;, &#039;level3&#039; etc being defined. It is difficult to automatically search for the usage of such strings. Therefore, I (David) propose the following guideline (rule):&amp;lt;br /&amp;gt;String identifiers must follow our convention for naming $variables: single lowercase word, no underscore. The colon (:) sign can be used only in strings with the names of capabilities and nowhere else. The minus sign (-) can be used only in string identifiers witch are partially computed, as in &amp;lt;code&amp;gt;get_string(&#039;region-&#039; . $regionid, &#039;theme_example&#039;)&amp;lt;/syntaxhighlight&amp;gt; so that is a sign that we should be careful when trying to find an usage of such string in the code. The underscore is reserved for special _help and _desc suffixes.&lt;br /&gt;
&lt;br /&gt;
=== Central web-based translation tool ===&lt;br /&gt;
&lt;br /&gt;
See [[Automated_Manipulation_of_Strings_2.0]]&lt;br /&gt;
&lt;br /&gt;
== Implementation proposals ==&lt;br /&gt;
&lt;br /&gt;
Read [http://moodle.org/mod/forum/discuss.php?d=118707#p542197 Petr&#039;s proposal] to store strings in one central database and to disable direct commits. That is roughly valid with the exception that the &amp;quot;no change meaning&amp;quot; rule is not forced. AMOS is able to track changes and inform translators that their translation is outdated. So we will be able to fix/update/extend English string as needed. Together with branching, this will lead to a nice &amp;quot;reduced&amp;quot; packs without redundancy.&lt;br /&gt;
&lt;br /&gt;
=== Translation tools and the process ===&lt;br /&gt;
&lt;br /&gt;
See MDL-15252 (Cleanup of English language pack) and the discussion at http://moodle.org/mod/forum/discuss.php?d=118707 for Koen&#039;s proposition. Branching issue, the translation process and other aspects discussed there.&lt;br /&gt;
&lt;br /&gt;
Some notes:&lt;br /&gt;
&lt;br /&gt;
From Martin in Dev chat:  &#039;&#039;if you want crazy ideas, how about get_string returns some special tags and those tags get converted to ajax on the GUI so that translators can translate directly in the main Moodle GUI?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
What a cool idea. Could be a special mode you have to turn on in the admin screens. Perhaps even if you turned this mode on, it would still only be active for people with certain roles, or perhaps when it was turned on, it would have to apply to all roles, so that you could edit strings for not-logged-in users. Anyway, when this mode was on, it would:&lt;br /&gt;
&lt;br /&gt;
# Adds &amp;amp;lt;span class=&amp;quot;moodle-lang-string&amp;quot; id=&amp;quot;lang_string|admin|langedit&amp;quot;&amp;gt;Language editing&amp;lt;/span&amp;gt; around each string on the page - to use one example.&lt;br /&gt;
# $PAGE-&amp;gt;requires-&amp;gt;js an extra JS file that adds an on-click handler to all such spans, so that when you click on it, it pops up the language editing UI in a YUI dialogue.&lt;br /&gt;
&lt;br /&gt;
:: [[User:David Mudrak|David Mudrak]] 14:07, 23 November 2009 (UTC): the solution based on wrapping &amp;amp;lt;span&amp;amp;gt; around every string was already considered and dropped. It may badly break XHTML as the string itself may appear as a value of an HTML tag&#039;s attribute: &amp;lt;code&amp;gt;&amp;amp;lt;img title=&amp;quot;&amp;amp;lt;span class=&amp;quot;moodle-lang-string&amp;quot; ...&amp;lt;/syntaxhighlight&amp;gt;. We are unable to say the scope where the string will appear.&lt;br /&gt;
:: David&#039;s contra-proposal: get_string() could track all strings used at the current page and the AJAX form to edit them all could be rendered before the footer(). Or &#039;Edit system text on this page&#039; link would appear there.&lt;br /&gt;
&lt;br /&gt;
=== Getting the history of strings into database ===&lt;br /&gt;
&lt;br /&gt;
Source code management systems can&#039;t show us how the given string evolved during the time. Translators on the other hand need to know &amp;quot;personal history&amp;quot; of any given string, each with the author of the change, date, comment etc. String timeline will be populated from DB. To let it work, we will need to load all the strings history into DB. That can be done using our git mirror. This conversion is done:&lt;br /&gt;
&lt;br /&gt;
# Regularly for the master English strings that are part of Moodle source code. David already has a prototype of script to track commits into languages files and updates the database.&lt;br /&gt;
# Once for all other languages. When we have the new translation portal prepared, we will stop supporting direct CVS commits into languages. The history of all commits into all lang packs will be transferred into the database and further translations will be recorded there.&lt;br /&gt;
&lt;br /&gt;
David is writing these migration script as a part of his [[Languages/AMOS]] tool.&lt;br /&gt;
&lt;br /&gt;
== Design decisions and voting ==&lt;br /&gt;
&lt;br /&gt;
* MDL-21690 Central master database of all strings and their translations&lt;br /&gt;
* MDL-21635 Decide how to implement information in langconfig.php in AMOS&lt;br /&gt;
* MDL-21693 Drop _utf8 suffix from language codes and folder names&lt;br /&gt;
* MDL-21694 Move language files to the plugin space&lt;br /&gt;
* MDL-21695 Replace built-in HTML help files with proper strings&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [http://live.gnome.org/TranslationProject/GitHowTo How to use Git for GNOME translators]&lt;br /&gt;
* [http://translate.sourceforge.net/wiki/ Nice site with tools, localisation problems and alternatives...]&lt;br /&gt;
* [[Languages:Tim&#039;s crazy proposal based on maketext]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Language]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=How_to_fix_gradebook_issues&amp;diff=61082</id>
		<title>How to fix gradebook issues</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=How_to_fix_gradebook_issues&amp;diff=61082"/>
		<updated>2021-08-11T14:54:17Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How to fix Grade book issues==&lt;br /&gt;
&lt;br /&gt;
There has been a policy decision that any fixes to the grade book must not result in any changes to grades. Some fixes may result in grades being changed and in these situations we need to freeze the grade book and let the teacher / admin / higher power agree to applying the change.&lt;br /&gt;
&lt;br /&gt;
For future fixes to the grade book we will be putting revision numbers and nested code into the grade book libraries.&lt;br /&gt;
&lt;br /&gt;
===Fixing the issue===&lt;br /&gt;
&lt;br /&gt;
Choose a freeze number that is greater than the current build number but will be less than the next build number.&lt;br /&gt;
&lt;br /&gt;
When making changes wrap your code in an if statement. &lt;br /&gt;
&lt;br /&gt;
example: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$gradebookcalculationsfreeze = get_config(&#039;core&#039;, &#039;gradebook_calculations_freeze_&#039; . $courseid);&lt;br /&gt;
// Stick with the original code if the grade book is frozen.&lt;br /&gt;
if ($gradebookcalculationsfreeze &amp;amp;&amp;amp; (int)$gradebookcalculationsfreeze &amp;lt;= {your code freeze number}) {&lt;br /&gt;
    {original code goes here}&lt;br /&gt;
} else {&lt;br /&gt;
    {new fixed code goes here}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Enter in details about your fix at https://docs.moodle.org/29/en/Gradebook_calculation_changes&lt;br /&gt;
&lt;br /&gt;
===Upgrade code===&lt;br /&gt;
&lt;br /&gt;
Code will be required to determine if the site being upgraded is affected. If so then it should be flagged to be frozen.&lt;br /&gt;
&lt;br /&gt;
example (lib/db/upgrade.php):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    if ($oldversion &amp;lt; 2015062500.01) {&lt;br /&gt;
        // MDL-48239. Changed calculated grade items so that the maximum and minimum grade can be set.&lt;br /&gt;
&lt;br /&gt;
        // If the changes are accepted and a regrade is done on the gradebook then some grades may change significantly.&lt;br /&gt;
        // This is here to freeze the gradebook in affected courses.&lt;br /&gt;
&lt;br /&gt;
        // This script is included in each major version upgrade process so make sure we don&#039;t run it twice.&lt;br /&gt;
        if (empty($CFG-&amp;gt;upgrade_calculatedgradeitemsignored)) {&lt;br /&gt;
            upgrade_calculated_grade_items();&lt;br /&gt;
&lt;br /&gt;
            // To skip running the same script on the upgrade to the next major release.&lt;br /&gt;
            set_config(&#039;upgrade_calculatedgradeitemsignored&#039;, 1);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Main savepoint reached.&lt;br /&gt;
        upgrade_main_savepoint(true, 2015062500.01);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The code for doing this check should be located in lib/db/upgradelib.php so that it can also be run when a course is being restored.&lt;br /&gt;
&lt;br /&gt;
===New installations===&lt;br /&gt;
&lt;br /&gt;
Make sure to not run the upgrade step with the new installation&lt;br /&gt;
&lt;br /&gt;
example (lib/db/install.php:: xmldb_main_install() line 135): &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    &#039;upgrade_calculatedgradeitemsignored&#039; =&amp;gt; 1, // New installs should not run this upgrade step.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Restoration code===&lt;br /&gt;
&lt;br /&gt;
Code should be generated so that a regrading of the gradebook will fix the problem. Any solution that requires direct alteration of the grades in the database will result in an extremely complex set of restore code.&lt;br /&gt;
&lt;br /&gt;
example (backup/moodle2/restore_stepslib.php):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Calculated grade items need recalculating for backups made between 2.8 release (20141110) and the fix release (20150627).&lt;br /&gt;
if (!$gradebookcalculationsfreeze &amp;amp;&amp;amp; $backupbuild &amp;gt;= 20141110 &amp;amp;&amp;amp; $backupbuild &amp;lt; 20150627) {&lt;br /&gt;
    require_once($CFG-&amp;gt;libdir . &#039;/db/upgradelib.php&#039;);&lt;br /&gt;
    upgrade_calculated_grade_items($this-&amp;gt;get_courseid());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===Tests===&lt;br /&gt;
&lt;br /&gt;
Create a behat test to make sure that when the gradebook is frozen that grades are not changed.&lt;br /&gt;
Create a behat test to make sure that when the gradebook is not frozen that the issue is solved.&lt;br /&gt;
&lt;br /&gt;
Create unit tests to check functions in the upgradelib.php file.&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Global_search_(GSoC2013)&amp;diff=61081</id>
		<title>Global search (GSoC2013)</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Global_search_(GSoC2013)&amp;diff=61081"/>
		<updated>2021-08-11T14:54:17Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{obsolete}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Global search&lt;br /&gt;
|state = Coding period&lt;br /&gt;
|tracker = MDL-31989&lt;br /&gt;
|discussion = [https://moodle.org/mod/forum/discuss.php?d=227805 Writing Moodle&#039;s Global Search]&lt;br /&gt;
|assignee = [https://moodle.org/user/view.php?id=1565904&amp;amp;course=5 Prateek Sachan]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;GSOC&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt; &#039;13&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Global Search will have the feature of searching keywords within the entire Moodle site across modules keeping the security intact having full-text advance search capabilities.&lt;br /&gt;
*It will display results based on relevance weightage.&lt;br /&gt;
*Security will be preserved throughout the search.&lt;br /&gt;
*Search Modules will enable chosen search engine integration with ease. Admins will have the option for selecting the modules that could be made &amp;quot;searchable&amp;quot;&lt;br /&gt;
*It will include keywords from other files types (like PDFs, PPTs, HTML content and others).&lt;br /&gt;
*Following are the features that I&#039;m considering in implementing in the first version of Global Search:&lt;br /&gt;
# Groupings of boolean operators:&amp;lt;code&amp;gt;AND&amp;lt;/syntaxhighlight&amp;gt;, &amp;lt;code&amp;gt;OR&amp;lt;/syntaxhighlight&amp;gt;, &amp;lt;code&amp;gt;NOT&amp;lt;/syntaxhighlight&amp;gt;. Eg.: &amp;lt;code&amp;gt;(&amp;quot;query1&amp;quot; AND &amp;quot;query2&amp;quot;) OR (&amp;quot;query3&amp;quot; NOT &amp;quot;query4&amp;quot;)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Highlighting: All matched keywords will be highlighted. For long content, only a short part will be displayed alongwith the highlighted keyword.&lt;br /&gt;
# Searching for phrases. Results with matched phrase will have higher priority and hence will be shown higher in the results.&lt;br /&gt;
# Wildcard (&amp;lt;code&amp;gt;*&amp;lt;/syntaxhighlight&amp;gt;) (&amp;lt;code&amp;gt;?&amp;lt;/syntaxhighlight&amp;gt;) feature.&lt;br /&gt;
# Stemming. Eg.: &amp;lt;code&amp;gt;bag&amp;lt;/syntaxhighlight&amp;gt; will return results both from &amp;lt;code&amp;gt;bag&amp;lt;/syntaxhighlight&amp;gt; and &amp;lt;code&amp;gt;bags&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Proximity Searches: &lt;br /&gt;
:*&amp;quot;mood&amp;quot;~2 returns &amp;quot;moodle&amp;quot;. (2 alphabets away from the searched term).&lt;br /&gt;
:*&amp;quot;moodle australia&amp;quot;~3 returns results containing &amp;quot;moodle hq at perth australia&amp;quot; (the queried terms were within 3 words of each other)&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
*Moodle 2.5 and above.&lt;br /&gt;
*PHP Solr extension.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&#039;&#039;&#039;Adding a Global Search Block&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Add_Global_Search_Block.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Search through Global Search Block&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Block.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Results UI&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Results_UI.png|900px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Admin Solr settings&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Admin_Solr_Settings.png|900px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Admin Modules Activation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Admin_Module_Activation.png|900px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Global Search Admin Indexing Statistics&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Global_Search_Admin_Indexing_Statistics.png|900px]]&lt;br /&gt;
&lt;br /&gt;
== Admin Controls ==&lt;br /&gt;
These controls appear under Site Administration &amp;gt; Global Search. (Please refer the screenshots above).&lt;br /&gt;
=== Search Engine ===&lt;br /&gt;
This will enable you to choose your preferred Search Engine. Currently, Global Search only supports Apache Solr.&lt;br /&gt;
=== Solr Settings ===&lt;br /&gt;
This section lists down the various server connection settings that you&#039;ll need to configure for your server.&lt;br /&gt;
=== Activated Modules ===&lt;br /&gt;
This section lists down the modules that are enabled in Global Search for indexing and searching of the content within them. You may activate/deactivate modules.&lt;br /&gt;
=== Indexing Statistics ===&lt;br /&gt;
*This lists down the indexing statistics of Global Search.&lt;br /&gt;
*It also gives you the control for deleting index from specific modules or deleting the entire index in one go. (Deleting &amp;quot;Entire Index&amp;quot; deletes the entire Solr index irrespective of whether a module is activated/deactivated).&lt;br /&gt;
*The content will have to be re-indexed through cron.&lt;br /&gt;
&lt;br /&gt;
== Installing PHP Solr extension==&lt;br /&gt;
=== UNIX ===&lt;br /&gt;
*You may download pecl-php-solr extension version &amp;lt;code&amp;gt;1.0.3-alpha&amp;lt;/syntaxhighlight&amp;gt; by &amp;lt;code&amp;gt;git clone https://github.com/lukaszkujawa/php-pecl-solr.git&amp;lt;/syntaxhighlight&amp;gt; or official versions &amp;lt;code&amp;gt;&amp;lt;=1.0.2&amp;lt;/syntaxhighlight&amp;gt; from http://pecl.php.net/package/solr. (Extract the contents in a directory)&lt;br /&gt;
*Install the extension dependencies by executing &amp;lt;code&amp;gt;apt-get install libxml2-dev libcurl4-openssl-dev libpcre3-dev&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*Restart apache server. &amp;lt;code&amp;gt;sudo service apache2 restart&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*Assuming you cloned or downloaded the extension in a directory, you&#039;ll have to compile the downloaded extension.&lt;br /&gt;
*&amp;lt;code&amp;gt;cd /your-downloaded-or-cloned-php-solr-extension-directory/&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;phpize&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
**This a shell script used to prepare the build environment for a php extension to be compiled. If you don&#039;t have &amp;lt;code&amp;gt;phpize&amp;lt;/syntaxhighlight&amp;gt;, you can install it by executing &amp;lt;code&amp;gt;sudo apt-get install php5-dev&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;sudo ./configure&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*sudo make&lt;br /&gt;
*sudo make install&lt;br /&gt;
&lt;br /&gt;
The above procedure will compile and install it in the &amp;lt;code&amp;gt;extension_dir&amp;lt;/syntaxhighlight&amp;gt; directory in the &amp;lt;code&amp;gt;php.ini&amp;lt;/syntaxhighlight&amp;gt; file. To enable, the installed extension, you could follow any of the following two steps:&lt;br /&gt;
&lt;br /&gt;
1. Navigate to the directory &amp;lt;code&amp;gt;/etc/php5/conf.d&amp;lt;/syntaxhighlight&amp;gt; and create a new &amp;lt;code&amp;gt;solr.ini&amp;lt;/syntaxhighlight&amp;gt; file with the following line:&lt;br /&gt;
 extension=solr.so&lt;br /&gt;
&lt;br /&gt;
OR&lt;br /&gt;
&lt;br /&gt;
2. Open your &amp;lt;code&amp;gt;php.ini&amp;lt;/syntaxhighlight&amp;gt; file and include the following line:&lt;br /&gt;
 extension=solr.so&lt;br /&gt;
&lt;br /&gt;
You may follow any of the above two steps. You will need to restart your apache server after that by executing &amp;lt;code&amp;gt;sudo service apache2 restart&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now view the &#039;&#039;&#039;solr&#039;&#039;&#039; extension details by clicking &#039;&#039;&#039;PHP info&#039;&#039;&#039; from Site administration &amp;gt; Server in browser or &amp;lt;code&amp;gt;php -m&amp;lt;/syntaxhighlight&amp;gt; in Terminal (&amp;lt;code&amp;gt;Ctrl+Alt+T&amp;lt;/syntaxhighlight&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== OSX using macports ===&lt;br /&gt;
This method provides an easy install of php solr extension without any downloads.(php solr extension version: &amp;lt;code&amp;gt;&amp;lt;=1.0.2&amp;lt;/syntaxhighlight&amp;gt;)&lt;br /&gt;
 - sudo port install apache-solr4&lt;br /&gt;
 - sudo port install php54-solr&lt;br /&gt;
&lt;br /&gt;
you can choose your relevant available versions @ http://www.macports.org/ports.php?by=name&amp;amp;substr=solr&lt;br /&gt;
&lt;br /&gt;
== Setting up Global Search for Moodle ==&lt;br /&gt;
&lt;br /&gt;
After installing the php-pecl-solr extension, users will have to download the required [http://lucene.apache.org/solr/ Apache Solr] release (version 4.x for solr-php extension &amp;lt;code&amp;gt;1.0.3-alpha&amp;lt;/syntaxhighlight&amp;gt; or 3.x for solr-php extension version &amp;lt;code&amp;gt;&amp;lt;=1.0.2&amp;lt;/syntaxhighlight&amp;gt;), unzip it and keep it in an external directory of Moodle.&lt;br /&gt;
&lt;br /&gt;
Users will have to replace &amp;lt;code&amp;gt;solconfig.xml&amp;lt;/syntaxhighlight&amp;gt; and &amp;lt;code&amp;gt;schema.xml&amp;lt;/syntaxhighlight&amp;gt; inside the downloaded directory &amp;lt;code&amp;gt;example/solr/collection1/conf/&amp;lt;/syntaxhighlight&amp;gt; with the ones that Global Search will provide in &amp;lt;code&amp;gt;/search/solr/conf/&amp;lt;/syntaxhighlight&amp;gt; directory. &lt;br /&gt;
&lt;br /&gt;
Once the files have been copied and replaced, users will have to start the java jetty server &amp;lt;code&amp;gt;start.jar&amp;lt;/syntaxhighlight&amp;gt; located in &amp;lt;code&amp;gt;/example/&amp;lt;/syntaxhighlight&amp;gt; directory by executing &amp;lt;code&amp;gt;java -jar start.jar&amp;lt;/syntaxhighlight&amp;gt;. For the production setup you may prefert to [http://jmuras.com/blog/2012/setup-solr-4-tomcat-ubuntu-server-12-04-lts run solr on tomcat 6 or 7] and Ubuntu server.&lt;br /&gt;
&lt;br /&gt;
Admins will then have to Enable Global Search in Site Administration &amp;gt; Plugins &amp;gt; Global Search &amp;gt; Manage Global Search&lt;br /&gt;
&lt;br /&gt;
== Searchable content in Global Search==&lt;br /&gt;
Following are the modules/resources covered so far in Global Search. I&#039;ll be continuing my work, including other modules shortly as well.&lt;br /&gt;
&lt;br /&gt;
All the contents of the following modules including all uploaded rich document media(PDFs, PPTXs, .TXTs, etc.) will be indexed and made searchable taking proper care of security through Moodle capabilities.&lt;br /&gt;
 &lt;br /&gt;
*Book Resource&lt;br /&gt;
*Forum Module&lt;br /&gt;
*Glossary Module&lt;br /&gt;
*Label Resource&lt;br /&gt;
*Lesson Module&lt;br /&gt;
*Page Resource&lt;br /&gt;
*File Resource&lt;br /&gt;
*Url Resource&lt;br /&gt;
*Wiki Module&lt;br /&gt;
&lt;br /&gt;
The search results will display highlighted matched queries alongwith context links/direct links to the corresponding record.&lt;br /&gt;
&lt;br /&gt;
== Implementation and Milestones ==&lt;br /&gt;
*Writing cron jobs:(17th June - 21st June)&lt;br /&gt;
**Addition of records.&lt;br /&gt;
**Deletion of records.[shouldn&#039;t be focused upon just now]&lt;br /&gt;
**Update of records.&lt;br /&gt;
*Design the solr schema and solconfig files. (22nd June - 26th June)&lt;br /&gt;
**These files will be embedded in the in a separate directory under the Global Search directory. Users will have to copy these two files to the Apache Solr example directory that they will download which will run the Solr jetty server. See Installation for more. &lt;br /&gt;
**&amp;lt;code&amp;gt;schema.xml&amp;lt;/syntaxhighlight&amp;gt; contains all the properties about the documents fields which are being indexed. There may be different fields pertaining to different modules. &lt;br /&gt;
**&amp;lt;code&amp;gt;solrconfig.xml&amp;lt;/syntaxhighlight&amp;gt; contains the configurational parameters for solr.&lt;br /&gt;
*Writing the core search API for all searchable modules. (27th June - 3rd July)&lt;br /&gt;
**_SEARCH_ITERATOR($from=0)&lt;br /&gt;
**_SEARCH_DOCUMENTS($id)&lt;br /&gt;
*Adding proper security to the search API.(4th July - 8th July)&lt;br /&gt;
**_SEARCH_ACCESS($id)&lt;br /&gt;
***Use of Access API&lt;br /&gt;
****ACCESS_DENIED&lt;br /&gt;
****ACCESS_GRANTED&lt;br /&gt;
***ACCESS_DELETED: Situations where the records may have been deleted-hence not viewable.&lt;br /&gt;
*Reviewing all the above once. (9th July - 10th July)&lt;br /&gt;
*Integrating Apache Tika to handle indexing from external files (&amp;lt;code&amp;gt;PDFs&amp;lt;/syntaxhighlight&amp;gt;, &amp;lt;code&amp;gt;PPTX&amp;lt;/syntaxhighlight&amp;gt; etc.) (11th July - 13th July)&lt;br /&gt;
*Writing the search functions for querying. (Just a basic search UI to be used at this moment). (14th July - 17th July)&lt;br /&gt;
**Input for query.&lt;br /&gt;
**Input for filter fields for filtering the search results.&lt;br /&gt;
**Input for AND/OR.&lt;br /&gt;
**Phrase searches.&lt;br /&gt;
**Stemming.&lt;br /&gt;
**Support for wildcards.&lt;br /&gt;
*Admin page for search configuration options. (18th July - 21st July) (The UI page here will be the default type as being currently used. For example, Site Administration&amp;gt;Advance features)&lt;br /&gt;
**Deletion of index.&lt;br /&gt;
***Deletion of entire index in one go.&lt;br /&gt;
***Deletion of index by specific modules only.(For example, only the index of records belonging to &#039;forum&#039; module is to be deleted).&lt;br /&gt;
**configurational options for cron&lt;br /&gt;
***Time of cron run.&lt;br /&gt;
*Implementing and releasing the first prototype &amp;lt;code&amp;gt;version: 1.0&amp;lt;/syntaxhighlight&amp;gt; for developers&#039; feedback. (22nd July - 28th July)&lt;br /&gt;
**See the &#039;&#039;&#039;Prototype&#039;&#039;&#039; section.&lt;br /&gt;
*Preparing for mid-term evaluation. (29th July - 1st August)&lt;br /&gt;
*MID_TERM EVALUATION (2nd August)&lt;br /&gt;
*Re-designing the search page. (2nd August - 7th August) (Taking ideas from community+discussion in [https://moodle.org/mod/forum/discuss.php?d=227805 forum])&lt;br /&gt;
*Improving the prototype after feedback from developers.(8th August - 15th August)&lt;br /&gt;
**Bug-fixing.&lt;br /&gt;
**Fixing security leaks.&lt;br /&gt;
**Improving relevance &amp;amp; speed of search results.&lt;br /&gt;
*Running Test cases and performance testing. (16th August - 21st August) (Performance testing will be good at this point as the code would have been optimized to some level as instructed by the developers above)&lt;br /&gt;
*Debugging. (22nd August - 29th August)&lt;br /&gt;
*Finalizing the Global Search documentation. (30th August - 6th September)&lt;br /&gt;
**Discussing it with my mentors whether everything has been properly covered or not.&lt;br /&gt;
*Buffer Period. (7th September - 8th September)&lt;br /&gt;
**Making sure everything above has been implemented correctly and efficiently. &lt;br /&gt;
*Submitting my code to Moodle and Google. (9th September - 15th September)&lt;br /&gt;
*Suggested Pencils Down Period. (16th September)&lt;br /&gt;
*Performing edits to the documentation after feedback from the Moodle community. (17th September - 22nd September)&lt;br /&gt;
*Firm Pencils Down and Final Evaluation. (23rd September)&lt;br /&gt;
&lt;br /&gt;
== Quick setup for testing ==&lt;br /&gt;
This covers the features and procedure to install Global Search plugin. It would be very good if developers may come forward to test it and give their feedback which would be very crucial for improving it.&lt;br /&gt;
Developers may check out the cases in the &#039;&#039;&#039;Testing&#039;&#039;&#039; section. Developers may add their own preferred test cases and results (pass/fail) in that section which would be helpful for the other developers or you may comment on [https://moodle.org/mod/forum/discuss.php?d=227805 Global Search] discussion on Developer Forum. &lt;br /&gt;
*Here are some things that I&#039;ve summarized that may be focused upon:&lt;br /&gt;
**Finding out any security leaks that I may have missed out.&lt;br /&gt;
**Relevance/speed of displaying search results.&lt;br /&gt;
**Taking ideas to optimize the [https://github.com/prateeksachan/moodle/tree/gs2rebased source code] wherever possible.&lt;br /&gt;
**Getting feedback.&lt;br /&gt;
**Addition/deletion of any search features that you may feel would be useful.&lt;br /&gt;
*Features included in this prototype:&lt;br /&gt;
**Indexing/Searching of content in all the above mentioned modules/resources.&lt;br /&gt;
**Support for indexing/searching rich documents.&lt;br /&gt;
**Admin configuration options.&lt;br /&gt;
**Support for advanced search queries as stated above.&lt;br /&gt;
*Steps to install and test Global Search plugin:&lt;br /&gt;
**Make sure you&#039;ve installed your preferred PHP Solr extension (see sections above).&lt;br /&gt;
**You can simply clone my Github branch and checkout &amp;lt;code&amp;gt;gs2rebased&amp;lt;/syntaxhighlight&amp;gt; branch.&lt;br /&gt;
:&amp;lt;code language=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/prateeksachan/moodle.git&lt;br /&gt;
git checkout gs2rebased&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
**Go to &#039;&#039;&#039;Setting up Global Search in Moodle after installing PHP Solr extension&#039;&#039;&#039; section above.&lt;br /&gt;
**Open &amp;lt;code&amp;gt;../moodle/admin&amp;lt;/syntaxhighlight&amp;gt; in your browser, and update the admin Global Search settings.&lt;br /&gt;
**Indexing is through cron. You will have to run the cron script to index content.&lt;br /&gt;
&lt;br /&gt;
==Search workflow==&lt;br /&gt;
===Simple version===&lt;br /&gt;
# Moodle sends a query to standard solr handler.&lt;br /&gt;
# solr returns 1000 results. Results include all fields required to render search result row. Results are ordered by relevancy.&lt;br /&gt;
# Moodle checks each result in order to establish if it should be visible for current user or not&lt;br /&gt;
# Once 100 visible results are found, Moodle stops checking the rest and displays 100 results&lt;br /&gt;
&lt;br /&gt;
The best case scenario is that Moodle needs to check only 100 returned results (first 100 are accessible for the current user).&lt;br /&gt;
The worst case scenario is that out of 1000 returned documents, none of them is available for the current user. In this case Moodle performs 1000 checks and displays &amp;quot;no results found&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
===Advanced version===&lt;br /&gt;
More advanced version will use a logic on solr side to pre-filter some of the results.&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
A list of test cases.&lt;br /&gt;
===New content===&lt;br /&gt;
* index&lt;br /&gt;
* add new forum post&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure new content is searchable&lt;br /&gt;
&lt;br /&gt;
===Updated content===&lt;br /&gt;
* index&lt;br /&gt;
* edit existing forum post&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure new content is searchable&lt;br /&gt;
* make sure old content is not searchable&lt;br /&gt;
&lt;br /&gt;
===Deleted content===&lt;br /&gt;
* index&lt;br /&gt;
* delete existing forum post&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure deleted content is not searchable&lt;br /&gt;
&lt;br /&gt;
===Backup restored===&lt;br /&gt;
* index&lt;br /&gt;
* restore whole course from a backup&lt;br /&gt;
* re-index&lt;br /&gt;
&lt;br /&gt;
* make sure restored content is searchable&lt;br /&gt;
&lt;br /&gt;
===Access Tests===&lt;br /&gt;
====Common Access====&lt;br /&gt;
*Add courses.&lt;br /&gt;
*Create activity modules/resources that are supported by Global Search (See section &#039;&#039;&#039;Searchable content in Global Search&#039;&#039;&#039;).&lt;br /&gt;
*Insert content or attach files (wherever possible)&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure the results are visible only to those who have access to the respective course&#039;s activity/resource.&lt;br /&gt;
*Set Common Module Settings of activities/resources as Hidden.&lt;br /&gt;
*Make sure those activities/resources do not appear in search results.&lt;br /&gt;
&lt;br /&gt;
====Forum Activity Module Access====&lt;br /&gt;
*Create a course.&lt;br /&gt;
*Create groups in it.&lt;br /&gt;
*Create a Forum Activity.&lt;br /&gt;
*Post in the forum discussions from members of different groups. (+you may also attach files)&lt;br /&gt;
*Index.&lt;br /&gt;
*Make sure members see posts only from those groups which they are a member of.&lt;br /&gt;
&lt;br /&gt;
====Lesson Activity Module Access====&lt;br /&gt;
*Create a course.&lt;br /&gt;
*Create a Lesson Activity.&lt;br /&gt;
1. Type 1&lt;br /&gt;
*Assign Availability &lt;br /&gt;
**Available From only&lt;br /&gt;
**Deadline only&lt;br /&gt;
**Time limit&lt;br /&gt;
**Password Protection&lt;br /&gt;
**Combinations of the above&lt;br /&gt;
*Index.&lt;br /&gt;
*Make sure there are no access leaks when searching as a student.&lt;br /&gt;
*Make sure the teacher, manager are able to see the searches.&lt;br /&gt;
&lt;br /&gt;
2. Type 2&lt;br /&gt;
*Assign Prerequisite Lesson&lt;br /&gt;
**Set Dependent On Prerequisite feature.&lt;br /&gt;
**Set Time spent Prerequisite feature.&lt;br /&gt;
**Toggle completed Prerequisite feature.&lt;br /&gt;
**Set Grade Prerequisite feature.&lt;br /&gt;
**Combinations of the above.&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure there are no access leaks when searching as a student.&lt;br /&gt;
*Make sure the teacher, manager are able to see the searches.&lt;br /&gt;
&lt;br /&gt;
====Wiki Activity Module Access====&lt;br /&gt;
*Create a course.&lt;br /&gt;
*Create Groups.&lt;br /&gt;
*Create a Wiki Activity.&lt;br /&gt;
*Set Group Mode On&lt;br /&gt;
1. Type 1&lt;br /&gt;
*Group Mode: Separate Groups&lt;br /&gt;
*Add Wikipages. (+you may also attach files)&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure there are no access leaks: A group shouldn&#039;t see results from other groups.&lt;br /&gt;
2. Type 2&lt;br /&gt;
*Group Mode: Visible Groups&lt;br /&gt;
*Add Wikipages.(+you may also attach files)&lt;br /&gt;
*Index&lt;br /&gt;
*Make sure there are no access leaks: A group shouldn&#039;t see results from other groups.&lt;br /&gt;
&lt;br /&gt;
====Results====&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
*My Mentors:[https://moodle.org/user/view.php?id=353008&amp;amp;course=5 Tomasz Muras] &amp;amp; [https://moodle.org/user/view.php?id=1146834&amp;amp;course=5 Aparup Banerjee]&lt;br /&gt;
*[http://lucene.apache.org/solr/ Apache Solr Community]&lt;br /&gt;
*[https://github.com/ecaron/php-pecl-solr PHP-Solr extension for Solr 4.x]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[GSOC/2013|Moodle GSoC projects for 2013]]&lt;br /&gt;
* [[GSOC|Moodle GSoC Overview page]]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=227805 Writing Moodle&#039;s Global Search Discussion]&lt;br /&gt;
&lt;br /&gt;
[[Category:GSOC]]&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=61080</id>
		<title>Git for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=61080"/>
		<updated>2021-08-11T14:54:16Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for helping you get started on Moodle development with Git. For further details of Git, see [[:Category:Git]].&lt;br /&gt;
&lt;br /&gt;
== General workflow ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A reasonable knowledge of the Git basics is a good idea before you start to use it for development. If you are new to Git, you are encouraged to go to &#039;See also&#039; for some more general reading.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
Detailed explanation of the workflow can be found in the [[Process]] page. In short, the Moodle development with Git looks like this:&lt;br /&gt;
&lt;br /&gt;
* You as the contributor commit changes into your personal repository at your computer&lt;br /&gt;
* You push the changes into your public repository and publish links to your changes in the Moodle Tracker&lt;br /&gt;
* You request a peer review of your code from another developer&lt;br /&gt;
* When peer reviewer is happy they submit issue for integration&lt;br /&gt;
* Moodle integrators pull the changes from your public repository and if they like them, they put them into Moodle integration repository&lt;br /&gt;
* The integrated change is tested and finally pushed into Moodle production repository&lt;br /&gt;
* You update your local repository with all changes from the production repository and the next cycle may start again&lt;br /&gt;
&lt;br /&gt;
This workflow runs in roughly weekly cycles. The integration happens on Monday and Tuesday and the testing on Wednesday. On Thursday (or Friday if testing takes too long), the production repository moodle.git is usually updated with changes from the last development week.&lt;br /&gt;
&lt;br /&gt;
Most Moodle developers have their public repositories hosted at [http://github.com/ Github]. Alternatively you may want to try [http://gitorious.org Gitorious] or the legendary [http://repo.or.cz repo.or.cz]. In the examples in this guide we assume you&#039;ll set up your public repository at Github.&lt;br /&gt;
&lt;br /&gt;
When you first register on tracker you can not assign issues to yourself or send them for peer review. You will be added to the developers group after your first bug fix is integrated. Before that just comment on the issue with a link to your branch and component lead or another developer will send issue for peer review for you.&lt;br /&gt;
&lt;br /&gt;
== Installing Git on your computer ==&lt;br /&gt;
&lt;br /&gt;
Install Git on your computer. Most Linux distributions have Git available as a package to install. On Debian/Ubuntu, type &#039;&#039;&#039;&#039;sudo apt-get install git&#039;&#039;&#039;&#039; on the terminal. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in a few clicks. &lt;br /&gt;
&lt;br /&gt;
Immediately after the installation, set your name and contact e-mail. The name and e-mail will become part of your commits and they can&#039;t be changed later once your commits are accepted into the Moodle code. Therefore we ask contributors to use their real names written in capital letters, eg &amp;quot;John Smith&amp;quot; and not &amp;quot;john smith&amp;quot; or even &amp;quot;john5677&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
    git config --global user.name &amp;quot;Your Name&amp;quot;&lt;br /&gt;
    git config --global user.email yourmail@domain.tld&lt;br /&gt;
&lt;br /&gt;
Unless you are the repository maintainer, it is wise to set your Git to not push changes in file permissions:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.filemode false&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to verify that the your git installation is not performing any transformation between LFs and CRLFs. All Moodle &#039;&#039;&#039;uses only LFs&#039;&#039;&#039; and you should &#039;&#039;&#039;fetch/edit and push&#039;&#039;&#039; it that way (may need to configure your editor/IDE too). Note that having any &amp;quot;magic&amp;quot; enabled is known to cause [[Common unit test problems#The_test_file_.22evolution.test.22_should_not_contain_section_named_.22.5Blots_of_content.5D.22|problems with unit tests]] execution. So we recommend you to set:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.autocrlf false&lt;br /&gt;
&lt;br /&gt;
== Setting-up the public repository ==&lt;br /&gt;
&lt;br /&gt;
1. Go to [http://github.com/ Github] and create an account.&lt;br /&gt;
&lt;br /&gt;
2. Go to the [http://github.com/moodle/moodle official Moodle Github repository] and click on the Fork button. You now have your own Github Moodle repository.&lt;br /&gt;
&lt;br /&gt;
3. Now you need to set up your SSH public key, so you can push to your Github Moodle repository from your local Moodle repository. On Mac you can go on this [http://help.github.com/mac-key-setup/ Github help page]. If you are on another system, go to your Github administration page, to the section SSH Public Keys, and you should see a link to a help page. Done? Good! That was the most difficult part!&lt;br /&gt;
&lt;br /&gt;
4. If you want, you can set up [[Travis integration]] with your GitHub repository so that when you push your code, Travis will automatically run a suite of tests for you against your changes. This way you can quickly catch issues without having to set up a testing environment locally (and before you share your code with other Moodle developers!). Another option to automate the execution of the Moodle test suite is to setup [[Github actions integration]].&lt;br /&gt;
&lt;br /&gt;
== Setting-up the local repository at your computer  ==&lt;br /&gt;
&lt;br /&gt;
Create a local clone repository of your Github repository. In a terminal:&lt;br /&gt;
&lt;br /&gt;
    git clone git://github.com/YOUR_GITHUB_USERNAME/moodle.git LOCALDIR&lt;br /&gt;
&lt;br /&gt;
    (or:  git clone git@github.com:YOUR_GITHUB_USERNAME/moodle.git LOCALDIR)&lt;br /&gt;
&lt;br /&gt;
This command does several jobs for you. It creates a new folder, initializes an empty Git repository in it, sets your Github repository as the remote repository called &#039;origin&#039; and makes a local checkout of the branch &#039;master&#039; from it. The important point to remember now is that your Github repository is aliased as &#039;origin&#039; for your local clone.&lt;br /&gt;
&lt;br /&gt;
Note that the format of the URL here is important. In the first example, the URL starts &amp;quot;git://github.com&amp;quot; and this will give read-only access to the repository at github.com. If you use this URL, the &amp;quot;git push origin&amp;quot; command that appears later in this document will not work. Therefore, if you want to be able to update the &amp;quot;origin&amp;quot; repository, you should use the URL that starts &amp;quot;git@github.com&amp;quot;, i.e. the second of the two &amp;quot;git clone&amp;quot; commands given above. This will give you read and write access to the repository on github.com.&lt;br /&gt;
&lt;br /&gt;
== Keeping your public repository up-to-date ==&lt;br /&gt;
&lt;br /&gt;
[[image:git-sync-github.png|right|thumb|400px|Fetching changes from upstream and pushing them to github]]&lt;br /&gt;
Your fork at Github is not updated automatically. To keep it synced with the upstream Moodle repository, you have to fetch the recent changes from the official moodle.git and push them to your public repository. To avoid problems with this it is strongly recommended that you never modify the standard Moodle branches. &#039;&#039;Remember: never commit directly into master and MOODLE_xx_STABLE branches.&#039;&#039; In other words, always create topic branches to work on. In Gitspeak, the master branch and MOODLE_xx_STABLE branches should be always fast-forwardable.&lt;br /&gt;
&lt;br /&gt;
To keep your public repository up-to-date, we will register remote repository git://git.moodle.org/moodle.git under &#039;upstream&#039; alias. Then we create a script to be run regularly that fetches changes from the upstream repository and pushes them to your public repository. Note that this procedure will not affect your local working directory.&lt;br /&gt;
&lt;br /&gt;
To register the upstream remote:&lt;br /&gt;
&lt;br /&gt;
    cd moodle&lt;br /&gt;
    git remote add upstream git://git.moodle.org/moodle.git&lt;br /&gt;
&lt;br /&gt;
The following commands can be used to keep the standard Moodle branches at your Github repository synced with the upstream repository. You may wish to store them in a script so that you can run it every week after the upstream repository is updated.&lt;br /&gt;
&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_{19..39}_STABLE MOODLE_{310..311}_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:refs/heads/$BRANCH&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
The git-fetch command does not modify your current working dir (your checkout). It just downloads all recent changes from a remote repository and stores them into so called remote-tracking branches. The git-push command takes these remote-tracking branches from upstream and pushes them to Github under the same name. Understanding this fully requires a bit knowledge of Git internals - see gitrevisions(7) man page.&lt;br /&gt;
&lt;br /&gt;
Note there is no need to switch the local branch during this. You can even execute this via cron at your machine. Just note that the upstream repository updates typically just once a week.&lt;br /&gt;
&lt;br /&gt;
=== New branches ===&lt;br /&gt;
&lt;br /&gt;
Occasionally, moodle.org will create a new branch that does not exist in your public (e.g. Github.com) repository. If you try to push this new branch, you will see an error such as the following:&lt;br /&gt;
&lt;br /&gt;
    error: unable to push to unqualified destination: MOODLE_99_STABLE&lt;br /&gt;
    The destination refspec neither matches an existing ref on the remote&lt;br /&gt;
    nor begins with refs/, and we are unable to guess a prefix based on the source ref.&lt;br /&gt;
    error: failed to push some refs to &#039;git@github.com:YOUR_GITHUB_USERNAME/moodle.git&#039;&lt;br /&gt;
&lt;br /&gt;
In the above example, &amp;quot;MOODLE_99_STABLE&amp;quot;, is the name of the new branch that does not exist in your public repository. To fix the error, you need to create the new branch on your public repository, using the following commands, replacing &amp;quot;MOODLE_99_STABLE&amp;quot; with the name of the new branch you wish to create:&lt;br /&gt;
&lt;br /&gt;
    git checkout MOODLE_99_STABLE&lt;br /&gt;
    git push origin MOODLE_99_STABLE:MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
The above code will create a new copy of the &amp;quot;MOODLE_99_STABLE&amp;quot; branch in your local repository. If you do not need to keep a local copy of the new branch - and probably you do not need it, you then can remove it from your local repository as follows:&lt;br /&gt;
&lt;br /&gt;
    git checkout master&lt;br /&gt;
    git branch -D MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
== Preparing a patch ==&lt;br /&gt;
&lt;br /&gt;
As said earlier at this page, you never work on standard Moodle branches directly. Every time you are going to edit something, switch to a local branch. Fork the local branch off the standard branch you think it should be merged to. So if you are working on a patch for 1.9 or 2.0, fork the branch off MOODLE_19_STABLE or MOODLE_20_STABLE, respectively. Patches for the next [[Moodle versions|major version]] should be based on the master branch.&lt;br /&gt;
&lt;br /&gt;
    git checkout -b MDL-xxxxx-master_brief_name origin/master&lt;br /&gt;
&lt;br /&gt;
Note that if you forget to specify the starting point, the branch is based on the currently checked-out branch. It may not be what you want. It is recommended to always specify the starting point.&lt;br /&gt;
&lt;br /&gt;
To check the current branch, run&lt;br /&gt;
&lt;br /&gt;
    git branch&lt;br /&gt;
&lt;br /&gt;
The current branch is highlighted.&lt;br /&gt;
&lt;br /&gt;
Now go and fix the issue with your favorite IDE. Check the status of the files, view the change to be committed and finally commit the change:&lt;br /&gt;
&lt;br /&gt;
    vim filename.php&lt;br /&gt;
    git status&lt;br /&gt;
    git diff&lt;br /&gt;
    git commit -a&lt;br /&gt;
&lt;br /&gt;
For the commit message, please do respect the guidelines given on in the article [[Coding style#Git_commits|Coding_style]].&lt;br /&gt;
&lt;br /&gt;
Note that this is safe as the commit is recorded just locally, nothing is sent to any server yet (as it would in CVS). To see history of the commits, use&lt;br /&gt;
&lt;br /&gt;
    git log&lt;br /&gt;
&lt;br /&gt;
Once your local branch contains the change (note that it may consists of several patches) and you are happy with it, publish the branch at your public repository:&lt;br /&gt;
&lt;br /&gt;
    git push origin MDL-xxxxx-master_brief_name&lt;br /&gt;
&lt;br /&gt;
Now as your branch is published, you can ask Moodle core developers to review it and eventually integrate it into the standard Moodle repository.&lt;br /&gt;
&lt;br /&gt;
=== Changing commit message, reordering and squashing commits ===&lt;br /&gt;
&lt;br /&gt;
It often happens that you made a mistake in your patch or in the commit message and helpful CiBot pointed it out for you. You can &amp;quot;rewrite the history&amp;quot; and change the existing commits.&lt;br /&gt;
&lt;br /&gt;
Option 1. Reset all the changes in the branch and commit again. &lt;br /&gt;
&lt;br /&gt;
    git reset --mixed origin/master&lt;br /&gt;
&lt;br /&gt;
Now all your changes are still present but all commits on top of &amp;quot;master&amp;quot; branch are gone. You can create a new commit&lt;br /&gt;
&lt;br /&gt;
Option 2. Discover &#039;&#039;&#039;git rebase --interactive&#039;&#039;&#039; - this is a powerful tool to change the sequence of commit, change the commit messages, squash commits, etc. We will not cover it here, there are many articles in the Internet about it, for example: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History.&lt;br /&gt;
&lt;br /&gt;
Whatever option you chose, you have &amp;quot;rewritten the history&amp;quot; and you can not simply push the changes to github again because they would need to overwrite the commits that were already pushed. If you try &amp;quot;git push MDL-xxxxx-master_brief_name&amp;quot; you will get an error message suggesting you to force push. &lt;br /&gt;
To force push the changed commits use:&lt;br /&gt;
&lt;br /&gt;
    git push -f origin MDL-xxxxx-master_brief_name&lt;br /&gt;
&lt;br /&gt;
If an error occurs because you are still using the git protocol (read only), use this command : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin https://github.com/&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
A prompt will ask for your credentials, if you previously setup your SSH public key you can also use this one : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin git@github.com:&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
=== Checking if a branch has already been merged ===&lt;br /&gt;
&lt;br /&gt;
After some time contributing to Moodle you would have a lot of branches both in your local repository and in your public repository. To prune their list and delete those that were accepted by upstream, use the following&lt;br /&gt;
&lt;br /&gt;
    git fetch upstream                                      (1)&lt;br /&gt;
    git branch --merged upstream/master                     (2)&lt;br /&gt;
    git branch --merged upstream/MOODLE_20_STABLE           (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) fetches the changes from your upstream repository at git.moodle.org (remember that git-fetch does not modify your working dir so it is safe to run it whenever). Command (2) and (3) print all branches that are merged into the upstream master branch and MOODLE_20_STABLE branch, respectively. To delete these local branches, use&lt;br /&gt;
&lt;br /&gt;
    git branch -d MDL-xxxxx-master_accepted_branch&lt;br /&gt;
&lt;br /&gt;
The similar approach can be used to check the branches published at your origin repository at github.com&lt;br /&gt;
&lt;br /&gt;
    git fetch origin                                        (1)&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    git branch -r --merged upstream/master                  (2)&lt;br /&gt;
    git branch -r --merged upstream/MOODLE_20_STABLE        (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) makes sure that you have all your branches from github.com recorded as the remote tracking branch locally. Commands (2) and (3) work the same as in the previous example but they list remote tracking branches only ([http://www.kernel.org/pub/software/scm/git/docs/git-branch.html see -r param]). To delete a branch at github.com, use&lt;br /&gt;
&lt;br /&gt;
    git push origin :MDL-xxxxx-master_branch_to_delete&lt;br /&gt;
&lt;br /&gt;
This syntax may look weird to you. However it is pretty logical. The general syntax of the git-push command is&lt;br /&gt;
&lt;br /&gt;
    git push &amp;lt;repository&amp;gt; &amp;lt;source ref&amp;gt;:&amp;lt;target ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so deleting a remote branch can be understood as pushing an &amp;quot;empty (null) reference&amp;quot; to it.&lt;br /&gt;
&lt;br /&gt;
== Peer-reviewing someone else&#039;s code ==&lt;br /&gt;
&lt;br /&gt;
To review a branch that someone else pushed into their public repository, you do not need to register a new remote (unless you work with such repository frequently, of course). Let us imagine your friend Alice pushed a work-in-progress branch called &#039;wip-feature&#039; into her Github repository and asked you to review it. You need to know the read-only address of the repository and the name of the branch.&lt;br /&gt;
&lt;br /&gt;
    git fetch git://github.com/alice/moodle.git wip-feature&lt;br /&gt;
&lt;br /&gt;
This will download all required data and will keep the pointer to the tip of the wip-feature branch in a local symbolic reference FETCH_HEAD. To see what&#039;s there on that branch, use&lt;br /&gt;
&lt;br /&gt;
    git log -p FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see how a particular file looks at Alice&#039;s branch&lt;br /&gt;
&lt;br /&gt;
    git show FETCH_HEAD:admin/blocks.php&lt;br /&gt;
&lt;br /&gt;
To create a new local branch called &#039;alice-wip-feature&#039; containing the work by Alice, use&lt;br /&gt;
&lt;br /&gt;
    git checkout -b alice-wip-feature FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To merge Alice&#039;s work into your current branch:&lt;br /&gt;
&lt;br /&gt;
    git merge FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see what would be merged into the current branch without actually modifying anything:&lt;br /&gt;
&lt;br /&gt;
    git diff ...FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
Once you are all set and reviewing code, this [[Peer_reviewing_checklist|checklist]] should prove to be useful.&lt;br /&gt;
&lt;br /&gt;
== Rebasing a branch ==&lt;br /&gt;
&lt;br /&gt;
Rebasing is a process when you cut off the branch from its current start point and transplant it to another point. Let us assume the following history exists:&lt;br /&gt;
&lt;br /&gt;
          A---B---C topic&lt;br /&gt;
         /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
From this point, the result of the command:&lt;br /&gt;
&lt;br /&gt;
    git rebase master topic&lt;br /&gt;
&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
                  A&#039;--B&#039;--C&#039; topic&lt;br /&gt;
                 /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
and would end with &#039;topic&#039; being your current branch.&lt;br /&gt;
&lt;br /&gt;
You may be asked to rebase your branch submitted for the integration if the submitted branch was based on an outdated commit. The typical case is if you create a new branch as a fork off the upstream master branch on Tuesday. Then on Wednesday, the upstream master branch grows as all changes from the last integration cycle are merged to it. To make diff easy on Github for next weekly pull request review, you want to rebase your branch against the updated master.&lt;br /&gt;
&lt;br /&gt;
    git rebase master MDL-xxxxx-master_topic_branch&lt;br /&gt;
&lt;br /&gt;
Note that rebasing effectively rewrites the history of the branch. &#039;&#039;&#039;Do not rebase the branch if there is a chance that somebody has already forked it and based their own branch on it.&#039;&#039;&#039; For this reason, many Git tutorials discourage from rebasing any branch that has been published. However in Moodle, all branches submitted for integration are potential subject of rebase (even though we try to not to do it often) and you should not base your own branches on them.&lt;br /&gt;
&lt;br /&gt;
=== Conflicts during rebase ===&lt;br /&gt;
&lt;br /&gt;
During the rebase procedure, conflicts may appear. git-status commands reports the conflicted files. Explore them carefully and fix them in your editor (like you would do with CVS). Then add the files with &#039;git add&#039; command and continue.&lt;br /&gt;
&lt;br /&gt;
    vim conflicted.php&lt;br /&gt;
    git add conflicted.php&lt;br /&gt;
    git rebase --continue&lt;br /&gt;
&lt;br /&gt;
== Applying changes from one branch to another ==&lt;br /&gt;
&lt;br /&gt;
Most bugs are fixed at a stable branch (like MOODLE_20_STABLE) and the fix must be prepared for other branches, too (like MOODLE_21_STABLE and the main development branch - master). In Moodle, we do not merge stable branches into the master one. So usually the contributor prepares at least two branches - with the fix for the stable branch(es) and with the fix for the master branch.&lt;br /&gt;
&lt;br /&gt;
If you have a patch prepared on a local branch (let us say MDL-xxxxx-20_brief_name), it is possible to re-apply it to another branch.&lt;br /&gt;
&lt;br /&gt;
=== Cherry-picking a single commit ===&lt;br /&gt;
&lt;br /&gt;
Let us have two local Git repositories ~/public_html/moodle21 containing local installation of Moodle 2.1 and ~/public_html/moodledev with the local installation of most recent development version of Moodle. They both use your public repository at github.com as the origin. You have a branch in moodle21 called MDL-xxxxx-21_topic that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxxx-master_topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxxx-master_topic origin/master    (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxxx-21_topic                (2)&lt;br /&gt;
    git cherry-pick FETCH_HEAD                              (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) creates new local branch forked off the master. The command (2) fetches all data needed to re-apply the topic branch and stores the pointer to the tip of that branch to FETCH_HEAD symbolic reference. The command (3) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch.&lt;br /&gt;
There is also a variant of the cherry-pick command that supports multiple commits, shortly (see its man page for details): &amp;lt;code bash&amp;gt;$ git cherry-pick A^..B&amp;lt;/syntaxhighlight&amp;gt; if you want to include from A - see &#039;&#039;&#039;^&#039;&#039;&#039; - to B, A should be older than B. We will use another approach for cherry-picking multiple commits.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxxx-21_topic from the previous example consists of several commits, it may be easier to use git-format-patch and git-am combo to re-apply the whole set of patches (aka patchset). Firstly you will export all commits from the topic branch to files.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodle21&lt;br /&gt;
    mkdir .patches&lt;br /&gt;
    git format-patch -o .patches MOODLE_21_STABLE..MDL-xxxxx-21_topic         (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) takes all commits from the topic branch that are not in MOODLE_21_STABLE and exports them one by one to the output directory .patches. Look at the generated files. They contain the patch itself (in diff format) and additional information about the commit. You could eg send these files by email to a friend of yours for peer-review. We will use them in another repository.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxxx-master_topic origin/master&lt;br /&gt;
    git am -3 ../moodle21/.patches/*                        (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) applies all the files from the .patches directory. When a patch does not apply cleanly, the command tries fall back on 3-way merge (see the -3 parameter). If conflicts occur during the procedure, you can either deal with them and then use `git am --continue` or abort the whole procedure with `git am --abort`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Git tips]]&lt;br /&gt;
&lt;br /&gt;
; Moodle forum discussions&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=165236 Best way to manage CONTRIB code with GIT]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167063 Handy Git tip for tracking 3rd-party modules and plugins]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167730 Moodle Git repositories]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=183409 Git help!! I don&#039;t understand rebase enough...]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=217617 add MOODLE_24_STABLE to github.com repository]&lt;br /&gt;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [https://mirrors.edge.kernel.org/pub/software/scm/git/docs/giteveryday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [https://git-scm.com/book/en/v2 &#039;Pro Git&#039; complete book]&lt;br /&gt;
* [http://vimeo.com/14629850 Getting git by Scott Chacon] - an recording of an excellent 1-hour presentation that introducing git, including a simple introduction to what is going on under the hood.&lt;br /&gt;
* [http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html Tim Hunt&#039;s blog: Fixing a bug in Moodle core: the mechanics]&lt;br /&gt;
* [https://github.com/k88hudson/git-flight-rules/blob/master/README.md#flight-rules-for-git Flight rules for Git]&lt;br /&gt;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=CodeSniffer&amp;diff=61079</id>
		<title>CodeSniffer</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=CodeSniffer&amp;diff=61079"/>
		<updated>2021-08-11T14:54:16Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
===Scope===&lt;br /&gt;
This document describes the CodeSniffing/Code checker tools their purpose and usage.&lt;br /&gt;
&lt;br /&gt;
===Function===&lt;br /&gt;
The function of the CodeSniffer tool is to analyse PHP5 (only) code, apply a set of rules that match the [[Coding_style | Moodle Coding Style]], and output a report showing which parts of the code do not conform to this style.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
===Using codechecker===&lt;br /&gt;
&lt;br /&gt;
codechecker is a local plugin that creates a web based interface for checking the syntax of a given file. It can be found at&lt;br /&gt;
https://github.com/moodlehq/moodle-local_codechecker&lt;br /&gt;
&lt;br /&gt;
Once installed a new codechecker option will appear in site administration\development page.&lt;br /&gt;
&lt;br /&gt;
This page allows for the code in a specified directory to be checked, e.g. if you wanted to check the code for the shortanswer question type you would enter&lt;br /&gt;
/question/type/shortanswer&lt;br /&gt;
&lt;br /&gt;
You would then be presented with a list of the count of files processed and any warnings or errors.&lt;br /&gt;
&lt;br /&gt;
===Installing codechecker===&lt;br /&gt;
&lt;br /&gt;
To install using git, type this command in the root of your Moodle install&lt;br /&gt;
    git clone git://github.com/moodlehq/moodle-local_codechecker.git local/codechecker&lt;br /&gt;
&lt;br /&gt;
Then edit .gitignore in your development folder eg: &lt;br /&gt;
    gedit /var/www/moodle/.gitignore&lt;br /&gt;
&lt;br /&gt;
And add /local/codechecker/ - including the slash at the end&lt;br /&gt;
&lt;br /&gt;
Alternatively, download the zip from &lt;br /&gt;
&lt;br /&gt;
https://github.com/moodlehq/moodle-local_codechecker/zipball/master&lt;br /&gt;
&lt;br /&gt;
unzip it into the local folder, and then rename the new folder to codechecker.&lt;br /&gt;
&lt;br /&gt;
===Installing PHP CS===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Using pear installer&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. Install the Pear package for PHP CS, pear install PHP_CodeSniffer&lt;br /&gt;
&lt;br /&gt;
2. Download the standard: PHPCompatibility and moodle directories from https://github.com/moodlehq/moodle-local_codechecker&lt;br /&gt;
&lt;br /&gt;
3.  Copy the previous directories to the PHP CS standard path:&lt;br /&gt;
* in Mac with Macports is /opt/local/lib/php/PHP/CodeSniffer/Standards/&lt;br /&gt;
* In Mac with Homebrew is /usr/local/share/pear\@7.0/PHP/CodeSniffer/Standards/&lt;br /&gt;
* in Linux is /usr/share/php/PHP/CodeSniffer/Standards/ or /usr/share/php/PHP/CodeSniffer/src/Standards&lt;br /&gt;
&lt;br /&gt;
4.  If they are installed properly, moodle and PHPCompatibility will show up in the output of `phpcs -i`. Here is a typical example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
The installed coding standards are MySource, PHPCompatibility, Squiz, PSR2, moodle, PEAR, PSR1, PSR12 and Zend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Optionally, you can set the default standard in a configuration file:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    phpcs --config-set default_standard moodle&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Install using composer&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. Run the following in your terminal from your moodle folder:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
composer global require &amp;quot;squizlabs/php_codesniffer=3.*&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Download the standard: PHPCompatibility and moodle directories from https://github.com/moodlehq/moodle-local_codechecker&lt;br /&gt;
to an accessible location on your computer - it doesn&#039;t have to be your project folder.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;quot;blackboard-open-source/moodle-coding-standard&amp;quot; is no longer being maintained.&lt;br /&gt;
&lt;br /&gt;
3. Tell phpcs about where to find the Moodle code checker&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
phpcs  --config-set  installed_paths /path/to/moodle-local_codechecker # adds moodle&#039;s standard to phpcs&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4.  If they are installed properly, moodle and PHPCompatibility will show up in the output of `phpcs -i`. Here is a typical example:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
The installed coding standards are MySource, PHPCompatibility, Squiz, PSR2, moodle, PEAR, PSR1, PSR12 and Zend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Optionally, you can set the default standard in a configuration file:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    phpcs --config-set default_standard moodle&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Codechecker output===&lt;br /&gt;
&lt;br /&gt;
The output is similar to the following &lt;br /&gt;
&lt;br /&gt;
Files found: 21&lt;br /&gt;
&lt;br /&gt;
question\type\calculated\backup\moodle1\lib.php - 1 error(s) and 10 warning(s)&lt;br /&gt;
then a list of all files checked with a count of errors and warnings..followed by a summary&lt;br /&gt;
Total: 31 error(s) and 262 warning(s)&lt;br /&gt;
&lt;br /&gt;
Then a list describing the exact issue in each file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;question\type\calculated\backup\moodle1\lib.php&lt;br /&gt;
&lt;br /&gt;
2: The opening &amp;lt;?php tag must be followed by exactly one newline.&lt;br /&gt;
········//·convert·and·write·the·answers·first&lt;br /&gt;
50: Inline comments must start with a capital letter, digit or 3-dots sequence&lt;br /&gt;
etc etc&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;You can then edit the files to attempt to remove each issue.&lt;br /&gt;
&lt;br /&gt;
===IDE plugin alternatives===&lt;br /&gt;
&lt;br /&gt;
Using the web based interface means switching between the browser and the editing environment. You may find it easier to use a plugin that allows you to check your code against the standards as you go along. &lt;br /&gt;
&lt;br /&gt;
For Eclipse users&lt;br /&gt;
http://www.phpsrc.org/&lt;br /&gt;
&lt;br /&gt;
For Netbeans users&lt;br /&gt;
&lt;br /&gt;
Make sure you have the PEAR php Codesniffer code installed, you can find instructions at &lt;br /&gt;
http://pear.php.net/package/PHP_CodeSniffer/download/All&lt;br /&gt;
&lt;br /&gt;
Then install the netbeans plugin which can be found at &lt;br /&gt;
&lt;br /&gt;
https://github.com/beberlei/netbeans-php-enhancements/downloads&lt;br /&gt;
&lt;br /&gt;
Once installed you can check it within Netbeans by going to &lt;br /&gt;
Tools/Options/PHP and click on the codesniffer tab.&lt;br /&gt;
&lt;br /&gt;
====Windows set up====&lt;br /&gt;
&lt;br /&gt;
There is an option for the codesniffer script. On my windows xampp install this needs to point to &lt;br /&gt;
&lt;br /&gt;
C:\xampp\php\phpcs.bat&lt;br /&gt;
&lt;br /&gt;
Underneath this should be a list of some of the coding standards available, but by default this will not include Moodle. To install the moodle standard, copy the&amp;quot;moodle&amp;quot; and &amp;quot;phpcompatibility&amp;quot; folders from local\codechecker into your standards directory which for me was under&lt;br /&gt;
&lt;br /&gt;
php\PEAR\PHP\CodeSniffer\Standards&lt;br /&gt;
&lt;br /&gt;
[[Image:codesniffer.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now when you restart your Netbeans you should see a new moodle coding standard. Right clicking on a file name should present you with a new option of &amp;quot;Show Code Standard Violations&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Linux set up====&lt;br /&gt;
&lt;br /&gt;
After installing codesniffer and codechecker, copy the moodle and phpcompatibility standard folders from (assuming you have the code in /local/codechecker)&lt;br /&gt;
&lt;br /&gt;
/var/www/moodle/local/codechecker/&lt;br /&gt;
&lt;br /&gt;
to &lt;br /&gt;
&lt;br /&gt;
/usr/share/pear/PHP/CodeSniffer/Standards/&lt;br /&gt;
&lt;br /&gt;
There is an option to set the default standard in a configuration file:&lt;br /&gt;
&lt;br /&gt;
    phpcs --config-set default_standard moodle&lt;br /&gt;
&lt;br /&gt;
Then restart Netbeans and it should now work. You can also switch between coding standards.&lt;br /&gt;
&lt;br /&gt;
===Simple example===&lt;br /&gt;
The script is located in lib/pear/PHP and is called runsniffer. To check the syntax of a given file (e.g. index.php), run:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer index.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will get a report that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FOUND 139 ERROR(S) AND 24 WARNING(S) AFFECTING 130 LINE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
     1 | WARNING | $Id$ tag is no longer required, please remove.&lt;br /&gt;
    28 | ERROR   | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
    50 | ERROR   | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
    50 | ERROR   | A cast statement must be followed by a single space&lt;br /&gt;
    55 | ERROR   | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
  ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first column shows the line at which the ERROR or WARNING was found. The CodeSniffer uses a set of rules which are still being defined, so that what is currently defined as ERROR or WARNING is likely to change in the near future. &lt;br /&gt;
&lt;br /&gt;
You should fix all ERRORs, but may safely ignore the WARNINGs. Fixing warnings will help your code be even more readable and consistent with other code that follow this standard.&lt;br /&gt;
&lt;br /&gt;
===Advanced Usage===&lt;br /&gt;
====Ignoring warnings====&lt;br /&gt;
You can run the CodeSniffer with the -n flag to ignore warnings:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer -n index.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Resulting output:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FOUND 139 ERROR(S) AFFECTING 125 LINE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
    28 | ERROR | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
    50 | ERROR | line indented incorrectly; expected 0 spaces, found 4&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Recursive analysis====&lt;br /&gt;
If you give the name of a folder instead of a file, it will search, analyse and report on all PHP files found in this folder and all its subfolders. This will produce a full report for each PHP file. Since this is likely to be too much information, you may want to print only a summary report, by using the following syntax (search the files/ folder as an example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer --report=summary files&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Report:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  PHP CODE SNIFFER REPORT SUMMARY&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FILE                                                            ERRORS  WARNINGS&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  /web/htdocs/moodle_blog2/files/index.php                        11      58&lt;br /&gt;
  /web/htdocs/moodle_blog2/files/draftfiles.php                   6       22&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  A TOTAL OF 17 ERROR(S) AND 80 WARNING(S) WERE FOUND IN 2 FILE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use the -n flag to ignore warnings.&lt;br /&gt;
&lt;br /&gt;
====Several files in one folder====&lt;br /&gt;
If you want to search all files under a folder, but not recurse through the subfolders, you can use the -l flag (local files only):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
lib/pear/PHP/runsniffer --report=summary -l grade&lt;br /&gt;
&lt;br /&gt;
  PHP CODE SNIFFER REPORT SUMMARY&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  FILE                                                            ERRORS  WARNINGS&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  /web/htdocs/moodle_blog2/grade/index.php                        0       2&lt;br /&gt;
  /web/htdocs/moodle_blog2/grade/lib.php                          6       210&lt;br /&gt;
  /web/htdocs/moodle_blog2/grade/querylib.php                     5       39&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
  A TOTAL OF 11 ERROR(S) AND 251 WARNING(S) WERE FOUND IN 3 FILE(S)&lt;br /&gt;
  --------------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can pass as many files and folders to the script as you want, the analysis and flags will apply to all of them.&lt;br /&gt;
&lt;br /&gt;
===Special rules===&lt;br /&gt;
&lt;br /&gt;
When recursing through folders, the CodeSniffer script looks for a file called thirdpartylibs.xml. Currently there is only one, found under lib/. It lists directories and files which are meant to stay &#039;as-is&#039; in Moodle core, in order to ensure minimum hassle when upgrading these libraries. You can use this file as a template to create your own list of exceptions.&lt;br /&gt;
&lt;br /&gt;
For using the thirdpartylibs.xml in your plugins, please see [[Plugin files#thirdpartylibs.xml]].&lt;br /&gt;
&lt;br /&gt;
===Other report formats===&lt;br /&gt;
CodeSniffer can export its reports in the following formats:&lt;br /&gt;
#full: default, shown first above&lt;br /&gt;
#summary: also shown above&lt;br /&gt;
#xml: Simple XML format&lt;br /&gt;
#csv: Comma-separated list&lt;br /&gt;
#checkstyle: XML format intended for use with CruiseControl&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
#[[Coding]]&lt;br /&gt;
#[[Coding style]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Bug_triage&amp;diff=61078</id>
		<title>Bug triage</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Bug_triage&amp;diff=61078"/>
		<updated>2021-08-11T14:54:16Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Triage.png|200px|right|alt Triage image]]&lt;br /&gt;
Triage is medical term referring to the process of prioritising patients based on the severity of their condition so as to maximise benefit (help as many as possible) when resources are limited.&lt;br /&gt;
&lt;br /&gt;
Bug triage is a process where tracker issues are screened and prioritised. Triage should help ensure we appropriately manage all reported issues - bugs as well as improvements and feature requests.&lt;br /&gt;
&lt;br /&gt;
Triage initially happens shortly after the issue was reported but it can be repeated later if the initial assumptions were wrong, issue was resolved otherwise, affected versions need updating or there are other reasons to review the issue.&lt;br /&gt;
&lt;br /&gt;
==Get involved==&lt;br /&gt;
&lt;br /&gt;
Anybody can do triage in form of correcting the components and/or affected versions, linking to related issues, and of course commenting asking for clarification, confirming bug, redirecting to forum, etc. Users in &#039;&#039;jira-developers&#039;&#039; and &#039;&#039;moodle-triage&#039;&#039; groups can edit any issue, &#039;&#039;jira-users&#039;&#039; can comment on any issue or edit issues they reported. Please see MDLSITE-3592 if you are not a developer but would like to help with triage process.&lt;br /&gt;
&lt;br /&gt;
Adding &#039;&#039;triaged&#039;&#039; label and placing the issue on the backlog should only be done by component lead or HQ developer. At the same time other users can remove &#039;&#039;triaged&#039;&#039; label from the old issues or replace it with &#039;&#039;triaging_in_progress&#039;&#039; if they want to request an additional triage.&lt;br /&gt;
&lt;br /&gt;
==The triage process==&lt;br /&gt;
&lt;br /&gt;
===Initial screening===&lt;br /&gt;
&lt;br /&gt;
First of all, identify the issues that should be closed or placed under investigation. Ask the following questions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Is the issue a request for support/help?&#039;&#039;&#039; If so, the reporter should be directed to the forums to seek help and the issue should be closed as &amp;quot;Not a bug&amp;quot;. Sometimes improvement requests can be phrased as a question, though; if this is the case, ask the reporter to reword the description to describe an improvement.&lt;br /&gt;
* &#039;&#039;&#039;Have the reporter mistaken the Moodle Tracker with their own support desk?&#039;&#039;&#039; Sometimes people mistake the Moodle Tracker as a place to request help about their own Moodle instance, often about logging in. We need to refer the user to their instance administrators and close the issue as &amp;quot;Not a bug&amp;quot;. &lt;br /&gt;
* &#039;&#039;&#039;Has the issue been reported previously?&#039;&#039;&#039; If so, link to a duplicate issue and close the newly reported issue as a &amp;quot;Duplicate&amp;quot; with no fix version set. Encourage the reporter to search before reporting. If a newer issue has a patch or more voters/watchers, consider closing the older issue. Checking for duplicates first will save you having to check the rest of the issue. See [[Tracker tips]] for help with effective search of tracker.&lt;br /&gt;
* &#039;&#039;&#039;Does the problem affect only unsupported versions?&#039;&#039;&#039; If so, the issue should be closed using &amp;quot;Fixed&amp;quot; (preferred as it sounds better) when the issue is resolved in current versions or &amp;quot;Not a bug&amp;quot; when the issue has disappeared due to changes leading to current versions. See [Releases] to find currently supported versions&lt;br /&gt;
* &#039;&#039;&#039;Did the problem arise because of mistake in documentation or lack thereof?&#039;&#039;&#039; If it appears that the reporter does not understand a particular feature in Moodle and the documentation is lacking, ask the reporter where would he expect to find documentation about it. Then simply edit the relevant pages in the documentation wiki and close the issue. If required change is significant, add &#039;&#039;Documentation&#039;&#039; component and &#039;&#039;docs_required&#039;&#039; label.&lt;br /&gt;
* &#039;&#039;&#039;Is the problem a language string change?&#039;&#039;&#039; Language string problems can be corrected by [[Contributing a translation|contributing a translation]] or by contacting the language pack maintainer as listed in the [https://lang.moodle.org/local/amos/credits.php Translation credits]. English language string typo fixes and suggested improvements can be [[Improving English language strings|contributed to the English (fixes) (en_fix) language pack]] or given the component &#039;Language&#039; for fixing by the Language component lead. Such issues should be closed in the Tracker using &amp;quot;Deferred&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Is it a usability issue?&#039;&#039;&#039; If so, add the component &amp;quot;Usability&amp;quot; in addition to the component(s) specifying the area of Moodle. &lt;br /&gt;
* &#039;&#039;&#039;Was the problem caused by additional code or 3rd party plugins?&#039;&#039;&#039; If you can identify the plugin, move the issue to the respective component of CONTRIB project. Otherwise comment and close as &amp;quot;Not a bug&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Can this be implemented as a plugin?&#039;&#039;&#039; And maybe the plugin already exists in the plugins directory. Explanation should be given to the reporter that Moodle provides the framework but does not work on any possible plugin. Add label &amp;quot;addon_candidate&amp;quot; but do not close the issue. This can also apply to the requests to significantly redesign existing plugins and it would be more preferable to create a new alternative plugin.&lt;br /&gt;
* &#039;&#039;&#039;Does the problem seem rational?&#039;&#039;&#039; If not, then the problem may simply be an misunderstanding on the part of the reporter. It might be a problem exclusive to the reporter&#039;s server set-up. If you can replicate the problem quickly, do so. If you can&#039;t replicate the problem, ask the reporter to attempt to replicate the problem on http://demo.moodle.net. If the problem seems persistent but strange, consider asking a developer with experience working in the area to consider the problem and determine if it could be a real problem.&lt;br /&gt;
* &#039;&#039;&#039;Can the problem be replicated?&#039;&#039;&#039; If not, or information on the issue is insufficient, ask the reporter to add error messages, screenshots, environment information (OS, web server, browser) and exact replication instructions&lt;br /&gt;
&lt;br /&gt;
As a result of initial screening up to 20% of new issues may be closed. When closing the issues make sure to set the correct resolution and write a polite comment with explanation, refer to the templates below. If you have doubts, ask the questions and always add label [https://tracker.moodle.org/issues/?jql=labels%20in%20%28triaging_in_progress%29 triaging_in_progress]. Subscribe to the filter [https://tracker.moodle.org/issues/?jql=labels%20in%20%28triaging_in_progress%29%20AND%20project%20%3D%20MDL%20AND%20resolution%20%3D%20Unresolved%20AND%20Participants%20%3D%20currentUser%28%29%20AND%20updatedDate%20%3C%20-30d My old issues in triage] and you will receive notifications after 30 days of inactivity on such issues. See [[Tracker tips]] about how to subscribe to filter. Very often the reporter never follows up on their own issues and this is a good way to find such issues and ping reporter again or make a final decision about closing.&lt;br /&gt;
&lt;br /&gt;
===Confirming the issue===&lt;br /&gt;
&lt;br /&gt;
When you confirm that issue is indeed a bug or a reasonable improvement request that was not reported previously, make sure that the following is accurate:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Security level.&#039;&#039;&#039; Security level must be set as soon as possible if the reported bug discloses vulnerability in Moodle that can be exploited to access information without appropriate level, create an attack on the site, embed XSS or forge a request. In some rare cases Improvements may be also marked as security&lt;br /&gt;
* &#039;&#039;&#039;Summary.&#039;&#039;&#039; Summary of the issue should clearly describe the problem or improvement area, rephrase such summaries as &amp;quot;Some improvements in xxx&amp;quot; or &amp;quot;Error in Moodle&amp;quot;, etc.&lt;br /&gt;
* &#039;&#039;&#039;Issue Type.&#039;&#039;&#039; The following issue types are used in Moodle:&lt;br /&gt;
** Bug - represents an actual bug and should be fixed in all supported versions. Very often when reporter expects something to be better than it actually is they call it a bug when it&#039;s in fact an improvement.&lt;br /&gt;
** Improvement - improvement to existing functionality. If addressed, will be integrated in the following major release only&lt;br /&gt;
** New feature - completely new feature, also will not be applied to the released versions (unless implemented as a plugin and submitted to plugins directory)&lt;br /&gt;
** Task - usually created by developers themselves and can not be classified as Bug or Improvement, for example, adding automated tests, improving documentation, etc.&lt;br /&gt;
** Epic - created by HQ developers or component leads to collect together issues that represents parts of one project. META issues and sub-tasks should not be used any more&lt;br /&gt;
* &#039;&#039;&#039;Priority.&#039;&#039;&#039; Some reporters over-state an issue&#039;s priority. Some reporters don&#039;t know they can set a priority. Priority is used as one of the criteria when sorting issues in the backlog, so it should reflect the position of this issue comparing to the others. Usually Improvements have Minor or Major priority and Bugs can have any priority up to Blocker. Priority levels have specific criteria. Please see [https://docs.moodle.org/dev/Tracker_guide#When_editing_an_issue the Tracker guide]&lt;br /&gt;
* &#039;&#039;&#039;Component/s.&#039;&#039;&#039; Listing components correctly is important as they are the primary variable used for searching for issues, also adding a component automatically include the component lead as a watcher. Issue may have several components when needed&lt;br /&gt;
* &#039;&#039;&#039;Affects version.&#039;&#039;&#039; This field should include one or more released *and supported* versions of Moodle that are affected by the issue, with the following exceptions:&lt;br /&gt;
** The issue is a bug in code that is present in the Master branch only, in which case the next major version should be used. (The next major version should not be used in conjunction with previous released versions, this won&#039;t make sense later.)&lt;br /&gt;
** The issue is a new feature and is unrelated to any existing code in Moodle, in which case the &#039;Future dev&#039; version should be used.&lt;br /&gt;
* &#039;&#039;&#039;Labels.&#039;&#039;&#039; &lt;br /&gt;
** Remove functionality tags that some reporters add as labels, only  [https://docs.moodle.org/dev/Tracker_issue_labels standard] labels or partner-specific labels are used in Moodle&lt;br /&gt;
** Issues with proposed fixes are labelled &#039;&#039;patch&#039;&#039; so that they can be found easily and given attention. When this is the case, consider whether moving the issue to the &#039;Waiting for peer review&#039; state in the workflow might be more appropriate&lt;br /&gt;
** Add &#039;&#039;addon_candidate&#039;&#039; label if the functionality can be implemented as a plugin;&lt;br /&gt;
** If you are component lead or HQ developer you may also add &#039;&#039;triaged&#039;&#039; label to indicate that triage process is completed. Use it only when the issue has actually been added to the backlog&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that &amp;quot;Fix version&amp;quot; is no longer used during triage. If you are in &amp;quot;moodle-triage&amp;quot; group, you can use the &#039;&#039;&#039;Triage screen&#039;&#039;&#039; to edit only aforementioned fields, see MDLSITE-3592.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When commenting on the issue give more details on replication, environment or testing. Ask questions, add watchers, modify description if needed. Link to as many related issues as possible. Do everything that will make the issues scope more clear and attract opinions, discussions and patches.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to show &#039;&#039;&#039;Gratitude and encouragement&#039;&#039;&#039;.  After triaging many issues, it&#039;s easy to lose sight of the fact that the reporter has contributed their time and energy to report an issue for the benefit of the community.&lt;br /&gt;
&lt;br /&gt;
It is easy to become defensive of Moodle if reports are seen as criticism (and sometimes reporters may use phrasing that suggests this), however the triagers response must always be one of sincere gratitude.&lt;br /&gt;
&lt;br /&gt;
It is also important to encourage reporters to continue being involved with the issue after it is triaged. We must not give the sense that we are taking the issue ownership away from the reporter. Instead the reporter should be encouraged to discover the cause of the problem and present a solution; this is appropriate in an open-source project. It is amazing that such a challenge can lead to a sense of purpose for the reporters.&lt;br /&gt;
&lt;br /&gt;
=== Following up on issues ===&lt;br /&gt;
&lt;br /&gt;
Tracker is set up by default so as soon as you comment on any issue or edit it, you become an automatic watcher and any following change on the issue will be emailed to you. &lt;br /&gt;
&lt;br /&gt;
If you have encouraged the reporter well, they may &#039;&#039;&#039;submit a patch&#039;&#039;&#039; or somebody else may do it. Make sure that the &#039;&#039;patch&#039;&#039; label is added or issue is sent to peer review. On the contrary, if &#039;&#039;patch&#039;&#039; label was added by somebody else but you clearly see that patch is far from ready, remove the label and leave a comment explaining it.&lt;br /&gt;
&lt;br /&gt;
Users may also comment with additional details, screenshots, replicating instructions. It may happen that the issue gets re-evaluated and priority or summary changed.&lt;br /&gt;
&lt;br /&gt;
=== Revisiting old issues ===&lt;br /&gt;
&lt;br /&gt;
While searching the tracker you may come over issues that were reported long time ago but still remain open. Again, ask the following questions&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Is this still an issue?&#039;&#039;&#039; If it is not applicable any more either close it or comment about it on the issue and recommend to close. Very few tracker users actually have permission to close issues but the component lead or watchers will see your comment and revisit issue. Another good practice is to replace &#039;&#039;triaged&#039;&#039; label with &#039;&#039;triaging_in_progress&#039;&#039; and add a comment asking if the issue can be closed. If users confirm that it was resolved or nobody replies in 30 days, issue should be closed.&lt;br /&gt;
* &#039;&#039;&#039;Do affected versions need correction?&#039;&#039;&#039; If the issue is still applicable, make sure to add missing current affected versions or comment about it on the issue if you can&#039;t edit it.&lt;br /&gt;
* &#039;&#039;&#039;Does the issue have patch and if yes, is it still applicable?&#039;&#039;&#039; If the issue has patch that still works but &#039;&#039;patch&#039;&#039; label is missing, look through comments or history to see if the &#039;&#039;patch&#039;&#039; label was removed after reviewing the current patch. If you find that label was never added, do it yourself. On contrary if the issue has &#039;&#039;patch&#039;&#039; label but the patch is no longer applicable or not sufficient, remove the label.&lt;br /&gt;
* &#039;&#039;&#039;Are there any duplicating issues?&#039;&#039;&#039; When finding duplicates among the old issues it might not be obvious which issue to close as a duplicate. Usually we should leave the first reported issue but if the later issues have more watchers, better description, more votes, useful comments, attached patch, etc. you may decide to close the earlier issue and leave the later. Sometimes both issues have lots of watchers and they both remain open. In any case, always create links between duplicates or related issues.&lt;br /&gt;
* &#039;&#039;&#039;Does the issue have assignee who forgot about it or misleading status &amp;quot;Development in process&amp;quot;?&#039;&#039;&#039; Due to some  [[Changes_to_issue_assignment|process changes]] in May 2013 some issues still have a real user in the &#039;&#039;Assignee&#039;&#039; field but this user actually does not work on the issue. Sometimes &#039;&#039;Assignee&#039;&#039; remains filled after failing peer review, sometimes developers simply forget that the issue was assigned to them. If you suspect that &#039;&#039;Assignee&#039;&#039; does not actually work on the issue, comment asking they about it and in some cases remove the &#039;&#039;Assignee&#039;&#039; completely. Allow somebody else to work on the issue without feeling that the issue is &amp;quot;taken&amp;quot;. Please also note that for some time tracker had a restriction that &#039;&#039;Assignee&#039;&#039; could not be empty so you can find lots of issues assigned to &#039;&#039;moodle.com&#039;&#039; or &#039;&#039;Nobody&#039;&#039;. Do not modify such issues as this creates unnecessary activity, emails to watchers and irrelevant change in the &amp;quot;Last update date&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Comments templates ===&lt;br /&gt;
====Redirecting someone with a support request====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for taking the time to create an issue. However, the problem you describe seems to be specific to your site, since I am unable to reproduce it on http://demo.moodle.net/. Thus I suggest you post asking for help in one of our community forums https://moodle.org/community/.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
I&#039;m going to close this issue now. If you find that your problem can indeed be reproduced on http://demo.moodle.net/ or you have a suggestion for an improvement, please create a new issue providing as much detail as you can.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Redirecting someone making a &#039;feature request&#039; that is actually already possible====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thank you for taking the time to request a new feature / suggest an improvement. However, what you ask for is already possible. I suggest you post asking for help about how to set up what you want in one of our community forums https://moodle.org/community/.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
I&#039;m going to close this issue now.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Refer the user to their instance administrators====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;You have posted an issue on the Moodle Tracker, which relates to the improvement of Moodle code, not the Moodle site you are using at your institution. I recommend you contact the administrators of your Moodle site.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Closing duplicate====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for your report.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
It seems you&#039;re not the only one to have come across this bug, as it&#039;s been reported previously - see MDL-xyz. I&#039;m going to close this issue now so we can focus on MDL-xyz. Please watch, vote or comment on MDL-xyz if there is any additional information you can provide.&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Issue affects only unsupported versions====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for your report and apologies for it not being looked at before now. I tried but couldn&#039;t reproduce the problem in the latest stable version of Moodle. Thus, it seems it has been fixed as part of another issue and so I am closing this issue with resolution &#039;Cannot Reproduce&#039;. If you find that the problem can indeed be reproduced in the latest stable version of Moodle (for example on the [Moodle sandbox demo|https://sandbox.moodledemo.net]) please create a new issue with clear steps to reproduce and link it to this one.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Requesting more information====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for reporting this.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Could you please add more information to your report such as replication instructions, error messages and screenshots. If you are able to suggest a workaround, that would be immediately helpful to others experiencing this problem. If you can determine the cause of the problem or even determine a solution, that will be very valuable.&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Request to correct translation====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for reporting this.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;The problem that you are describing refers to the translation in another language. Language string problems can be corrected by [Contributing a translation|https://docs.moodle.org/dev/Contributing_a_translation] or by contacting the language pack maintainer as listed in the [Translation credits|http://lang.moodle.org/local/amos/credits.php]. I&#039;m going to close this issue because Moodle does not include translations in the standard download package.&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Correction to English language strings====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for reporting this.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Please note that English language string typo fixes and suggested improvements can be &amp;lt;nowiki&amp;gt;[contributed to the English (fixes) (en_fix) language pack|https://docs.moodle.org/dev/Improving_English_language_strings]&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Bug in contributed plugin (plugin can be identified)====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
You have created an issue under MDL project in the tracker. However the problem that you are describing refers to contributed plugin xxx. &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;I have moved your issue in the appropriate component of the CONTRIB project in tracker. I will also recommend you to leave a comment on the plugin page in the [Moodle plugins directory|https://moodle.org/plugins/]&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Triaging a bug report====&lt;br /&gt;
Thanks for reporting this issue.&lt;br /&gt;
&lt;br /&gt;
You can help us resolve it as quickly as possible by:&lt;br /&gt;
&lt;br /&gt;
* Adding further information in a comment or attaching a screenshot if requested by a developer investigating the issue.&lt;br /&gt;
* Posting the issue number in a moodle.org forum discussion about it.&lt;br /&gt;
* If you are able to provide a patch or links to your Git repository branch, please add a patch label so we will spot it.&lt;br /&gt;
&lt;br /&gt;
====Triaging an improvement or new feature====&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
Thanks for suggesting an improvement or new feature. &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;Please try [searching moodle.org|http://moodle.org/public/search/] to check whether someone else has had the same idea, then either join an existing discussion or start a new discussion in [Moodle in English|http://moodle.org/course/view.php?id=5]. Comment here with the link to the discussion, and mention this issue number in the discussion to encourage others to watch, vote or comment on it.&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;If you can propose a code solution, please [create a patch|https://docs.moodle.org/dev/How_to_create_a_patch] or provide links to your Git repository branch, then add the patch label to the issue. &amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;For more ways to maximize the chance of your idea being implemented, see the guide [New feature ideas|https://docs.moodle.org/dev/New_feature_ideas].&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Creating a filter and gadget for triaging==&lt;br /&gt;
&lt;br /&gt;
If you are a component lead you are responsible for triaging issues that involve your component. A good way to monitor newly created issues is to create a filter in the Tracker and add a gadget on your dashboard to show the results of the filter.&lt;br /&gt;
&lt;br /&gt;
===Adding a filter===&lt;br /&gt;
&lt;br /&gt;
In Tracker...&lt;br /&gt;
# Select &#039;&#039;Issues&#039;&#039; &amp;gt; &#039;&#039;Search for Issues&#039;&#039;.&lt;br /&gt;
# Create a search for untriaged issues in your component, for example...&lt;br /&gt;
#: &amp;lt;code&amp;gt;component in (Assignment) AND resolution = Unresolved AND (labels is EMPTY OR labels not in (triaged)) ORDER BY created DESC&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Run the search query by pressing &#039;&#039;Enter&#039;&#039; or clicking the magnifying glass icon to the right of the search box.&lt;br /&gt;
# When the search query results are displayed, click the &#039;&#039;Save as&#039;&#039; button.&lt;br /&gt;
# Save the search query with an appropriate name, like &amp;quot;Untriaged Assignment issues&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Adding a filter in a gadget to your dashboard===&lt;br /&gt;
&lt;br /&gt;
In Tracker...&lt;br /&gt;
# Click &#039;&#039;Dashboards&#039;&#039; &amp;gt; &#039;&#039;Dashboard for XXX&#039;&#039; (where &#039;&#039;XXX&#039;&#039; is your name).&lt;br /&gt;
# Click &#039;&#039;+ Add Gadget&#039;&#039;.&lt;br /&gt;
# Find the &#039;&#039;Filter Results&#039;&#039; gadget.&lt;br /&gt;
# Click &#039;&#039;Add it Now&#039;&#039;.&lt;br /&gt;
# Click &#039;&#039;Finished&#039;&#039;.&lt;br /&gt;
# In the &#039;&#039;Saved Filter&#039;&#039; input, search for and select your newly created filter.&lt;br /&gt;
# Click &#039;&#039;Save&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The most recent untriaged issues should appear in reverse-date order.&lt;br /&gt;
&lt;br /&gt;
==Triaging priorities and the Triaging Dashboard==&lt;br /&gt;
&lt;br /&gt;
The following are the priorities for ordering issues to be triaged that are reflected on the [http://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11153 Triaging dashboard].&lt;br /&gt;
&lt;br /&gt;
# Security issues - should always be reduced to 0&lt;br /&gt;
# High-priority issue - aim for blockers and critical issues to be reduced to 0&lt;br /&gt;
# Partner issues - aim for partner issues to be reduced to 0&lt;br /&gt;
# Patched issues - aim to triage as soon as possible&lt;br /&gt;
# Developer-reported issues (HQ and non-HQ) - should be quick to triage&lt;br /&gt;
# Recent community bugs - should be triaged last-in-first-out&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Tracker guide]]&lt;br /&gt;
*[[Process]]&lt;br /&gt;
*[[Talk:Bug triage]]&lt;br /&gt;
*[[Tracker tips]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Processes]]&lt;br /&gt;
[[Category:Quality Assurance]]&lt;br /&gt;
[[Category:Tracker]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Backup_2.0_for_developers&amp;diff=61076</id>
		<title>Backup 2.0 for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Backup_2.0_for_developers&amp;diff=61076"/>
		<updated>2021-08-11T14:54:09Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;/code&amp;gt;&amp;quot; to &amp;quot;&amp;lt;/syntaxhighlight&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Backup 2.0}}{{Moodle_2.0}}{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page tries to explain, from a development perspective, &#039;&#039;&#039;how to implement&#039;&#039;&#039; the backup feature for various Moodle 2.x plugins, mainly, modules and blocks. &lt;br /&gt;
&lt;br /&gt;
Note that, at the time of writing this, the backup &amp;amp; restore subsystem itself is &#039;&#039;&#039;under development&#039;&#039;&#039;, so still there are some missing bits, specially about the way to handle &#039;&#039;&#039;subplugins&#039;&#039;&#039; (question types, data fields...) under the new backup infrastructure, so any module using such artifacts, like data, assignment, quiz, workshop, aren&#039;t  good candidates right now. This will be addressed (and this Docs updated) once we have determined how each subplugin is expected to work (from a DB / backup perspective).&lt;br /&gt;
&lt;br /&gt;
Everything in backup &#039;&#039;&#039;is about tasks and steps&#039;&#039;&#039; (see [[Backup 2.0 general architecture|Backup 2.0 general architecture]] for more information), all them conforming one backup plan. Each module instance and each block instance will be backup by one backup task instance that is, basically, one collection of backup steps. How steps are organized within the task will dictate to the backup system what to do and in which order.&lt;br /&gt;
&lt;br /&gt;
Another important point is that Moodle backup 2.0, supports &#039;&#039;&#039;multiple backup formats&#039;&#039;&#039; (&amp;quot;moodle2&amp;quot;, &amp;quot;imscc&amp;quot;...) each one having its own tasks/steps, completely unrelated between them. In any case, for now, we are focusing all the explanations below in the &amp;quot;moodle2&amp;quot; format, that is the one required in order to keep any module/block &#039;&#039;&#039;transportable between Moodle instances&#039;&#039;&#039; without any loss of data. Surely, for the rest of formats, we&#039;ll end with other documents describing them, since each one can have its own particularities.&lt;br /&gt;
&lt;br /&gt;
Talking about backup steps we must differentiate &#039;&#039;&#039;two type of steps&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Execution steps&#039;&#039;&#039;: That, simply, execute arbitrary PHP code. They are useful to prepare different structures, create directories, whatever have to be done not involving the generation of XML files. Normally you won&#039;t need them.&lt;br /&gt;
* &#039;&#039;&#039;Structure steps&#039;&#039;&#039;: That, using one PHP API (detailed below) define completely the XML structure to be exported and its contents. Hopefully, &amp;quot;normal&amp;quot; modules only will have to use one step of this type in order to have the backup functionality 100% implemented.&lt;br /&gt;
&lt;br /&gt;
Said that, in the next steps we are going through all the steps necessary to create the backup of one simple module and one block, in order to get all the possibilities covered.&lt;br /&gt;
&lt;br /&gt;
== How to backup one module ==&lt;br /&gt;
&lt;br /&gt;
For this section, we have selected one simple module (choice) that requires practically all the backup &amp;quot;machinery&amp;quot; to be used, so it will get explained as we progress in the development. The only point not covered here are the &amp;quot;subplugin&amp;quot; facilities, covered later in a separate section.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
In order to achieve the backup implementation for the module, some prerequisites should be fulfilled.  They are default recommendations that are especially helpful while getting used to the backup process.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Learn about the module&#039;&#039;&#039;. If you aren&#039;t the creator of the module, spend some time playing with the module, creating and using it, exploring each one of its functionalities. By doing this you will end with some &amp;quot;real&amp;quot; data in the module instances that will be really useful when testing / debugging how the module backup is being generated.&lt;br /&gt;
# &#039;&#039;&#039;Draw one schema of the module&#039;&#039;&#039; DB structures. While you are playing with the module, look continuously to the DB, how records are saved and what the relationships are between the module&#039;s tables. Since a backup is, basically, one &amp;quot;selective dump&amp;quot; of those tables, knowing the maximum about them is highly recommended. At the end, you must end with one tree structure will be the basis for the generated XML file.&lt;br /&gt;
# &#039;&#039;&#039;Annotate which tables contain user-related info&#039;&#039;&#039; and which ones don&#039;t. One of the core functionalities that must be present on each module is the ability to include user related information or skip it, as you will need that information later.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip&#039;&#039;&#039;: If the module already existed before Moodle 2.0, it can be a &#039;&#039;&#039;good idea&#039;&#039;&#039; to look at its 1.9 backuplib.php file, since the structure is already defined there and can help to understand the organization better and, at the same time, &#039;&#039;&#039;keeping the XML structure as similar as possible&#039;&#039;&#039;, that will, definitively, &#039;&#039;&#039;make things easier&#039;&#039;&#039; when converting 1.9 backup files to the new backup 2.0 format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: It&#039;s important to highlight that the structure schema, should be as stable as possible moving forward, because any change in the structure makes restore much more complex to implement. There aren&#039;t problems with adding/deleting fields, nor adding new elements to the structure. &#039;&#039;&#039;The structure (tree) itself must persist as stable as possible&#039;&#039;&#039;, so be careful when deciding it, as it will have implications on future maintenance.&lt;br /&gt;
&lt;br /&gt;
Applying these pre-requisites to our candidate module (choice), here it&#039;s the corresponding schema. We&#039;ll use it along the whole process.&lt;br /&gt;
&lt;br /&gt;
=== Schema ===&lt;br /&gt;
&lt;br /&gt;
In the schema, you must try to put as much information as possible, so that will produce the coding process later to be quicker and easier while keeping the final results free from errors and missing bits. So, once more, don&#039;t start coding immediately, instead spend some time with the requisites above, understanding how the module works and designing the final structure that represents it better.&lt;br /&gt;
&lt;br /&gt;
==== The (correct) candidate ====&lt;br /&gt;
&lt;br /&gt;
[[Image:Backup20 choice alt.png‎|left|Alternative choice backup structure]]&lt;br /&gt;
&lt;br /&gt;
The tree on the left shows the ER/DB structure of the choice module, where one choice have one or more options and each option is answered by users one or more times (note: ignore cardinality accuracy in the previous phrase).&lt;br /&gt;
&lt;br /&gt;
And that&#039;s the best schema representing the structure of the module, with each element properly nested so, we won&#039;t have any problem with restore since the order required by restore (1, 2, 3) are naturally given. &lt;br /&gt;
&lt;br /&gt;
Looks easy, cool, but continue reading… you will get surprised! :-)&amp;lt;br style=&amp;quot;clear: both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The (chosen) candidate ====&lt;br /&gt;
&lt;br /&gt;
Instead we are going to use the (complete this time) diagram below. See the rationale about that after the image.&lt;br /&gt;
&lt;br /&gt;
[[Image:Backup20 choice.png‎|center|Used choice backup structure]]&lt;br /&gt;
&lt;br /&gt;
The main reason to use this tree (instead of the &amp;quot;correct&amp;quot; one) is that this is the structure that has been used by Moodle 1.9 backup since ages ago for the choice module and, of course have done its work ok. As commented above we must &#039;&#039;&#039;try to reduce the number of structural changes&#039;&#039;&#039; in one module backup in order to keep the restore operations working along the time (the same is applicable for the conversion of 1.9 backup files to the new 2.0 format). Finally, this is a good example about how one module &#039;&#039;&#039;can have different XML representations&#039;&#039;&#039; and we need to try to get that best one (this is not the case) on each case. So, once more, &#039;&#039;&#039;spending some time analyzing&#039;&#039;&#039; the activity is worth it.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s analyze the schema with some detail:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Detecting user information&#039;&#039;&#039;: We must be able to define the entities (tables) in the diagram that are used to store user information. One of the core features of the backup subsystem since its early days have been the ability to produce backup with and without user information. So we need that info. Hence, the &amp;quot;no user info&amp;quot; in the choice and choice_options elements (they are configuration, user-independent), while the choice_answers is marked as &amp;quot;user info&amp;quot; (contains user&#039;s answers to the choice).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Determining the correct order of backup&#039;&#039;&#039;: This, while simple, is critical too (especially from a restore perspective). Since the restore reads progressively the xml file and performs actions in that order, we &#039;&#039;&#039;must guarantee that the &amp;quot;read order&amp;quot; is the correct&#039;&#039;&#039; one, fulfilling any possible dependency. Back to our schema it&#039;s clear that we need to backup the &amp;quot;choice&amp;quot; element at first, and then the &amp;quot;choice_options&amp;quot; and &amp;quot;choice_answers&amp;quot; ones. Moreover, the &amp;quot;choice_options&amp;quot; must be backup before &amp;quot;choice_answers&amp;quot;, since the later needs to save the values of the former (the &amp;quot;optionid&amp;quot; information). Note that, as commented some paragraphs above, the &amp;quot;correct&amp;quot; alternative really gave us that order information easily. Doesn&#039;t matter, since we have been able to establish it also in the &amp;quot;chosen&amp;quot; schema.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Attributes and elements&#039;&#039;&#039;: Now it&#039;s time to decide which fields will be considered attributes in the resulting XML file and which ones will be child elements (tags). The rule is simple: &#039;&#039;&#039;All the &amp;quot;id&amp;quot; fields must (should) be defined as attributes&#039;&#039;&#039;. Note this is just one arbitrary rule without much rationale behind it since, from a restore perspective, everything (attributes and child tags) will be handled in the same way (object attributes). So, in our schema, all the &amp;quot;id&amp;quot; fields have been marked as &amp;quot;attr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Not needed elements&#039;&#039;&#039;: If we have designed the schema properly, we&#039;ll find that some fields aren&#039;t necessary, since such information is already included in some parent element. In our schema, the field &amp;quot;choiceid&amp;quot;, pointing to the &amp;quot;choice-&amp;gt;id&amp;quot;, both in the options and in the answer elements, have been marked as &amp;quot;not needed&amp;quot; since their parent &amp;quot;choice&amp;quot; already contains it. Something similar happens with the &amp;quot;course&amp;quot; field in the choice element. It doesn&#039;t need to be included in the backup file since something above it (course element, outside the module scope) already has it defined. Finally, there is one element marked as &amp;quot;needed&amp;quot; that shows us, once more, that the schema we are using is not the best. Since &amp;quot;choice_answers&amp;quot; isn&#039;t nested under &amp;quot;choice_options&amp;quot;, we must keep the &amp;quot;choice_answers-&amp;gt;optionid&amp;quot; field in the backup, or restore won&#039;t know to which option each answer belongs to. Instead, with the &amp;quot;correct&amp;quot; schema, where answers are nested under options, that field is not needed. Summarizing, &#039;&#039;&#039;any field except those already existing in parent elements must be included in backup&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Detecting file areas used by the module&#039;&#039;&#039;: Along the module we can be using various file areas in different elements and fields. We need to know exactly which file area is handled by which element and the (optional) itemid information used for that file area. In general, &#039;&#039;&#039;anything being one text field, or anything looking like one attachment&#039;&#039;&#039; has high chances to have one (hidden) file area associated. In our schema, we have one file area (choice_intro) corresponding to the introduction of the module and available to put any images or whatever in that field. Also, in general, all the &amp;quot;xxx_intro&amp;quot; file areas use to have no itemid, since the module&#039;s context is enough to define them without ambiguities. So, we mark the choice-&amp;gt;intro as &amp;quot;choice_intro&amp;quot; file area and &amp;quot;no itemid&amp;quot;). From our expertise playing with the module we know there are no more file areas associated with this module.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;annotate_is_important&amp;quot;&amp;gt;&#039;&#039;&#039;Annotating some important bits&#039;&#039;&#039;:&amp;lt;/span&amp;gt; Due to the modularity of the backup and in order to know exactly which information must be saved (because it&#039;s used) and which one can be skipped, &#039;&#039;&#039;it&#039;s important to annotate some important elements along the whole backup&#039;&#039;&#039; process. So, back to our schema, we have marked the &amp;quot;choice_answer-&amp;gt;userid&amp;quot; field as &amp;quot;annotation&amp;quot; (so backup will, automatically, add all the information for that user). Here it&#039;s the list of elements that we must not forget to annotate (or we could end with non-restorable backups). Note that we must, always, be annotating &amp;quot;id&amp;quot; values and not other types of data:&lt;br /&gt;
** &#039;&#039;&#039;user&#039;&#039;&#039;: Any field pointing to one user-&amp;gt;id present along the schema (as said above, our schema has one).&lt;br /&gt;
** &#039;&#039;&#039;grouping&#039;&#039;&#039;: Any field pointing to one grouping-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;group&#039;&#039;&#039;: Any field pointing to one group-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;role&#039;&#039;&#039;: Any field pointing to one role-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;scale&#039;&#039;&#039;: Any field pointing to one scale-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;outcome&#039;&#039;&#039;: Any field pointing to one outcome-&amp;gt;id&lt;br /&gt;
&lt;br /&gt;
And this is all the information we need to know, before starting to code. Surely, once used to backup and restore, you will be able to start coding sooner, but &#039;&#039;&#039;don&#039;t forget about the importance of choosing one good and stable structure&#039;&#039;&#039; before anything else. It&#039;s really the critical part of any module&#039;s backup.&lt;br /&gt;
&lt;br /&gt;
That said, let&#039;s see how to code all this information in order to get one cool backup for our beloved module.&lt;br /&gt;
&lt;br /&gt;
=== Coding ===&lt;br /&gt;
&lt;br /&gt;
Already here? Have you read, at least once, all the explanations and comments in the previous sections? Yes? Sure? I can imagine it&#039;s hard to read so much text, just imagine how hard is to write it! Go, go, go and read it!&lt;br /&gt;
&lt;br /&gt;
Jokes aside, in this section we are going to code the module&#039;s (choice, in our example) backup code. As you&#039;ll see soon, all the information gathered in previous steps is really important and will make the coding task easier and less prone to errors.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the environment ====&lt;br /&gt;
&lt;br /&gt;
By default, any backup operation will end with one .zip file stored in some course / section / activity area. That means that, each time you execute one backup, you&#039;ll need to go across the web interface to that file area, download the generated .zip file, uncompress it, and then see how things have been generated. And you will be executing a bunch of backup files until you get everything working as expected, so the whole develop / test process isn&#039;t really &amp;quot;agile&amp;quot;. To improve things a bit, there is one $CFG setting that you should consider using &#039;&#039;&#039;in your development environment&#039;&#039;&#039;. Just put this in your config.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;keeptempdirectoriesonbackup = true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this setting enabled, backup won&#039;t delete the temporary directory where everything is calculated, so you will be able to access to it directly, skipping all the ui / download / unzip steps above. Those temp directories are under $CFG-&amp;gt;dataroot/temp/backup. Note that, for each backup invocation, a new directory is created.&lt;br /&gt;
&lt;br /&gt;
Also, in order to be able to execute backups quickly (instead of navigating along the UI), you can, simply, put one script like this in your $CFG-&amp;gt;dirroot directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
define(&#039;CLI_SCRIPT&#039;, 1);&lt;br /&gt;
require_once(&#039;config.php&#039;);&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/backup/util/includes/backup_includes.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$course_module_to_backup = XX; // Set this to one existing choice cmid in your dev site&lt;br /&gt;
$user_doing_the_backup   = YY; // Set this to the id of your admin account&lt;br /&gt;
&lt;br /&gt;
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $course_module_to_backup, backup::FORMAT_MOODLE,&lt;br /&gt;
                            backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user_doing_the_backup);&lt;br /&gt;
$bc-&amp;gt;execute_plan();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Just set proper values for XX and YY above and execute it from the command line. If you get one error about one not found class (with the name of your module) everything is ok.&lt;br /&gt;
&lt;br /&gt;
To get the analogous restore code please see: https://docs.moodle.org/dev/Restore_2.0_for_developers#Automatically_triggering_restore_in_code&lt;br /&gt;
&lt;br /&gt;
==== Required stuff ====&lt;br /&gt;
&lt;br /&gt;
The first thing you need to make is to, explicitly, declare that your module (choice in our example) is going to support the MOODLE2 backup format, to do so, you need to go to mod/choice/lib.php and, in the choice_supports() function add one new feature by adding this line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
case FEATURE_BACKUP_MOODLE2:          return true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you execute another backup (with the script provided above, you will continue getting one error, since we haven&#039;t still coded anything related to backup, that&#039;s ok.&lt;br /&gt;
&lt;br /&gt;
Next step is to create the directory where all the backup code for the choice module will be. Just create the directory(s) mod/choice/backup/moodle2&lt;br /&gt;
&lt;br /&gt;
At this point, we have all the required stuff ready and all the pending tasks will be done under that recently created directory.&lt;br /&gt;
&lt;br /&gt;
==== Settings, Steps and Tasks ====&lt;br /&gt;
&lt;br /&gt;
In the introduction of the tutorial, we commented about backup being structured into tasks, each one being one collection of steps (and potentially using some custom settings). Those are, exactly, the objects that we need to create to achieve the backup functionality in our module.&lt;br /&gt;
&lt;br /&gt;
First of all, lets&#039; create the settings file, where all the custom settings to be used by our module will be defined and implemented. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_settingslib.php&#039;&#039;&#039; and their contents are really meaningful:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * @package moodlecore&lt;br /&gt;
 * @subpackage backup-moodle2&lt;br /&gt;
 * @copyright 2010 onwards YOUR_NAME_GOES_HERE {@link YOUR_URL_GOES_HERE}&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 // This activity has not particular settings but the inherited from the generic&lt;br /&gt;
 // backup_activity_task so here there isn&#039;t any class definition, like the ones&lt;br /&gt;
 // existing in /backup/moodle2/backup_settingslib.php (activities section)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looks simple, isn&#039;t it? Nothing but a few comments. This is looking really easy. For now, we aren&#039;t going to introduce any custom setting for any module, only the &amp;quot;core activity settings&amp;quot; will be used. Once backup and Moodle 2.0 is stable we can start analyzing useful settings to customize how the module&#039;s backup is performed. For now, just leave it blank, please. In fact, if it&#039;s empty,&#039;&#039;&#039; you can safely not create it&#039;&#039;&#039; at all. It&#039;s here just for explanation purposes.&lt;br /&gt;
&lt;br /&gt;
Side note: To save some space, we only will be showing the © message/license in the code above. Just add it to each file created.&lt;br /&gt;
&lt;br /&gt;
Now we are going to create the steps file, where all the steps to be executed by our backup activity task will be defined and implemented. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;&#039;&#039; and their contents are these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Define all the backup steps that will be used by the backup_choice_activity_task&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yes, it&#039;s another empty file. No worries we&#039;ll fill it later.&lt;br /&gt;
&lt;br /&gt;
Finally we need to create the task file, where our just created settings and steps files will be included and used. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_activity_task.class.php&#039;&#039;&#039; and their contents are these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;); // Because it exists (must)&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/backup_choice_settingslib.php&#039;); // Because it exists (optional)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * choice backup task that provides all the settings and steps to perform one&lt;br /&gt;
 * complete backup of the activity&lt;br /&gt;
 */&lt;br /&gt;
class backup_choice_activity_task extends backup_activity_task {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular settings this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_settings() {&lt;br /&gt;
        // No particular settings for this activity&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular steps this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_steps() {&lt;br /&gt;
        // Choice only has one structure step&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Code the transformations to perform in the activity in&lt;br /&gt;
     * order to get transportable (encoded) links&lt;br /&gt;
     */&lt;br /&gt;
    static public function encode_content_links($content) {&lt;br /&gt;
        return $content;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the main file (class) of the choice backup and it will be used to define any setting (define_my_settings()  method) and any step (define_my_steps() method) to be executed in the backup process. It also contains one 3rd method (encode_content_links($content)) that will allow manually URLs pointing to the choice to be properly converted when the choice is moved to other site / course using the backup / restore functionality.&lt;br /&gt;
&lt;br /&gt;
As you see, for now, the three required methods are doing nothing. Just execute the backup again. Wow, no errors anymore. We have already fulfilled all the minimum coding needs in order to have the choice backup working. &lt;br /&gt;
&lt;br /&gt;
Now you should go to your $CFG-&amp;gt;dataroot/temp/backup/xxxx directory (the more recent) and spend some time looking what has been created under the activities/choice_XX directory. There is already a lot of stuff that backup has generated for you: comments, blocks, logs, grades, module info, roles... some of them empty and others already showing real information.&lt;br /&gt;
&lt;br /&gt;
In any case, now, we need to add one important file there, the &amp;quot;choice.xml&amp;quot; where the real information for your module will be present, following the specs given by the schema we decided some sections above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s go, it&#039;s time to create our choice structure step. To do so, we edit the &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;&#039;&#039; file and add this code after the existing comments:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Define the complete choice structure for backup, with file and id annotations&lt;br /&gt;
 */     &lt;br /&gt;
class backup_choice_activity_structure_step extends backup_activity_structure_step {&lt;br /&gt;
&lt;br /&gt;
    protected function define_structure() {&lt;br /&gt;
&lt;br /&gt;
        // To know if we are including userinfo&lt;br /&gt;
        $userinfo = $this-&amp;gt;get_setting_value(&#039;userinfo&#039;);&lt;br /&gt;
&lt;br /&gt;
        // Define each element separated&lt;br /&gt;
&lt;br /&gt;
        // Build the tree&lt;br /&gt;
&lt;br /&gt;
        // Define sources&lt;br /&gt;
&lt;br /&gt;
        // Define id annotations&lt;br /&gt;
&lt;br /&gt;
        // Define file annotations&lt;br /&gt;
&lt;br /&gt;
        // Return the root element (choice), wrapped into standard activity structure&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, we have defined one structure step that will be the responsible, using one PHP API to provide backup with all the information needed to generate the choice.xml file. Now, go back to the task file and add these contents in the define_my_steps() methods:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $this-&amp;gt;add_step(new backup_choice_activity_structure_step(&#039;choice_structure&#039;, &#039;choice.xml&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That way, our choice task knows it must execute one new step, the one involving the generation of the choice.xml file. Let&#039;s execute one new backup and see results.You should be getting one new error with something like that &amp;quot;backup_structure_step_wrong_structure&amp;quot;. It means that everything is ok up to now, the task has tried to execute the structure step, but this is not properly defined.&lt;br /&gt;
&lt;br /&gt;
===== Defining each element =====&lt;br /&gt;
&lt;br /&gt;
So, next step is about to define the choice structure. Going back to our step, under the &#039;&#039;// Define each element separate&#039;&#039; comment we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice = new backup_nested_element(&#039;choice&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;name&#039;, &#039;intro&#039;, &#039;introformat&#039;, &#039;publish&#039;,&lt;br /&gt;
            &#039;showresults&#039;, &#039;display&#039;, &#039;allowupdate&#039;, &#039;allowunanswered&#039;,&lt;br /&gt;
            &#039;limitanswers&#039;, &#039;timeopen&#039;, &#039;timeclose&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
        $options = new backup_nested_element(&#039;options&#039;);&lt;br /&gt;
&lt;br /&gt;
        $option = new backup_nested_element(&#039;option&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;text&#039;, &#039;maxanswers&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
        $answers = new backup_nested_element(&#039;answers&#039;);&lt;br /&gt;
&lt;br /&gt;
        $answer = new backup_nested_element(&#039;answer&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;userid&#039;, &#039;optionid&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Return the root element =====&lt;br /&gt;
&lt;br /&gt;
And also, in order to get it working, let&#039;s define the return element, so, after the &#039;&#039;// Return the root element&#039;&#039; comment, add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        return $this-&amp;gt;prepare_activity_structure($choice);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we can execute the backup again and, as long as we have already defined the root element of the module, should have now one choice.xml file created (without proper contents but must be there).&lt;br /&gt;
&lt;br /&gt;
About the code above, all we have done is to define, separately each element that will be part of the choice.xml file. Special note about the $options and $answers elements. Since Moodle 1.9 we use to enclose real elements (the singular ones) inside one extra plural element, hence we create them here (as empty elements without attributes nor child tags). About the rest (the singular ones) we use 3 params in the instantiation:&lt;br /&gt;
* The name of the element&lt;br /&gt;
* One array of attributes of the element&lt;br /&gt;
* One array of child tags (fields) of the element.&lt;br /&gt;
And we include all the fields that previously we had defined in our schema &#039;&#039;&#039;but&#039;&#039;&#039; the ones marked as &#039;&#039;&#039;not needed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Building the tree =====&lt;br /&gt;
&lt;br /&gt;
Now it&#039;s time to declare the relations between all those elements, so, after the &#039;&#039;// Build the tree&#039;&#039; comment we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;add_child($options);&lt;br /&gt;
        $options-&amp;gt;add_child($option);&lt;br /&gt;
&lt;br /&gt;
        $choice-&amp;gt;add_child($answers);&lt;br /&gt;
        $answers-&amp;gt;add_child($answer);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Self explanatory, using $choice as root element, we define the whole tree using the add_child() method. And, of course, we respect &#039;&#039;&#039;the order&#039;&#039;&#039; that we had decided, so $options will be &#039;&#039;&#039;physically&#039;&#039;&#039; before $answers in the tree (and in the generated XML).&lt;br /&gt;
&lt;br /&gt;
===== Defining the sources =====&lt;br /&gt;
&lt;br /&gt;
After this, it&#039;s the moment to instruct our tree about how to fetch information from DB in order to generate the choice.xml file, so after the &#039;&#039;// Define sources&#039;&#039; comment, we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;set_source_table(&#039;choice&#039;, array(&#039;id&#039; =&amp;gt; backup::VAR_ACTIVITYID));&lt;br /&gt;
&lt;br /&gt;
        $option-&amp;gt;set_source_sql(&#039;&lt;br /&gt;
            SELECT *&lt;br /&gt;
              FROM {choice_options}&lt;br /&gt;
             WHERE choiceid = ?&#039;,&lt;br /&gt;
            array(backup::VAR_PARENTID));&lt;br /&gt;
&lt;br /&gt;
        // All the rest of elements only happen if we are including user info&lt;br /&gt;
        if ($userinfo) {&lt;br /&gt;
            $answer-&amp;gt;set_source_table(&#039;choice_answers&#039;, array(&#039;choiceid&#039; =&amp;gt; &#039;../../id&#039;));&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we define the source for the $choice element as the information present in the &#039;choice&#039; table for the id that is being backup (backup::VAR_ACTIVITYID). Or we define the source for the $option element like one SQL (could have been one table too, just to show more possibilities of the API, using the parent (the choice one) as value for the query (backup::VAR_PARENTID).&lt;br /&gt;
&lt;br /&gt;
And finally, conditionally, if user information is going to be included, we define the source for the $answer (note we had already annotated in our schema that this element was dependent of that). &lt;br /&gt;
&lt;br /&gt;
And we define the source condition as having the &#039;choiceid&#039; field matching the value of the &#039;id&#039; field two levels above (../../id). If you follow the tree created in the previous code section, that&#039;s exactly the choice-&amp;gt;id (remember we have introduced one extra level (the plural one between the &#039;choice&#039; and the &#039;answer&#039; singular elements). Note this is 100% equivalent to use backup::VAR_PARENTID (as we have done in the $option source) just used to show possibilities of the API.&lt;br /&gt;
&lt;br /&gt;
Summarizing, with the API, we have these 3 method for defining sources:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_source_table($tablename, array $conditions)&#039;&#039;&#039;: When the information is get straight from one table (vast majority of cases in backup)&lt;br /&gt;
* &#039;&#039;&#039;set_source_sql($sql, array $params)&#039;&#039;&#039;: When the information doesn&#039;t map one table directly and we need something more complex&lt;br /&gt;
* &#039;&#039;&#039;set_source_array($array)&#039;&#039;&#039;: When we have some fixed information to backup. Not really useful in nested information, but used by core here and there.&lt;br /&gt;
&lt;br /&gt;
Note that both the $conditions and $params above only accept one limited number of constants or values (not all available in all backups!), mainly:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_COURSEID&#039;&#039;&#039;: The id of the course this activity belongs to / the course id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_SECTIONID&#039;&#039;&#039;: The id of the section this activity belongs to / the section id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_ACTIVITYID&#039;&#039;&#039;: The id of the activity id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_MODID&#039;&#039;&#039;: The id of the course_module being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_MODULENAME&#039;&#039;&#039;: The name of the module being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_BLOCKID&#039;&#039;&#039;: The id of the block being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_BLOCKNAME&#039;&#039;&#039;: The name of the block being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_CONTEXTID&#039;&#039;&#039;: The context id of the activity / course being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_PARENTID&#039;&#039;&#039;: The value of the first parent id found in the structure.&lt;br /&gt;
* &#039;&#039;&#039;../some/path/to/parent&#039;&#039;&#039;: To manually point to other value of any parent.&lt;br /&gt;
&lt;br /&gt;
Is important to note that, in 99% of the case we should be using, exclusively, some of the constants above, and backup, automatically will handle them properly. In case we have any other condition or param to be added like, for example, the number 23, or the string &#039;user&#039;, we cannot add them directly, but enclose them with the helper &#039;&#039;&#039;backup_helper::is_sqlparam(23)&#039;&#039;&#039; or &#039;&#039;&#039;backup_helper::is_sqlparam(&#039;user&#039;)&#039;&#039;&#039;. That way backup will know they are raw SQL params not needing any special handling, like the constants above.&lt;br /&gt;
&lt;br /&gt;
Well, now it&#039;s time to run backup again and take a look to our activities/choice_XX/choice.xml file. Now everything should be there, properly nested, the choice, the options and the answers. We are really near finishing now.&lt;br /&gt;
&lt;br /&gt;
===== Annotating IDs =====&lt;br /&gt;
&lt;br /&gt;
Now it&#039;s time to perform all the annotations that we had already detected in our analysis of the module. So, after the &#039;&#039;// Define id annotations&#039;&#039; comment we&#039;ll be adding:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $answer-&amp;gt;annotate_ids(&#039;user&#039;, &#039;userid&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It simply means, annotate for each $answer element, the value of the &#039;userid&#039; field as one &#039;user&#039; to be backup. In other words we are instructing backup that there is one new user to include later, when generating the users information and, at the same time, we are determining that those users are needed for the choice XX, so, if on restore we decide to skip that choice and such user isn&#039;t necessary for any other module / subsystem, it won&#039;t be restored. All this &amp;quot;uses&amp;quot; information is handled by the &amp;quot;inforef.xml&amp;quot; files within each activity backup, just in case you&#039;re interested to take a look to them. Else, just consider them, &amp;quot;dark magic&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: If you&#039;re not sure about which elements must be annotated, review [[Backup 2.0 for developers #annotate_is_important|&amp;quot;Annotating some important bits&amp;quot;]] above for details about &#039;&#039;&#039;must-be-done&#039;&#039;&#039; annotations.&lt;br /&gt;
&lt;br /&gt;
===== Annotating files =====&lt;br /&gt;
&lt;br /&gt;
And, finally, reviewing our elaborate and detailed schema, the last thing we need to take care of are the file areas used, so, after the &#039;&#039;// Define file annotations&#039;&#039; comment we&#039;ll add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;annotate_files(&#039;mod_choice&#039;, &#039;intro&#039;, null, $contextid = null); // This file area does not have an itemid.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That means that, within the $choice element we have one file area in use, of course belonging to the &#039;mod_choice&#039; component (where all the choice module files belong to), named &#039;intro&#039; and not using itemid (null). Note that, since it is possible to have multiple file areas in the same element (table), you may end up having multiple calls to the annotate_files() method, one for each filearea to be added to backup. The third parameter, if it is needed, must be the name of one of the attributes or fields of the $choice element (usually, in the vast majority of cases, the &#039;id&#039; of the element), otherwise we&#039;ll use null. The fourth parameter is optional and will default to the context id of the backup, but if you want to specify the context id you do so here.&lt;br /&gt;
&lt;br /&gt;
=== One encoded wor(l)d ===&lt;br /&gt;
&lt;br /&gt;
Already out from the step definition, that should be working ok now, with the choice.xml file being generated and all the annotations being processed and added to the inforef.xml file, there is one more point to fulfill before considering choice&#039;s backup 100% finished.&lt;br /&gt;
&lt;br /&gt;
And it&#039;s about how to provide the ability to transform some links to the choice module when the backup file is restored into another server / course. That is automatically handled by a two-step approach:&lt;br /&gt;
# On backup, we transform as many well-know URLs as possible to one encoded form.&lt;br /&gt;
# On restore, we transform those encoded URLS back to their original form, but pointing to their new targets.&lt;br /&gt;
&lt;br /&gt;
So, in backup, we must provide services for the point 1 above, and that is done by adding some &amp;quot;encoding&amp;quot; conversions to the &#039;&#039;&#039;encode_content_links()&#039;&#039;&#039; method in our &#039;&#039;&#039;backup_choice_activity_task&#039;&#039;&#039;. So, define it to look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Code the transformations to perform in the activity in&lt;br /&gt;
     * order to get transportable (encoded) links&lt;br /&gt;
     */&lt;br /&gt;
    static public function encode_content_links($content) {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
&lt;br /&gt;
        $base = preg_quote($CFG-&amp;gt;wwwroot,&amp;quot;/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Link to the list of choices&lt;br /&gt;
        $search=&amp;quot;/(&amp;quot;.$base.&amp;quot;\/mod\/choice\/index.php\?id\=)([0-9]+)/&amp;quot;;&lt;br /&gt;
        $content= preg_replace($search, &#039;$@CHOICEINDEX*$2@$&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
        // Link to choice view by moduleid&lt;br /&gt;
        $search=&amp;quot;/(&amp;quot;.$base.&amp;quot;\/mod\/choice\/view.php\?id\=)([0-9]+)/&amp;quot;;&lt;br /&gt;
        $content= preg_replace($search, &#039;$@CHOICEVIEWBYID*$2@$&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
        return $content;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Básically, it gets any URL (manually written) in any content of the backup being generated and transform some (well-known) URLs to one encoded alternative. In this case we are encoding:&lt;br /&gt;
* Any URL pointing to the list of choices in a course == is changed to ==&amp;gt; $@CHOICEINDEX*XX@$&lt;br /&gt;
* Any URL pointing to one exact choice == is changed to ==&amp;gt; $@CHOICEVIEWBYID*YY@$&lt;br /&gt;
&lt;br /&gt;
In restore, well have the opposite conversions happening, replacing the XX and YY above to their new equivalents, so those links will be transportable via backup/restore without any need to edit them manually later.&lt;br /&gt;
&lt;br /&gt;
Tip: Don&#039;t forget to look to the module&#039;s 1.9 backup code, as far as there you&#039;ll find which conversions must be considered to be added here.&lt;br /&gt;
&lt;br /&gt;
=== Final notes ===&lt;br /&gt;
&lt;br /&gt;
* Don&#039;t get stressed, it&#039;s really more difficult / longer to explain than to do it. 100% guaranteed, else we&#039;ll return your money. :-P&lt;br /&gt;
* If you&#039;ve become lost, or your code is not working properly, you always can [https://github.com/moodle/moodle/tree/master/mod/choice/backup/moodle2 see the complete choice working code in git]. Or, alternatively, look to other well known modules, like [https://github.com/moodle/moodle/blob/master/mod/forum/backup/moodle2/ forum] or also the [https://github.com/moodle/moodle/blob/master/backup/moodle2/backup_stepslib.php big core library of steps], where you will find all sort of uses of the API.&lt;br /&gt;
* If you are going to implement backup for module XXXX, just copy this document, replace any &amp;quot;choice&amp;quot; occurrence within it by XXXX and follow it from the beginning to the end. Should work.&lt;br /&gt;
* If the module already existed in Moodle 1.x, try to follow the same structure if possible, that will make things easier for restore / conversion.&lt;br /&gt;
* Right now there are some pending tasks related with different exceptions that will be thrown if you code something wrongly (bad nesting, incorrect field names, bad constant/sql param uses...) and how they are shown. Fix for that will be coming soon.&lt;br /&gt;
* Also, as stated at the beginning of this tutorial, we are still missing &amp;quot;subplugins&amp;quot; final support in modules, so try to avoid implementing backup on them for now. Once ready, there will be one new section in this document about them.&lt;br /&gt;
* Any question / improvement / comment, feel free to contact with Moodle HQ, better if using the Tracker or, alternatively, forums / email / direct contact with your very-best-developer-friend. Note this is version x.0 (dot zero) of the backup API, so sure there are possibilities to improve it along the time.&lt;br /&gt;
&lt;br /&gt;
== Other components that can be backed up ==&lt;br /&gt;
&lt;br /&gt;
Most plugins which can be added to a course can also include data in a course backup. Some examples:&lt;br /&gt;
&lt;br /&gt;
* Course formats&lt;br /&gt;
* Themes: [[ Backup 2.0 theme data| Backup 2.0 theme data]]&lt;br /&gt;
* Plagiarism plugins&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=How_to_fix_gradebook_issues&amp;diff=61075</id>
		<title>How to fix gradebook issues</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=How_to_fix_gradebook_issues&amp;diff=61075"/>
		<updated>2021-08-11T14:53:40Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code php&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How to fix Grade book issues==&lt;br /&gt;
&lt;br /&gt;
There has been a policy decision that any fixes to the grade book must not result in any changes to grades. Some fixes may result in grades being changed and in these situations we need to freeze the grade book and let the teacher / admin / higher power agree to applying the change.&lt;br /&gt;
&lt;br /&gt;
For future fixes to the grade book we will be putting revision numbers and nested code into the grade book libraries.&lt;br /&gt;
&lt;br /&gt;
===Fixing the issue===&lt;br /&gt;
&lt;br /&gt;
Choose a freeze number that is greater than the current build number but will be less than the next build number.&lt;br /&gt;
&lt;br /&gt;
When making changes wrap your code in an if statement. &lt;br /&gt;
&lt;br /&gt;
example: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$gradebookcalculationsfreeze = get_config(&#039;core&#039;, &#039;gradebook_calculations_freeze_&#039; . $courseid);&lt;br /&gt;
// Stick with the original code if the grade book is frozen.&lt;br /&gt;
if ($gradebookcalculationsfreeze &amp;amp;&amp;amp; (int)$gradebookcalculationsfreeze &amp;lt;= {your code freeze number}) {&lt;br /&gt;
    {original code goes here}&lt;br /&gt;
} else {&lt;br /&gt;
    {new fixed code goes here}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Enter in details about your fix at https://docs.moodle.org/29/en/Gradebook_calculation_changes&lt;br /&gt;
&lt;br /&gt;
===Upgrade code===&lt;br /&gt;
&lt;br /&gt;
Code will be required to determine if the site being upgraded is affected. If so then it should be flagged to be frozen.&lt;br /&gt;
&lt;br /&gt;
example (lib/db/upgrade.php):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    if ($oldversion &amp;lt; 2015062500.01) {&lt;br /&gt;
        // MDL-48239. Changed calculated grade items so that the maximum and minimum grade can be set.&lt;br /&gt;
&lt;br /&gt;
        // If the changes are accepted and a regrade is done on the gradebook then some grades may change significantly.&lt;br /&gt;
        // This is here to freeze the gradebook in affected courses.&lt;br /&gt;
&lt;br /&gt;
        // This script is included in each major version upgrade process so make sure we don&#039;t run it twice.&lt;br /&gt;
        if (empty($CFG-&amp;gt;upgrade_calculatedgradeitemsignored)) {&lt;br /&gt;
            upgrade_calculated_grade_items();&lt;br /&gt;
&lt;br /&gt;
            // To skip running the same script on the upgrade to the next major release.&lt;br /&gt;
            set_config(&#039;upgrade_calculatedgradeitemsignored&#039;, 1);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Main savepoint reached.&lt;br /&gt;
        upgrade_main_savepoint(true, 2015062500.01);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The code for doing this check should be located in lib/db/upgradelib.php so that it can also be run when a course is being restored.&lt;br /&gt;
&lt;br /&gt;
===New installations===&lt;br /&gt;
&lt;br /&gt;
Make sure to not run the upgrade step with the new installation&lt;br /&gt;
&lt;br /&gt;
example (lib/db/install.php:: xmldb_main_install() line 135): &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    &#039;upgrade_calculatedgradeitemsignored&#039; =&amp;gt; 1, // New installs should not run this upgrade step.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Restoration code===&lt;br /&gt;
&lt;br /&gt;
Code should be generated so that a regrading of the gradebook will fix the problem. Any solution that requires direct alteration of the grades in the database will result in an extremely complex set of restore code.&lt;br /&gt;
&lt;br /&gt;
example (backup/moodle2/restore_stepslib.php):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Calculated grade items need recalculating for backups made between 2.8 release (20141110) and the fix release (20150627).&lt;br /&gt;
if (!$gradebookcalculationsfreeze &amp;amp;&amp;amp; $backupbuild &amp;gt;= 20141110 &amp;amp;&amp;amp; $backupbuild &amp;lt; 20150627) {&lt;br /&gt;
    require_once($CFG-&amp;gt;libdir . &#039;/db/upgradelib.php&#039;);&lt;br /&gt;
    upgrade_calculated_grade_items($this-&amp;gt;get_courseid());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Tests===&lt;br /&gt;
&lt;br /&gt;
Create a behat test to make sure that when the gradebook is frozen that grades are not changed.&lt;br /&gt;
Create a behat test to make sure that when the gradebook is not frozen that the issue is solved.&lt;br /&gt;
&lt;br /&gt;
Create unit tests to check functions in the upgradelib.php file.&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Backup_2.0_for_developers&amp;diff=61073</id>
		<title>Backup 2.0 for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Backup_2.0_for_developers&amp;diff=61073"/>
		<updated>2021-08-11T14:53:37Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;&amp;lt;code php&amp;gt;&amp;quot; to &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Backup 2.0}}{{Moodle_2.0}}{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page tries to explain, from a development perspective, &#039;&#039;&#039;how to implement&#039;&#039;&#039; the backup feature for various Moodle 2.x plugins, mainly, modules and blocks. &lt;br /&gt;
&lt;br /&gt;
Note that, at the time of writing this, the backup &amp;amp; restore subsystem itself is &#039;&#039;&#039;under development&#039;&#039;&#039;, so still there are some missing bits, specially about the way to handle &#039;&#039;&#039;subplugins&#039;&#039;&#039; (question types, data fields...) under the new backup infrastructure, so any module using such artifacts, like data, assignment, quiz, workshop, aren&#039;t  good candidates right now. This will be addressed (and this Docs updated) once we have determined how each subplugin is expected to work (from a DB / backup perspective).&lt;br /&gt;
&lt;br /&gt;
Everything in backup &#039;&#039;&#039;is about tasks and steps&#039;&#039;&#039; (see [[Backup 2.0 general architecture|Backup 2.0 general architecture]] for more information), all them conforming one backup plan. Each module instance and each block instance will be backup by one backup task instance that is, basically, one collection of backup steps. How steps are organized within the task will dictate to the backup system what to do and in which order.&lt;br /&gt;
&lt;br /&gt;
Another important point is that Moodle backup 2.0, supports &#039;&#039;&#039;multiple backup formats&#039;&#039;&#039; (&amp;quot;moodle2&amp;quot;, &amp;quot;imscc&amp;quot;...) each one having its own tasks/steps, completely unrelated between them. In any case, for now, we are focusing all the explanations below in the &amp;quot;moodle2&amp;quot; format, that is the one required in order to keep any module/block &#039;&#039;&#039;transportable between Moodle instances&#039;&#039;&#039; without any loss of data. Surely, for the rest of formats, we&#039;ll end with other documents describing them, since each one can have its own particularities.&lt;br /&gt;
&lt;br /&gt;
Talking about backup steps we must differentiate &#039;&#039;&#039;two type of steps&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Execution steps&#039;&#039;&#039;: That, simply, execute arbitrary PHP code. They are useful to prepare different structures, create directories, whatever have to be done not involving the generation of XML files. Normally you won&#039;t need them.&lt;br /&gt;
* &#039;&#039;&#039;Structure steps&#039;&#039;&#039;: That, using one PHP API (detailed below) define completely the XML structure to be exported and its contents. Hopefully, &amp;quot;normal&amp;quot; modules only will have to use one step of this type in order to have the backup functionality 100% implemented.&lt;br /&gt;
&lt;br /&gt;
Said that, in the next steps we are going through all the steps necessary to create the backup of one simple module and one block, in order to get all the possibilities covered.&lt;br /&gt;
&lt;br /&gt;
== How to backup one module ==&lt;br /&gt;
&lt;br /&gt;
For this section, we have selected one simple module (choice) that requires practically all the backup &amp;quot;machinery&amp;quot; to be used, so it will get explained as we progress in the development. The only point not covered here are the &amp;quot;subplugin&amp;quot; facilities, covered later in a separate section.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
In order to achieve the backup implementation for the module, some prerequisites should be fulfilled.  They are default recommendations that are especially helpful while getting used to the backup process.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Learn about the module&#039;&#039;&#039;. If you aren&#039;t the creator of the module, spend some time playing with the module, creating and using it, exploring each one of its functionalities. By doing this you will end with some &amp;quot;real&amp;quot; data in the module instances that will be really useful when testing / debugging how the module backup is being generated.&lt;br /&gt;
# &#039;&#039;&#039;Draw one schema of the module&#039;&#039;&#039; DB structures. While you are playing with the module, look continuously to the DB, how records are saved and what the relationships are between the module&#039;s tables. Since a backup is, basically, one &amp;quot;selective dump&amp;quot; of those tables, knowing the maximum about them is highly recommended. At the end, you must end with one tree structure will be the basis for the generated XML file.&lt;br /&gt;
# &#039;&#039;&#039;Annotate which tables contain user-related info&#039;&#039;&#039; and which ones don&#039;t. One of the core functionalities that must be present on each module is the ability to include user related information or skip it, as you will need that information later.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip&#039;&#039;&#039;: If the module already existed before Moodle 2.0, it can be a &#039;&#039;&#039;good idea&#039;&#039;&#039; to look at its 1.9 backuplib.php file, since the structure is already defined there and can help to understand the organization better and, at the same time, &#039;&#039;&#039;keeping the XML structure as similar as possible&#039;&#039;&#039;, that will, definitively, &#039;&#039;&#039;make things easier&#039;&#039;&#039; when converting 1.9 backup files to the new backup 2.0 format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: It&#039;s important to highlight that the structure schema, should be as stable as possible moving forward, because any change in the structure makes restore much more complex to implement. There aren&#039;t problems with adding/deleting fields, nor adding new elements to the structure. &#039;&#039;&#039;The structure (tree) itself must persist as stable as possible&#039;&#039;&#039;, so be careful when deciding it, as it will have implications on future maintenance.&lt;br /&gt;
&lt;br /&gt;
Applying these pre-requisites to our candidate module (choice), here it&#039;s the corresponding schema. We&#039;ll use it along the whole process.&lt;br /&gt;
&lt;br /&gt;
=== Schema ===&lt;br /&gt;
&lt;br /&gt;
In the schema, you must try to put as much information as possible, so that will produce the coding process later to be quicker and easier while keeping the final results free from errors and missing bits. So, once more, don&#039;t start coding immediately, instead spend some time with the requisites above, understanding how the module works and designing the final structure that represents it better.&lt;br /&gt;
&lt;br /&gt;
==== The (correct) candidate ====&lt;br /&gt;
&lt;br /&gt;
[[Image:Backup20 choice alt.png‎|left|Alternative choice backup structure]]&lt;br /&gt;
&lt;br /&gt;
The tree on the left shows the ER/DB structure of the choice module, where one choice have one or more options and each option is answered by users one or more times (note: ignore cardinality accuracy in the previous phrase).&lt;br /&gt;
&lt;br /&gt;
And that&#039;s the best schema representing the structure of the module, with each element properly nested so, we won&#039;t have any problem with restore since the order required by restore (1, 2, 3) are naturally given. &lt;br /&gt;
&lt;br /&gt;
Looks easy, cool, but continue reading… you will get surprised! :-)&amp;lt;br style=&amp;quot;clear: both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The (chosen) candidate ====&lt;br /&gt;
&lt;br /&gt;
Instead we are going to use the (complete this time) diagram below. See the rationale about that after the image.&lt;br /&gt;
&lt;br /&gt;
[[Image:Backup20 choice.png‎|center|Used choice backup structure]]&lt;br /&gt;
&lt;br /&gt;
The main reason to use this tree (instead of the &amp;quot;correct&amp;quot; one) is that this is the structure that has been used by Moodle 1.9 backup since ages ago for the choice module and, of course have done its work ok. As commented above we must &#039;&#039;&#039;try to reduce the number of structural changes&#039;&#039;&#039; in one module backup in order to keep the restore operations working along the time (the same is applicable for the conversion of 1.9 backup files to the new 2.0 format). Finally, this is a good example about how one module &#039;&#039;&#039;can have different XML representations&#039;&#039;&#039; and we need to try to get that best one (this is not the case) on each case. So, once more, &#039;&#039;&#039;spending some time analyzing&#039;&#039;&#039; the activity is worth it.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s analyze the schema with some detail:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Detecting user information&#039;&#039;&#039;: We must be able to define the entities (tables) in the diagram that are used to store user information. One of the core features of the backup subsystem since its early days have been the ability to produce backup with and without user information. So we need that info. Hence, the &amp;quot;no user info&amp;quot; in the choice and choice_options elements (they are configuration, user-independent), while the choice_answers is marked as &amp;quot;user info&amp;quot; (contains user&#039;s answers to the choice).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Determining the correct order of backup&#039;&#039;&#039;: This, while simple, is critical too (especially from a restore perspective). Since the restore reads progressively the xml file and performs actions in that order, we &#039;&#039;&#039;must guarantee that the &amp;quot;read order&amp;quot; is the correct&#039;&#039;&#039; one, fulfilling any possible dependency. Back to our schema it&#039;s clear that we need to backup the &amp;quot;choice&amp;quot; element at first, and then the &amp;quot;choice_options&amp;quot; and &amp;quot;choice_answers&amp;quot; ones. Moreover, the &amp;quot;choice_options&amp;quot; must be backup before &amp;quot;choice_answers&amp;quot;, since the later needs to save the values of the former (the &amp;quot;optionid&amp;quot; information). Note that, as commented some paragraphs above, the &amp;quot;correct&amp;quot; alternative really gave us that order information easily. Doesn&#039;t matter, since we have been able to establish it also in the &amp;quot;chosen&amp;quot; schema.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Attributes and elements&#039;&#039;&#039;: Now it&#039;s time to decide which fields will be considered attributes in the resulting XML file and which ones will be child elements (tags). The rule is simple: &#039;&#039;&#039;All the &amp;quot;id&amp;quot; fields must (should) be defined as attributes&#039;&#039;&#039;. Note this is just one arbitrary rule without much rationale behind it since, from a restore perspective, everything (attributes and child tags) will be handled in the same way (object attributes). So, in our schema, all the &amp;quot;id&amp;quot; fields have been marked as &amp;quot;attr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Not needed elements&#039;&#039;&#039;: If we have designed the schema properly, we&#039;ll find that some fields aren&#039;t necessary, since such information is already included in some parent element. In our schema, the field &amp;quot;choiceid&amp;quot;, pointing to the &amp;quot;choice-&amp;gt;id&amp;quot;, both in the options and in the answer elements, have been marked as &amp;quot;not needed&amp;quot; since their parent &amp;quot;choice&amp;quot; already contains it. Something similar happens with the &amp;quot;course&amp;quot; field in the choice element. It doesn&#039;t need to be included in the backup file since something above it (course element, outside the module scope) already has it defined. Finally, there is one element marked as &amp;quot;needed&amp;quot; that shows us, once more, that the schema we are using is not the best. Since &amp;quot;choice_answers&amp;quot; isn&#039;t nested under &amp;quot;choice_options&amp;quot;, we must keep the &amp;quot;choice_answers-&amp;gt;optionid&amp;quot; field in the backup, or restore won&#039;t know to which option each answer belongs to. Instead, with the &amp;quot;correct&amp;quot; schema, where answers are nested under options, that field is not needed. Summarizing, &#039;&#039;&#039;any field except those already existing in parent elements must be included in backup&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Detecting file areas used by the module&#039;&#039;&#039;: Along the module we can be using various file areas in different elements and fields. We need to know exactly which file area is handled by which element and the (optional) itemid information used for that file area. In general, &#039;&#039;&#039;anything being one text field, or anything looking like one attachment&#039;&#039;&#039; has high chances to have one (hidden) file area associated. In our schema, we have one file area (choice_intro) corresponding to the introduction of the module and available to put any images or whatever in that field. Also, in general, all the &amp;quot;xxx_intro&amp;quot; file areas use to have no itemid, since the module&#039;s context is enough to define them without ambiguities. So, we mark the choice-&amp;gt;intro as &amp;quot;choice_intro&amp;quot; file area and &amp;quot;no itemid&amp;quot;). From our expertise playing with the module we know there are no more file areas associated with this module.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;annotate_is_important&amp;quot;&amp;gt;&#039;&#039;&#039;Annotating some important bits&#039;&#039;&#039;:&amp;lt;/span&amp;gt; Due to the modularity of the backup and in order to know exactly which information must be saved (because it&#039;s used) and which one can be skipped, &#039;&#039;&#039;it&#039;s important to annotate some important elements along the whole backup&#039;&#039;&#039; process. So, back to our schema, we have marked the &amp;quot;choice_answer-&amp;gt;userid&amp;quot; field as &amp;quot;annotation&amp;quot; (so backup will, automatically, add all the information for that user). Here it&#039;s the list of elements that we must not forget to annotate (or we could end with non-restorable backups). Note that we must, always, be annotating &amp;quot;id&amp;quot; values and not other types of data:&lt;br /&gt;
** &#039;&#039;&#039;user&#039;&#039;&#039;: Any field pointing to one user-&amp;gt;id present along the schema (as said above, our schema has one).&lt;br /&gt;
** &#039;&#039;&#039;grouping&#039;&#039;&#039;: Any field pointing to one grouping-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;group&#039;&#039;&#039;: Any field pointing to one group-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;role&#039;&#039;&#039;: Any field pointing to one role-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;scale&#039;&#039;&#039;: Any field pointing to one scale-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;outcome&#039;&#039;&#039;: Any field pointing to one outcome-&amp;gt;id&lt;br /&gt;
&lt;br /&gt;
And this is all the information we need to know, before starting to code. Surely, once used to backup and restore, you will be able to start coding sooner, but &#039;&#039;&#039;don&#039;t forget about the importance of choosing one good and stable structure&#039;&#039;&#039; before anything else. It&#039;s really the critical part of any module&#039;s backup.&lt;br /&gt;
&lt;br /&gt;
That said, let&#039;s see how to code all this information in order to get one cool backup for our beloved module.&lt;br /&gt;
&lt;br /&gt;
=== Coding ===&lt;br /&gt;
&lt;br /&gt;
Already here? Have you read, at least once, all the explanations and comments in the previous sections? Yes? Sure? I can imagine it&#039;s hard to read so much text, just imagine how hard is to write it! Go, go, go and read it!&lt;br /&gt;
&lt;br /&gt;
Jokes aside, in this section we are going to code the module&#039;s (choice, in our example) backup code. As you&#039;ll see soon, all the information gathered in previous steps is really important and will make the coding task easier and less prone to errors.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the environment ====&lt;br /&gt;
&lt;br /&gt;
By default, any backup operation will end with one .zip file stored in some course / section / activity area. That means that, each time you execute one backup, you&#039;ll need to go across the web interface to that file area, download the generated .zip file, uncompress it, and then see how things have been generated. And you will be executing a bunch of backup files until you get everything working as expected, so the whole develop / test process isn&#039;t really &amp;quot;agile&amp;quot;. To improve things a bit, there is one $CFG setting that you should consider using &#039;&#039;&#039;in your development environment&#039;&#039;&#039;. Just put this in your config.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;keeptempdirectoriesonbackup = true;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this setting enabled, backup won&#039;t delete the temporary directory where everything is calculated, so you will be able to access to it directly, skipping all the ui / download / unzip steps above. Those temp directories are under $CFG-&amp;gt;dataroot/temp/backup. Note that, for each backup invocation, a new directory is created.&lt;br /&gt;
&lt;br /&gt;
Also, in order to be able to execute backups quickly (instead of navigating along the UI), you can, simply, put one script like this in your $CFG-&amp;gt;dirroot directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
define(&#039;CLI_SCRIPT&#039;, 1);&lt;br /&gt;
require_once(&#039;config.php&#039;);&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/backup/util/includes/backup_includes.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$course_module_to_backup = XX; // Set this to one existing choice cmid in your dev site&lt;br /&gt;
$user_doing_the_backup   = YY; // Set this to the id of your admin account&lt;br /&gt;
&lt;br /&gt;
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $course_module_to_backup, backup::FORMAT_MOODLE,&lt;br /&gt;
                            backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user_doing_the_backup);&lt;br /&gt;
$bc-&amp;gt;execute_plan();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Just set proper values for XX and YY above and execute it from the command line. If you get one error about one not found class (with the name of your module) everything is ok.&lt;br /&gt;
&lt;br /&gt;
To get the analogous restore code please see: https://docs.moodle.org/dev/Restore_2.0_for_developers#Automatically_triggering_restore_in_code&lt;br /&gt;
&lt;br /&gt;
==== Required stuff ====&lt;br /&gt;
&lt;br /&gt;
The first thing you need to make is to, explicitly, declare that your module (choice in our example) is going to support the MOODLE2 backup format, to do so, you need to go to mod/choice/lib.php and, in the choice_supports() function add one new feature by adding this line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
case FEATURE_BACKUP_MOODLE2:          return true;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you execute another backup (with the script provided above, you will continue getting one error, since we haven&#039;t still coded anything related to backup, that&#039;s ok.&lt;br /&gt;
&lt;br /&gt;
Next step is to create the directory where all the backup code for the choice module will be. Just create the directory(s) mod/choice/backup/moodle2&lt;br /&gt;
&lt;br /&gt;
At this point, we have all the required stuff ready and all the pending tasks will be done under that recently created directory.&lt;br /&gt;
&lt;br /&gt;
==== Settings, Steps and Tasks ====&lt;br /&gt;
&lt;br /&gt;
In the introduction of the tutorial, we commented about backup being structured into tasks, each one being one collection of steps (and potentially using some custom settings). Those are, exactly, the objects that we need to create to achieve the backup functionality in our module.&lt;br /&gt;
&lt;br /&gt;
First of all, lets&#039; create the settings file, where all the custom settings to be used by our module will be defined and implemented. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_settingslib.php&#039;&#039;&#039; and their contents are really meaningful:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * @package moodlecore&lt;br /&gt;
 * @subpackage backup-moodle2&lt;br /&gt;
 * @copyright 2010 onwards YOUR_NAME_GOES_HERE {@link YOUR_URL_GOES_HERE}&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 // This activity has not particular settings but the inherited from the generic&lt;br /&gt;
 // backup_activity_task so here there isn&#039;t any class definition, like the ones&lt;br /&gt;
 // existing in /backup/moodle2/backup_settingslib.php (activities section)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looks simple, isn&#039;t it? Nothing but a few comments. This is looking really easy. For now, we aren&#039;t going to introduce any custom setting for any module, only the &amp;quot;core activity settings&amp;quot; will be used. Once backup and Moodle 2.0 is stable we can start analyzing useful settings to customize how the module&#039;s backup is performed. For now, just leave it blank, please. In fact, if it&#039;s empty,&#039;&#039;&#039; you can safely not create it&#039;&#039;&#039; at all. It&#039;s here just for explanation purposes.&lt;br /&gt;
&lt;br /&gt;
Side note: To save some space, we only will be showing the © message/license in the code above. Just add it to each file created.&lt;br /&gt;
&lt;br /&gt;
Now we are going to create the steps file, where all the steps to be executed by our backup activity task will be defined and implemented. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;&#039;&#039; and their contents are these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Define all the backup steps that will be used by the backup_choice_activity_task&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yes, it&#039;s another empty file. No worries we&#039;ll fill it later.&lt;br /&gt;
&lt;br /&gt;
Finally we need to create the task file, where our just created settings and steps files will be included and used. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_activity_task.class.php&#039;&#039;&#039; and their contents are these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;); // Because it exists (must)&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/backup_choice_settingslib.php&#039;); // Because it exists (optional)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * choice backup task that provides all the settings and steps to perform one&lt;br /&gt;
 * complete backup of the activity&lt;br /&gt;
 */&lt;br /&gt;
class backup_choice_activity_task extends backup_activity_task {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular settings this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_settings() {&lt;br /&gt;
        // No particular settings for this activity&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular steps this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_steps() {&lt;br /&gt;
        // Choice only has one structure step&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Code the transformations to perform in the activity in&lt;br /&gt;
     * order to get transportable (encoded) links&lt;br /&gt;
     */&lt;br /&gt;
    static public function encode_content_links($content) {&lt;br /&gt;
        return $content;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the main file (class) of the choice backup and it will be used to define any setting (define_my_settings()  method) and any step (define_my_steps() method) to be executed in the backup process. It also contains one 3rd method (encode_content_links($content)) that will allow manually URLs pointing to the choice to be properly converted when the choice is moved to other site / course using the backup / restore functionality.&lt;br /&gt;
&lt;br /&gt;
As you see, for now, the three required methods are doing nothing. Just execute the backup again. Wow, no errors anymore. We have already fulfilled all the minimum coding needs in order to have the choice backup working. &lt;br /&gt;
&lt;br /&gt;
Now you should go to your $CFG-&amp;gt;dataroot/temp/backup/xxxx directory (the more recent) and spend some time looking what has been created under the activities/choice_XX directory. There is already a lot of stuff that backup has generated for you: comments, blocks, logs, grades, module info, roles... some of them empty and others already showing real information.&lt;br /&gt;
&lt;br /&gt;
In any case, now, we need to add one important file there, the &amp;quot;choice.xml&amp;quot; where the real information for your module will be present, following the specs given by the schema we decided some sections above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s go, it&#039;s time to create our choice structure step. To do so, we edit the &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;&#039;&#039; file and add this code after the existing comments:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Define the complete choice structure for backup, with file and id annotations&lt;br /&gt;
 */     &lt;br /&gt;
class backup_choice_activity_structure_step extends backup_activity_structure_step {&lt;br /&gt;
&lt;br /&gt;
    protected function define_structure() {&lt;br /&gt;
&lt;br /&gt;
        // To know if we are including userinfo&lt;br /&gt;
        $userinfo = $this-&amp;gt;get_setting_value(&#039;userinfo&#039;);&lt;br /&gt;
&lt;br /&gt;
        // Define each element separated&lt;br /&gt;
&lt;br /&gt;
        // Build the tree&lt;br /&gt;
&lt;br /&gt;
        // Define sources&lt;br /&gt;
&lt;br /&gt;
        // Define id annotations&lt;br /&gt;
&lt;br /&gt;
        // Define file annotations&lt;br /&gt;
&lt;br /&gt;
        // Return the root element (choice), wrapped into standard activity structure&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, we have defined one structure step that will be the responsible, using one PHP API to provide backup with all the information needed to generate the choice.xml file. Now, go back to the task file and add these contents in the define_my_steps() methods:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $this-&amp;gt;add_step(new backup_choice_activity_structure_step(&#039;choice_structure&#039;, &#039;choice.xml&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That way, our choice task knows it must execute one new step, the one involving the generation of the choice.xml file. Let&#039;s execute one new backup and see results.You should be getting one new error with something like that &amp;quot;backup_structure_step_wrong_structure&amp;quot;. It means that everything is ok up to now, the task has tried to execute the structure step, but this is not properly defined.&lt;br /&gt;
&lt;br /&gt;
===== Defining each element =====&lt;br /&gt;
&lt;br /&gt;
So, next step is about to define the choice structure. Going back to our step, under the &#039;&#039;// Define each element separate&#039;&#039; comment we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice = new backup_nested_element(&#039;choice&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;name&#039;, &#039;intro&#039;, &#039;introformat&#039;, &#039;publish&#039;,&lt;br /&gt;
            &#039;showresults&#039;, &#039;display&#039;, &#039;allowupdate&#039;, &#039;allowunanswered&#039;,&lt;br /&gt;
            &#039;limitanswers&#039;, &#039;timeopen&#039;, &#039;timeclose&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
        $options = new backup_nested_element(&#039;options&#039;);&lt;br /&gt;
&lt;br /&gt;
        $option = new backup_nested_element(&#039;option&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;text&#039;, &#039;maxanswers&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
        $answers = new backup_nested_element(&#039;answers&#039;);&lt;br /&gt;
&lt;br /&gt;
        $answer = new backup_nested_element(&#039;answer&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;userid&#039;, &#039;optionid&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Return the root element =====&lt;br /&gt;
&lt;br /&gt;
And also, in order to get it working, let&#039;s define the return element, so, after the &#039;&#039;// Return the root element&#039;&#039; comment, add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        return $this-&amp;gt;prepare_activity_structure($choice);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we can execute the backup again and, as long as we have already defined the root element of the module, should have now one choice.xml file created (without proper contents but must be there).&lt;br /&gt;
&lt;br /&gt;
About the code above, all we have done is to define, separately each element that will be part of the choice.xml file. Special note about the $options and $answers elements. Since Moodle 1.9 we use to enclose real elements (the singular ones) inside one extra plural element, hence we create them here (as empty elements without attributes nor child tags). About the rest (the singular ones) we use 3 params in the instantiation:&lt;br /&gt;
* The name of the element&lt;br /&gt;
* One array of attributes of the element&lt;br /&gt;
* One array of child tags (fields) of the element.&lt;br /&gt;
And we include all the fields that previously we had defined in our schema &#039;&#039;&#039;but&#039;&#039;&#039; the ones marked as &#039;&#039;&#039;not needed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Building the tree =====&lt;br /&gt;
&lt;br /&gt;
Now it&#039;s time to declare the relations between all those elements, so, after the &#039;&#039;// Build the tree&#039;&#039; comment we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;add_child($options);&lt;br /&gt;
        $options-&amp;gt;add_child($option);&lt;br /&gt;
&lt;br /&gt;
        $choice-&amp;gt;add_child($answers);&lt;br /&gt;
        $answers-&amp;gt;add_child($answer);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Self explanatory, using $choice as root element, we define the whole tree using the add_child() method. And, of course, we respect &#039;&#039;&#039;the order&#039;&#039;&#039; that we had decided, so $options will be &#039;&#039;&#039;physically&#039;&#039;&#039; before $answers in the tree (and in the generated XML).&lt;br /&gt;
&lt;br /&gt;
===== Defining the sources =====&lt;br /&gt;
&lt;br /&gt;
After this, it&#039;s the moment to instruct our tree about how to fetch information from DB in order to generate the choice.xml file, so after the &#039;&#039;// Define sources&#039;&#039; comment, we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;set_source_table(&#039;choice&#039;, array(&#039;id&#039; =&amp;gt; backup::VAR_ACTIVITYID));&lt;br /&gt;
&lt;br /&gt;
        $option-&amp;gt;set_source_sql(&#039;&lt;br /&gt;
            SELECT *&lt;br /&gt;
              FROM {choice_options}&lt;br /&gt;
             WHERE choiceid = ?&#039;,&lt;br /&gt;
            array(backup::VAR_PARENTID));&lt;br /&gt;
&lt;br /&gt;
        // All the rest of elements only happen if we are including user info&lt;br /&gt;
        if ($userinfo) {&lt;br /&gt;
            $answer-&amp;gt;set_source_table(&#039;choice_answers&#039;, array(&#039;choiceid&#039; =&amp;gt; &#039;../../id&#039;));&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we define the source for the $choice element as the information present in the &#039;choice&#039; table for the id that is being backup (backup::VAR_ACTIVITYID). Or we define the source for the $option element like one SQL (could have been one table too, just to show more possibilities of the API, using the parent (the choice one) as value for the query (backup::VAR_PARENTID).&lt;br /&gt;
&lt;br /&gt;
And finally, conditionally, if user information is going to be included, we define the source for the $answer (note we had already annotated in our schema that this element was dependent of that). &lt;br /&gt;
&lt;br /&gt;
And we define the source condition as having the &#039;choiceid&#039; field matching the value of the &#039;id&#039; field two levels above (../../id). If you follow the tree created in the previous code section, that&#039;s exactly the choice-&amp;gt;id (remember we have introduced one extra level (the plural one between the &#039;choice&#039; and the &#039;answer&#039; singular elements). Note this is 100% equivalent to use backup::VAR_PARENTID (as we have done in the $option source) just used to show possibilities of the API.&lt;br /&gt;
&lt;br /&gt;
Summarizing, with the API, we have these 3 method for defining sources:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_source_table($tablename, array $conditions)&#039;&#039;&#039;: When the information is get straight from one table (vast majority of cases in backup)&lt;br /&gt;
* &#039;&#039;&#039;set_source_sql($sql, array $params)&#039;&#039;&#039;: When the information doesn&#039;t map one table directly and we need something more complex&lt;br /&gt;
* &#039;&#039;&#039;set_source_array($array)&#039;&#039;&#039;: When we have some fixed information to backup. Not really useful in nested information, but used by core here and there.&lt;br /&gt;
&lt;br /&gt;
Note that both the $conditions and $params above only accept one limited number of constants or values (not all available in all backups!), mainly:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_COURSEID&#039;&#039;&#039;: The id of the course this activity belongs to / the course id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_SECTIONID&#039;&#039;&#039;: The id of the section this activity belongs to / the section id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_ACTIVITYID&#039;&#039;&#039;: The id of the activity id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_MODID&#039;&#039;&#039;: The id of the course_module being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_MODULENAME&#039;&#039;&#039;: The name of the module being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_BLOCKID&#039;&#039;&#039;: The id of the block being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_BLOCKNAME&#039;&#039;&#039;: The name of the block being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_CONTEXTID&#039;&#039;&#039;: The context id of the activity / course being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_PARENTID&#039;&#039;&#039;: The value of the first parent id found in the structure.&lt;br /&gt;
* &#039;&#039;&#039;../some/path/to/parent&#039;&#039;&#039;: To manually point to other value of any parent.&lt;br /&gt;
&lt;br /&gt;
Is important to note that, in 99% of the case we should be using, exclusively, some of the constants above, and backup, automatically will handle them properly. In case we have any other condition or param to be added like, for example, the number 23, or the string &#039;user&#039;, we cannot add them directly, but enclose them with the helper &#039;&#039;&#039;backup_helper::is_sqlparam(23)&#039;&#039;&#039; or &#039;&#039;&#039;backup_helper::is_sqlparam(&#039;user&#039;)&#039;&#039;&#039;. That way backup will know they are raw SQL params not needing any special handling, like the constants above.&lt;br /&gt;
&lt;br /&gt;
Well, now it&#039;s time to run backup again and take a look to our activities/choice_XX/choice.xml file. Now everything should be there, properly nested, the choice, the options and the answers. We are really near finishing now.&lt;br /&gt;
&lt;br /&gt;
===== Annotating IDs =====&lt;br /&gt;
&lt;br /&gt;
Now it&#039;s time to perform all the annotations that we had already detected in our analysis of the module. So, after the &#039;&#039;// Define id annotations&#039;&#039; comment we&#039;ll be adding:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $answer-&amp;gt;annotate_ids(&#039;user&#039;, &#039;userid&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It simply means, annotate for each $answer element, the value of the &#039;userid&#039; field as one &#039;user&#039; to be backup. In other words we are instructing backup that there is one new user to include later, when generating the users information and, at the same time, we are determining that those users are needed for the choice XX, so, if on restore we decide to skip that choice and such user isn&#039;t necessary for any other module / subsystem, it won&#039;t be restored. All this &amp;quot;uses&amp;quot; information is handled by the &amp;quot;inforef.xml&amp;quot; files within each activity backup, just in case you&#039;re interested to take a look to them. Else, just consider them, &amp;quot;dark magic&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: If you&#039;re not sure about which elements must be annotated, review [[Backup 2.0 for developers #annotate_is_important|&amp;quot;Annotating some important bits&amp;quot;]] above for details about &#039;&#039;&#039;must-be-done&#039;&#039;&#039; annotations.&lt;br /&gt;
&lt;br /&gt;
===== Annotating files =====&lt;br /&gt;
&lt;br /&gt;
And, finally, reviewing our elaborate and detailed schema, the last thing we need to take care of are the file areas used, so, after the &#039;&#039;// Define file annotations&#039;&#039; comment we&#039;ll add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;annotate_files(&#039;mod_choice&#039;, &#039;intro&#039;, null, $contextid = null); // This file area does not have an itemid.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That means that, within the $choice element we have one file area in use, of course belonging to the &#039;mod_choice&#039; component (where all the choice module files belong to), named &#039;intro&#039; and not using itemid (null). Note that, since it is possible to have multiple file areas in the same element (table), you may end up having multiple calls to the annotate_files() method, one for each filearea to be added to backup. The third parameter, if it is needed, must be the name of one of the attributes or fields of the $choice element (usually, in the vast majority of cases, the &#039;id&#039; of the element), otherwise we&#039;ll use null. The fourth parameter is optional and will default to the context id of the backup, but if you want to specify the context id you do so here.&lt;br /&gt;
&lt;br /&gt;
=== One encoded wor(l)d ===&lt;br /&gt;
&lt;br /&gt;
Already out from the step definition, that should be working ok now, with the choice.xml file being generated and all the annotations being processed and added to the inforef.xml file, there is one more point to fulfill before considering choice&#039;s backup 100% finished.&lt;br /&gt;
&lt;br /&gt;
And it&#039;s about how to provide the ability to transform some links to the choice module when the backup file is restored into another server / course. That is automatically handled by a two-step approach:&lt;br /&gt;
# On backup, we transform as many well-know URLs as possible to one encoded form.&lt;br /&gt;
# On restore, we transform those encoded URLS back to their original form, but pointing to their new targets.&lt;br /&gt;
&lt;br /&gt;
So, in backup, we must provide services for the point 1 above, and that is done by adding some &amp;quot;encoding&amp;quot; conversions to the &#039;&#039;&#039;encode_content_links()&#039;&#039;&#039; method in our &#039;&#039;&#039;backup_choice_activity_task&#039;&#039;&#039;. So, define it to look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Code the transformations to perform in the activity in&lt;br /&gt;
     * order to get transportable (encoded) links&lt;br /&gt;
     */&lt;br /&gt;
    static public function encode_content_links($content) {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
&lt;br /&gt;
        $base = preg_quote($CFG-&amp;gt;wwwroot,&amp;quot;/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Link to the list of choices&lt;br /&gt;
        $search=&amp;quot;/(&amp;quot;.$base.&amp;quot;\/mod\/choice\/index.php\?id\=)([0-9]+)/&amp;quot;;&lt;br /&gt;
        $content= preg_replace($search, &#039;$@CHOICEINDEX*$2@$&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
        // Link to choice view by moduleid&lt;br /&gt;
        $search=&amp;quot;/(&amp;quot;.$base.&amp;quot;\/mod\/choice\/view.php\?id\=)([0-9]+)/&amp;quot;;&lt;br /&gt;
        $content= preg_replace($search, &#039;$@CHOICEVIEWBYID*$2@$&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
        return $content;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Básically, it gets any URL (manually written) in any content of the backup being generated and transform some (well-known) URLs to one encoded alternative. In this case we are encoding:&lt;br /&gt;
* Any URL pointing to the list of choices in a course == is changed to ==&amp;gt; $@CHOICEINDEX*XX@$&lt;br /&gt;
* Any URL pointing to one exact choice == is changed to ==&amp;gt; $@CHOICEVIEWBYID*YY@$&lt;br /&gt;
&lt;br /&gt;
In restore, well have the opposite conversions happening, replacing the XX and YY above to their new equivalents, so those links will be transportable via backup/restore without any need to edit them manually later.&lt;br /&gt;
&lt;br /&gt;
Tip: Don&#039;t forget to look to the module&#039;s 1.9 backup code, as far as there you&#039;ll find which conversions must be considered to be added here.&lt;br /&gt;
&lt;br /&gt;
=== Final notes ===&lt;br /&gt;
&lt;br /&gt;
* Don&#039;t get stressed, it&#039;s really more difficult / longer to explain than to do it. 100% guaranteed, else we&#039;ll return your money. :-P&lt;br /&gt;
* If you&#039;ve become lost, or your code is not working properly, you always can [https://github.com/moodle/moodle/tree/master/mod/choice/backup/moodle2 see the complete choice working code in git]. Or, alternatively, look to other well known modules, like [https://github.com/moodle/moodle/blob/master/mod/forum/backup/moodle2/ forum] or also the [https://github.com/moodle/moodle/blob/master/backup/moodle2/backup_stepslib.php big core library of steps], where you will find all sort of uses of the API.&lt;br /&gt;
* If you are going to implement backup for module XXXX, just copy this document, replace any &amp;quot;choice&amp;quot; occurrence within it by XXXX and follow it from the beginning to the end. Should work.&lt;br /&gt;
* If the module already existed in Moodle 1.x, try to follow the same structure if possible, that will make things easier for restore / conversion.&lt;br /&gt;
* Right now there are some pending tasks related with different exceptions that will be thrown if you code something wrongly (bad nesting, incorrect field names, bad constant/sql param uses...) and how they are shown. Fix for that will be coming soon.&lt;br /&gt;
* Also, as stated at the beginning of this tutorial, we are still missing &amp;quot;subplugins&amp;quot; final support in modules, so try to avoid implementing backup on them for now. Once ready, there will be one new section in this document about them.&lt;br /&gt;
* Any question / improvement / comment, feel free to contact with Moodle HQ, better if using the Tracker or, alternatively, forums / email / direct contact with your very-best-developer-friend. Note this is version x.0 (dot zero) of the backup API, so sure there are possibilities to improve it along the time.&lt;br /&gt;
&lt;br /&gt;
== Other components that can be backed up ==&lt;br /&gt;
&lt;br /&gt;
Most plugins which can be added to a course can also include data in a course backup. Some examples:&lt;br /&gt;
&lt;br /&gt;
* Course formats&lt;br /&gt;
* Themes: [[ Backup 2.0 theme data| Backup 2.0 theme data]]&lt;br /&gt;
* Plagiarism plugins&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.0.1_release_notes&amp;diff=61069</id>
		<title>Moodle 3.0.1 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.0.1_release_notes&amp;diff=61069"/>
		<updated>2021-08-10T15:11:49Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 21 December 2015&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.0.1%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.0.1].&lt;br /&gt;
 &lt;br /&gt;
===Highlights===&lt;br /&gt;
 &lt;br /&gt;
Moodle 3.0.1 is a special release outside of the normal release schedule. The main highlight is support of PHP 7.0. This is the new major version of the programming language Moodle is written in; it has significantly better performance but at the same time lots of changes in the engine. Please note that Moodle 2.9 will show errors if run on PHP 7.&lt;br /&gt;
&lt;br /&gt;
Before upgrading to PHP 7 version on production servers, you are recommended to &#039;&#039;&#039;test all plugins thoroughly&#039;&#039;&#039;. See [[Moodle and PHP7]] for developer documentation.&lt;br /&gt;
&lt;br /&gt;
PHP 7 was released on 3 December 2015 and is still very young. Not all libraries and/or drivers are available yet for PHP 7. For example, &#039;&#039;&#039;there are no drivers for SQL*Server&#039;&#039;&#039;. Other drivers required by your plugins may also be missing. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PHP 7 compatibility makes Moodle faster&#039;&#039;&#039;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|[[File:php7 time logging in.png]]&lt;br /&gt;
|[[File:course-time-300x177.png]]&lt;br /&gt;
|-&lt;br /&gt;
|20% faster when logging in*&lt;br /&gt;
|59% faster when loading the course page*&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PHP 7 compatibility significantly reduces memory used&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|[[File:php7 memory logging in.png]]&lt;br /&gt;
|[[File:php7 memory viewing course.png]]&lt;br /&gt;
|-&lt;br /&gt;
|42% less memory used when logging in*&lt;br /&gt;
|38% less memory used when viewing a course*&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
: * Test results obtained on a test Moodle instance with one course in topics format with over 100 activities and resources.&lt;br /&gt;
&lt;br /&gt;
===Other fixes and improvements===&lt;br /&gt;
 &lt;br /&gt;
* MDL-44330 - When using assignment grading in several tabs the links to individual students grades work correctly&lt;br /&gt;
* MDL-37834 - Excel can be used to edit the assignment offline grading worksheet &lt;br /&gt;
* MDL-42571 - Edit PDF: Fixed bug with viewing a second PDF on the assignment grading page&lt;br /&gt;
* MDL-43069 - Assignment grading: &amp;quot;Submission comments&amp;quot; fail to expand if you hide the &amp;quot;file submissions&amp;quot; column&lt;br /&gt;
* MDL-37308 - Uploaded PNG images preserve transparency when resized&lt;br /&gt;
* MDL-49490 - Fixed export to portfolio link in assignment with additional files&lt;br /&gt;
* MDL-52194 - Fixed Flowplayer not working with insecure configuration of request_order&lt;br /&gt;
&lt;br /&gt;
===For developers===&lt;br /&gt;
&lt;br /&gt;
* MDL-51582 - Switch to grunt to compile LESS as recess is no longer maintained&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
There are no security issues in this release. Security issues will be included in Moodle 3.0.2 which is due for release in January 2016.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.0 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.0]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.0.1]]&lt;br /&gt;
[[es:Notas de Moodle 3.0.1]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_2.9_release_notes&amp;diff=61068</id>
		<title>Moodle 2.9 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_2.9_release_notes&amp;diff=61068"/>
		<updated>2021-08-10T15:11:48Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
Release date: Monday, 11th May 2015&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%222.9%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 2.9].&lt;br /&gt;
&lt;br /&gt;
See our [https://docs.moodle.org/29/en/New_features New Features page] for a more user-friendly introduction to Moodle 2.9 with screenshots.&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from previous version, make sure to read the [https://docs.moodle.org/29/en/Upgrading Upgrading] documentation. &lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 2.2 or later (if upgrading from earlier versions, you must upgrade to 2.2.11 as a first step)&lt;br /&gt;
* PHP version: minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported&lt;br /&gt;
* Ghostscript should be installed for pdf annotation.&lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.1&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 10.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended version&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.google.com/intl/en_au/chrome/browser/ Google Chrome]&lt;br /&gt;
| 30.0&lt;br /&gt;
| Latest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mozilla.org/en-US/ Mozilla Firefox]&lt;br /&gt;
| 25.0&lt;br /&gt;
| Latest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.apple.com/safari/ Apple Safari]&lt;br /&gt;
| 6&lt;br /&gt;
| Latest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [http://windows.microsoft.com/en-AU/internet-explorer/download-ie Microsoft Internet Explorer]&lt;br /&gt;
| 9&lt;br /&gt;
| Latest&lt;br /&gt;
| Version 10 is required for drag-and-drop upload of content from outside the browser into Moodle&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
===Navigation improvements===&lt;br /&gt;
&lt;br /&gt;
One of the biggest project was improvements in Navigation and Users pages, see also MDL-45774. It includes:&lt;br /&gt;
&lt;br /&gt;
* MDL-45894, MDL-49634 - [https://docs.moodle.org/29/en/Overview_report Grades page] listing all my courses, and all courses I am teaching in one place (linked from User Menu) &lt;br /&gt;
* MDL-48936 - My Home is now  [https://docs.moodle.org/29/en/Dashboard Dashboard]&lt;br /&gt;
* MDL-48932, MDL-45898 - Redesign [https://docs.moodle.org/29/en/User_profiles profile page], make it pluggable &lt;br /&gt;
* MDL-45895 - New [https://docs.moodle.org/29/en/Preferences Preferences] page (linked from user menu) &lt;br /&gt;
* MDL-45896 - Consistent header for user pages &lt;br /&gt;
* MDL-48931 - Consistent header for user sub pages &lt;br /&gt;
* MDL-48935 - Consistent bread crumbs for user pages &lt;br /&gt;
* MDL-49635 - Remove redundant nodes from nav tree&lt;br /&gt;
* MDL-49983 - Improve consistency of the use of the word &amp;quot;My&amp;quot; in navigation&lt;br /&gt;
&lt;br /&gt;
===User interface improvements===&lt;br /&gt;
&lt;br /&gt;
* MDL-43996 - Drag and drop image into [https://docs.moodle.org/29/en/Text_editor Atto editor] inserts it as a file &lt;br /&gt;
* MDL-19670 - Teacher can post the same forum question to all groups at once &lt;br /&gt;
* MDL-47172 - “You have assignments that need attention” in the [https://docs.moodle.org/29/en/Course_overview_block course overview block] displays relevant information for teachers &lt;br /&gt;
* MDL-48933 - Ajax interface for [https://docs.moodle.org/29/en/Messaging messaging] &lt;br /&gt;
* MDL-23296 - Provide search function for [https://docs.moodle.org/29/en/Server_files_repository Server files area] in the file picker&lt;br /&gt;
* MDL-48937 - Don&#039;t show the category in the breadcrumb if there is only one category&lt;br /&gt;
* MDL-26226 - Section names in the navigation can link to the sections&lt;br /&gt;
* MDL-49694 - Overview report shows the full course name&lt;br /&gt;
* MDL-47527 - Allow access to overview report for users who can view all grades&lt;br /&gt;
* MDL-36009, MDL-46662 - Grader report accessibility improvement&lt;br /&gt;
* MDL-47562 - UI Fixes and improvements for SingleView report&lt;br /&gt;
* MDL-47434 - Do not display &#039;General&#039; section in navigation block if it&#039;s empty&lt;br /&gt;
&lt;br /&gt;
===Course creation improvements===&lt;br /&gt;
&lt;br /&gt;
* MDL-10405 - Added button to quickly delete a whole section on the [https://docs.moodle.org/29/en/Course_homepage course homepage]&lt;br /&gt;
* MDL-31500 - Allow backup and restore on the front page&lt;br /&gt;
* MDL-5583 - Fields in database module can be set as required &lt;br /&gt;
* MDL-28526 - Glossary can export/import embedded images and attached files &lt;br /&gt;
* MDL-49006, MDL-49101 - Removed default requirement of activity description and substituted with a single setting&lt;br /&gt;
* MDL-13831 - Grade to pass can be set by editing activity without going to gradebook &lt;br /&gt;
* MDL-46960 - Completion status is updated immediately for student when activity is graded&lt;br /&gt;
* MDL-27074 - Display group name for group events in the calendar&lt;br /&gt;
* MDL-48969 - New [https://docs.moodle.org/29/en/Activity_results_block activity results block]&lt;br /&gt;
* MDL-18177 - Add option to choose whether groups and/or groupings are included in a back up&lt;br /&gt;
* MDL-20053 - Database activity: create ##userpicture## tag to allow the user&#039;s profile picture to be displayed&lt;br /&gt;
* MDL-49543 - Add a WYSIWYG field to Badges which is displayed on the criteria page&lt;br /&gt;
* MDL-46416 - Possible to change / remove picture from group&lt;br /&gt;
* MDL-49687 - Adding a single person to multiple groups at the same time&lt;br /&gt;
* MDL-21724 - The course edit page needs a way to redirect to some page other than the main course page after saving&lt;br /&gt;
* MDL-47628 - When grouping is selected for the activity display a button to quickly create access restriction (helps users who were used to groupmembersonly)&lt;br /&gt;
* MDL-23178 - Allow indenting again for activities in the Main Menu block&lt;br /&gt;
* MDL-46238 - Add a simple way to go back from enrol/users.php page to the course&lt;br /&gt;
&lt;br /&gt;
===Administrator features===&lt;br /&gt;
&lt;br /&gt;
* MDL-15187 - Assign global roles using CSV upload&lt;br /&gt;
* MDL-30937 - Backup report again links to the individual course backup summaries&lt;br /&gt;
* MDL-32547 - Configure temporary file deletion, to avoid moodledata/temp/backup filling up the filesystem&lt;br /&gt;
* MDL-49684 - Replace custom Moodle timezone stuff with standard PHP date/time code&lt;br /&gt;
* MDL-25763 - CLI version of admin/replace.php&lt;br /&gt;
* MDL-44874 - Per-request temp directories&lt;br /&gt;
* MDL-46064 - Drop support for MyISAM&lt;br /&gt;
* MDL-49298 - Make tgz backups standard&lt;br /&gt;
* MDL-47834 - New option for restriction of concurrent logins in [https://docs.moodle.org/29/en/Managing_authentication managing authentication]&lt;br /&gt;
* MDL-47800 - Logout user when somebody changes their password&lt;br /&gt;
* MDL-47830 - Add password rotation restrictions&lt;br /&gt;
* MDL-48559 - Web CRON should be disabled by default&lt;br /&gt;
* MDL-48080 - Never send mail to domains ending in .invalid&lt;br /&gt;
* MDL-48595 - Log exports no longer fails because of memory limit&lt;br /&gt;
* MDL-28513 - Allow specification of admin user email in CLI installer&lt;br /&gt;
* MDL-49842 - Allow specification of front page summary in CLI installer&lt;br /&gt;
* MDL-47803 - New page that shows all [https://docs.moodle.org/29/en/Browser_sessions browser sessions] of current user&lt;br /&gt;
* MDL-34684 - New health check to detect incorrect category path order and/or missing parent categories&lt;br /&gt;
* MDL-48493 - Automatically detect the plugin type when installing from ZIP&lt;br /&gt;
* MDL-48894 - [https://docs.moodle.org/29/en/Site_registration Site registration] page states if site is registered&lt;br /&gt;
* MDL-18183 - Option to verify peer and host of MNet peer using HTTPS&lt;br /&gt;
&lt;br /&gt;
===Files and repositories===&lt;br /&gt;
&lt;br /&gt;
* MDL-42616 - New admin tool for [https://docs.moodle.org/29/en/Working_with_files adding custom file types]&lt;br /&gt;
* MDL-43752 - [https://docs.moodle.org/29/en/Amazon_S3_repository Amazon S3 repository] allows an endpoint to be set&lt;br /&gt;
&lt;br /&gt;
===Authentication, enrolments and access===&lt;br /&gt;
&lt;br /&gt;
* Several improvements to meta enrolments, such as: populate groups from courses MDL-17929, sorting courses alphabetically MDL-35696, button to quickly add a new method MDL-49439&lt;br /&gt;
* MDL-26017 - Keyholder capability in self-enrolment plugin&lt;br /&gt;
* MDL-20365 - Salted Crypt passwords option for external database authentication&lt;br /&gt;
* MDL-49380 - Chose &amp;quot;Create new group&amp;quot; when synchronising cohort enrolment with a group&lt;br /&gt;
* MDL-49677 - Improvement of Custom welcome message in self-enrolment plugin&lt;br /&gt;
* MDL-43415 - Custom profile fields should be syncable with external DB auth&lt;br /&gt;
* MDL-49638 - reCAPTCHA should be moved below custom profile fields during self registration&lt;br /&gt;
&lt;br /&gt;
===Quiz===&lt;br /&gt;
&lt;br /&gt;
* MDL-40988 - Add section headings to quiz&lt;br /&gt;
* MDL-40992 - Option for teachers to allow students to redo a finished question within a quiz attempt&lt;br /&gt;
* MDL-40990 - Teachers can require students to complete Question 1 before they can see Question 2&lt;br /&gt;
* MDL-25721 - The question bank can be sorted by date&lt;br /&gt;
* MDL-348 - Printer-friendly option for quizzes &lt;br /&gt;
* MDL-6340 - force unique/unseen questions in  retakes&lt;br /&gt;
* MDL-35280 - quiz_reset_userdata does not have an option to remove user/group overrides&lt;br /&gt;
* MDL-48898 - Quiz time period setting should use admin_setting_configduration&lt;br /&gt;
&lt;br /&gt;
===Lesson===&lt;br /&gt;
&lt;br /&gt;
* MDL-48803 - support for groups  &lt;br /&gt;
* MDL-48715 - moving “time spent” from prerequisite to the proper completion rule  &lt;br /&gt;
* MDL-43387 - UI for grading essays &lt;br /&gt;
* MDL-48244 - Lessons with no questions show completed after the first page is viewed&lt;br /&gt;
* MDL-47587 - Make progress bar available on the very last page of a lesson.&lt;br /&gt;
* MDL-49642 - Give time/date extensions to users and groups in lesson&lt;br /&gt;
* MDL-40286 - non-editing teacher should see Grade analysis in Lesson&lt;br /&gt;
* MDL-48473 - Lesson shortanswer question: add fill in the blank option&lt;br /&gt;
* MDL-48984 - Lesson content page jump descriptions, numerical and shortanswer questions answers allow rich html but should be plain text&lt;br /&gt;
* MDL-18553 - Removing grade info from lesson pages if lesson grade is 0&lt;br /&gt;
* MDL-26689 - in order to prevent interactivity references from being broken move the &amp;quot;Dependent on&amp;quot; feature to the completion/availability subsystem&lt;br /&gt;
* MDL-49183 -  Page creation, update and delete events added&lt;br /&gt;
* MDL-48883 - Content page viewed, Question page viewed and Question page answered events added&lt;br /&gt;
&lt;br /&gt;
===Other modules===&lt;br /&gt;
&lt;br /&gt;
* MDL-48221 - Make forum subscription combinations less confusing with different combinations&lt;br /&gt;
* MDL-48822 - Find last visual post in a discussion&lt;br /&gt;
* MDL-46755 - Allow teachers to configure the number of discussions displayed using the social course format&lt;br /&gt;
* MDL-49069 - Ability to specify default values for Forum RSS&lt;br /&gt;
* MDL-48159 - For users without group prevent submissions instead of using &amp;quot;Default team&amp;quot; in group assignments&lt;br /&gt;
* MDL-47777 - Convert assignment maximum files per submission maximum to global setting&lt;br /&gt;
* MDL-45848 - Possible to assign Marker on a marking guide or rubric assignment without giving a grade&lt;br /&gt;
* MDL-49220 - Allow preview of Choice options before activity is opened for submission&lt;br /&gt;
* MDL-34375 - Choice module should display information in &amp;quot;Course overview&amp;quot; block&lt;br /&gt;
* MDL-43770 - Exclude inactive users&#039; responses from Choice report (with an option to include)&lt;br /&gt;
* MDL-32285 - Added &amp;quot;Continue&amp;quot; button under Error notification message (IMS CP)&lt;br /&gt;
* MDL-49730 - Workshop: use full page width when displaying contents&lt;br /&gt;
* MDL-36874 - Text navigation for Books&lt;br /&gt;
* MDL-49563 - Allow glossary entry to be updated from glossary navigation&lt;br /&gt;
&lt;br /&gt;
===Various===&lt;br /&gt;
&lt;br /&gt;
* MDL-46763 - Save user images as JPEG if uploaded in that format.&lt;br /&gt;
* MDL-48760 - MathJax library updated to 2.5&lt;br /&gt;
* MDL-47232 - Course completion: &amp;quot;Activities to be completed&amp;quot; should not require passing grade&lt;br /&gt;
* MDL-48437 - Make Visible/All [https://docs.moodle.org/29/en/Groups groups] selector show own groups first&lt;br /&gt;
* MDL-47501 - Add an indication that the [https://docs.moodle.org/29/en/Grade_letters grade letters] have been overridden&lt;br /&gt;
* MDL-47159 - Link plugin in Atto should add &amp;lt;nowiki&amp;gt;&#039;http://&#039;&amp;lt;/nowiki&amp;gt; prefix when necessary&lt;br /&gt;
* MDL-9443 - Run *.xhtml file through the text filters&lt;br /&gt;
* MDL-48616 - Add Macrons in Atto character map&lt;br /&gt;
* MDL-46665 - ID number filter added to [https://docs.moodle.org/29/en/Browse_list_of_users Browse list of users]&lt;br /&gt;
* MDL-48499 - Show which users have not received messages in bulk messaging&lt;br /&gt;
* MDL-49333 - Return additional information in WebService core_get_site_info&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
 &lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313681 MSA-15-0018] Quiz manual-grading is an XSS risk, but does not declare that&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313682 MSA-15-0019] Possible phishing when redirecting to external site using referer header&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313683 MSA-15-0020] User fullname disclosure through account confirmation link&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313684 MSA-15-0021] Any authenticated user can subscribe to site-wide event monitor rules&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313685 MSA-15-0022] Potential XSS risk when returning text entered by student from Web Services&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313686 MSA-15-0023] Suspended user is able to login when confirming email&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313687 MSA-15-0024] User with suspended enrolment can see sections in the navigation tree&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=313688 MSA-15-0025] Capability to manage own files is not respected in Web Services&lt;br /&gt;
&lt;br /&gt;
==For developers==&lt;br /&gt;
 &lt;br /&gt;
* MDL-49046 - Support for Asynchronous Module Definition formatted javascript modules. Developer docs: [[Javascript Modules]]&lt;br /&gt;
* MDL-49163 - Support for calling webservice functions directly from javascript. Developer docs: [[AJAX]]&lt;br /&gt;
* MDL-49152 - Support for implementing renderers as mustache templates (php and javascript). Developer docs: [[Templates]]&lt;br /&gt;
* MDL-44874 - A new per-request directory API has been added, and should be used instead of make_temp_directory wherever possible.&lt;br /&gt;
* MDL-49604 - Support for in browser caching (localstorage) of strings and templates &lt;br /&gt;
* MDL-49650 - [https://docs.moodle.org/29/en/Template_library Template Library] - tool for displaying templates in the current theme &lt;br /&gt;
* MDL-48887 - New auth hook to intercept code before login page is shown. &lt;br /&gt;
* MDL-48177 - Allow plugin environment checks to work without defining explicit versions of Moodle&lt;br /&gt;
* MDL-46728 - WOFF2 fonts are supported in themes.&lt;br /&gt;
* MDL-39752, MDL-49456 - Behat tests runs in parallel&lt;br /&gt;
* MDL-49163 - Unified Ajax script handler. Developer docs: [[AJAX]]&lt;br /&gt;
* MDL-27548 - The comments table contains the component&lt;br /&gt;
* MDL-49269 - Add an AMD log module&lt;br /&gt;
* MDL-49534 - Delete pear/HTTP/WebDav&lt;br /&gt;
* MDL-48212 - Introduces a new class \core\message\message that should be used instead of \stdClass for creating messages.&lt;br /&gt;
* MDL-37477 - html_table API supports caption tag&lt;br /&gt;
* MDL-49643 - Deprecate inconsistent API to extend the navigation by local plugins&lt;br /&gt;
* MDL-49361 - Ability to provide alternate strings manager&lt;br /&gt;
* MDL-44642 - Implemented backend to keep session alive &lt;br /&gt;
* MDL-45725 - User preferences for flexible tables can be set persistent across sessions&lt;br /&gt;
* MDL-49306 - When copying block instances the instance data is also copied&lt;br /&gt;
* MDL-47915 - Theme layout &amp;quot;embedded&amp;quot; uses id=&#039;page-content&#039; rather than &#039;content&#039; to be consistent with other layouts&lt;br /&gt;
* MDL-48212 - Implement new message api to support specific text only on a given handler&lt;br /&gt;
* MDL-49262 - Delete the yui versions of the bootstrap plugins&lt;br /&gt;
* MDL-40864 - Use div.logo instead of a.logo in Bootstrapbase / Clean / More home links&lt;br /&gt;
* MDL-48160 - For theme developers: changes to block region layouts when coded for RTL&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 2.9]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 2.9]]&lt;br /&gt;
[[es:Notas de Moodle 2.9]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Mobile_device_support&amp;diff=61067</id>
		<title>Mobile device support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Mobile_device_support&amp;diff=61067"/>
		<updated>2021-08-10T15:11:48Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.6}}&lt;br /&gt;
This pages summarizes development efforts being made as part of the development of Moodle 2.6. Specifically, enhancing the experience for users accessing Moodle via a tablet or smartphone. Mobile devices are now extremely common and Moodle must evolve to allow Moodle users to make full use of their devices.&lt;br /&gt;
&lt;br /&gt;
==Priorities==&lt;br /&gt;
Mobile device support will be an ongoing priority for Moodle HQ. With additional core development and base theme alterations Moodle should be able to function equally well on desktops, tablets and smartphones. This will enable Moodle sites to be confident that their Moodle installation will be usable on whatever devices are in use by their students and staff.&lt;br /&gt;
&lt;br /&gt;
To enable us to achieve the greatest impact with finite resources we have decided on the following set of priorities.&lt;br /&gt;
&lt;br /&gt;
===Content Before Configuration===&lt;br /&gt;
It&#039;s extremely important that users be able to easily access course content on their various devices. For the time being it is acceptable to require the user to use a desktop or laptop computer to perform site or course configuration. Once we have ensured that users can easily access course content we will move on to improving the mobile experience for admins and users who are creating courses.&lt;br /&gt;
&lt;br /&gt;
===1. Students===&lt;br /&gt;
Students typically outnumber staff by a large margin and have a very high rate of mobile device ownership. &amp;quot;Read only&amp;quot; tasks like checking assignment due dates, retrieving grades and accessing course resources must be painless. &amp;quot;Write&amp;quot; tasks like submitting photos taken with the device camera should be accommodated as much as possible.&lt;br /&gt;
&lt;br /&gt;
===2. Teachers===&lt;br /&gt;
Less numerous than students. They should be able to participate in their courses, for example participating in forum discussions, as well as perform some core activities like grading of assignment submissions. Some areas, most notably the gradebook, will likely not be optimized for mobile devices until a later release.&lt;br /&gt;
&lt;br /&gt;
===3. Admins===&lt;br /&gt;
Site administration is expected to still be performed primarily on desktop and laptop computers. Mobile optimization of admin tasks may occur in the future but is not a priority for this release.&lt;br /&gt;
&lt;br /&gt;
=== Summary ===&lt;br /&gt;
&lt;br /&gt;
In summary, the following types of use are anticipated:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Activity&lt;br /&gt;
! Student&lt;br /&gt;
! Teacher&lt;br /&gt;
! Administrator&lt;br /&gt;
|-&lt;br /&gt;
! Checking Assignment metadata&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
|-&lt;br /&gt;
! Viewing Gradebook&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
|-&lt;br /&gt;
! Editing Gradebook&lt;br /&gt;
| N/A&lt;br /&gt;
| T / D&lt;br /&gt;
| N/A&lt;br /&gt;
|-&lt;br /&gt;
! Accessing Course Resources&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
|-&lt;br /&gt;
! Reading forum discussions&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
|-&lt;br /&gt;
! Participating in forum discussions&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
|-&lt;br /&gt;
! Uploading multimedia (images, video, audio)&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
| M / T / D&lt;br /&gt;
|-&lt;br /&gt;
! Uploading other files&lt;br /&gt;
| D&lt;br /&gt;
| D&lt;br /&gt;
| D&lt;br /&gt;
|-&lt;br /&gt;
! Site administration&lt;br /&gt;
| N/A&lt;br /&gt;
| N/A&lt;br /&gt;
| D&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
M = Mobile;&lt;br /&gt;
T = Tablet;&lt;br /&gt;
D = Desktop (or Laptop).&lt;br /&gt;
&lt;br /&gt;
==Device Support==&lt;br /&gt;
Rather than listing or blacklisting devices that do or do not present Moodle correctly, we are aiming to create a list of recommended specifications for a device in order to have an optimum experience with Moodle.&lt;br /&gt;
&lt;br /&gt;
===Android===&lt;br /&gt;
We recommend a 1GHz single core, or better device, with 512MB or more RAM. A resolution of 480x320 in Landscape mode is also recommended.&lt;br /&gt;
&lt;br /&gt;
===iOS===&lt;br /&gt;
Any device capable of running iOS 4 or greater is recommended. &lt;br /&gt;
&lt;br /&gt;
==Device Testing==&lt;br /&gt;
Testing of current Moodle functionality on a range of mobile devices has been performed. iPads, recent iPhones, Android tablets and Android phones have been targeted for thorough testing. This testing will be repeated in the future to detect device specific problems.&lt;br /&gt;
&lt;br /&gt;
Testing is limited by what devices are physically available to HQ staff. As we near the release of 2.6 testing by the community will be required to test additional devices, most notably the iPhone 5.&lt;br /&gt;
&lt;br /&gt;
===High Priority Devices Available to HQ===&lt;br /&gt;
{|&lt;br /&gt;
! align=&amp;quot;right&amp;quot;| Operating System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;| Device&lt;br /&gt;
! Browser&lt;br /&gt;
|-&lt;br /&gt;
|iOS&lt;br /&gt;
|iPad 2&lt;br /&gt;
|Safari&lt;br /&gt;
|-&lt;br /&gt;
|iOS&lt;br /&gt;
|iPad 3&lt;br /&gt;
|Safari&lt;br /&gt;
|-&lt;br /&gt;
|iOS&lt;br /&gt;
|iPod Touch&lt;br /&gt;
|Safari&lt;br /&gt;
|-&lt;br /&gt;
|iOS&lt;br /&gt;
|iPhone 3gs&lt;br /&gt;
|Safari&lt;br /&gt;
|-&lt;br /&gt;
|iOS&lt;br /&gt;
|iPhone 4s&lt;br /&gt;
|Safari, Chrome and Opera &lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|Acer Iconia 10&amp;quot;&lt;br /&gt;
|Stock 4.0.3&lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|HTC Sensation 4&amp;quot;&lt;br /&gt;
|Stock 4.0.2&lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|LG Optimus L7&lt;br /&gt;
|Stock (Android 4) and Chrome&lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|Samsung Tab 2 7&amp;quot;&lt;br /&gt;
|Stock (Android 4) and Chrome&lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|Nexus 4&lt;br /&gt;
|Chrome&lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|HTC Desire&lt;br /&gt;
|Stock (Android 2.3)&lt;br /&gt;
|-&lt;br /&gt;
|Android&lt;br /&gt;
|Motorola Xoom 10&amp;quot;&lt;br /&gt;
|Chrome&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Getting It Done==&lt;br /&gt;
Tracker issues have been created as part of device testing and also after discussions about possible improvements. The tracker issues are sub-tasks of MDL-38856 and MDL-39665.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking the issues can be grouped by area. Note that this listing will fall out of date very quickly. It is only intended to provide an approximate sense of where work is to be done. Please consult MDL-38856 and MDL-39665 for a completely up to date summary of the work being done.&lt;br /&gt;
&lt;br /&gt;
===Blocks===&lt;br /&gt;
*Navigation - Major improvement could be done here. The hamburger menu icon could display a navigation side bar similar to the current HTML5 mobile app. Also the paddding, font size is too small (Xoom, HTC Desire) MDL-39715&lt;br /&gt;
*Calendar - Use ajax to avoid reloading MDL-39818 MDL-38347&lt;br /&gt;
*Add New Block - Samsung tab II &amp;amp; LG Optimus L7: Chrome and Stock browsers. Adding new block doesn&#039;t automatically added the block to the page. It requires tabbing the select option box to initiate the process. (And Xoom and HTC Desire) MDL-39776&lt;br /&gt;
&lt;br /&gt;
===Front Page===&lt;br /&gt;
*Reports - On Front page settings &amp;gt; reports &amp;gt; course participation, improve alignment/layout for the page. MDL-39798&lt;br /&gt;
&lt;br /&gt;
===Course Page===&lt;br /&gt;
*Adding activities/resources - Could be improved. Not working on Nexus 4 - 4.2 - Chrome. Selecting &#039;folder&#039; do not redirect to the folder creation page. However the second time you click on it, the select box automatically trigger the exist choice and this time goes to the &#039;folder&#039; creation page. Not working on HTC Desire at all (can&#039;t trigger select). Not working on Xoom at all - activity chooser locked up. MDL-39750 MDL-39816&lt;br /&gt;
*Grading - Smaller screens have a really long scroll before you can start to move horizontally, then a big scroll back to the area you wanted to see MDL-39817&lt;br /&gt;
&lt;br /&gt;
===Activities/Resources===&lt;br /&gt;
*Assignment - Using advanced grading: add new criteria and edit the levels - the size of the input boxes for name and points are too wide.  Then, add new level for the criteria, input text for the name is smaller than the point input text. The size of input boxes should be consistent and smaller.	MDL-39748&lt;br /&gt;
*Forum - ipod touch/iphone 4s (potrait view): on discussion page, user name is overlapping with profile picture	MDL-39746			&lt;br /&gt;
*SCORM - &amp;lt;480px screens don&#039;t have enough space to display SCORM at present. Semi Working on &amp;lt;768px screens. Totally broken again on &amp;lt;980px and &amp;lt;1200px screens. Doesn&#039;t reflow along with the rest of the page. It needs to in order to allow for rotation of the screen. MDL-39736 MDL-39737&lt;br /&gt;
*Folders/Files - Mobile friendly. Works well.&lt;br /&gt;
*Lesson - At the end of lesson page, add a space between &amp;quot;Return to lesson&amp;quot; and &amp;quot;View grades&amp;quot; MDL-39773&lt;br /&gt;
*Chat - Some bugs to fix but it is usable. On an iphone users can currently choose between tiny text or lots of scrolling MDL-39770 MDL-39705 MDL-39704&lt;br /&gt;
*Wiki - Fix alignment for required field (red *) on creating new wiki page MDL-39779&lt;br /&gt;
*URL - Embedded URLs display at a fixed width that is small on a desktop and too large on a small screen. Embedded URLs do not load on an iphone 3gs. MDL-39766 MDL-39771&lt;br /&gt;
&lt;br /&gt;
==Major Projects==&lt;br /&gt;
Several projects are under way to attempt to resolve many of these issues at once. They are...&lt;br /&gt;
===Full Screen Popups===&lt;br /&gt;
Popups such as the file picker and the message notification popup function poorly on a small screen. Refactoring them could significantly improve the experience throughout Moodle.&lt;br /&gt;
* MDL-39851 - Full screen popup for mobile (filepicker./activitychooser)&lt;br /&gt;
* MDL-39852 - Adjust file picker / activity chooser forms to full screen popup.&lt;br /&gt;
&lt;br /&gt;
===Relative Scaling===&lt;br /&gt;
Text sizing in Moodle is currently often done with hard coded pixel sizes. This makes scaling for different devices difficult. Switching Moodle to using relative scaling based around the html concepts of &amp;quot;em&amp;quot; and &amp;quot;rem&amp;quot; should allow us to make better use of the available screen real estate throughout Moodle.&lt;br /&gt;
&lt;br /&gt;
* MDL-39843 - Use REM on bootstrapbase to make font-size cascade and scalable&lt;br /&gt;
&lt;br /&gt;
===Blocks===&lt;br /&gt;
Where and how the blocks should be displayed on small screens is the subject of debate. See MDL-39715.&lt;br /&gt;
===Navigation===&lt;br /&gt;
Further information is needed about how the navigation tree can be optimized and when it should be displayed in full or at all.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=LTI_2_support&amp;diff=61066</id>
		<title>LTI 2 support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=LTI_2_support&amp;diff=61066"/>
		<updated>2021-08-10T15:11:48Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = LTI 2 support&lt;br /&gt;
|state = Implemented&lt;br /&gt;
|tracker = MDL-45843&lt;br /&gt;
|discussion = [https://moodle.org/mod/forum/discuss.php?d=261527#p1132968 Adding LTI 2.0 support]&lt;br /&gt;
|assignee = [[User:Stephen Vickers|Stephen Vickers]]&lt;br /&gt;
}}&lt;br /&gt;
==Project goals==&lt;br /&gt;
The main goal of this project is to implement LTI 2.0 functionality for Moodle which is capable of passing the IMS certification tests.  It is not expected that the required changes will have any significant impact on the current LTI 1.1 functionality; indeed it is hoped that the work will also have some beneficial side-effects for the current LTI implementation.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
[http://vitalsource.com/ Vital Source Technologies] recognises the benefits that the [http://www.imsglobal.org/lti IMS Learning Tools Interoperability (LTI) 2 specification] can deliver to tool providers and has, therefore, agreed to sponsor this project in the interests of the whole community.  The work will be undertaken in collaboration with Moodlerooms as an adaptation of the existing LTI (External tool) module which they manage on behalf of the Moodle community.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Moodle already provides support for LTI 1.1, this project will build on this support to add support for LTI 2.0; it will not remove any existing functionality but it is expected that the LTI 1 support will also be enhanced as a consequence of this work.  The main differences between LTI 1.1 and LTI 2.0 are as follows:&lt;br /&gt;
&lt;br /&gt;
; Tool registration : Rather than passing a launch URL, consumer key and shared secret from the tool provider to the tool consumer using some out-of-band communication, LTI 2 uses an interactive registration process; all a tool consumer administrator needs is the URL for initiating this process.&lt;br /&gt;
; Tool Consumer Profile : as part of the registration process, a tool consumer makes available to the tool provider a profile describing itself and the capabilities/services it is willing to make available.&lt;br /&gt;
; Tool Proxy : when &amp;quot;sealing the deal&amp;quot; between the two parties, the tool provider sends a Tool Proxy to the tool consumer which includes a profile about itself and details of the capabilities/services which it proposes to use.  A tool Proxy can be used to register more than one tool (resource handler), all of which are secured using the consumer key and shared secret agreed by the two systems during this process.&lt;br /&gt;
; Launch process : whilst the mechanics of launching an LTI tool remain unchanged from LTI 1, the tool proxy allows the data passed on launch to be tailored to specific requirements.  The custom parameter substitution variables (available in LTI 1 but not implemented in the current Moodle implementation) are used to enable this functionality.&lt;br /&gt;
; Tool Settings service : LTI 2.0 includes a service which allows a tool provider to request a tool consumer to record data (name and value pairs) which are passed back on each launch.  Settings may be saved at one of three levels: system-wide (Tool Proxy level), context-wide (Tool Proxy binding level, e.g. course-wide) and resource specific (LTI link level, i.e. specific to an individual link added to a course).  This service is helpful as it ensures settings are deleted when a link or course is deleted, and it can also help when a course containing links to a tool provider is copied.&lt;br /&gt;
; Discoverable services : the addition of the tool consumer and tool profiles allows each party to declare services which it is willing to offer the other party.  These services may be ones included in the IMS LTI specification (e.g. Tool Settings), but may equally be ones written by other parties which have yet to become part of the specification (and perhaps never will).  Provided both the tool consumer and tool provider have implemented the service, the trust relationship established using LTI can be leveraged to secure the request messages between the servers.  This transforms an LTI tool consumer into an extensible platform for learning tools and resources.&lt;br /&gt;
&lt;br /&gt;
==Current issues with existing LTI functionality==&lt;br /&gt;
There are a number of open Moodle Tracker items relating to enhancements to the LTI implementation.  Whilst this project is not directly concerned with resolving these issues, it does provide an opportunity to review them and see how they might guide the decisions being taken so they are consistent and may indeed provide solutions as a byproduct.  Here is a list of those identified so far (some are from discussion postings or other sources):&lt;br /&gt;
# Add support for multi-tenancy sites to permit different LTI credentials for courses in different sites&lt;br /&gt;
# MDL-37041: The LTI consumer does not pass the user&#039;s profile picture in the user_image launch parameter&lt;br /&gt;
# MDL-37445: Add ability to set Maximum Grade for External Tool&lt;br /&gt;
# MDL-38120: course reports for external tool misssing&lt;br /&gt;
# MDL-39134: Create an LTI filter&lt;br /&gt;
# MDL-41202: LTI course identifier is not configurable; relies on shortname exclusively&lt;br /&gt;
# MDL-41724 (Fixed, as of Moodle 3.0): Implement the IMS LTI contexts membership service&lt;br /&gt;
# MDL-45064 (Fixed, as of Moodle 3.1): Option to add LTI Tool to Activity Chooser&lt;br /&gt;
# Visibility of external tools in the activity choose&lt;br /&gt;
# Support for both activity and resource types&lt;br /&gt;
# [https://moodle.org/mod/forum/discuss.php?d=196469 passing the Username?]&lt;br /&gt;
# More flexibility with passing appropriate roles&lt;br /&gt;
# Support for success and log messages on return URL&lt;br /&gt;
If you know of any missing from this list then please add a comment or get in touch; no promises that it will get included!&lt;br /&gt;
&lt;br /&gt;
==User interface changes==&lt;br /&gt;
It is anticipated that the LTI 2 functionality can be added on top of the existing LTI 1.1 support with minimal impact on the current user interface.  This section describes the current proposals for the new registration workflows.&lt;br /&gt;
&lt;br /&gt;
===Plugin settings page (existing)===&lt;br /&gt;
# Move the &amp;quot;Add external tool configuration&amp;quot; link outside the &amp;quot;Active&amp;quot; tab and place below the tool list (may need to go above to save scrolling when the list of tools is long)&lt;br /&gt;
# Add a new link labelled something like &amp;quot;Register new external tool&amp;quot; which can be used to initiate the tool registration process&lt;br /&gt;
# Add a new tab set to list enabled and disabled services with icon to toggle their current status (by default a new service would be disabled)&lt;br /&gt;
See also &amp;quot;Registration process&amp;quot; section below.&lt;br /&gt;
&lt;br /&gt;
===Register new external tool page (new)===&lt;br /&gt;
New page allowing the following data entry:&lt;br /&gt;
; registration URL : simple text box&lt;br /&gt;
; select capabilities to be offered to the tool provider : textarea of selected capabilities, textarea of potential capabilities, buttons to add and remove capabilities from selection&lt;br /&gt;
; select services to be made available for use by the tool provider : textarea of selected services, textarea of potential services, buttons to add and remove services from selection&lt;br /&gt;
; option to initiate the registration process : button&lt;br /&gt;
; option to cancel the process : button&lt;br /&gt;
Initiating the registration would generate a random key and secret and redirect the administrator to the tool provider using a ToolProxyRegistrationRequest message.  The next part of the process is dependent upon the implementation by the tool provider based on their business rules.  It would, however, depend upon the provision of a Tool Consumer Profile service; the profile provided would be based on the capabilities and services selected on this page (i.e. would be specific to a registration request).  On completion the tool provider will call the Tool Proxy service.&lt;br /&gt;
&lt;br /&gt;
===Registration process===&lt;br /&gt;
Once initiated a Tool Proxy registration will have one of the following states:&lt;br /&gt;
# created&lt;br /&gt;
# in process&lt;br /&gt;
# completed&lt;br /&gt;
# rejected&lt;br /&gt;
# cancelled&lt;br /&gt;
A rejected or cancelled registration would be logged but not remain visible in the UI.  A new tab would be required on the Plugin settings page for any &amp;quot;in process&amp;quot; registrations (initiated but not yet completed by the creation of a tool proxy).  An icon would be included next to each link to cancel a registration.  A completed registration will generate a tool proxy associated with each of the tools (resource handlers) it specifies (which would be added to the &amp;quot;Pending&amp;quot; tab on the Plugin settings page).&lt;br /&gt;
&lt;br /&gt;
===Managing tools===&lt;br /&gt;
Once a Tool Proxy has been accepted its resource handlers will be added as if they were external tools created manually using the current LTI 1 process.  Their initial state will be pending; an administrator must enable them to make them available.  They will appear to instructors (and learners) just like an LTI 1 external tool - there is no need for them to see any difference.  The only difference will be behind the scenes when a launch request is made, the launch parameters will be determined on the basis of the resource handler definition from the tool proxy rather than being a generic LTI 1 launch.  Support would also be added for custom parameter substitution variables which could/would also be available to LTI 1 launches.&lt;br /&gt;
&lt;br /&gt;
==Database changes==&lt;br /&gt;
It is anticipated that the addition of LTI 2 support will require the following database changes:&lt;br /&gt;
* new table to capture details of tool proxies&lt;br /&gt;
* new fields to lti_types table to record:&lt;br /&gt;
** foreign key for tool proxy&lt;br /&gt;
** enabled capabilities&lt;br /&gt;
** launch parameters&lt;br /&gt;
** icon and secureicon URLs&lt;br /&gt;
* new table to record tool settings&lt;br /&gt;
&lt;br /&gt;
===lti_tool_proxies table===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| Primary key&lt;br /&gt;
|-&lt;br /&gt;
| regurl&lt;br /&gt;
| text&lt;br /&gt;
| Registration URL&lt;br /&gt;
|-&lt;br /&gt;
| state&lt;br /&gt;
| tinyint(2)&lt;br /&gt;
| Current state of tool proxy processing&lt;br /&gt;
|-&lt;br /&gt;
| guid&lt;br /&gt;
| varchar(255)&lt;br /&gt;
| Consumer key&lt;br /&gt;
|-&lt;br /&gt;
| secret&lt;br /&gt;
| varchar(255)&lt;br /&gt;
| Shared secret&lt;br /&gt;
|-&lt;br /&gt;
| capabilityoffered&lt;br /&gt;
| text&lt;br /&gt;
| Capabilities offered to Tool Provider&lt;br /&gt;
|-&lt;br /&gt;
| serviceoffered&lt;br /&gt;
| text&lt;br /&gt;
| Services offered to Tool Provider&lt;br /&gt;
|-&lt;br /&gt;
| toolproxy&lt;br /&gt;
| text&lt;br /&gt;
| Copy of agreed Tool Proxy (JSON)&lt;br /&gt;
|-&lt;br /&gt;
| createdby&lt;br /&gt;
| int(10)&lt;br /&gt;
| ID of user which initiated the registration process&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
| Date/time at which the record was created&lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
| Date/time at which the record was last modified&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===lti_types table===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| toolproxyid&lt;br /&gt;
| int(10)&lt;br /&gt;
| Primary key of related tool proxy (null for LTI 1 tools)&lt;br /&gt;
|-&lt;br /&gt;
| enabledcapability&lt;br /&gt;
| text&lt;br /&gt;
| Enabled capabilities (null for LTI 1 tools)&lt;br /&gt;
|-&lt;br /&gt;
| parameter&lt;br /&gt;
| text&lt;br /&gt;
| Launch parameters (null for LTI 1 tools)&lt;br /&gt;
|-&lt;br /&gt;
| icon&lt;br /&gt;
| text&lt;br /&gt;
| URL to icon file&lt;br /&gt;
|-&lt;br /&gt;
| secureicon&lt;br /&gt;
| text&lt;br /&gt;
| Secure URL to icon file&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===lti_tool_settings===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| Primary key&lt;br /&gt;
|-&lt;br /&gt;
| toolproxyid&lt;br /&gt;
| int(10)&lt;br /&gt;
| Primary key of related tool proxy&lt;br /&gt;
|-&lt;br /&gt;
| course&lt;br /&gt;
| int(10)&lt;br /&gt;
| Primary key of course (null for system-wide settings)&lt;br /&gt;
|-&lt;br /&gt;
| coursemoduleid&lt;br /&gt;
| int(10)&lt;br /&gt;
| Primary key of course module - tool link added to course (null for system-wide and context-wide settings)&lt;br /&gt;
|-&lt;br /&gt;
| name&lt;br /&gt;
| varchar(255)&lt;br /&gt;
| Setting name&lt;br /&gt;
|-&lt;br /&gt;
| value&lt;br /&gt;
| varchar(255)&lt;br /&gt;
| Setting value&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Defining services==&lt;br /&gt;
The goal is to enable the list of available services to be extensible, this includes the Tool Consumer Profile, Tool Proxy and Tool Settings services which are required elements of LTI 2.0.  A service is an endpoint to which requests may be sent; these requests send or receive resources of a specified media type.&lt;br /&gt;
&lt;br /&gt;
===Service definitions===&lt;br /&gt;
* Properties:&lt;br /&gt;
** ID - unique ID for service&lt;br /&gt;
** Name - a display name for service&lt;br /&gt;
** IsEnabled - whether the service is currently enabled&lt;br /&gt;
** Resources - list of media types associated with the service&lt;br /&gt;
** Endpoint - URL for service requests&lt;br /&gt;
* Methods:&lt;br /&gt;
** ParseValue - parse a custom parameter value for substitution variables defined by the service and/or its resources&lt;br /&gt;
** CheckSignature - check the OAuth signature for a request received&lt;br /&gt;
&lt;br /&gt;
===Resource definitions===&lt;br /&gt;
* Properties:&lt;br /&gt;
** ID - unique ID for resource&lt;br /&gt;
** Template - URL template for service requests&lt;br /&gt;
** Media types - list of supported media types&lt;br /&gt;
** Methods - supported HTTP methods&lt;br /&gt;
** Capabilities - names of available capabilities&lt;br /&gt;
** Parameters - values of parameters included in request template&lt;br /&gt;
* Methods:&lt;br /&gt;
** Endpoint - fully qualified URL&lt;br /&gt;
** ParseValue - parse a custom parameter value for substitution variables defined by the resource&lt;br /&gt;
&lt;br /&gt;
===Installing services===&lt;br /&gt;
The initial approach will be to try to implement the above requirements using the existing [https://docs.moodle.org/dev/External_tool LTI Source Plugins] functionality.&lt;br /&gt;
&lt;br /&gt;
==Tasks==&lt;br /&gt;
* registration page&lt;br /&gt;
* defining services&lt;br /&gt;
* tool consumer profile service&lt;br /&gt;
* tool proxy service&lt;br /&gt;
* tool settings service&lt;br /&gt;
* enable/disable tools&lt;br /&gt;
* generate launch request (including custom parameter substitution variables)&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Improve_SCORM_2004_Support&amp;diff=61065</id>
		<title>Improve SCORM 2004 Support</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Improve_SCORM_2004_Support&amp;diff=61065"/>
		<updated>2021-08-10T15:11:48Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Improve SCORM 2004 Support&lt;br /&gt;
|state = Community Bonding&lt;br /&gt;
|tracker = MDL-7068&lt;br /&gt;
|discussion = &lt;br /&gt;
|assignee = Mayank Gupta&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;GSOC&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt; &#039;12&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
==Abstract==&lt;br /&gt;
This document is the specification for Improving SCORM 2004 Support in Moodle, a Google Summer Of Code &#039;&#039;(GSoC)&#039;&#039; 2012 project.&lt;br /&gt;
The &#039;&#039;goal&#039;&#039; of this project is to work towards achieving full SCORM 2004 4th Edition compliance in Moodle without the need of any external plugins, that is, improving the support for SCORM 2004 content packages in Moodle.&lt;br /&gt;
&lt;br /&gt;
The project mentor is [http://moodle.org/user/profile.php?id=21591 Dan Marsden] and the program administrator is [http://moodle.org/user/view.php?id=381842 Michael de Raadt].&lt;br /&gt;
&lt;br /&gt;
==Context==&lt;br /&gt;
The project will improve the SCORM 2004 support in Moodle by using the [https://docs.moodle.org/dev/SCORM_Test_Harness SCORM Test Harness]. The automated test framework will help by automating the execution of SCORM 2004 tests in Moodle and thus, will help in identify the issues with SCORM 2004 support in Moodle.&lt;br /&gt;
This project will also indirectly help in improving the SCORM Test Harness itself, as by getting the Test Harness into action bugs would be identified and fixed in the Test Harness.&lt;br /&gt;
&lt;br /&gt;
In order for Moodle to be SCORM 2004 4th Edition compliant and pass all the 189 ADL SCORM 2004 conformance test packages, it needs to adhere to the specifications laid down by [http://www.adlnet.gov/wp-content/uploads/2011/07/SCORM_2004_4ED_v1_1_Doc_Suite.zip ADL SCORM 2004 &#039;&#039;4th Edition&#039;&#039;]. &lt;br /&gt;
The specification can be divided into three sub-specifications as - &lt;br /&gt;
* Content Aggregation Model &#039;&#039;&#039;(CAM)&#039;&#039;&#039;&lt;br /&gt;
* The Run-Time Environment &#039;&#039;&#039;(RTE)&#039;&#039;&#039;&lt;br /&gt;
* Sequencing and Navigation specification &#039;&#039;&#039;(SN)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Content Aggregation Model===&lt;br /&gt;
The Content Aggregation Model sub-specification of SCORM 2004 4th Edition specifies how SCORM 2004 content developers should package their content so that the packages can be imported into the LMS. According to SCORM 2004 specification the content developers should package the content in a self-contained directory or a ZIP file which is also called a &#039;&#039;&#039;Package Interchange File (PIF)&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
SCORM 2004 specifies that the packaged ZIP file should always contain an XML file with the name - &#039;&#039;&#039; &#039;imsmanifest.xml&#039; &#039;&#039;&#039;. This imsmanifest.xml file also called the manifest file should be located in the root of the ZIP file. The content developers have to make sure that this manifest file contains all the information the LMS would need to successfully deliver the SCORM 2004 content to the content viewers.&lt;br /&gt;
&lt;br /&gt;
The manifest file divides the course into one or more parts called SCOs, which in other words represents the activity tree for the course content. The manifest file contains an XML representation of the activity tree of the package, information about how to launch each SCO, and optional metadata that would describe the course and its part.&lt;br /&gt;
As a LMS it is the responsibility of Moodle&#039;s &amp;quot;SCORM module&#039;s code&amp;quot; to correctly parse the manifest file, store all the required information of the package in the database. &lt;br /&gt;
&lt;br /&gt;
====Current State====&lt;br /&gt;
The file &#039;&#039;&#039;/mod/scorm/datamodels/scormlib.php&#039;&#039;&#039; has the code that parses the manifest file. &lt;br /&gt;
Currently this file is not able to parse all the CAM definitions according to SCORM 2004 4th Edition Specifications. &lt;br /&gt;
For instance, the current code of &#039;&#039;&#039;scormlib.php&#039;&#039;&#039; is not able to parse correctly the &#039;&#039;&#039;ADLCP:DATA&#039;&#039;&#039;, and &#039;&#039;&#039;ADLCP:MAP&#039;&#039;&#039; sections of the manifest file. These sections define the &#039;&#039;&#039;Inter-SCO Storage Data Model Extension&#039;&#039;&#039;; that was introduced in ADL SCORM 2004 4th Edition specification. &lt;br /&gt;
Other sections of the manifest file that scormlib.php fails to parse successfully will be identified and resolved during the course of the project by running the SCORM Test Harness for individual SCORM 2004 conformance packages.&lt;br /&gt;
&lt;br /&gt;
===Run-Time Environment===&lt;br /&gt;
The Run-Time Environment (RTE) sub-specification of SCORM 2004 specification specifies how the LMS should launch the content package within itself. The RTE states that the SCORM 2004 content package should be launched within Moodle in a web browser as a new window or within a &#039;&#039;&#039;frameset&#039;&#039;&#039; in the same window. The RTE specification specifies that all the content in the SCORM 2004 package should be web deliverable and is always launched in a web browser. It also specifies that the LMS should launch one SCO at a time.&lt;br /&gt;
&lt;br /&gt;
In order to allow communication between the SCORM 2004 content package more specifically the launched SCO of the content package and the LMS; the LMS should provide an &#039;&#039;&#039;ECMAScript&#039;&#039;&#039; (JavaScript) API through which the SCO can communicate with it. All communication between the SCO and the LMS can take place through this JavaScript API only, that is, the content package can by no means communicate with the LMS through form posts, database access (read/write), web services or any other mechanism.&lt;br /&gt;
As a SCO can communicate only through the JavaScript API, the LMS  provides the JavaScript object of the API at a specific location within the browsers&#039; DOM. This API object has the special name of &#039;&#039;&#039; &#039;API_1484_11&#039; &#039;&#039;&#039; for SCORM 2004.&lt;br /&gt;
It is the responsibility of the content/SCO to locate this API object and then use it for all the communications it needs to do with the LMS. RTE specifies that only the SCO can initiate the communication as the LMS acts as a passive entity which is simply responding to the API calls made by the SCO. &lt;br /&gt;
&lt;br /&gt;
The API provides a set of eight functions that permit the exchange of data with the LMS. These functions are -&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Function&lt;br /&gt;
! Return Type&lt;br /&gt;
! Remarks&lt;br /&gt;
|-&lt;br /&gt;
| Initialize( “” )&lt;br /&gt;
| bool&lt;br /&gt;
| it indicates to the LMS that the content would like to begin a communication session.&lt;br /&gt;
|-&lt;br /&gt;
| Terminate( “” )&lt;br /&gt;
| bool&lt;br /&gt;
| it indicates to the LMS that the content has finished communicating&lt;br /&gt;
|-&lt;br /&gt;
| GetValue( element : CMIElement )&lt;br /&gt;
| string&lt;br /&gt;
| it allows the SCO/content to data from the LMS&lt;br /&gt;
|-&lt;br /&gt;
| SetValue( element : CMIElement, value : string)&lt;br /&gt;
| string&lt;br /&gt;
| it allows the SCO/content to persist data to the LMS.&lt;br /&gt;
|-&lt;br /&gt;
| Commit( “” )&lt;br /&gt;
| bool&lt;br /&gt;
| it is used by the SCO/content to signal the LMS that a significant chuck of data has been saved and that the LMS should ensure the data is properly persisted&lt;br /&gt;
|-&lt;br /&gt;
| GetLastError()&lt;br /&gt;
| CMIErrorCode&lt;br /&gt;
| it allows to determing if the last SCORM API call caused an error&lt;br /&gt;
|-&lt;br /&gt;
| GetErrorString( errorCode : CMIErrorCode )&lt;br /&gt;
| string&lt;br /&gt;
| it return a textual description of what the passed error code means&lt;br /&gt;
|-&lt;br /&gt;
| GetDiagnostic( errocCode : CMIErrorCode )&lt;br /&gt;
| string&lt;br /&gt;
| it returns detailed information about the prior error that can be useful in detecting the problem.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The Computer Managed Instruction or &#039;&#039;&#039;CMI&#039;&#039;&#039; data model provides a list of data elements which can be read and written using the API. Each data model element has its own meaning.&lt;br /&gt;
&lt;br /&gt;
Every SCO in a content package has its own set of run-time data. These data model elements have different values for different SCOs within a content package.&lt;br /&gt;
Before SCORM 2004 4th edition the RTE data model definitions came into existence these data model elements could not be shared across SCOs of the same or different content package.&lt;br /&gt;
When the content user or learner starts a new attempt on a SCO, the data model element&#039;s values are reset to the default values at the start of the new attempt. These data models have different default values and can be of either &#039;&#039;&#039;read-only&#039;&#039;&#039; or both read and &#039;&#039;&#039;write&#039;&#039;&#039; type.&lt;br /&gt;
&lt;br /&gt;
Some examples SCORM 2004 RTE data model elements include the &#039;&#039;&#039;cmi.completion_status&#039;&#039;&#039; element - that saves the status of the SCO  (completed or incomplete), &#039;&#039;&#039;cmi.success_status&#039;&#039;&#039; (passed or failed), the score of the learner, a bookmark to track the learner’s location, and the total amount of time the learner spent in the SCO.&lt;br /&gt;
&lt;br /&gt;
However, apart from the non-sharable data model elements defined before, the SCORM 2004 4th Edition RTE Data Model definitions define the &lt;br /&gt;
&#039;&#039;&#039;adl.data&#039;&#039;&#039; data model elements that provide the unique ability to share sets of data across the SCOs.&lt;br /&gt;
&lt;br /&gt;
====Current State====&lt;br /&gt;
The file &#039;&#039;&#039;/mod/scorm/datamodels/scorm_13.js.php&#039;&#039;&#039; has the code to deal with the data model elements that a SCO would require.&lt;br /&gt;
This code needs to be extended to support the data models defined by the SCORM 2004 4th Edition Run-Time Envirnoment Data Model definition. These data model elements mainly include adl.data elements - Inter-SCO Storage Data Model Extension.&lt;br /&gt;
Some progress has already been made on the tracker issue MDL-28805 - ADL TEST: Data Model Implementation (DMI).&lt;br /&gt;
While trying to fix the mentioned bug, a number of related issues that needed to be resolved before the bug MDL-28805 could be closed were identified. These bugs were - MDL-30666, MDL-30576, MDL-30577, MDL-30578, MDL-30579, MDL-30645.&lt;br /&gt;
As mentioned above, during the course of the project the data model code would be extended to support SCORM 2004 4th Edition Run-Time Environment Data Model definitions and other &#039;&#039; &#039;buggy areas&#039; &#039;&#039; would be identified by running the SCORM Test Harness for SCORM 2004 Conformance packages issues would be reported and patches will be provided.&lt;br /&gt;
&lt;br /&gt;
===Sequencing And Navigation===&lt;br /&gt;
&lt;br /&gt;
The Sequencing and Navigation sub-specification of SCORM 2004 4th Edition specification allows content developers to &#039;&#039;&#039;override&#039;&#039;&#039; the default navigation of SCOs and enable them to govern how the content user/learner is allowed to navigate between various SCOs in the content package and also how the progress data is &#039;&#039;&#039;rolled up&#039;&#039;&#039; to the course level of the content package.&lt;br /&gt;
&lt;br /&gt;
The content developers lay down the sequencing rules in the imsmanifest.xml file or the manifest file, in the root directory of the PIF. These rules in-turn determine which &#039;&#039;&#039;navigational controls&#039;&#039;&#039; should the LMS provide to the content user/learner, that is, whether or not a navigable table of contents &#039;&#039;&#039;(TOC)&#039;&#039;&#039; should be provided to the learner or just the previous/next buttons should be provided to the learner to navigate from one SCO to another in a linear sequence of SCOs.&lt;br /&gt;
By specifying sequencing and navigation rules in the manifest file the content developer can also specify that certain conditions like some SCOs/activities must be completed before the learner can navigate to the some other SCO/activity. &lt;br /&gt;
The content developer by adhering to the SCORM 2004 Sequence and Navigation specification can also apply a gradient weight to some parts or activities of the content package, that is, if some higher weighted activities when completed by the learner would add more to his total score than when he completes a relatively lower weighted activity. Not only this, the Sequencing and Navigation specifications can allow the content developer to randomly select a different subset of SCOs each time a new attempt is made. &lt;br /&gt;
The SN specification also powers the content developer to forcibly take the learner to initial SCO (that would generally have some instructions).&lt;br /&gt;
&lt;br /&gt;
Every activity of a SCORM 2004 content package has a &#039;&#039;&#039;tracking data&#039;&#039;&#039; and a &#039;&#039;&#039;sequencing definition&#039;&#039;&#039; associated with it. The tracking data has the information about the current state of the activity that is, the score of the learner, the status, etc. The sequencing definition is the set of rules that defines which activity should follow next, that is, which activity should be presented to the learner after he completes the activity depending upon the tracking data of the activity.&lt;br /&gt;
&lt;br /&gt;
The sequencing definition model rules can be subdivided as -&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Sequencing Control Modes&#039;&#039;&#039;&#039;&#039; – these define the type of navigation allowed to the learner, that is navigation through the TOC or linear navigation via previous/next buttons.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Constrain Choice Controls&#039;&#039;&#039;&#039;&#039; – Restrict the activities that the user may select from the table of contents.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Sequencing Rules&#039;&#039;&#039;&#039;&#039; – Specify if-then conditions that determine which activities are available for delivery and which activity should be delivered next.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Limit Conditions&#039;&#039;&#039;&#039;&#039; – Provide limits on the number of times activities can be attempted.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Rollup Rules&#039;&#039;&#039;&#039;&#039; – Specify if-then conditions that determine how status is rolled up to clusters throughout the activity tree.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Rollup Controls&#039;&#039;&#039;&#039;&#039; – Determine which activities participate in status rollup and how their status is weighted in relation to other activities.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Rollup Consideration Controls&#039;&#039;&#039;&#039;&#039; – Provide more precise control over status rollup than do the rollup controls.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Objectives&#039;&#039;&#039;&#039;&#039; – Provide a way to track the status of individual learning objectives and share this status across activities. Objectives are often overloaded and used as variables to control sequencing actions.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Selection Controls&#039;&#039;&#039;&#039;&#039; – Provide a way to specify that only a random subset of the available activities should be delivered.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Randomization Controls&#039;&#039;&#039;&#039;&#039; - Shuffle the order of the activities to be delivered.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Delivery Controls&#039;&#039;&#039;&#039;&#039; – Allow for non-communicative content to be delivered and sequenced.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Completion Threshold Controls&#039;&#039;&#039;&#039;&#039; – Allow the tracking of completion percentage. This was introduced in the SCORM 2004 4th Edition specification.&lt;br /&gt;
:&#039;&#039;&#039;&#039;&#039;Navigation Controls&#039;&#039;&#039;&#039;&#039; - Control which navigational UI elements should be presented by the LMS.&lt;br /&gt;
&lt;br /&gt;
====Current State====&lt;br /&gt;
The code that currently implements Sequencing and Navigation specification of ADL SCORM 2004 specification is in the file &#039;&#039;&#039;/mod/scorm/datamodels/sequencinglib.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The SCORM module currently supports &#039;&#039;&#039;activity restriction&#039;&#039;&#039;, that is, if the content developer has restricted some activities to not to be navigable directly by selecting from the table of contents, the TOC does not allow the learner to do so. Though, the TOC is correctly rendered, there are issues like when the initial SCO/activity is complete and it triggers the continue event, the next SCO is not launched, rather the same initial SCO is launched again.&lt;br /&gt;
In some cases the SCO uses &#039;&#039;&#039;adl.nav.request&#039;&#039;&#039; to navigate to a different location, this also causes the same issue of the SCO being launched again.&lt;br /&gt;
These are just a couple of the many issues that are currently there in the SCORM module to support SCORM 2004 Sequencing and Navigation specification specification.&lt;br /&gt;
&lt;br /&gt;
The bug that holds the next SCO from being launched will be the first issue that would be fixed as the part of the project to improve SCORM 2004 support in Moodle, because, this bug will prevent other SCORM 2004 test packages to load successfuly and thus, would not allow the SCORM 2004 conformance packages to run and test successfully.&lt;br /&gt;
A probable fix for the issue would be to store the structure so that code can continue but learner cannot use continue, TOC, links, etc.&lt;br /&gt;
The above can be implemented by shifting the URLs of the SCO to the id attribute of the spans HTML tags and then making JavaScript to fetch the ids and use them as URLs.&lt;br /&gt;
&lt;br /&gt;
Work is already being done to rewrite the function &#039;&#039;&#039;scorm_get_toc&#039;&#039;&#039; - MDL-32835.&lt;br /&gt;
&lt;br /&gt;
The SCORM Test Harness will help in identifying other Sequencing and Navigation issues in the SCORM module by helping to run the SCORM 2004 conformance test packages automatically.&lt;br /&gt;
&lt;br /&gt;
= Schedule of Deliverables =&lt;br /&gt;
&#039;&#039;&#039;May 31st - 5th June&#039;&#039;&#039;: Fix SN bug that prevents SCOs from loading, and potentially- [http://tracker.moodle.org/browse/MDL-28741 ADL Test: CM-02], [http://tracker.moodle.org/browse/MDL-28743 ADL Test: CM-03], and [http://tracker.moodle.org/browse/MDL-28802 ADL Test: DDM].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6th - 17th June&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28805 ADL Test: DMI], [http://tracker.moodle.org/browse/MDL-28804 ADL Test: DMB], [http://tracker.moodle.org/browse/MDL-28745 ADL Test: CM-04], [http://tracker.moodle.org/browse/MDL-28926 ADL Test: T-01]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;18th - 27th June&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28772 ADL Test: CO-01], [http://tracker.moodle.org/browse/MDL-28773 ADL Test: CO-02], [http://tracker.moodle.org/browse/MDL-28775 ADL Test: CO-03], [http://tracker.moodle.org/browse/MDL-28795 ADL Test: CT-01]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;27th June - 8th July&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28806 ADL Test: MS-01], [http://tracker.moodle.org/browse/MDL-28807 MS-02], [http://tracker.moodle.org/browse/MDL-28808 MS-03], [http://tracker.moodle.org/browse/MDL-28814 OB-01], [http://tracker.moodle.org/browse/MDL-28796 CT-02]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;9th - 15th July&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28854 ADL Test: RU-01], [http://tracker.moodle.org/browse/MDL-28858 ADL Test: RU-02], [http://tracker.moodle.org/browse/MDL-28860 ADL Test: RU-03], [http://tracker.moodle.org/browse/MDL-28862 ADL Test: RU-04]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This will be the midterm evaluation target - A detailed report on the then status of SCORM 2004 support in Moodle, mentioning all improvements and results of the closed issues to the Moodle Community.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;16th July - 22nd July&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28902 ADL Test: SX-02], [http://tracker.moodle.org/browse/MDL-28903 ADL Test: SX-03], [http://tracker.moodle.org/browse/MDL-28904 ADL Test: SX-04], [http://tracker.moodle.org/browse/MDL-28749 CM-05]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;23rd July - 1st August&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28750 ADL Test: CM-06], [http://tracker.moodle.org/browse/MDL-28751 ADL Test: CM-07], [http://tracker.moodle.org/browse/MDL-28779 ADL Test: CO-05], [http://tracker.moodle.org/browse/MDL-28781 ADL Test: CO-06], [http://tracker.moodle.org/browse/MDL-28782 ADL Test: CO-07]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2nd - 12th August&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28797 ADL Test: CT-03], [http://tracker.moodle.org/browse/MDL-28798 ADL Test: CT-04], [http://tracker.moodle.org/browse/MDL-28799 ADL Test: CT-05], [http://tracker.moodle.org/browse/MDL-28757 CM-08], [http://tracker.moodle.org/browse/MDL-28758 ADL Test: CM-09]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;13th - 19th August&#039;&#039;&#039;: Fix SCORM 2004 bugs, potentially- [http://tracker.moodle.org/browse/MDL-28818 ADL Test: OB-02], [http://tracker.moodle.org/browse/MDL-28819 ADL Test: OB-03], [http://tracker.moodle.org/browse/MDL-28822 ADL Test: 0B-04], [http://tracker.moodle.org/browse/MDL-28868 ADL Test: RU-05], [http://tracker.moodle.org/browse/MDL-28906 SX-05]&lt;br /&gt;
&lt;br /&gt;
= Relevant Links =&lt;br /&gt;
*[https://docs.moodle.org/dev/SCORM_Test_Harness SCORM Test Harness]&lt;br /&gt;
*[https://docs.moodle.org/en/SCORM_FAQ SCORM FAQ]&lt;br /&gt;
*[http://www.adlnet.gov/capabilities/scorm/scorm-2004-4th ADL SCORM 2004 4th Edition]&lt;br /&gt;
*[https://docs.moodle.org/dev/GSOC/2012 GSoC 2012 - Moodle]&lt;br /&gt;
&lt;br /&gt;
== Tracker ==&lt;br /&gt;
* [http://tracker.moodle.org/browse/MDL-7608 META: SCORM 2004 compliance + issues]&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Hack-a-thon_2013&amp;diff=61064</id>
		<title>Hack-a-thon 2013</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Hack-a-thon_2013&amp;diff=61064"/>
		<updated>2021-08-10T15:11:48Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Start Date&lt;br /&gt;
| To be announced&lt;br /&gt;
|-&lt;br /&gt;
! End Date&lt;br /&gt;
| To be announced&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What is a Moodle Hack-a-thon?==&lt;br /&gt;
&lt;br /&gt;
A Hack-a-thon is a period of intense community contribution to the Moodle project. Participants are rewarded for their involvement. There is a competitive aspect to the Hack-a-thon to encourage greater involvement.&lt;br /&gt;
&lt;br /&gt;
==Categories of work==&lt;br /&gt;
&lt;br /&gt;
The following categories are specifically targeted as areas of work for the Hack-a-thon.&lt;br /&gt;
&lt;br /&gt;
===Bugs patched===&lt;br /&gt;
&lt;br /&gt;
This category is for the most bugs resolved.&lt;br /&gt;
&lt;br /&gt;
There are two groups in this category, each with separate prize pools.&lt;br /&gt;
&lt;br /&gt;
* Recognised developers (in the [[Tracker#Tracker_groups_and_permissions|jira-developers]] Tracker group)&lt;br /&gt;
* New developers (not in the [[Tracker#Tracker_groups_and_permissions|jira-developers]] group)&lt;br /&gt;
&lt;br /&gt;
Moodle HQ employees are excluded from competing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Points&lt;br /&gt;
| 5 points for every bug + 1 point for every VOTE on that bug (so vote for your favourite bugs!) + 2 points for fixing on all supported branches&lt;br /&gt;
|-&lt;br /&gt;
! Reporting&lt;br /&gt;
| Participants should add themselves and links to their issues to [[Hack-a-thon_2013/Bugs_resolved]]. Participants should provide Git branches on the issue.&lt;br /&gt;
|-&lt;br /&gt;
! Verification&lt;br /&gt;
| Each reported fix will be reviewed by an authorised developer. Fixes may be allowed minor fixes after reviewing.&lt;br /&gt;
|-&lt;br /&gt;
! T-shirt standard&lt;br /&gt;
| 1 verified bug fix&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Dud issues identified===&lt;br /&gt;
&lt;br /&gt;
A [http://en.wikipedia.org/wiki/Dud dud] issue is one that is open, but should be closed, for one of the following reasons.&lt;br /&gt;
* It is a duplicate of another issue in the tracker (either a pre-existing issue or an active issue reported later; the point is that we end up closing one).&lt;br /&gt;
* It was an issue that has been fixed in current versions.&lt;br /&gt;
* It is an issue that has become obsolete because of changes present in current versions.&lt;br /&gt;
* It is not able to be replicated in any reasonable supported environment.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Points&lt;br /&gt;
| 3 points per identified issue (1 point for each additional duplicate after the first)&lt;br /&gt;
|-&lt;br /&gt;
! Reporting&lt;br /&gt;
| Participants should add themselves and links to their issues to [[Hack-a-thon_2013/Dud_issues_closed]]. Participants should comment on each issue they report.&lt;br /&gt;
|-&lt;br /&gt;
! Verification&lt;br /&gt;
| Each reported issue will be checked and closed by authorised person.&lt;br /&gt;
|-&lt;br /&gt;
! T-shirt standard&lt;br /&gt;
| 5 dud issues identified and verified as duds&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Docs updated===&lt;br /&gt;
&lt;br /&gt;
* Most Moodle [[Main_Page|Dev Docs]] API pages updated.&lt;br /&gt;
&lt;br /&gt;
There are numerous API features that are undocumented or out of date.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Points&lt;br /&gt;
| 1 point for each API page updated. 3 points for each API page created.&lt;br /&gt;
|-&lt;br /&gt;
! Reporting&lt;br /&gt;
| Participants should add themselves and links to their updates to [[Hack-a-thon_2013/Docs_updated]]&lt;br /&gt;
|-&lt;br /&gt;
! Verification&lt;br /&gt;
| Each reported page or update will be checked and verified. Changes should be necessary and more than corrections of grammar or spelling.&lt;br /&gt;
|-&lt;br /&gt;
! T-shirt standard&lt;br /&gt;
| 3 updates or 1 page created&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Plugins updated===&lt;br /&gt;
&lt;br /&gt;
* Most Contributed plugins updated&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Points&lt;br /&gt;
| ???&lt;br /&gt;
|-&lt;br /&gt;
! Reporting&lt;br /&gt;
| Participants should add themselves and links to their plugins to [[Hack-a-thon_2013/Plugins_updated]]&lt;br /&gt;
|-&lt;br /&gt;
! Verification&lt;br /&gt;
| ???&lt;br /&gt;
|-&lt;br /&gt;
! T-shirt standard&lt;br /&gt;
| ???&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Prizes and recognition==&lt;br /&gt;
&lt;br /&gt;
Each participant who fulfils the minimum t-shirt standard will receive a limited edition Hack-a-thon t-shirt.&lt;br /&gt;
&lt;br /&gt;
Cash prizes will be awarded for each category (including two prizes for bug fixing). Prizes will be awarded as follows.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| First prize&lt;br /&gt;
| AU$200&lt;br /&gt;
|-&lt;br /&gt;
| Second prize&lt;br /&gt;
| AU$100&lt;br /&gt;
|-&lt;br /&gt;
| Third prize&lt;br /&gt;
| AU$50&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Cash prizes will be paid via Paypal.&lt;br /&gt;
&lt;br /&gt;
Winners in each category will be named in a news item on moodle.org, a feature story on moodle.com and recorded here in the Docs.&lt;br /&gt;
&lt;br /&gt;
The judges decision is final. We reserve the right to disqualify someone if it becomes obvious they are cheating the system (eg. by filing fake reports, setting up fake accounts, reassigning bugs from other people after they are done etc.). &lt;br /&gt;
&lt;br /&gt;
==See also...==&lt;br /&gt;
&lt;br /&gt;
* [[Bugathon]] 2007&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_January_2015&amp;diff=61063</id>
		<title>Developer meeting January 2015</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_January_2015&amp;diff=61063"/>
		<updated>2021-08-10T15:11:47Z</updated>

		<summary type="html">&lt;p&gt;Moodlebot: Text replacement - &amp;quot;class=&amp;quot;nicetable&amp;quot;&amp;quot; to &amp;quot;class=&amp;quot;wikitable&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Developer meetings]] &amp;gt; January 2015 meeting notes&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Time&lt;br /&gt;
| [http://timeanddate.com/worldclock/fixedtime.html?year=2015&amp;amp;month=1&amp;amp;day=20&amp;amp;hour=13&amp;amp;min=0&amp;amp;sec=0 13:00 UTC on Tuesday, 20 January 2015]&lt;br /&gt;
|-&lt;br /&gt;
| Meeting room&lt;br /&gt;
| [https://www.youtube.com/watch?v=JNJMF1l3udM Live stream at YouTube]&lt;br /&gt;
|-&lt;br /&gt;
| Chat&lt;br /&gt;
| [https://moodle.org/local/chatlogs/info.php Regular dev chat]&lt;br /&gt;
|-&lt;br /&gt;
| Twitter&lt;br /&gt;
| [https://twitter.com/search?q=%23moodledev #moodledev]&lt;br /&gt;
|-&lt;br /&gt;
| Event page&lt;br /&gt;
| [https://plus.google.com/events/cn6hb5p6vnjhafraaa8sjttjems Google+ page]&lt;br /&gt;
|-&lt;br /&gt;
| Meeting notes&lt;br /&gt;
| [https://docs.google.com/document/d/1uXHZPSbU3wZzlFj0Qk6ZHMwQ06KalvNdk0pqn2wmt_Q/edit?usp=sharing Google doc]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The meeting will be streamed live on YouTube with chat through the regular Dev chat room and comments on Twitter.&lt;br /&gt;
&lt;br /&gt;
You are encouraged to participate on composing the meeting notes in the shared document (see the link above) while listening to the presenters.&lt;br /&gt;
&lt;br /&gt;
== Agenda ==&lt;br /&gt;
&lt;br /&gt;
=== Moodle JS framework prototypes research (Invited speaker) ===&lt;br /&gt;
&lt;br /&gt;
* by [https://moodle.org/user/profile.php?id=1337843 Damyon Wiese]&lt;br /&gt;
* I will cover a lot here including, Javascript loaders, Javascript Build Tools, Javascript Combo Loading, Javascript Accessible Widget Libraries, Templates for Renderers&lt;br /&gt;
* Please see [[JS Framework Specification]] and [[Render library specification]]&lt;br /&gt;
* Estimated length: 50 minutes&lt;br /&gt;
&lt;br /&gt;
=== Prechecking against Moodle coding guidelines from your command line ===&lt;br /&gt;
&lt;br /&gt;
* by Frédéric Massart&lt;br /&gt;
* The patch precheck job in Moodle continuous integration process - see [[Automated code review]]&lt;br /&gt;
* Short demonstration of the possibility to execute the CI precheck  job from the command line (without the need to use the &#039;cime&#039; label in the tracker), especially when using mdk&lt;br /&gt;
* Estimated length: 5-10 minutes&lt;br /&gt;
&lt;br /&gt;
=== Quizventure game development ===&lt;br /&gt;
&lt;br /&gt;
* by John Okely&lt;br /&gt;
* Short demonstration of the [https://moodle.org/plugins/view/mod_quizgame Quizventure game] module highlighting interesting things you can do with our existing APIs&lt;br /&gt;
* Estimated length: 5-10 minutes&lt;br /&gt;
&lt;br /&gt;
=== Prototype for a new &#039;Send a message&#039; feature ===&lt;br /&gt;
&lt;br /&gt;
* by Frédéric Massart&lt;br /&gt;
* Rather than redirecting you somewhere to send a message inside Moodle, this new feature would open a dialog, etc...&lt;br /&gt;
* Estimated length: 5-10 minutes&lt;br /&gt;
&lt;br /&gt;
=== Development of the quiz fault-tolerant mode ===&lt;br /&gt;
&lt;br /&gt;
* by Tim Hunt&lt;br /&gt;
* This allows the students to continue working on their quiz attempt, even if the network is unreliable, by storing everything on the client-side, and using Ajax when possible. I will try to show some more of the details.&lt;br /&gt;
* If the network connection never comes back, you can download the responses as an ecrypted file, which can later be uploaded ot the server.&lt;br /&gt;
* Work in progress code is at [https://github.com/timhunt/moodle-quizaccess_offlinemode Tim&#039;s github repo]&lt;br /&gt;
* Do we want this in standard Moodle? If so, when, and how do we add it? (It was developed as a plugin while it was an experiment. If it went into standard Moodle it would need to be merged into the main quiz code.)&lt;br /&gt;
* Estimated length: 20 minutes&lt;br /&gt;
&lt;br /&gt;
=== Database foreign keys enforcement ===&lt;br /&gt;
* by Avi Levi, Asaf Ohayon&lt;br /&gt;
* Fixes done on 2.9 Dev branch&lt;br /&gt;
* Tracker : https://tracker.moodle.org/browse/MDL-30799&lt;br /&gt;
* Discussion : https://moodle.org/mod/forum/discuss.php?d=275290&lt;br /&gt;
* GitHub : https://github.com/AdminTheWeb/moodle/commits/MDL-30799-master&lt;br /&gt;
* Estimated length: 10-15 minutes&lt;br /&gt;
&lt;br /&gt;
=== Developer hackfests at upcoming Moodle moots ===&lt;br /&gt;
&lt;br /&gt;
* by Michael de Raadt&lt;br /&gt;
* MoodleMoot IE-UK, May 11-13, Hackfest May 14 [http://mootieuk15.moodlemoot.org/mod/page/view.php?id=3 program]&lt;br /&gt;
* MoodleMoot Australia, July 6-8, Hackfest July 9 [http://mootau15.moodlemoot.org/mod/page/view.php?id=14 program]&lt;br /&gt;
* MoodleMoot US, Aug 4-5, Hackfest August 6 [http://mootus15.moodlemoot.org/ site]&lt;br /&gt;
&lt;br /&gt;
=== Add more ===&lt;br /&gt;
&lt;br /&gt;
* You are welcome to participate at the meeting as a speaker, too. We appreciate any Moodle development experience sharing&lt;br /&gt;
* If you have something you&#039;d like to add to this page, please edit this page or contact [https://moodle.org/user/profile.php?id=1601 David Mudrák].&lt;/div&gt;</summary>
		<author><name>Moodlebot</name></author>
	</entry>
</feed>